Python 向QListWidget添加项目,而不冻结UI?

Python 向QListWidget添加项目,而不冻结UI?,python,pyqt,pyqt4,Python,Pyqt,Pyqt4,我在向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):

我在向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在每次添加项目时都进行更新。有什么办法可以做到这一点吗?

运行起来比较慢,但是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_())

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