QTableWidget 上的 PYQT5 setCellWidget() 会减慢 UI
Posted
技术标签:
【中文标题】QTableWidget 上的 PYQT5 setCellWidget() 会减慢 UI【英文标题】:PYQT5 setCellWidget() on QTableWidget slows down UI 【发布时间】:2020-02-25 14:09:41 【问题描述】:在 QTableWidget()
上使用 PyQT5 中的 setCellWidget()
时,我遇到了性能问题。一旦我的for
-loop 包含来自 SQL 数据库的大约 100 条记录,延迟就会变得明显。大约 500 条记录时,延迟最多需要 3 秒。
我已禁用 setCellWidget()
部分并测试了 20.000 条记录,几乎没有延迟。因此执行和获取查询不会延迟代码。
self.queueTable
是一个 QTableWidget(),有 8 列,行数与存储在变量 tasks
中的查询返回的行数一样多
这是我使用的代码:
def buildQueueInUI(self):
global userAccount
.....
tasks = Query(SQLconn, 'SQLITE', False).readParameterized(QueryStrings.myQueuedJobsList, [userAccount])
for row in tasks:
rowPosition = self.queueTable.rowCount()
self.queueTable.insertRow(rowPosition)
btt=QPushButton('DELETE')
btt.clicked.connect(cancelTask)
self.queueTable.setCellWidget(rowPosition, 0, btt) ##turning this into a comment fixes the slowdown issue
self.queueTable.setItem(rowPosition, 1, Tables.noEditTableWidget(self, str(row[0])))
self.queueTable.setItem(rowPosition, 2, Tables.noEditTableWidget(self, str(row[2])))
....
我读到 QPushButton
是“昂贵的”(Why get's Python with PyQt5 slow when creating a large amount of QPushButtons?) ,但是在使用其他小部件(例如组合框)时问题仍然存在(组合框的不实用代码示例:)
def buildQueueInUI(self):
global userAccount
.....
tasks = Query(SQLconn, 'SQLITE', False).readParameterized(QueryStrings.myQueuedJobsList, [userAccount])
for row in tasks:
rowPosition = self.queueTable.rowCount()
self.queueTable.insertRow(rowPosition)
combo = QComboBox()
combo.addItem("keep")
combo.addItem("remove")
self.queueTable.setCellWidget(rowPosition, 0, combo) ##turning this into a comment fixes the slowdown issue
self.queueTable.setItem(rowPosition, 1, Tables.noEditTableWidget(self, str(row[0])))
self.queueTable.setItem(rowPosition, 2, Tables.noEditTableWidget(self, str(row[2])))
....
只有不使用QPushButton()
或QComboBox()
对QTableWidget
进行setCellWidget()
调用,我才能毫无延迟地呈现表格。
在典型的用例中,大约有 500 - 750 个排队的任务。我怎样才能拥有QPushButton()
而没有setCellWidget()
造成的延迟?我已经有一个cellDoubleClicked.connect
listener 和一个自定义上下文菜单在桌子上,所以这些不是一个选项。
我的系统:
Python 3.7 PYQT5 5.14.1 Windows 10 64 位【问题讨论】:
您可以尝试在 for 循环之前将表的rowCount
设置为类似于 self.queueTable.rowCount()+len(tasks)
的值,而不是在 for 循环中一次插入一行。
它创造了奇迹;谢谢!但是为什么只有结合setWidgetItem才有这样的效果呢?根据您的建议,我将self.queueTable.setRowCount(len(tasks))
放在for
循环的前面,并使用迭代器将每个任务放在不同的行中。如果您将其发布为答案,我可以将其标记为这样。
我对 PyQt5 的内部工作原理了解得不够多,恐怕无法解释时差。尽管如此,我还是发布了我的评论作为答案。
【参考方案1】:
您可以尝试在 for 循环之前设置行数,而不是一次添加一行。例如下面的例子
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QTableWidgetItem
from time import time
class CreateTable(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__(parent)
fill_button_1 = QtWidgets.QPushButton('fill table - set row count')
fill_button_1.clicked.connect(self.buildQueueInUI_1)
fill_button_2 = QtWidgets.QPushButton('fill table - insert rows')
fill_button_2.clicked.connect(self.buildQueueInUI_2)
hlayout = QtWidgets.QHBoxLayout()
hlayout.addWidget(fill_button_1)
hlayout.addWidget(fill_button_2)
self.table = QtWidgets.QTableWidget(self)
self.table.setColumnCount(2)
layout = QtWidgets.QVBoxLayout(self)
layout.addLayout(hlayout)
layout.addWidget(self.table)
def buildQueueInUI_1(self):
nrows = 500
self.table.setRowCount(0)
t0 = time()
last_row = self.table.rowCount()
self.table.setRowCount(nrows+self.table.rowCount())
for i in range(500):
row = last_row+i
button = QtWidgets.QPushButton('Click', self)
button.clicked.connect(lambda _, x=row+1: print('button', x))
self.table.setCellWidget(row, 0, button)
self.table.setItem(row, 1, QTableWidgetItem(f'item row'))
print(f'set row count: time()-t0:.4f seconds')
def buildQueueInUI_2(self):
nrows = 500
self.table.setRowCount(0)
t0 = time()
for i in range(nrows):
row = self.table.rowCount()
self.table.insertRow(row)
button = QtWidgets.QPushButton('Click', self)
button.clicked.connect(lambda _, x=row+1: print('button', x))
self.table.setCellWidget(row, 0, button)
self.table.setItem(row, 1, QTableWidgetItem(f'item row'))
print(f'insert rows: time() - t0:.4f seconds')
if __name__ == "__main__":
app = QApplication([])
win = CreateTable()
win.show()
app.exec_()
输出
set row count: 0.0359 seconds
insert rows: 1.0572 seconds
【讨论】:
以上是关于QTableWidget 上的 PYQT5 setCellWidget() 会减慢 UI的主要内容,如果未能解决你的问题,请参考以下文章
如何在 PyQt5 中设置 QTableWidget 的单元格样式?
如何使用 PYQT5 使 QTableWidget 单元格只读?