【问题标题】:Unable to connect pyqtSignal with pyQtSlot - PyQt5 and Python 3.5无法将 pyqtSignal 与 pyQtSlot 连接 - PyQt5 和 Python 3.5
【发布时间】:2017-10-09 19:55:24
【问题描述】:

尝试使用 QThread 和 PyQt5 的插槽/信号在后台线程中处理多个文件。

我正在使用 Python 3.5.2 和 PyQt5.8.2。 PyCharm 2017.1 向我发出警告:

  • # FAILS HEREUnresolved attribute referenceconnect 部分 w.done.connect(..)
  • Cannot find reference 'connect' in 'function'thread.started.connect(...)

当我尝试在 PyCharm 之外运行时,我得到 TypeError: decorated slot has no signature compatible with Worker.done[]。 在 PyCharm 中查看选项卡完成时,没有显示 connect()disconnect() 方法,但 emit() 显示。 SO上的所有教程和问题都说以下内容应该有效。

简化代码为:

from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QThread
from PyQt5.QtWidgets import QMainWindow

class MyApp(QMainWindow, myUiMainWindow):

    def __init__(self):
        super(self.__class__, self).__init()
        self.setupUI(self)

    @pyqtSlot()
    def update_this(self):
        <update things>

    def doMyStuff(self):
        <get a file_list>
        for f in file_list:
            w = Worker(f)
            thread = QThread()
            w.moveToThread(thread)
            w.done.connect(self.update_this)       # FAILS HERE
            thread.started.connect(w.process)      # FAILS HERE
            thread.start()

class Worker(QObject):
    done = pyqtSignal()
    def __init__(self, file_path):
        super(Worker, self).__init__(parent=None)
        self.f = file_path

    @pyqtSlot()
    def process(self):
        <do stuff>
        self.done.emit()

更新:我终于能够通过卸载 pyqt5 并从此处重新安装 (anaconda.org/bpentz/pyqt5) 来解决这个问题。我不知道这是如何解决问题的,但确实如此。但是,此代码不起作用,它几乎立即关闭 QThread()。我更新了以下相关代码(如下),现在我在终端或 PyCharm 中遇到了没有 Traceback 的 python 崩溃(奇怪的是,这在调试器中工作得很好)。目标是遍历文件并在多个 QThreads() 中处理它们,更新进度条 (update_this),然后在处理完所有文件时提醒用户。

from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QThread
from PyQt5.QtWidgets import QMainWindow

        class MyApp(QMainWindow, myUiMainWindow):

            def __init__(self):
                super(self.__class__, self).__init()
                self.setupUI(self)
                self.pushButton.clicked.connect(self.doMyStuff)

            @pyqtSlot()
            def thread_complete(self):
                self.num_completed += 1
                if self.num_completed == len(self.file_list):
                    <reset things>

            def doMyStuff(self):
            <get a self.file_list>
            self.num_completed = 0
            self.threads = []
            for f in self.file_list:
                w = Worker(f)
                self.threads.append(QThread())
                w.moveToThread(threads[-1])       
                self.threads[-1].started.connect(w.process)  
                self.threads[-1].finished.connect(self.thread_complete)    
                self.threads[-1].start()

        class Worker(QObject):
            def __init__(self, file_path):
                super(Worker, self).__init__(parent=None)
                self.f = file_path

            @pyqtSlot()
            def process(self):
                <do stuff with self.f>

附加更新:如前所述,问题不在于将工作人员保留在内存中。完成此操作后,线程场景就起作用了。然而,同样如前所述,使用 QThread() 并没有实现我一直在寻找并认为 QThreading 可能实现的多处理效率的想法,并且比仅在单个 QThread() 中串行处理文件更糟糕。尝试使用多重处理会导致其他问题here

工作 QThread() 代码(虽然很慢!):

def doMyStuff(self):
    <get a self.file_list>
    self.num_completed = 0
    self.threads = []
    self.workers = []
    for f in self.file_list:
        w = Worker(f)
        w.done.connect(self.update_this)
        thread = QThread()
        w.moveToThread(thread)
        thread.started.connect(w.process)
        thread.finished.connect(self.thread_complete)
        self.threads.append(thread)
        self.workers.append(worker)

【问题讨论】:

  • MyApp 类的构造函数?
  • @pyqtSlot(object) 更改为@pyqtSlot()
  • @eyllanesc - 谢谢。我早些时候改变了它,它没有工作。我可以通过卸载 pyqt5 并从这里重新安装 (anaconda.org/bpentz/pyqt5) 来解决这个问题。我不知道这是如何解决问题的,但确实如此。但是,此代码不起作用,它几乎立即关闭 QThread()。我已将代码更新为上面的编辑和新问题。
  • 请显示完整代码。
  • @launchpadmcquack 你需要保留对工作人员的引用,否则当doMyStuff 返回时它们会被删除(在你的线程有机会运行之前)。像处理线程一样将它们添加到列表中。

标签: python python-3.x pyqt pyqt5 qthread


【解决方案1】:

你应该直接继承 QThread

class WorkerThread(QThread):
    def __init__(self, data):
        super(WorkerThread, self).__init__()
        self.setTerminationEnabled(True)
        self.start()

    def run(self):
        pass
        #do work here

你可以连接到这个对象一个槽,线程发出“完成”

 myworker = WorkerThread(data)
 myworker.finished.connect(doWhatYouWant)

【讨论】:

    猜你喜欢
    • 2016-10-04
    • 2016-04-22
    • 2016-11-16
    • 2016-10-25
    • 1970-01-01
    • 2014-09-23
    • 2018-09-22
    • 1970-01-01
    • 2020-07-13
    相关资源
    最近更新 更多