大屏分屏控制软件
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
10 KiB

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)