使用多线程填充QListWidget对象

时间:2015-05-06 07:57:48

标签: python multithreading user-interface pyqt

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

    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都会崩溃,问题是什么以及如何避免这种情况?

2 个答案:

答案 0 :(得分:1)

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

但请注意,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))

答案 1 :(得分:0)

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

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_())