py demo2

February 26, 2025

PyQt5 Dock Widget 布局修改实现

问题分析

根据新的要求,需要修改代码,使得:

  • table A 和 table B 分别在两个独立的dock widget中
  • table C 和 table D 在同一个dock widget中
  • table C 和 table D 需要使用两个独立的方法定义

这样的结构可以提高代码的模块化程度,使每个表格的定义和管理更加清晰。

解决方案

我将修改代码,创建三个dock widget,并在第三个dock widget中放置table C和table D。同时,将table C和table D的创建分别放在两个独立的方法中。

import sys from PyQt5.QtWidgets import (QApplication, QMainWindow, QDockWidget, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget, QLabel) from PyQt5.QtCore import Qt, QSize class MainWindow(QMainWindow): def __init__(self): super().__init__() # 设置窗口标题和大小 self.setWindowTitle("四表格Dock Widget布局") self.setMinimumSize(800, 600) # 创建中央部件(虽然不会显示,但QMainWindow需要一个中央部件) central_widget = QWidget() self.setCentralWidget(central_widget) # 创建三个dock widget self.create_table_a_dock() self.create_table_b_dock() self.create_table_cd_dock() # 包含table C和table D的dock widget # 设置dock widget的初始位置 self.setup_dock_layout() def create_table_a_dock(self): """创建表格A的dock widget""" # 创建dock widget self.dock_a = QDockWidget("表格A", self) self.dock_a.setObjectName("TableA") self.dock_a.setAllowedAreas(Qt.AllDockWidgetAreas) # 创建表格 table_a = QTableWidget(10, 5) # 10行5列的表格 table_a.setHorizontalHeaderLabels(["列1", "列2", "列3", "列4", "列5"]) # 添加一些示例数据 for row in range(10): for col in range(5): table_a.setItem(row, col, QTableWidgetItem(f"A-{row},{col}")) # 将表格设置为dock widget的内容 self.dock_a.setWidget(table_a) # 将dock widget添加到主窗口 self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_a) def create_table_b_dock(self): """创建表格B的dock widget""" # 创建dock widget self.dock_b = QDockWidget("表格B", self) self.dock_b.setObjectName("TableB") self.dock_b.setAllowedAreas(Qt.AllDockWidgetAreas) # 创建表格 table_b = QTableWidget(8, 4) # 8行4列的表格 table_b.setHorizontalHeaderLabels(["名称", "数量", "单价", "总价"]) # 添加一些示例数据 for row in range(8): table_b.setItem(row, 0, QTableWidgetItem(f"产品{row+1}")) table_b.setItem(row, 1, QTableWidgetItem(f"{row+2}")) table_b.setItem(row, 2, QTableWidgetItem(f"{(row+1)*10}")) table_b.setItem(row, 3, QTableWidgetItem(f"{(row+1)*(row+2)*10}")) # 将表格设置为dock widget的内容 self.dock_b.setWidget(table_b) # 将dock widget添加到主窗口 self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_b) def create_table_cd_dock(self): """创建包含表格C和表格D的dock widget""" # 创建dock widget self.dock_cd = QDockWidget("表格C和D", self) self.dock_cd.setObjectName("TableCD") self.dock_cd.setAllowedAreas(Qt.AllDockWidgetAreas) # 创建一个容器widget,用于放置两个表格 container = QWidget() layout = QVBoxLayout(container) # 使用独立方法创建表格C和表格D layout.addWidget(QLabel("表格C")) table_c = self.create_table_c() layout.addWidget(table_c) layout.addWidget(QLabel("表格D")) table_d = self.create_table_d() layout.addWidget(table_d) # 设置容器widget为dock widget的内容 self.dock_cd.setWidget(container) # 将dock widget添加到主窗口 self.addDockWidget(Qt.RightDockWidgetArea, self.dock_cd) def create_table_c(self): """创建表格C""" # 创建表格C table_c = QTableWidget(12, 3) # 12行3列的表格 table_c.setHorizontalHeaderLabels(["日期", "事件", "状态"]) # 添加一些示例数据到表格C for row in range(12): table_c.setItem(row, 0, QTableWidgetItem(f"2023-{row+1}-01")) table_c.setItem(row, 1, QTableWidgetItem(f"事件{row+1}")) table_c.setItem(row, 2, QTableWidgetItem("完成" if row % 2 == 0 else "进行中")) return table_c def create_table_d(self): """创建表格D""" # 创建表格D table_d = QTableWidget(6, 6) # 6行6列的表格 table_d.setHorizontalHeaderLabels(["A", "B", "C", "D", "E", "F"]) # 添加一些示例数据到表格D for row in range(6): for col in range(6): table_d.setItem(row, col, QTableWidgetItem(f"D-{row},{col}")) return table_d def setup_dock_layout(self): """设置dock widget的布局""" # 将dock_b放在dock_a下方 self.splitDockWidget(self.dock_a, self.dock_b, Qt.Vertical) # 将dock_cd放在dock_a的右边 self.splitDockWidget(self.dock_a, self.dock_cd, Qt.Horizontal) # 设置初始大小比例 self.resizeDocks([self.dock_a, self.dock_b], [200, 200], Qt.Vertical) self.resizeDocks([self.dock_a, self.dock_cd], [400, 400], Qt.Horizontal) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())

代码说明

  1. 主要修改点

    • 将表格C和表格D的创建分别放在了两个独立的方法中:create_table_c()create_table_d()
    • create_table_cd_dock()方法中调用这两个方法来获取表格实例。
  2. 模块化设计

    • 每个表格都有自己的创建方法,使代码结构更加清晰。
    • 表格A和表格B的创建方法同时负责创建对应的dock widget。
    • 表格C和表格D的创建方法只负责创建表格,然后由create_table_cd_dock()方法将它们放入同一个dock widget。
  3. 方法职责

    • create_table_c():专门负责创建和初始化表格C,返回创建好的QTableWidget实例。
    • create_table_d():专门负责创建和初始化表格D,返回创建好的QTableWidget实例。
    • create_table_cd_dock():负责创建包含表格C和表格D的dock widget,并设置布局。
  4. 布局设置

    • 保持了原有的布局设置逻辑,确保三个dock widget按照预期排列。
    • 在包含表格C和表格D的dock widget内部,使用QVBoxLayout垂直排列两个表格。
  5. 表格数据

    • 每个表格的数据填充逻辑被封装在各自的创建方法中,使代码更加模块化。

使用示例

运行上述代码后,将显示一个包含三个dock widget的窗口:

  1. 左上方是包含表格A的dock widget
  2. 左下方是包含表格B的dock widget
  3. 右侧是包含表格C和表格D的dock widget,两个表格垂直排列

用户可以:

  1. 通过拖动dock widget的标题栏来重新排列它们
  2. 双击dock widget的标题栏使其浮动或重新停靠
  3. 点击dock widget右上角的关闭按钮暂时隐藏它
  4. 调整dock widget之间的分隔线来改变它们的大小

优化建议

  1. 表格样式统一:可以创建一个通用的表格样式设置方法,应用于所有表格,确保界面风格统一。

  2. 表格交互增强:为表格添加排序、筛选、搜索等功能,提高用户体验。

  3. 数据模型分离:使用MVC模式,将数据模型与表格视图分离,使代码更加灵活和可维护。

  4. 配置保存:添加功能来保存和恢复用户的布局偏好和表格设置。

  5. 响应式设计:优化界面在不同屏幕尺寸下的表现,确保良好的用户体验。

  6. 表格间数据交互:如果有需要,可以添加表格间的数据联动功能,例如点击表格A中的某行会在表格C中显示相关数据。