【问题标题】:Add items to a QListWidget, without UI freezing?将项目添加到 QListWidget,而不冻结 UI?
【发布时间】:2018-06-22 22:21:45
【问题描述】:

我在向 QListWidget 添加大量项目时遇到了一点麻烦,而 UI 却没有立即冻结。到目前为止,这是我所拥有的:

import sys
from PyQt4 import QtGui, QtCore


class Worker(QtCore.QThread):
    def __init__(self):
        super(Worker, self).__init__()

    def run(self):
        for i in range(25000):
            self.emit(QtCore.SIGNAL('ping(QString)'), str(i))


class ListDemo(QtGui.QListWidget):
    def __init__(self):
        super(ListDemo, self).__init__()

    def addToList(self, item):
        self.insertItem(0, str(item))
        #app.processEvents()


class Demo(QtGui.QDialog):
    def __init__(self):
        super(Demo, self).__init__()
        self.setupUI()

    def setupUI(self):
        self.resize(434, 334)
        self.setWindowTitle('Tester')
        self.mainlayout = QtGui.QVBoxLayout(self)
        self.listwidget = ListDemo()
        self.mainlayout.addWidget(self.listwidget)
        self.button = QtGui.QPushButton('P O P U L A T E    L I S T')
        self.mainlayout.addWidget(self.button)
        self.button.clicked.connect(self.populate)

    def populate(self):
        self.listwidget.clear()
        self.worker = Worker()
        self.connect(self.worker, QtCore.SIGNAL("ping(QString)"), self.listwidget.addToList)
        self.worker.start()


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    myapp = Demo()
    sys.exit(myapp.exec_())

如果我启用app.processEvents(),python 会崩溃。如果我忽略它,UI 似乎会在更新之前等待线程完成。

我希望用户界面在每次添加项目时更新。有什么方法可以实现吗?

【问题讨论】:

  • 在这种情况下使用线程不会阻止 gui 冻结。事实上,即使它起作用了,它也可能会让事情变得更慢。根本无法在一个步骤中 有效地将大量项目添加到列表小部件。您需要采取完全不同的方法。最常见的解决方案之一是在滚动列表小部件时分批填充列表。另一种是将列表视图与自定义模型一起使用。 (见here)。
  • 感谢@ekhumoro 的链接。自定义模型似乎绝对是最有效的方法,但要明确的是,我不想一步添加项目。我的示例是我正在处理的更大脚本的一个极其简化的版本,我正在填充的列表可能需要一些时间来填充,所以我希望在填充时绘制每个项目,给人的印象用户界面正在运行,而不是冻结。
  • 在这种情况下,您的问题完全不清楚且具有误导性。第一句话是指“向 QListWidget 添加大量项目”,代码示例正试图做到这一点。我建议您根据您的实际需求重新编写问题并提供更相关的代码示例。
  • 我仍在尝试将大量项目添加到 QListWidget - 或 QListView... 我只是不想一步完成。我认为我的结束语基本上涵盖了这一点。到目前为止,我的示例与我想要实现的目标相去甚远吗?
  • 你现在只是在玩语义游戏。显然,无论您采用哪种方法,都必须逐个添加项目。这是每个批次中添加了多少项目的问题(正如我在第一条评论中已经建议的那样)。您当前的代码尝试转储 25000 个项目的连续流 - 更糟糕的是,它还尝试强制单独的 gui 更新为这些项目中的每一项。工作线程实际上并没有做任何有用的事情,所有耗时的工作仍在主线程内完成(只是以一种极其低效的方式)。

标签: python pyqt pyqt4


【解决方案1】:

运行速度较慢,但​​ UI 会定期刷新并且似乎没有挂起。可能有更好的解决方案,但就目前而言,这似乎可以解决问题。

import sys
import time
from PyQt4 import QtGui, QtCore

class Worker(QtCore.QThread):
    def __init__(self):
        super(Worker, self).__init__()

    def run(self):
        batch = []
        for i in range(25000):
            batch.append(str(i))
            if len(batch) >= 100: # update UI in batches
                time.sleep(0.005) # small time to rest
                self.emit(QtCore.SIGNAL('ping(PyQt_PyObject)'), batch)
                batch = []

        # leftovers
        self.emit(QtCore.SIGNAL('ping(PyQt_PyObject)'), batch)


class MyList(QtGui.QListWidget):
    def __init__(self):
        super(MyList, self).__init__()
        self.setUniformItemSizes(True) #reduces overhead in main thread

    def addToList(self, batch):
        self.insertItems(0, batch[::-1])


class MyWindow(QtGui.QDialog):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.setupUI()

    def setupUI(self):
        self.resize(434, 334)
        self.setWindowTitle('Tester')
        self.mainlayout = QtGui.QVBoxLayout(self)
        self.listwidget = MyList()
        self.mainlayout.addWidget(self.listwidget)
        self.button = QtGui.QPushButton('P O P U L A T E    L I S T')
        self.mainlayout.addWidget(self.button)
        self.button.clicked.connect(self.populate)

    def populate(self):
        self.listwidget.clear()
        self.worker = Worker()
        self.connect(self.worker, QtCore.SIGNAL("ping(PyQt_PyObject)"), self.listwidget.addToList)
        self.worker.start()


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    myapp = MyWindow()
    sys.exit(myapp.exec_())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2013-06-11
    • 1970-01-01
    • 2016-12-20
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多