使用多线程填充 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_())
我有 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_())