s:checkboxlist 设置回显选中

本文深入探讨了Struts框架的核心概念,包括其在MVC架构中的角色、配置方式以及如何使用Struts实现动态网页应用。通过实例讲解,读者可以了解Struts的工作流程、拦截器的使用及如何与数据库交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<s:checkboxlist list="#request.docTypeCodeMap" name="bean.projectPlanTask.docTypeCode" listKey="key" listValue="value" value="%{#request.docTypeCodeList}"></s:checkboxlist>
String[] docTypeCodes = bean.getProjectPlanTask().getDocTypeCode().split(",");
List<String> docTypeCodeList = new ArrayList<>();
for (String string : docTypeCodes) {
    docTypeCodeList.add(string.trim());
}
request.setAttribute("docTypeCodeList", docTypeCodeList);

将保存后的值,拆分存入list,传到前台。

import json import os import threading import PySimpleGUI as sg import telnetlib import time import queue import logging from datetime import datetime import re # ============== 全局配置 ============== DATA_FILE = 'pyremote_config.json' PROJECTS_FILE = 'projects_config.json' END_STR = "ROUTER_MPU /home\x1b[m # " LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s' ENCODING = 'utf-8' BUFFER_SIZE = 4096 CHUNK_SIZE = 10 CHUNK_DELAY = 0.15 COMMAND_DELAY = 0.5 MAX_PORTS = 2 # 支持的最大端口数 # ============== 日志配置 ============== def setup_logger(): """配置日志系统""" logger = logging.getLogger('RemoteControl') logger.setLevel(logging.DEBUG) # 文件处理器 file_handler = logging.FileHandler('remote_control.log') file_handler.setFormatter(logging.Formatter(LOG_FORMAT)) # 控制台处理器 console_handler = logging.StreamHandler() console_handler.setFormatter(logging.Formatter(LOG_FORMAT)) logger.addHandler(file_handler) logger.addHandler(console_handler) return logger logger = setup_logger() # ============== 项目管理类 ============== class ProjectManager: def __init__(self): self.projects = self.load_projects() def load_projects(self): """加载项目配置""" if os.path.exists(PROJECTS_FILE): try: with open(PROJECTS_FILE, 'r') as f: return json.load(f) except Exception as e: logger.error(f"加载项目配置失败: {e}") return {"projects": []} return {"projects": []} def save_projects(self): """保存项目配置""" try: with open(PROJECTS_FILE, 'w') as f: json.dump(self.projects, f, indent=4) return True except Exception as e: logger.error(f"保存项目配置失败: {e}") return False def add_project(self, name, commands): """添加新项目""" project = { "name": name, "commands": commands, "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } self.projects["projects"].append(project) if self.save_projects(): return project return None def update_project(self, index, name, commands): """更新项目""" if 0 <= index < len(self.projects["projects"]): self.projects["projects"][index]["name"] = name self.projects["projects"][index]["commands"] = commands if self.save_projects(): return True return False def delete_project(self, index): """删除项目""" if 0 <= index < len(self.projects["projects"]): del self.projects["projects"][index] return self.save_projects() return False def import_projects(self, file_path): """导入项目配置""" try: with open(file_path, 'r') as f: imported = json.load(f) if "projects" in imported and isinstance(imported["projects"], list): self.projects = imported return self.save_projects() except Exception as e: logger.error(f"导入项目失败: {e}") return False def export_projects(self, file_path): """导出项目配置""" try: with open(file_path, 'w') as f: json.dump(self.projects, f, indent=4) return True except Exception as e: logger.error(f"导出项目失败: {e}") return False def get_project_commands(self, index): """获取项目的命令列表""" if 0 <= index < len(self.projects["projects"]): return self.projects["projects"][index]["commands"] return [] # ============== 指令执行类(多端口支持) ============== class CommandExecutor: def __init__(self, port_id): self.port_id = port_id # 端口标识符 (1, 2, ...) self.tn = None self.is_connected = False self.response = "" self.prev_cmd = "" self.log_queue = queue.Queue() self.lock = threading.Lock() self.stop_event = threading.Event() self.pause_event = threading.Event() self.last_response = "" self.expected_prompt = END_STR self.current_command_index = -1 self.current_command = "" self.total_commands = 0 self.log_file = None # 日志文件对象 self.log_file_path = "" # 日志文件路径 def set_log_file(self, file_path): """设置日志文件路径""" self.log_file_path = file_path try: if self.log_file: self.log_file.close() self.log_file = open(file_path, 'a', encoding=ENCODING) return True except Exception as e: self.log_queue.put(f"打开日志文件失败: {str(e)}") return False def log_to_file(self, message): """记录日志到文件""" if self.log_file: try: timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] self.log_file.write(f"[{timestamp}] [Port {self.port_id}] {message}\n") self.log_file.flush() except Exception as e: self.log_queue.put(f"日志写入失败: {str(e)}") def connect(self, host, port): """连接设备""" try: with self.lock: self.tn = telnetlib.Telnet(host, port, timeout=10) self.is_connected = True self.log_queue.put(f"端口 {self.port_id} 已连接到 {host}:{port}") self.log_to_file(f"Connected to {host}:{port}") # 初始读取以清除欢迎信息 self.read_until_prompt(timeout=3) return True except Exception as e: self.log_queue.put(f"端口 {self.port_id} 连接失败: {str(e)}") return False def disconnect(self): """断开连接""" with self.lock: if self.tn: try: self.tn.close() except: pass self.is_connected = False self.log_queue.put(f"端口 {self.port_id} 连接已断开") self.log_to_file("Disconnected") if self.log_file: try: self.log_file.close() except: pass self.log_file = None def send(self, content): """发送命令(分块发送)""" if not self.is_connected: self.log_queue.put(f"端口 {self.port_id} 错误:未连接到设备") return False try: with self.lock: # 保存当前命令 self.current_command = content # 使用正确的编码发送 encoded_content = content.encode(ENCODING) # 分块发送 chunks = [encoded_content[i:i+CHUNK_SIZE] for i in range(0, len(encoded_content), CHUNK_SIZE)] for chunk in chunks: if self.stop_event.is_set(): self.log_queue.put(f"端口 {self.port_id} 发送已中止") return False while self.pause_event.is_set(): time.sleep(0.1) if self.stop_event.is_set(): return False self.tn.write(chunk) log_msg = f"发送分块: {chunk.decode(ENCODING, errors='replace')}" self.log_queue.put(log_msg) self.log_to_file(log_msg) time.sleep(CHUNK_DELAY) # 发送车符 self.tn.write(b"\r\n") self.log_queue.put(f"端口 {self.port_id} 发送车符") self.log_to_file("Sent ENTER") self.log_queue.put(f"端口 {self.port_id} 完整发送: {content.strip()}") self.log_to_file(f"Sent: {content.strip()}") self.prev_cmd = content return True except Exception as e: self.log_queue.put(f"端口 {self.port_id} 发送命令失败: {str(e)}") self.log_to_file(f"Send error: {str(e)}") return False def read_until_prompt(self, timeout=5): """读取直到遇到提示符""" if not self.is_connected: return "" try: response = self.tn.read_until(self.expected_prompt.encode(ENCODING), timeout=timeout) decoded_response = response.decode(ENCODING, errors='replace') # 移除命令回显 if self.prev_cmd and decoded_response.startswith(self.prev_cmd.strip()): decoded_response = decoded_response[len(self.prev_cmd.strip()):].lstrip() # 移除尾部的提示符 if decoded_response.endswith(self.expected_prompt): decoded_response = decoded_response[:-len(self.expected_prompt)].rstrip() self.last_response = decoded_response # 记录到日志 if decoded_response.strip(): self.log_queue.put(f"端口 {self.port_id} 响应: {decoded_response}") self.log_to_file(f"Response: {decoded_response}") return decoded_response except Exception as e: error_msg = f"端口 {self.port_id} 接收响应失败: {str(e)}" self.log_queue.put(error_msg) self.log_to_file(error_msg) return "" def execute_commands(self, commands): """执行命令序列(增强版)""" if not self.is_connected: self.log_queue.put(f"端口 {self.port_id} 错误:未连接到设备") return False self.stop_event.clear() self.pause_event.clear() self.total_commands = len(commands) self.log_queue.put(f"端口 {self.port_id} 开始执行 {self.total_commands} 条命令") self.log_to_file(f"Starting execution of {self.total_commands} commands") try: for idx, cmd in enumerate(commands): if self.stop_event.is_set(): self.log_queue.put(f"端口 {self.port_id} 命令执行已中止") self.log_to_file("Execution aborted") return False # 设置当前命令索引 self.current_command_index = idx # 检查暂停状态 while self.pause_event.is_set(): time.sleep(0.1) if self.stop_event.is_set(): return False if cmd.strip(): # 跳过空行 # 发送命令 if not self.send(cmd): return False # 等待命令完成 self.read_until_prompt(timeout=10) # 命令间延迟 delay_remaining = COMMAND_DELAY while delay_remaining > 0: if self.stop_event.is_set(): return False if self.pause_event.is_set(): time.sleep(0.1) continue time.sleep(0.1) delay_remaining -= 0.1 self.log_queue.put(f"端口 {self.port_id} 命令执行完成") self.log_to_file("Execution completed") self.current_command_index = -1 return True except Exception as e: error_msg = f"端口 {self.port_id} 命令执行失败: {str(e)}" self.log_queue.put(error_msg) self.log_to_file(error_msg) return False def stop_execution(self): """停止当前执行""" self.stop_event.set() self.log_queue.put(f"端口 {self.port_id} 正在停止执行...") self.log_to_file("Stopping execution") def pause_execution(self): """暂停当前执行""" if not self.pause_event.is_set(): self.pause_event.set() self.log_queue.put(f"端口 {self.port_id} 执行已暂停") self.log_to_file("Execution paused") return True return False def resume_execution(self): """继续执行""" if self.pause_event.is_set(): self.pause_event.clear() self.log_queue.put(f"端口 {self.port_id} 执行已继续") self.log_to_file("Execution resumed") return True return False def get_execution_status(self): """获取执行状态""" return { "port_id": self.port_id, "is_connected": self.is_connected, "is_running": not self.stop_event.is_set() and not self.pause_event.is_set(), "is_paused": self.pause_event.is_set(), "is_stopped": self.stop_event.is_set(), "current_command": self.current_command.strip(), "current_index": self.current_command_index, "total_commands": self.total_commands, "log_file_path": self.log_file_path } # ============== GUI 界面类(多端口支持) ============== class RemoteControlApp: def __init__(self): self.project_manager = ProjectManager() self.default_data = self.load_default_data() self.executors = {} # 端口ID到执行器的映射 self.window = None self.setup_gui() self.running = True # 初始化端口执行器 for port_id in range(1, MAX_PORTS + 1): self.executors[port_id] = CommandExecutor(port_id) def load_default_data(self): """加载默认配置""" default_data = { "IP1": "71.19.0.120", "port1": "1001", "IP2": "71.19.0.120", "port2": "1002", "FTP_IP": "71.19.0.120", "芯片名称": "Hi1260SV100", '发送信息': "", "board_local_ip": "71.19.0.53", 'interval': "1", "start_addr": "", "end_addr": "", "文件FTP路径": "", "log_dir": os.getcwd() # 默认日志目录 } if os.path.exists(DATA_FILE): try: with open(DATA_FILE, 'r') as f: data = json.load(f) default_data.update({k: data[k] for k in default_data if k in data}) except Exception as e: logger.error(f"加载默认配置失败: {e}") with open(DATA_FILE, 'w') as f: json.dump(default_data, f) else: with open(DATA_FILE, 'w') as f: json.dump(default_data, f) return default_data def save_config(self): """保存配置""" try: values = self.window.read()[1] if self.window else {} config = { "IP1": values.get("IP1", self.default_data["IP1"]), "port1": values.get("port1", self.default_data["port1"]), "IP2": values.get("IP2", self.default_data["IP2"]), "port2": values.get("port2", self.default_data["port2"]), "FTP_IP": values.get("FTP_IP", self.default_data["FTP_IP"]), "芯片名称": values.get("芯片名称", self.default_data["芯片名称"]), '发送信息': values.get("发送信息", self.default_data["发送信息"]), "board_local_ip": values.get("board_local_ip", self.default_data["board_local_ip"]), 'interval': values.get("interval", self.default_data["interval"]), "start_addr": values.get("start_addr", self.default_data["start_addr"]), "end_addr": values.get("end_addr", self.default_data["end_addr"]), "文件FTP路径": values.get("文件FTP路径", self.default_data["文件FTP路径"]), "log_dir": values.get("log_dir", self.default_data["log_dir"]) } with open(DATA_FILE, 'w') as f: json.dump(config, f) self.default_data = config return True except Exception as e: logger.error(f"保存配置失败: {e}") return False def create_project_buttons(self): """创建项目按钮区域""" layout = [] projects = self.project_manager.projects["projects"] if not projects: layout.append([sg.Text("没有项目,请添加新项目", text_color='red')]) for i, project in enumerate(projects): row = [ sg.Button(project["name"], key=f'-PROJECT-{i}-', size=(15,1), tooltip=f"创建于: {project['created_at']}\n命令数: {len(project['commands'])}"), sg.Button("一键升级", key=f'-UPGRADE-{i}-', button_color=('white', 'green')), sg.Button("编辑", key=f'-EDIT-{i}-', button_color=('white', 'blue')), sg.Button("删除", key=f'-DELETE-{i}-', button_color=('white', 'red')) ] layout.append(row) # 添加项目管理按钮 layout.append([ sg.Button("添加新项目", key='-ADD-PROJECT-', button_color=('white', 'purple')), sg.Button("导入项目", key='-IMPORT-PROJECTS-'), sg.Button("导出项目", key='-EXPORT-PROJECTS-'), sg.Button("生成模板", key='-CREATE-TEMPLATE-') ]) return layout def edit_project_window(self, index=None): """项目编辑窗口""" project = None if index is not None and 0 <= index < len(self.project_manager.projects["projects"]): project = self.project_manager.projects["projects"][index] layout = [ [sg.Text("项目名称:"), sg.Input(key='-PROJECT-NAME-', default_text=project["name"] if project else "")], [sg.Text("升级指令:")], [sg.Multiline(key='-PROJECT-COMMANDS-', size=(60, 10), default_text='\n'.join(project["commands"]) if project else "", tooltip="每行一个命令,命令将按顺序执行")], [sg.Button("保存", key='-SAVE-PROJECT-'), sg.Button("取消", key='-CANCEL-PROJECT-')] ] window = sg.Window("项目编辑", layout, modal=True) while True: event, values = window.read() if event in (sg.WINDOW_CLOSED, '-CANCEL-PROJECT-'): break elif event == '-SAVE-PROJECT-': name = values['-PROJECT-NAME-'].strip() commands = [cmd.strip() for cmd in values['-PROJECT-COMMANDS-'].split('\n') if cmd.strip()] if not name: sg.popup("项目名称不能为空") continue if index is None: new_project = self.project_manager.add_project(name, commands) if new_project: sg.popup(f"项目 '{name}' 添加成功") break else: if self.project_manager.update_project(index, name, commands): sg.popup(f"项目 '{name}' 更新成功") break sg.popup("操作失败,请查看日志") window.close() return True def setup_gui(self): """设置GUI界面(多端口支持)""" sg.theme('LightBlue1') # 输出区域 output = sg.Multiline( size=(80, 20), key='-OUTPUT-', autoscroll=True, background_color='#f0f0f0', text_color='black' ) # 状态信息区域 status_info = [ sg.Text("当前命令: ", size=(10,1)), sg.Text("无", key='-CURRENT-COMMAND-', size=(40,1), text_color='blue'), sg.Text("进度: ", size=(5,1)), sg.Text("0/0", key='-COMMAND-PROGRESS-', size=(10,1)) ] # 项目列表区域 projects_frame = sg.Frame("项目列表", [ [sg.Column( self.create_project_buttons(), scrollable=True, vertical_scroll_only=True, size=(700, 100), key='-PROJECTS-COLUMN-' )] ], key='-PROJECTS-FRAME-') # 执行控制区域 control_buttons = [ sg.Button('暂停执行', key='-PAUSE-EXECUTION-', button_color=('white', 'orange'), size=(10,1)), sg.Button('继续执行', key='-RESUME-EXECUTION-', button_color=('white', 'green'), size=(10,1)), sg.Button('停止执行', key='-STOP-EXECUTION-', button_color=('white', 'red'), size=(10,1)) ] # 端口连接区域 port_layouts = [] for port_id in range(1, MAX_PORTS + 1): port_layout = [ sg.Text(f'端口 {port_id} IP:', size=(8,1)), sg.Input(key=f"IP{port_id}", default_text=self.default_data[f"IP{port_id}"], size=(15,1)), sg.Text('端口:', size=(5,1)), sg.Input(key=f"port{port_id}", default_text=self.default_data[f"port{port_id}"], size=(8,1)), sg.Button(f'连接{port_id}', key=f'-CONNECT-{port_id}-', button_color=('white', 'green')), sg.Button(f'断开{port_id}', key=f'-DISCONNECT-{port_id}-', button_color=('white', 'red')), sg.Text('●', key=f'-STATUS-LIGHT-{port_id}-', text_color='red', font=('Arial', 12)), sg.Text("未连接", key=f'-CONNECTION-STATUS-{port_id}-') ] port_layouts.append(port_layout) # 日志保存区域 log_layout = [ sg.Text('日志目录:', size=(8,1)), sg.Input(key='log_dir', default_text=self.default_data["log_dir"], size=(40,1)), sg.FolderBrowse('浏览', key='-LOG-BROWSE-'), sg.Button('设置日志目录', key='-SET-LOG-DIR-') ] # 主布局 layout = [ # 端口连接区域 *port_layouts, [projects_frame], status_info, # 执行控制按钮 [sg.Frame("执行控制", [control_buttons], key='-CONTROL-FRAME-')], [sg.Text("发送信息:", size=(8,1)), sg.Input(key='发送信息', size=(50, 1), default_text=self.default_data["发送信息"])], [sg.Button('ROUTER_MPU下发送'), sg.Button('Shell下发送'), sg.Text('每隔', size=(3,1)), sg.Input(key='interval', default_text=self.default_data["interval"], size=(5,1)), sg.Text("秒", size=(2,1)), sg.Button('定时发送'), sg.Button("停止定时发送")], [sg.Button('接收1s')], # [sg.Text('芯片名称:', size=(8,1)), sg.Input(key="芯片名称", default_text=self.default_data["芯片名称"], size=(15,1)), # sg.Text('文件FTP路径:', size=(10,1)), sg.Input(key="文件FTP路径", default_text=self.default_data["文件FTP路径"], size=(30,1))], # # [sg.Text('FTP_IP:', size=(6,1)), sg.Input(key="FTP_IP", default_text=self.default_data["FTP_IP"], size=(15,1)), # sg.Text('单板IP:', size=(6,1)), sg.Input(key="board_local_ip", default_text=self.default_data["board_local_ip"], size=(15,1))], # # [sg.Text("SLT测试用"), sg.Button('重新获取sdk.out'), sg.Button("一键升级MT1"), sg.Button("一键升级MT2")], [sg.Button("使用说明", button_color=('white', 'blue'))], [sg.Text('起始地址:', size=(8,1)), sg.Input(key='start_addr', default_text=self.default_data["start_addr"], size=(12,1)), sg.Text('结束地址:', size=(8,1)), sg.Input(key='end_addr', default_text=self.default_data["end_addr"], size=(12,1)), sg.Button('dump寄存器')], # 日志保存区域 log_layout, [output], [sg.StatusBar("就绪", key='-STATUS-', size=(50, 1))] ] self.window = sg.Window('远程单板连接工具 (多端口)', layout, finalize=True, resizable=True) self.update_status_lights() def update_status_lights(self): """更新所有端口的状态指示灯""" for port_id in self.executors: executor = self.executors[port_id] color = 'green' if executor.is_connected else 'red' status = "已连接" if executor.is_connected else "未连接" self.window[f'-STATUS-LIGHT-{port_id}-'].update(text_color=color) self.window[f'-CONNECTION-STATUS-{port_id}-'].update(status) def update_output(self): """更新输出区域""" output_text = self.window['-OUTPUT-'].get() updated = False # 遍历所有端口的日志队列 for port_id, executor in self.executors.items(): while not executor.log_queue.empty(): try: message = executor.log_queue.get_nowait() output_text += message + '\n' updated = True except queue.Empty: break if updated: self.window['-OUTPUT-'].update(output_text) def update_status(self): """更新状态信息""" # 更新执行状态 for port_id, executor in self.executors.items(): status = executor.get_execution_status() # 更新当前命令示 if status["current_command"] and port_id == 1: # 只示第一个端口的命令 self.window['-CURRENT-COMMAND-'].update(status["current_command"]) # 更新进度示 if status["current_index"] >= 0 and status["total_commands"] > 0: progress_text = f"{status['current_index'] + 1}/{status['total_commands']}" self.window['-COMMAND-PROGRESS-'].update(progress_text) # 更新状态指示灯 color = 'green' if status["is_connected"] else 'red' self.window[f'-STATUS-LIGHT-{port_id}-'].update(text_color=color) self.window[f'-CONNECTION-STATUS-{port_id}-'].update("已连接" if status["is_connected"] else "未连接") # 更新按钮状态(基于第一个端口的状态) if self.executors[1].is_connected: status1 = self.executors[1].get_execution_status() if status1["is_running"]: self.window['-PAUSE-EXECUTION-'].update(disabled=False) self.window['-RESUME-EXECUTION-'].update(disabled=True) self.window['-STOP-EXECUTION-'].update(disabled=False) elif status1["is_paused"]: self.window['-PAUSE-EXECUTION-'].update(disabled=True) self.window['-RESUME-EXECUTION-'].update(disabled=False) self.window['-STOP-EXECUTION-'].update(disabled=False) else: self.window['-PAUSE-EXECUTION-'].update(disabled=True) self.window['-RESUME-EXECUTION-'].update(disabled=True) self.window['-STOP-EXECUTION-'].update(disabled=True) def refresh_project_list(self): """刷新项目列表""" self.window['-PROJECTS-COLUMN-'].update(visible=False) self.window['-PROJECTS-COLUMN-'].update(self.create_project_buttons()) self.window['-PROJECTS-COLUMN-'].update(visible=True) def run(self): """运行主循环(多端口支持)""" last_status_update = time.time() stop_loop = 0 interval = 10000 loop_msg = "" while True: event, values = self.window.read(timeout=100) # 100ms超时 if event == sg.WINDOW_CLOSED: break # 更新输出区域 self.update_output() # 定期更新状态(每0.5秒一次) current_time = time.time() if current_time - last_status_update > 0.5: self.update_status() last_status_update = current_time # 端口连接管理 if event.startswith('-CONNECT-'): port_id = int(event.split('-')[2]) ip_key = f"IP{port_id}" port_key = f"port{port_id}" if values[ip_key] and values[port_key]: if self.executors[port_id].connect(values[ip_key], int(values[port_key])): self.window['-STATUS-'].update(f"端口 {port_id} 已连接") self.update_status_lights() else: sg.popup(f"请输入端口 {port_id} 的IP和端口号") elif event.startswith('-DISCONNECT-'): port_id = int(event.split('-')[2]) self.executors[port_id].disconnect() self.window['-STATUS-'].update(f"端口 {port_id} 已断开") self.update_status_lights() # 日志目录设置 elif event == '-SET-LOG-DIR-': if 'log_dir' in values and values['log_dir']: self.default_data["log_dir"] = values['log_dir'] self.save_config() sg.popup(f"日志目录已设置: {values['log_dir']}") # 项目管理 elif event == '-ADD-PROJECT-': self.edit_project_window() self.refresh_project_list() elif event.startswith('-EDIT-'): index = int(event.split('-')[2]) self.edit_project_window(index) self.refresh_project_list() elif event.startswith('-DELETE-'): index = int(event.split('-')[2]) if self.project_manager.delete_project(index): sg.popup("项目删除成功") self.refresh_project_list() else: sg.popup("项目删除失败") elif event == '-IMPORT-PROJECTS-': file_path = sg.popup_get_file("选择项目配置文件", file_types=(("JSON Files", "*.json"),)) if file_path and self.project_manager.import_projects(file_path): sg.popup("项目导入成功") self.refresh_project_list() else: sg.popup("项目导入失败") elif event == '-EXPORT-PROJECTS-': file_path = sg.popup_get_file("保存项目配置文件", save_as=True, file_types=(("JSON Files", "*.json"),)) if file_path and self.project_manager.export_projects(file_path): sg.popup("项目导出成功") else: sg.popup("项目导出失败") elif event == '-CREATE-TEMPLATE-': self.create_template_file() sg.popup("模板文件已生成: projects_template.json") # 一键升级(多端口支持) elif event.startswith('-UPGRADE-'): index = int(event.split('-')[2]) if index < len(self.project_manager.projects["projects"]): project = self.project_manager.projects["projects"][index] # 选择端口对话框 port_layout = [ [sg.Text(f"选择执行 {project['name']} 的端口:")], *[[sg.Checkbox(f"端口 {port_id}", key=f'-PORT-{port_id}-', default=True)] for port_id in self.executors], [sg.Button("确定"), sg.Button("取消")] ] port_window = sg.Window("选择端口", port_layout, modal=True) port_event, port_values = port_window.read() port_window.close() if port_event == "确定": selected_ports = [port_id for port_id in self.executors if port_values[f'-PORT-{port_id}-']] if not selected_ports: sg.popup("请至少选择一个端口") continue # 设置日志文件 log_dir = self.default_data["log_dir"] timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") project_name_safe = re.sub(r'[\\/*?:"<>|]', "", project["name"]) for port_id in selected_ports: log_file = os.path.join(log_dir, f"{project_name_safe}_port{port_id}_{timestamp}.log") self.executors[port_id].set_log_file(log_file) # 在新线程中执行升级 threading.Thread( target=self.execute_project_upgrade, args=(index, selected_ports), daemon=True ).start() # 执行控制 elif event == '-PAUSE-EXECUTION-': for executor in self.executors.values(): if executor.get_execution_status()["is_running"]: executor.pause_execution() self.window['-STATUS-'].update("执行已暂停") elif event == '-RESUME-EXECUTION-': for executor in self.executors.values(): if executor.get_execution_status()["is_paused"]: executor.resume_execution() self.window['-STATUS-'].update("执行已继续") elif event == '-STOP-EXECUTION-': for executor in self.executors.values(): executor.stop_execution() self.window['-STATUS-'].update("执行已停止") # 其他原有功能... elif event == 'ROUTER_MPU下发送': if self.save_config() and values["发送信息"]: for port_id, executor in self.executors.items(): if executor.is_connected: executor.send(values["发送信息"]) executor.read_until_prompt() elif event == 'Shell下发送': if self.save_config() and values["发送信息"]: for port_id, executor in self.executors.items(): if executor.is_connected: executor.send(values["发送信息"]) executor.read_until_prompt() elif event == '定时发送': if self.save_config() and values["发送信息"] and values["interval"]: try: interval = float(values["interval"]) if interval <= 0: raise ValueError("间隔必须大于0") loop_msg = values["发送信息"] threading.Thread( target=self.periodic_send, args=(loop_msg, interval), daemon=True ).start() except Exception as e: sg.popup(f"无效的间隔: {str(e)}") else: sg.popup("请输入发送信息和有效间隔") elif event == "停止定时发送": for executor in self.executors.values(): executor.stop_execution() # 其他事件处理 elif event == '接收1s': for executor in self.executors.values(): if executor.is_connected: executor.read_until_prompt(timeout=1) elif event == 'dump寄存器': if values["start_addr"] and values["end_addr"]: for executor in self.executors.values(): if executor.is_connected: executor.send(f"dump {values['start_addr']} {values['end_addr']}") executor.read_until_prompt() elif event == '重新获取sdk.out': for executor in self.executors.values(): if executor.is_connected: executor.send("get_sdk.out") executor.read_until_prompt() elif event == '一键升级MT1': for executor in self.executors.values(): if executor.is_connected: executor.send("upgrade_mt1") executor.read_until_prompt() elif event == '一键升级MT2': for executor in self.executors.values(): if executor.is_connected: executor.send("upgrade_mt2") executor.read_until_prompt() elif event == '使用说明': self.show_help() self.running = False for executor in self.executors.values(): executor.disconnect() self.window.close() def execute_project_upgrade(self, index, port_ids): """在指定端口上执行项目升级""" commands = self.project_manager.get_project_commands(index) if commands: # 重置进度示 self.window['-CURRENT-COMMAND-'].update("") self.window['-COMMAND-PROGRESS-'].update("0/0") # 为每个端口启动升级线程 threads = [] for port_id in port_ids: executor = self.executors[port_id] thread = threading.Thread( target=self._execute_upgrade_on_port, args=(executor, commands, port_id), daemon=True ) thread.start() threads.append(thread) # 等待所有线程完成 for thread in threads: thread.join(timeout=300) # 5分钟超时 self.window['-STATUS-'].update("升级任务已完成") else: for port_id in port_ids: self.executors[port_id].log_queue.put("错误:项目没有配置命令") def _execute_upgrade_on_port(self, executor, commands, port_id): """在单个端口上执行升级命令""" self.window['-STATUS-'].update(f"端口 {port_id} 开始升级...") success = executor.execute_commands(commands) self.window['-STATUS-'].update(f"端口 {port_id} 升级{'成功' if success else '失败'}") def periodic_send(self, message, interval): """周期性发送消息(优化版)""" while not self.executors[1].stop_event.is_set(): for executor in self.executors.values(): if executor.is_connected: executor.send(message) executor.read_until_prompt() time.sleep(interval) def show_help(self): """示使用说明(多端口版)""" help_text = f""" === 远程单板连接工具使用说明 (多端口) === 1. 多端口连接管理: - 支持同时连接 {MAX_PORTS} 个端口 - 每个端口独立示连接状态(红:未连接, 绿:已连接) - 每个端口独立保存日志文件 2. 项目升级: - 选择项目后,会弹出端口选择对话框 - 可以为每个选择的端口设置独立的日志文件 - 日志文件保存在指定目录,文件名格式:项目名_portX_时间戳.log 3. 日志管理: - 默认日志目录:{self.default_data.get('log_dir', os.getcwd())} - 可以随时修改日志保存目录 - 每个端口连接会记录详细的操作日志 4. 命令执行控制: - 暂停执行:暂停所有端口的命令执行 - 继续执行:继续所有端口的命令执行 - 停止执行:停止所有端口的命令执行 5. 发送机制: - 命令发送到所有已连接的端口 - 每个端口独立处理响应 - 支持定时发送到所有端口 """ sg.popup(help_text, title="使用说明", font=("Arial", 11)) def create_template_file(self): """创建项目配置模板""" try: template = { "projects": [ { "name": "项目A", "commands": [ "ifconfig eth0 192.168.0.100", "ftpget -u user -p pass 192.168.0.1 /home/firmware.bin firmware.bin", "flash -w 0 0x0000000 0xa000000 0x2000000" ], "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") }, { "name": "项目B", "commands": [ "ifconfig eth0 192.168.0.101", "ping 192.168.0.1", "reboot" ], "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } ] } with open("projects_template.json", 'w') as f: json.dump(template, f, indent=4) return True except Exception as e: logger.error(f"创建模板文件失败: {e}") return False # ============== 主程序入口 ============== if __name__ == "__main__": # 启动应用 try: app = RemoteControlApp() app.run() except Exception as e: logger.exception("应用程序崩溃") sg.popup_error(f"应用程序发生致命错误: {str(e)}") 以上是我的代码,请分析我的代码,在我的代码功能保持不变的情况下,请帮我增加一个需求,链接端口后,当识别端口到的打印有“Press 'Ctrl+T' to skip boot”的字符串时,在1s内模拟键盘敲击Ctrl+T键,并且等待5s后,在该端口下发指令“watchdog -close”,将这个功能包装成一个“自动”按钮,点击后进行上述操作,不点击不进行上述操作,并给出完整代码
最新发布
07-03
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值