import socket import struct import tkinter as tk import threading from udpmsg import * from datetime import datetime from tkinter import font from tkinter import Frame from tkinter.ttk import * class disSys(Frame): def __init__(self,root): super().__init__(root) # 当前接受的消息,用于显示和更新 self.disHVB = msg_disHighVolBusFbMsg() self.disHVBA = msg_disHighAVolBusFbMsg() self.disHVBB = msg_disHighBVolBusFbMsg() self.disLVB = msg_disLowBusFbMsg() # 初始化列框架列表 self.col_frames = [] self.createWidgets() self.root = root self.root.after(2000, self.update_disp) # 启动数据更新定时器 self.update_data_job = None self.start_update_data() def createWidgets(self): # 定义每组的颜色 self.colors = ["#FFC0CB", "#ADD8E6", "#90EE90", "#FFD700"] # 创建自定义字体 self.custom_font = font.Font(family="Arial", size=12, weight='normal') # 创建4个Frame来分组显示元素的值 # 断路器的frame title=list(['高压母线断路器','高电压A母线断路器','高电压B母线断路器','低电压母线断路器']) self.frames = [] for i in range(4): frame = tk.Frame(self, bg=self.colors[i], padx=10, pady=10) # frame.pack(padx=10, pady=10, expand=True, fill='both') title_label = tk.Label(frame, text=title[i],bg=self.colors[i],relief='solid' ,font=("Arial", 16, "bold")) title_label.grid(row=0, column=0, columnspan=4, pady=(2, 2), sticky="nsew") self.frames.append(frame) self.frames[0].grid(row=0, column=0, sticky='nsew') self.frames[1].grid(row=0, column=1, sticky='nsew') self.frames[2].grid(row=1, column=0, sticky='nsew') self.frames[3].grid(row=1, column=1, sticky='nsew') ################################################故障选择######################################################### inputFrame = tk.LabelFrame(self, bg='Azure',text='故障选择',font=self.custom_font ,padx=10, pady=10) inputFrame.grid(row=0, column=2, columnspan=2, padx=2, pady=2, sticky="nsew") # # 添加输入框来更新值 TODO:添加输入框,更新故障信息 self.checkboxes = [] self.checkboxesVar = [] self.faultDict1 = {0:'动力母线绝缘低', 1:'A汇流排绝缘低', 2:'仪表电源失电', 3:'应急电源失电', 4:'DC/DC模块过温'} self.faultDict2 = {0:'仪表电源失电', 1:'应急电源失电', 2:'浸水报警'} self.faultDict3 = {0:'仪表电源失电', 1:'应急电源失电', 2:'仪表汇流排绝缘低'} self.faultDict4 = {0:'仪表失电', 1:'浸水报警'} spl_linenum = 1 for i, dictionary in enumerate([self.faultDict1, self.faultDict2, self.faultDict3, self.faultDict4]): self.checkboxes.append([]) self.checkboxesVar.append([]) spl = Separator(inputFrame, orient='vertical') spl.grid(row=0, column=spl_linenum+i*2, rowspan=5, pady=(2, 2), sticky="nsew") for j, (key, value) in enumerate(dictionary.items()): checkboxVar = tk.IntVar() checkbox = tk.Checkbutton(inputFrame, text=value, variable=checkboxVar,font=self.custom_font,anchor="w", command=lambda i=i, j=j: self.cheak_fault(i, j)) checkbox.grid(row=j, column=i*2, padx=1, pady=1, sticky="nsew") self.checkboxes[i].append(checkbox) self.checkboxesVar[i].append(checkboxVar) ################################################电路状态######################################################### dispFrame = tk.LabelFrame(self, bg='Azure',text='电路状态',font=self.custom_font ,padx=10, pady=10) dispFrame.grid(row=1, column=2, columnspan=2, padx=2, pady=2, sticky="nsew") # 调整输入框的上下边距并居中显示 value = '关闭' self.labelDcDc = tk.Label(dispFrame, text=f"{'DC/DC模块'}:{value}", font=self.custom_font, relief='groove' ,anchor="w") self.labelDcDc.grid(row=0, column=0, padx=1, pady=1, sticky="nsew") self.DcDcbutton = tk.Button(dispFrame, text="TURN", command=self.toggle_DcDc) self.DcDcbutton.grid(row=0, column=1, padx=1, pady=1, sticky="nsew") self.labelWaterInput = tk.Label(dispFrame, text=f"{'冷却水进水阀'}:{value}", font=self.custom_font, relief='groove' ,anchor="w") self.labelWaterInput.grid(row=1, column=0, padx=1, pady=1, sticky="nsew") self.buttonWaterInput = tk.Button(dispFrame, text="TURN", command=self.toggle_WaterInput) self.buttonWaterInput.grid(row=1, column=1, padx=1, pady=1, sticky="nsew") self.labelWaterOutput = tk.Label(dispFrame, text=f"{'冷却水出水阀'}:{value}", font=self.custom_font, relief='groove' ,anchor="w") self.labelWaterOutput.grid(row=2, column=0, padx=1, pady=1, sticky="nsew") self.buttonWaterOutput = tk.Button(dispFrame, text="TURN", command=self.toggle_WaterOutput) self.buttonWaterOutput.grid(row=2, column=1, padx=1, pady=1, sticky="nsew") self.buttonCurrenStateWin = tk.Button(dispFrame, text="显示电路状态", command=self.show_CurrentState) self.buttonCurrenStateWin.grid(row=0, rowspan=3 , columnspan=2 , column=3,padx=10, pady=1, sticky="nsew") # 添加更新按钮 # self.buttonCurrenStateWin = tk.Button(dispFrame, text="自动更新", command=self.update_currentState) # self.buttonCurrenStateWin.grid(row=0, rowspan=3 , columnspan=2 , column=5,padx=10, pady=1, sticky="nsew") # update_btn = tk.Button(btn_frame, text="立即更新", font=state_font, # command=self.update_currentState) # update_btn.pack(fill=tk.X, padx=5, pady=5) ################################################断路器操作######################################################### # 定义四个字典来存储元素的值 self.dict1={'燃料电池断路器':'闭合', '动力锂电池断路器':'闭合', '推进电机断路器':'闭合', '仪表锂电池断路器':'闭合', 'DC/DC5模块断路器':'闭合', '艏部高压配电断路器':'闭合', '艏部FT4/5断路器':'闭合', '艉舵1/2断路器':'闭合', '艉舵3/4断路器':'闭合', 'FB预留断路器':'闭合', 'TYZ预留断路器':'闭合', '预留断路器':'闭合'} self.dict2 = {'艏部FT1-3断路器':'闭合', '启闭机构断路器':'闭合', '桅杆舵机断路器':'闭合', 'XCZ断路器':'闭合', '艏舵断路器':'闭合', '敞开电缸断路器':'闭合'} self.dict3 = {'仪表锂电池断路器':'闭合', '艏部低压断路器':'闭合', 'UNIT4断路器':'闭合', 'DC/DC1断路器':'闭合', '预留断路器1':'闭合', '预留断路器2':'闭合', '艉部应急电池开关':'闭合'} self.dict4 = {'UNIT1断路器':'闭合', 'UNIT2断路器':'闭合', 'UNIT3断路器':'闭合', 'UNIT5断路器':'闭合', '艏部抛载断路器':'闭合', '预留断路器1':'闭合', '预留断路器2':'断开', '艏部应急电池开关':'闭合'} self.labels = [] for i, dictionary in enumerate([self.dict1, self.dict2, self.dict3, self.dict4]): self.labels.append([]) for j, (key, value) in enumerate(dictionary.items()): # 根据元素的值选择颜色 if value == "闭合": color = "green" else: color = "red" label = tk.Label(self.frames[i], text=f"{key}: {value}", fg=color, font=self.custom_font, relief='groove' ,anchor="w") if (j%2==0): label.grid(row=j//2 + 1, column=j%2, padx=1, pady=1,sticky="nsew") else: label.grid(row=j//2 + 1, column=j%2+1, padx=1, pady=1,sticky="nsew") self.labels[i].append(label) # 添加按钮来改变字典中的值 button = tk.Button(self.frames[i], text="TURN", command=lambda i=i, j=j: self.toggle_value(i, j)) if (j%2==0): button.grid(row=j//2+1, column=j%2+1, padx=1, pady=1) else: button.grid(row=j//2+1, column=j%2+2, padx=1, pady=1, sticky="nsew") self.update_disp() # 创建保存电流及电压信息的表格 self.disHVBData = [] self.disHVBAData = [] self.disHVBBData = [] self.disLVBData = [] def update_disp(self): for i, dictionary in enumerate([self.dict1, self.dict2, self.dict3, self.dict4]): for j, (key, value) in enumerate(dictionary.items()): # 根据元素的值选择颜色 if value == "闭合": color = "green" else: color = "red" self.labels[i][j].config(text=f"{key}: {value}", fg=color) def toggle_value(self, i, j): dictionary = [self.dict1, self.dict2, self.dict3, self.dict4][i] key = list(dictionary.keys())[j] if dictionary[key] == "闭合": dictionary[key] = "断开" else: dictionary[key] = "闭合" print(f'{key}操作') self.update_disp() def toggle_DcDc(self): if (self.labelDcDc.cget("text")[-1] == '开'): self.labelDcDc.config(text=f"{'DC/DC模块'}:关闭") else: self.labelDcDc.config(text=f"{'DC/DC模块'}:打开") print('DC/DC模块操作') def toggle_WaterInput(self): if (self.labelWaterInput.cget("text")[-1] == '开'): self.labelWaterInput.config(text=f"{'冷却水进水阀'}:关闭") else: self.labelWaterInput.config(text=f"{'冷却水进水阀'}:打开") print('冷却水进水阀操作') def toggle_WaterOutput(self): if (self.labelWaterOutput.cget("text")[-1] == '开'): self.labelWaterOutput.config(text=f"{'冷却水出水阀'}:关闭") else: self.labelWaterOutput.config(text=f"{'冷却水出水阀'}:打开") print('冷却水出水阀操作') def cheak_fault(self,i,j): #TODO:实现故障更新和选择 print(self.checkboxes[i][j].cget("text"),self.checkboxesVar[i][j].get()) # print(self.checkboxesVar[i][j].get()) def toggle_hex_mode(self): """切换16进制显示模式""" self.hex_mode = not self.hex_mode self.update_currentState() def update_currentState(self): # 更新所有数值显示 for struct, name, entry in self.state_entries: # 获取最新值 value = getattr(struct, name) # 根据显示模式格式化值 if self.hex_mode and isinstance(value, int): display_value = f"0x{value:02X}" else: display_value = str(value) # 更新entry显示 entry.config(state='normal') entry.delete(0, tk.END) entry.insert(0, display_value) entry.config(state='readonly') print('电路状态已更新') def _create_scrollable_column(self, parent_frame, title, data_struct, state_font): """创建带滚动条的列""" col_frame = tk.LabelFrame(parent_frame, text=title, font=state_font, bd=2, relief=tk.GROOVE, padx=5, pady=5) col_frame.grid(row=0, column=len(self.col_frames), padx=5, pady=5, sticky="nsew") col_frame.rowconfigure(0, weight=1) col_frame.columnconfigure(0, weight=1) self.col_frames.append(col_frame) # 创建滚动条容器 canvas = tk.Canvas(col_frame) v_scrollbar = tk.Scrollbar(col_frame, orient="vertical", command=canvas.yview) h_scrollbar = tk.Scrollbar(col_frame, orient="horizontal", command=canvas.xview) # 创建可滚动内容框架 scrollable_frame = tk.Frame(canvas) canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") # 配置滚动区域 def _configure_scrollregion(e): canvas.configure(scrollregion=canvas.bbox("all")) canvas.config(height=min(e.height, 800)) canvas.yview_moveto(0) canvas.xview_moveto(0) scrollable_frame.bind("", _configure_scrollregion) # 配置滚动条 canvas.configure(yscrollcommand=v_scrollbar.set, xscrollcommand=h_scrollbar.set) h_scrollbar.config(command=canvas.xview) v_scrollbar.config(command=canvas.yview) # 布局 canvas.grid(row=0, column=0, sticky="nsew") v_scrollbar.grid(row=0, column=1, sticky="ns") h_scrollbar.grid(row=1, column=0, sticky="ew") # 添加数据项 for name, value in data_struct.__dict__.items(): row_frame = tk.Frame(scrollable_frame) row_frame.pack(fill=tk.X, padx=5, pady=2) name_label = tk.Label(row_frame, text=name, font=state_font, width=30, anchor="w") name_label.pack(side=tk.LEFT, padx=5) entry = tk.Entry(row_frame, font=state_font, width=20) entry.pack(side=tk.RIGHT, padx=5, fill=tk.X, expand=True) entry.insert(0, str(value)) entry.config(state='readonly') self.state_entries.append((data_struct, name, entry)) def show_CurrentState(self): """显示当前电路状态窗口""" # 初始化窗口 self.currentStateWin = tk.Toplevel(self) self.currentStateWin.title("电路状态") self.currentStateWin.geometry("1400x800") self.currentStateWin.minsize(1000, 600) self.currentStateWin.protocol("WM_DELETE_WINDOW", self.on_close_currentState) # 初始化16进制显示模式 self.hex_mode = False # 创建主容器 main_frame = tk.Frame(self.currentStateWin) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 配置网格布局 for i in range(4): main_frame.columnconfigure(i, weight=1) # 创建自定义字体 state_font = font.Font(family="Arial", size=10, weight='bold') # 初始化状态条目列表 self.state_entries = [] self.col_frames = [] # 创建各状态列 self._create_scrollable_column(main_frame, "高压母线", self.disHVB, state_font) self._create_scrollable_column(main_frame, "高电压A母线", self.disHVBA, state_font) self._create_scrollable_column(main_frame, "高电压B母线", self.disHVBB, state_font) self._create_scrollable_column(main_frame, "低电压母线", self.disLVB, state_font) # 配置主框架布局权重 main_frame.rowconfigure(1, weight=1) # 添加底部按钮容器 btn_frame = tk.Frame(main_frame) btn_frame.grid(row=2, column=0, columnspan=4, pady=10, sticky="sew") # 添加更新按钮 update_btn = tk.Button(btn_frame, text="立即更新", font=state_font, command=self.update_currentState) update_btn.pack(side=tk.LEFT, padx=5) # 添加16进制显示切换按钮 hex_btn = tk.Button(btn_frame, text="16进制显示", font=state_font, command=self.toggle_hex_mode) hex_btn.pack(side=tk.LEFT, padx=5) # 启动定时更新 self.update_interval = 1000 # 1秒 self.schedule_update() def on_close_currentState(self): """窗口关闭回调""" if hasattr(self, 'update_job'): self.currentStateWin.after_cancel(self.update_job) self.currentStateWin.destroy() def start_update_data(self): """启动数据更新定时器""" self.update_data_job = self.root.after(500, self._update_data_loop) def stop_update_data(self): """停止数据更新定时器""" if self.update_data_job: self.root.after_cancel(self.update_data_job) self.update_data_job = None def _update_data_loop(self): """定时更新数据""" self.updata_data() self.update_data_job = self.root.after(500, self._update_data_loop) def schedule_update(self): """安排定时更新""" self.update_currentState() self.update_job = self.currentStateWin.after(self.update_interval, self.schedule_update) def updata_data(self): '''通过这个可以更新数据''' if (self.dict1['燃料电池断路器']=='闭合'): self.disHVB.DCB1 = 0x55 else: self.disHVB.DCB1 = 0xAA if (self.dict1['动力锂电池断路器']=='闭合'): self.disHVB.DCB2 = 0x55 else: self.disHVB.DCB2 = 0xAA if (self.dict1['推进电机断路器']=='闭合'): self.disHVB.ZK1 = 0x55 else: self.disHVB.ZK1 = 0xAA if (self.dict1['仪表锂电池断路器']=='闭合'): self.disHVB.ZK2 = 0x55 else: self.disHVB.ZK2 = 0xAA if (self.dict1['DC/DC5模块断路器']=='闭合'): self.disHVB.ZK3 = 0x55 else: self.disHVB.ZK3 = 0xAA if (self.dict1['艏部高压配电断路器']=='闭合'): self.disHVB.ZK4 = 0x55 else: self.disHVB.ZK4 = 0xAA if (self.dict1['艏部FT4/5断路器']=='闭合'): self.disHVB.ZK5 = 0x55 else: self.disHVB.ZK5 = 0xAA if (self.dict1['艉舵1/2断路器']=='闭合'): self.disHVB.ZK6 = 0x55 else: self.disHVB.ZK6 = 0xAA if (self.dict1['艉舵3/4断路器']=='闭合'): self.disHVB.ZK7 = 0x55 else: self.disHVB.ZK7 = 0xAA if (self.dict1['FB预留断路器']=='闭合'): self.disHVB.ZK8 = 0x55 else: self.disHVB.ZK8 = 0xAA if (self.dict1['TYZ预留断路器']=='闭合'): self.disHVB.ZK9 = 0x55 else: self.disHVB.ZK9 = 0xAA if (self.dict1['预留断路器']=='闭合'): self.disHVB.ZK10 = 0x55 else: self.disHVB.ZK10 = 0xAA ###################################################### if (self.dict2['艏部FT1-3断路器']=='闭合'): self.disHVBA.bowFTDevice123CircuitBreaker = 0x55 else: self.disHVBA.bowFTDevice123CircuitBreaker = 0xAA if (self.dict2['启闭机构断路器']=='闭合'): self.disHVBA.actuatorCircuitBreaker = 0x55 else: self.disHVBA.actuatorCircuitBreaker = 0xAA if (self.dict2['桅杆舵机断路器']=='闭合'): self.disHVBA.mastSteeringGearControlBoxCircuitBreaker = 0x55 else: self.disHVBA.mastSteeringGearControlBoxCircuitBreaker = 0xAA if (self.dict2['XCZ断路器']=='闭合'): self.disHVBA.xczCircuitBreaker = 0x55 else: self.disHVBA.xczCircuitBreaker = 0xAA if (self.dict2['艏舵断路器']=='闭合'): self.disHVBA.bowRudderControlBoxCircuitBreaker = 0x55 else: self.disHVBA.bowRudderControlBoxCircuitBreaker = 0xAA if (self.dict2['敞开电缸断路器']=='闭合'): self.disHVBA.openWaterCoverStartCylinderCircuitBreaker = 0x55 else: self.disHVBA.openWaterCoverStartCylinderCircuitBreaker = 0xAA #################################################################### if (self.dict3['仪表锂电池断路器']=='闭合'): self.disHVBB.lithiumBatteryGroupInstrumentCircuitBreaker = 0x55 else: self.disHVBB.lithiumBatteryGroupInstrumentCircuitBreaker = 0xAA if (self.dict3['艏部低压断路器']=='闭合'): self.disHVBB.bowLowVoltageDistributionCircuitBreaker = 0x55 else: self.disHVBB.bowLowVoltageDistributionCircuitBreaker = 0xAA if (self.dict3['UNIT4断路器']=='闭合'): self.disHVBB.unit4CircuitBreaker = 0x55 else: self.disHVBB.unit4CircuitBreaker = 0xAA if (self.dict3['DC/DC1断路器']=='闭合'): self.disHVBB.dcdc1CircuitBreaker = 0x55 else: self.disHVBB.dcdc1CircuitBreaker = 0xAA if (self.dict3['预留断路器1']=='闭合'): self.disHVBB.reservedCircuitBreaker1 = 0x55 else: self.disHVBB.reservedCircuitBreaker1 = 0xAA if (self.dict3['预留断路器2']=='闭合'): self.disHVBB.reservedCircuitBreaker2 = 0x55 else: self.disHVBB.reservedCircuitBreaker2 = 0xAA if (self.dict3['艉部应急电池开关']=='闭合'): self.disHVBB.emergencyLithiumBatteryGroup2CircuitBreaker = 0x55 else: self.disHVBB.emergencyLithiumBatteryGroup2CircuitBreaker = 0xAA ###################################################################### if (self.dict4['UNIT1断路器']=='闭合'): self.disLVB.unit1CircuitBreaker = 0x55 else: self.disLVB.unit1CircuitBreaker = 0xAA if (self.dict4['UNIT2断路器']=='闭合'): self.disLVB.unit2CircuitBreaker = 0x55 else: self.disLVB.unit2CircuitBreaker = 0xAA if (self.dict4['UNIT3断路器']=='闭合'): self.disLVB.unit3CircuitBreaker = 0x55 else: self.disLVB.unit3CircuitBreaker = 0xAA if (self.dict4['UNIT5断路器']=='闭合'): self.disLVB.unit5CircuitBreaker = 0x55 else: self.disLVB.unit5CircuitBreaker = 0xAA if (self.dict4['预留断路器1']=='闭合'): self.disLVB.reservedCircuitBreaker1 = 0x55 else: self.disLVB.reservedCircuitBreaker1 = 0xAA if (self.dict4['预留断路器2']=='闭合'): self.disLVB.reservedCircuitBreaker2 = 0x55 else: self.disLVB.reservedCircuitBreaker2 = 0xAA if (self.dict4['艏部抛载断路器']=='闭合'): self.disLVB.bowPZDeviceCircuitBreaker = 0x55 else: self.disLVB.bowPZDeviceCircuitBreaker = 0xAA if (self.dict4['艏部应急电池开关']=='闭合'): self.disLVB.emergencyLithiumBatteryGroup1CircuitBreaker = 0x55 else: self.disLVB.emergencyLithiumBatteryGroup1CircuitBreaker = 0xAA # a = match.sin(time.time()) print("更新数据") def get_date(self): a = self.disHVB.pack() b = self.disHVBA.pack() c = self.disHVBB.pack() d = self.disLVB.pack() return a,b,c,d if __name__ == "__main__": root = tk.Tk() app = disSys(root) app.pack() root.mainloop()