from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QListWidget, QPushButton, QHBoxLayout, QLineEdit, QMessageBox, QMenu, QAction, QTableWidget, QAbstractItemView) from utils.globals import get_serial_manager from utils.logger import logger from utils.config_manager import ConfigManager from PyQt5.QtCore import Qt class PresetPanel(QWidget): def __init__(self, preset_manager, screen_manager, parent=None): super().__init__(parent) self.preset_manager = preset_manager self.screen_manager = screen_manager # 用来获取当前选中或发送指令 self.init_ui() # --- 新增:实例化配置管理器 --- self.config_manager = ConfigManager() # --- 新增:初始化时尝试加载配置 --- self.load_presets_from_disk() def init_ui(self): layout = QVBoxLayout() # 名称输入和保存按钮 top_layout = QHBoxLayout() self.name_input = QLineEdit() self.name_input.setPlaceholderText("输入预案名称") save_btn = QPushButton("保存当前布局") save_btn.clicked.connect(self.on_save) top_layout.addWidget(self.name_input) top_layout.addWidget(save_btn) # 预案列表 self.list_widget = QListWidget() self.list_widget.addItems(self.preset_manager.presets.keys()) self.list_widget.itemDoubleClicked.connect(self.on_call) # 双击调用 # 操作按钮 btn_layout = QHBoxLayout() call_btn = QPushButton("调用") del_btn = QPushButton("删除") call_btn.clicked.connect(self.on_call) del_btn.clicked.connect(self.on_delete) btn_layout.addWidget(call_btn) btn_layout.addWidget(del_btn) layout.addLayout(top_layout) layout.addWidget(self.list_widget) layout.addLayout(btn_layout) self.setLayout(layout) # 1. 先创建表格对象 self.table_widget = QTableWidget(4, 4) # 请替换为你实际的行列数 self.table_widget.setWindowTitle("分屏布局") # 2. 设置表格属性(现在的 self.table_widget 已经存在了) self.table_widget.setContextMenuPolicy(Qt.CustomContextMenu) self.table_widget.customContextMenuRequested.connect(self.open_context_menu) # 3. 设置选择模式 (之前提到的多选功能) self.table_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) # 4. 将表格加入布局 main_layout = QVBoxLayout() main_layout.addWidget(self.table_widget) self.setLayout(main_layout) # 1. 设置表格的右键菜单策略 self.table_widget.setContextMenuPolicy(Qt.CustomContextMenu) # 2. 连接信号 self.table_widget.customContextMenuRequested.connect(self.open_context_menu) def on_save(self): name = self.name_input.text() if not name: return # 获取当前的布局参数 (这里需要你从 screen_manager 或当前选中状态获取) # 假设 get_current_layout_params() 是你封装好的方法 current_layouts = self.screen_manager.get_current_layout_params() self.preset_manager.save_preset(name, current_layouts) self.list_widget.addItem(name) # 刷新界面 print(f"预案 {name} 保存成功") def on_call(self): try: serial_manager = get_serial_manager() if serial_manager.is_connected: # 发送指令... current_item = self.list_widget.currentItem() if current_item: preset_name = current_item.text() preset_data = self.preset_manager.get_preset(preset_name) if preset_data and 'layouts' in preset_data: for layout in preset_data['layouts']: # 确保参数完整 self.screen_manager.send_mosaic_command( start=layout.get('start', 0), hcount=layout.get('hcount', 1), vcount=layout.get('vcount', 1) ) else: logger.warning("没连上,别发") except Exception as e: print(f"调用预案时出错: {e}") def on_delete(self): """ 处理删除预案的逻辑 """ # 1. 获取当前选中的列表项 current_item = self.list_widget.currentItem() if current_item: # 2. 获取预案名称 preset_name = current_item.text() # 3. 从列表控件中移除 self.list_widget.takeItem(self.list_widget.row(current_item)) # 4. 从数据管理器中删除 if preset_name in self.preset_manager.presets: del self.preset_manager.presets[preset_name] self.preset_manager.save_to_file() # 立即保存到文件 print(f"预案 {preset_name} 已删除") def save_presets_to_disk(self): """ 将当前界面的预案保存到磁盘 """ name = self.name_input.text() if not name: return # 1. 准备数据:遍历所有按钮,把它们的参数抓出来 preset_list = [] current_layouts = self.screen_manager.get_current_layout_params() self.preset_manager.save_preset(name, current_layouts) self.list_widget.addItem(name) # 刷新界面 current_item = self.list_widget.currentItem() print(current_item) if current_item: preset_name = current_item.text() preset_data = self.preset_manager.get_preset(preset_name) print(preset_data) if preset_data and 'layouts' in preset_data: for layout in preset_data['layouts']: preset_data = { "name": preset_name, "start": layout.start_idx, # 假设你存了 "hcount": layout.h_count, "vcount": layout.v_count } # 这里需要根据你实际存储参数的方式修改 # 比如:我之前把参数存到了按钮的属性里 preset_list.append(preset_data) # 2. 交给管家保存 if self.config_manager.save_presets(preset_list): logger.info("💾 预案保存成功") else: logger.error("💾 预案保存失败") def load_presets_from_disk(self): """ 从磁盘加载预案,并重建按钮 """ # 1. 从硬盘读数据 preset_data_list = self.config_manager.load_presets() if not preset_data_list: logger.info("📭 没有找到历史预案,开始新工作") return # 2. 遍历数据,重建按钮 logger.info(f"📂 正在加载 {len(preset_data_list)} 个预案...") for data in preset_data_list: # 调用你创建按钮的函数 # 假设你有一个 create_button(name, start, h, v) 函数 self.create_button( name=data["name"], start=data["start"], hcount=data["hcount"], vcount=data["vcount"] ) # 假设你在 init_ui 里有一个保存按钮 self.btnSave def on_save_clicked(self): """ 当用户点击保存按钮时 """ self.save_presets_to_disk() QMessageBox.information(self, "成功", "当前的预案布局已保存!") # ------------------------------- # 右键菜单核心逻辑 # ------------------------------- def open_context_menu(self, pos): """ 打开右键菜单 :param pos: 鼠标位置 (QPoint) """ # 获取选中的单元格 selected_items = self.table_widget.selectedItems() if not selected_items: return # 创建菜单 menu = QMenu(self) # --- 获取实际的信号列表 --- # 这里去问 manager 要数据 sources = self.preset_manager.get_source_list() if not sources: # 防止列表为空时难看 no_action = QAction("暂无信号源", self) no_action.setEnabled(False) menu.addAction(no_action) else: # 遍历实际的信号列表,创建菜单项 for source in sources: action = QAction(source, self) # 绑定点击事件,传入参数 source action.triggered.connect(lambda checked, s=source: self.handle_source_selected(s, selected_items)) menu.addAction(action) # 在鼠标位置显示菜单 # 注意:pos 是相对于表格的坐标,需要转成全局坐标 menu.exec_(self.table_widget.mapToGlobal(pos)) # ------------------------------- # 菜单点击处理逻辑 # ------------------------------- def handle_source_selected(self, source_name, target_items): """ 处理用户点击了某个信号源 """ # 这里可以弹个确认框,或者直接执行 reply = QMessageBox.question( self, "确认", f"确定将 {len(target_items)} 个分屏切换到 [{source_name}] 吗?", QMessageBox.Yes | QMessageBox.No ) if reply == QMessageBox.Yes: # 执行批量切换逻辑 self.batch_update_layout(source_name, target_items) def batch_update_layout(self, source_name, target_items): """ 批量更新界面和数据 """ for item in target_items: row = item.row() col = item.column() # 1. 更新表格显示 item.setText(f"{source_name}\n({row},{col})") item.setBackground(Qt.cyan) # 高亮显示 # 2. 这里可以更新你的内部数据结构 # 例如:self.current_layout.set_input(row, col, source_name) # 3. 提示成功 self.statusBar().showMessage(f"已批量设置为 {source_name}", 2000)