当前位置: 首页 > 知识库问答 >
问题:

PYQT5中的QThreads:在worker类的构造函数中创建新对象可以吗?

印振国
2023-03-14

 · · · >以下文章解释了为什么在使用第二种方法时需要小心:https://mayaposch.wordpress.com/2011/11/01/how-to-realt-realt-use-qthreads-the-full-explanation/

 · · · >下面的文章解释了为什么这两种方法都有各自的优点:https://woboq.com/blog/qthread-you-were-noth-down-so-wurn.html

我引述:

作为经验法则:

由于我确实需要在QApplication线程和新的QThread之间进行某种通信(我相信signal-slot是一种很好的通信方式),所以我将使用Worker-Object方法

 

在QThreads上的官方Qt5文档(参见http://doc.qt.io/qt-5/qthread.html),您可以找到示例代码。我已经努力将它翻译成Python:
(请参见这个stackoverflow问题以了解更多关于翻译的细节:PyQT5中的QThreads:这是官方QThread文档的正确C++到Python翻译吗?)

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

class Worker(QObject):

    resultReady = pyqtSignal(str)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Note: this constructor is empty now.
        # But would it be okay to instantiate new
        # objects here, and use them in doWork(..)?

    # A more general question: is it okay if
    # doWork(..) accesses variables that were
    # created in another thread (perhaps the
    # main QApplication thread)?

    @pyqtSlot(str)
    def doWork(self, param):
        result = "hello world"
        print("foo bar")
        # ...here is the expensive or blocking operation... #
        self.resultReady.emit(result)


class Controller(QObject):

    operate = pyqtSignal(str)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # 1. Create 'workerThread' and 'worker' objects
        # ----------------------------------------------
        self.workerThread = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.workerThread)

        # 2. Connect all relevant signals
        # --------------------------------
        self.workerThread.finished.connect(self.worker.deleteLater)
        self.operate.connect(self.worker.doWork)
        self.worker.resultReady.connect(self.handleResults)

        # 3. Start the thread
        # --------------------
        self.workerThread.start()

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

    @pyqtSlot(str)
    def handleResults(self, param):
        print(param)
        global app
        app.exit()


if __name__ == '__main__':
    app = QCoreApplication([])
    controller = Controller()
    controller.operate.emit("foo")
    sys.exit(app.exec_())

 

来自MSS的伟大文章。Maya Posch(https://mayaposch.wordpress.com/2011/11/01/how-to-realt-realt-use-qthreads-the-full-explantion/),我引用如下:

顺便说一下,这里需要注意的一件非常重要的事情是,永远不要在QObject类的构造函数中分配堆对象(使用new),因为这种分配是在主线程上执行的,而不是在新的QThread实例上执行的,这意味着新创建的对象由主线程而不是QThread实例拥有。这将使您的代码无法工作。相反,在主函数槽(如process())中分配这样的资源,在本例中,当调用它时,对象将位于新线程实例上,因此它将拥有资源。
[Maya Posch-How to realth use qthreads,完整解释]

本文是为C++软件编写的。

特此提供我当前的系统设置:
 、 、 、 > Qt5(QT_version_str=5.10.1)
    > PyQt5(pyqt_version_str=5.10.1)
    > Python 3.6.3
 · · · > Windows 10,64位

共有1个答案

赵嘉赐
2023-03-14

在这个回答中,我将对我的评论的所有任务进行排序。

很多时候,如果文档被修改,他会混淆thread和QThread的概念:

QThread类提供了一种独立于平台的方式来管理线程

 类似资料:
  • 我在弄清楚如何根据给定的类型在构造函数中创建一个新对象时遇到了困难。 例如,我有一个机器人驱动程序,它有一个默认构造函数,不接受任何参数,并创建一个基本的机器人。但我有另一个构造器,根据这个论点创造了一个新的机器人。 是一个接口。那么,如果我想创建,使其是另一种类型,比如?我需要做一些类型的铸造吗?

  • 说明: Worker::__construct([string $listen , array $context]) 初始化一个Worker容器实例,可以设置容器的一些属性和回调接口,完成特定功能。 参数 $listen 如果有设置监听$listen参数,则会执行socket监听。 $listen的格式为 <协议>://<监听地址> <协议> 可以为以下格式: tcp: 例如 tcp://0.0.

  • 问题内容: 我一直认为无需调用构造函数即可创建对象。 但是,在 明智地 阅读《有效的Java 项目11:覆盖克隆》时 ,我发现了一条声明,指出 “没有调用构造函数”的规定太强了。行为良好的克隆方法可以调用构造函数来创建正在构建的克隆内部的对象。如果该类是最终的,则clone甚至可以返回由构造函数创建的对象。 有人可以向我解释一下吗? 问题答案: 我一直以为clone()会创建一个对象而不调用构造函

  • 我一直认为,clone()创建对象时不需要调用构造函数。 但是,在阅读有效Java第11条:明智地覆盖克隆时,我发现了一条声明,上面写着 “不调用构造函数”的规定太强了。行为良好的克隆方法可以调用构造函数来创建正在构建的克隆内部的对象。如果类是最终的,克隆甚至可以返回构造函数创建的对象。 谁能给我解释一下吗?

  • 问题内容: 我正在尝试修复我的一个程序中的错误,我认为这可能是由于Hibernate弄清楚了如何在不调用其默认(或任何其他)构造函数的情况下实例化对象的实例。 问题答案: 实际上,是的,如果使用objenesis为您实例化对象,则可以在实例化对象时绕过构造函数。它执行字节码操作来实现此目的。 反序列化对象也将绕过构造函数。 使用反射无法做到这一点。

  • 写一个名为Circle的类。该类需要一个名为radius的类型为double的字段(实例变量) 该类需要有一个参数半径为double类型的构造函数,并且需要初始化字段。 如果半径参数小于0,则需要将半径字段值设置为0。 编写以下方法(实例方法): 方法名为getRadius,没有任何参数,需要返回半径字段的值。 名为getArea的方法,没有任何参数,需要返回计算的面积(半径*半径*PI)。对于P