PyQT6 QAbstractTableModel复选框操作性能优化问询
PyQt6自定义QAbstractTableModel复选框勾选延迟优化方案
核心问题定位
延迟的主要原因是setData中同步执行数据库写入操作,阻塞了UI线程;其次是数据类型判断、列权限控制等细节上的冗余开销。
具体优化步骤
1. 异步执行数据库操作
把阻塞UI的数据库写入放到子线程,先更新内存数据刷新UI,再异步持久化:
from PyQt6.QtCore import QThread, pyqtSignal class DBWorker(QThread): finished = pyqtSignal() error = pyqtSignal(str) def __init__(self, row_data, column): super().__init__() self.row_data = row_data self.column = column def run(self): try: queries.set_checkbox(self.row_data, self.column) except Exception as e: self.error.emit(str(e)) finally: self.finished.emit() # 修改TableModel的setData方法 def setData(self, index, value, role): if role == Qt.ItemDataRole.CheckStateRole: new_val = value == Qt.CheckState.Checked # 先更新内存数据,立即触发UI刷新 self._data[index.row(), index.column()] = new_val self.dataChanged.emit(index, index) # 异步执行数据库操作,不阻塞UI worker = DBWorker(self._data[index.row()], index.column()) worker.finished.connect(worker.deleteLater) worker.error.connect(lambda err: print(f"数据库操作错误: {err}")) worker.start() return True return False
2. 优化数据判断逻辑与类型
避免字符串类型的布尔值判断,改用numpy布尔数组;同时只对复选框列处理相关逻辑:
def __init__(self, data, headers): super(TableModel, self).__init__() self._data = data self._headers = headers # 缓存复选框起始列索引,避免重复计算 self._checkbox_start_col = len(headers) - 3 def data(self, index, role): if not index.isValid(): return None # PyQt6可直接返回Python类型,无需QVariant value = self._data[index.row(), index.column()] col = index.column() is_checkbox_col = col >= self._checkbox_start_col if role == Qt.ItemDataRole.DisplayRole: return "" if is_checkbox_col else str(value) elif role == Qt.ItemDataRole.CheckStateRole: if is_checkbox_col: return Qt.CheckState.Checked if value else Qt.CheckState.Unchecked elif role == Qt.ItemDataRole.BackgroundRole: if is_checkbox_col: return QtGui.QColor("green") if value else QtGui.QColor("yellow") elif role == Qt.ItemDataRole.TextAlignmentRole: return Qt.AlignmentFlag.AlignCenter
3. 精确控制可勾选列
只让最后3列拥有可勾选属性,减少不必要的角色处理:
def flags(self, index): base_flags = Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled if index.column() >= self._checkbox_start_col: base_flags |= Qt.ItemFlag.ItemIsUserCheckable return base_flags
4. 优化表格初始化时的列宽调整
先隐藏表格再调整列宽,减少重复重绘:
def get_table(self, view, month): """从数据库获取数据并展示在TableView""" deliveries = queries.get_deliveries(month) headers = queries.get_delivery_headers() self.model = TableModel(deliveries, headers) proxymodel = QSortFilterProxyModel() proxymodel.setSourceModel(self.model) view.setModel(proxymodel) view.sortByColumn(0, Qt.SortOrder.AscendingOrder) # 先隐藏表格,减少调整列宽时的重绘次数 view.hide() for x in range(2, len(headers)): view.resizeColumnToContents(x) view.show()
额外建议
- 确保数据库返回的numpy数组中,复选框列的类型为
bool,避免字符串与布尔值的转换开销 - 如果数据量极大,可考虑实现
batchData或使用QSqlTableModel等内置模型的优化特性
内容的提问来源于stack exchange,提问作者Solumath
相关产品推荐
相关产品推荐

