【问题标题】:PyQt QThread MultiThreading does not workPyQt QThread 多线程不起作用
【发布时间】:2015-07-31 12:11:04
【问题描述】:

我有 2 个QListWidget 列表,当从 List1 中选择了某些项目时,正在填充 List2

问题是,在填充 List2 之前,我必须做很多任务,这会使我的 UI 冻结大约 5 秒,这太烦人了,我想让它用 QThread 填充 List2,但它不工作,因为在初始化整个班级之前我我遇到了一个恼人的错误

from ui import Ui_Win
from PyQt4 import QtGui, QtCore

class GenericThread(QtCore.QThread):
    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)

    def __del__(self):
        self.quit()
        self.wait()

    def run(self):
        self.emit( QtCore.SIGNAL('itemSelectionChanged()'))
        return

class MainUI(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self)
        self.ui = Ui_Win()
        self.ui.setupUi(self)
        ...

        genericThread = GenericThread(self)
        self.connect(genericThread, QtCore.SIGNAL("itemSelectionChanged()"), self.fill_List2 )
        genericThread.start()

    def fill_List2(self):
        self.ui.List2.clear()
        list1SelectedItem = str(self.ui.List1.currentItem().text()) # ERROR HERE

追溯: # AttributeError: 'NoneType' object has no attribute 'text'

这是因为self.ui.List1.currentItem().text()None

为什么在触发itemSelectionChanged 信号之前调用这个函数?

【问题讨论】:

  • 不是。您启动线程,该线程立即发出itemSelectionChanged 信号,然后调用fill_List2。你预计会发生什么?
  • @ekhumoro 我认为当我单击 List1 中的项目时应该启动线程...我如何修复代码以使其按预期工作?
  • 您需要将List1itemSelectionChanged 连接到创建线程并启动它的插槽。线程完成后,它应该发出一个自定义信号,该信号将返回 List2 的项目(您不得尝试直接更新工作线程中的 gui)。
  • 什么是from ui import Ui_Win?我不熟悉该导入,因此它使问题非常难以回答。您还没有显示设置或添加列表小部件的代码。我会写一个答案,但如果你能显示ui 是什么并添加设置代码,这个问题对未来的用户会更有用。

标签: python multithreading user-interface pyqt


【解决方案1】:
from ui import Ui_Win ## ui.py is a file that has been generated from Qt Designer and it contains main GUI objects like QListWidget
from PyQt4 import QtGui, QtCore

class GenericThread(QtCore.QThread):
    def __init__(self, parent=None, listIndex=0):
        QtCore.QThread.__init__(self, parent)
        self.listIndex = listIndex

    def __del__(self):
        self.quit()
        self.wait()

    def run(self):
        if self.listIndex == 2:
            for addStr in Something:
                #Some long stuff
                self.emit( QtCore.SIGNAL('fillListWithItems(QString, int'), addStr, self.listIndex)

class MainUI(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self)
        self.ui = Ui_Win()
        self.ui.setupUi(self)
        ...

        self.ui.List1.list1SelectedItem.connect(self.fill_List2)

    @QtCore.pyqtSlot(QString, int)
    def self.fillListWithItems(addStr, lstIdx):
        if lstIdx==2:
            self.ui.List2.addItem(addStr)

    def fill_List2(self):
        self.ui.List2.clear()
        list1SelectedItem = str(self.ui.List1.currentItem().text())

        genericThread = GenericThread(self, listIndex=2)
        self.connect(genericThread, QtCore.SIGNAL("fillListWithItems(QString, int)"), self.fillListWithItems )
        genericThread.start()

谢谢@ekhumoro

【讨论】:

  • 啊,我看到你自己有一个工作版本。我是通过您不久前在 Python 聊天中留下的评论来到这里的——不知道为什么它没有告诉我您已经得到了答案。无论如何 - 我会在这里重复我的评论 - 我认为如果你概述了 ui 是什么并展示了 List1List2 是如何填充的,我认为这对任何未来的访问者都会有所帮助
  • 而且您的自定义信号解决方案更好 - 即使它有效,我也不确定我的解决方案是否非常好,所以我想我会删除它或编辑它。
  • @JRichardSnape 而Ui_Win 只不过是从 QtDesigner 生成的代码,它没有任何重大意义
  • 好的 - 我会取消删除它,我想它可以替代,如果他们不喜欢它发出 itemSelectionChanged,也许有人会发表评论。了解 UI_Win 前面 - 也许只是写一行说明它是什么并且它不包含任何非常有用的东西,但确实包含 List1List2 小部件,它们是 QListWidget 类型(我认为他们是)
【解决方案2】:

您的问题是简单地启动线程正在触发itemSelectionChanged() 信号(因为它在run 函数中),您已将其连接到fill_List2() 函数。您需要将List1 上的itemSelectionChanged 事件连接到SLOT,这将触发线程进行繁重的计算并更新List2

我不得不对ui 是什么、List1List2 是什么以及它们是如何设置做出一些假设,但这里有一个工作示例。我已经用简单的 2 秒延迟替换了 GenericThread 中的繁重计算。

如果我误解/做出了错误的假设,请更新问题并发表评论

test_slotting.py

from ui import Ui_Win
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import pyqtSlot
from PyQt4.QtGui import *
import time

class GenericThread(QtCore.QThread):
    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)

    def __del__(self):
        self.quit()
        self.wait()

    def run(self):
        #Do all your heavy processing here
        #I'll just wait for 2 seconds
        time.sleep(2)
        self.emit( QtCore.SIGNAL('itemSelectionChanged()'))
        return

class MainUI(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self)
        self.ui = Ui_Win()
        self.ui.setupUi(self)
        self.ui.List1 = QListWidget(self)
        self.ui.List2 = QListWidget(self)

        hbox = QtGui.QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.ui.List1)
        hbox.addWidget(self.ui.List2)

        self.ui.centralWidget.setLayout(hbox)

        self.ui.List1.addItems(['alpha','beta','gamma','delta','epsilon'])
        self.ui.List2.addItems(['Item1','Item2'])

        self.ui.List1.itemSelectionChanged.connect(self.start_heavy_processing_thread)

    @pyqtSlot()
    def start_heavy_processing_thread(self):
        genericThread = GenericThread(self)
        self.connect(genericThread, QtCore.SIGNAL("itemSelectionChanged()"), self.fill_List2 )
        genericThread.start()

    def fill_List2(self):
        self.ui.List2.clear()
        list1SelectedItem = str(self.ui.List1.currentItem().text())
        self.ui.List2.addItem(list1SelectedItem)

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = MainUI()
    MainWindow.show()
    sys.exit(app.exec_())

ui.py

from PyQt4 import QtCore, QtGui

class Ui_Win(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(416, 292)
        self.centralWidget = QtGui.QWidget(MainWindow)
        self.centralWidget.setObjectName("centralWidget")
        MainWindow.setCentralWidget(self.centralWidget)

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_Win()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

【讨论】:

    猜你喜欢
    • 2013-12-03
    • 2017-07-31
    • 2017-02-13
    • 2022-01-06
    • 2011-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多