首页 > 解决方案 > 将项目添加到 QListWidget,而不冻结 UI?

问题描述

我在将大量项目添加到 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 似乎会在更新之前等待线程完成。

我想要的是每次添加项目时 UI 都会更新。有什么办法可以做到这一点?

标签: pythonpyqtpyqt4

解决方案


运行速度较慢,但​​ 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_())

推荐阅读