使用多线程填充 QListWidget 对象

Filling QListWidget object using Multi Threading

我有 2 个 QListWidget 列表对象,第一个在显示主 GUI 之前包含一些数据,第二个在从第一个列表中选择某些内容时填充另一个数据...我正在尝试使用多线程用 100 万个项目填充第二个列表,以便在该任务正在进行时不冻结主 GUI windows。

    self.lst1= QtGui.QListWidget(self.groupBox)
    self.lst2= QtGui.QListWidget(self.groupBox)

    self.lst1.itemSelectionChanged.connect(lambda: self.thread_list_filler(idx = 0))

    def thread_list_filler(self, idx):
        if idx == 0:
            th = Thread(target = self.fill_List2)
        th.start()

    def fill_List2(self):
        self.lst2.clear()
        for i in range(1,1000000+1):
            self.lst2.addItem(str(i))

每次我按下 lst1 中的某些项目时,GUI 都会崩溃,这是什么问题以及如何避免这种情况?

您不应该在主线程之外与 gui 元素交互。 IE。您应该在线程中发出一个信号,并将该信号连接到一个插槽,该插槽将执行实际的添加到列表业务。

但是请注意,要将 100 万个项目放入 QListWidget 中是一个巨大的数据量。

无论如何,类似的方法可能会起作用:

class MyWidget(QtGui.QWidget):

    addRequested = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)

        layout = QtGui.QVBoxLayout(self)
        self.groupBox = QtGui.QGroupBox('Test', self)
        layout.addWidget(self.groupBox)

        vlayout = QtGui.QVBoxLayout(self.groupBox)
        self.button = QtGui.QPushButton("Fill it", self.groupBox)
        self.lst2 = QtGui.QListWidget(self.groupBox)
        vlayout.addWidget(self.button)
        vlayout.addWidget(self.lst2)

        self.button.clicked.connect(self.thread_list_filler)
        self.addRequested.connect(self.lst2.addItem)

    def thread_list_filler(self):
        self.lst2.clear()
        th = threading.Thread(target = self.fill_List2)
        th.start()

    def fill_List2(self):
        for i in range(1,1000000+1):
            self.addRequested.emit(str(i))

虽然我问这个问题已经有一段时间了,但这里有一个非常适合我的问题的解决方案。

from PyQt4 import QtGui, QtCore
from qTest import Ui_Form
import sys
from time import sleep

class WorkerThread(QtCore.QThread):
    def __init__(self, parent):
        super(WorkerThread, self).__init__(parent)
        self.stopFlag = False

    def run(self):
        for i in xrange(0, 1000000):
            if self.stopFlag:
                break
            self.emit(QtCore.SIGNAL('addIntoList(int)'), i)
            sleep(0.001)
        self.stopFlag = False

    def stop(self):
        self.stopFlag = True

class TEST(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.ui.pushButton.clicked.connect(self.stopThread)
        self.ui.pushButton_2.clicked.connect(self.close)

        self.lst1 = self.ui.listWidget_1
        self.lst2 = self.ui.listWidget_2

        self.qThread = WorkerThread(self)
        self.connect(self.qThread, QtCore.SIGNAL("addIntoList(int)"), self.addIntoList)

        for i in range(10):
            self.lst1.addItem("%d" % i)
        self.lst1.currentRowChanged.connect(self.thread_list_filler)

    @QtCore.pyqtSlot(int)
    def addIntoList(self, item):
        self.lst2.addItem(str(item))

    def stopThread(self):
        self.qThread.stop()

    def thread_list_filler(self, row):
        if self.qThread.isRunning():
            self.qThread.stop()
            self.qThread.wait()
        self.lst2.clear()
        if row == 0:
            self.qThread.start()


QtGui.QApplication.setStyle('cleanlooks')
font = QtGui.QFont()
font.setPointSize(10)
font.setFamily('Arial')
app = QtGui.QApplication(sys.argv)
app.setAttribute(QtCore.Qt.AA_DontShowIconsInMenus,False)
app.setFont(font)

window = TEST()
window.show()
sys.exit(app.exec_())