如何在pyqt中使用moveToThread()正确使用QThread?

 依稀边_228 发布于 2023-02-13 14:33

我读了这篇文章如何真正地,真正地使用QThreads; 完整解释,它说而不是子类qthread,并重新实现run(),应该使用moveToThread使用moveToThread(QThread*)将QObject推送到QThread实例

这是c ++示例,但我不知道如何将其转换为python代码.

class Worker : public QObject
 {
     Q_OBJECT
     QThread workerThread;

 public slots:
     void doWork(const QString ¶meter) {
         // ...
         emit resultReady(result);
     }

 signals:
     void resultReady(const QString &result);
 };

 class Controller : public QObject
 {
     Q_OBJECT
     QThread workerThread;
 public:
     Controller() {
         Worker *worker = new Worker;
         worker->moveToThread(&workerThread);
         connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
         connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString)));
         connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
         workerThread.start();
     }
     ~Controller() {
         workerThread.quit();
         workerThread.wait();
     }
 public slots:
     void handleResults(const QString &);
 signals:
     void operate(const QString &);
 };



QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();

我一直在使用这种方法来生成qthread,但正如你所看到的,它使用了不推荐的方式.如何重新编写它以使用首选方法?

class GenericThread(QThread):
    def __init__(self, function, *args, **kwargs):
        QThread.__init__(self)
        # super(GenericThread, self).__init__()

        self.function = function
        self.args = args
        self.kwargs = kwargs

    def __del__(self):
        self.wait()

    def run(self, *args):
        self.function(*self.args, **self.kwargs)

编辑:两年后......我尝试了qris的代码,它的工作原理和不同的线程

import sys
import time
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import pyqtSignal, pyqtSlot
import threading


def logthread(caller):
    print('%-25s: %s, %s,' % (caller, threading.current_thread().name,
                              threading.current_thread().ident))


class MyApp(QtGui.QWidget):

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 280, 600)
        self.setWindowTitle('using threads')

        self.layout = QtGui.QVBoxLayout(self)

        self.testButton = QtGui.QPushButton("QThread")
        self.testButton.released.connect(self.test)
        self.listwidget = QtGui.QListWidget(self)

        self.layout.addWidget(self.testButton)
        self.layout.addWidget(self.listwidget)

        self.threadPool = []
        logthread('mainwin.__init__')

    def add(self, text):
        """ Add item to list widget """
        logthread('mainwin.add')
        self.listwidget.addItem(text)
        self.listwidget.sortItems()

    def addBatch(self, text="test", iters=6, delay=0.3):
        """ Add several items to list widget """
        logthread('mainwin.addBatch')
        for i in range(iters):
            time.sleep(delay)  # artificial time delay
            self.add(text+" "+str(i))

    def test(self):
        my_thread = QtCore.QThread()
        my_thread.start()

        # This causes my_worker.run() to eventually execute in my_thread:
        my_worker = GenericWorker(self.addBatch)
        my_worker.moveToThread(my_thread)
        my_worker.start.emit("hello")
        # my_worker.finished.connect(self.xxx)

        self.threadPool.append(my_thread)
        self.my_worker = my_worker


class GenericWorker(QtCore.QObject):

    start = pyqtSignal(str)
    finished = pyqtSignal()

    def __init__(self, function, *args, **kwargs):
        super(GenericWorker, self).__init__()
        logthread('GenericWorker.__init__')
        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.start.connect(self.run)

    @pyqtSlot()
    def run(self, *args, **kwargs):
        logthread('GenericWorker.run')
        self.function(*self.args, **self.kwargs)
        self.finished.emit()


# run
app = QtGui.QApplication(sys.argv)
test = MyApp()
test.show()
app.exec_()

输出是:

mainwin.__init__         : MainThread, 140221684574016,
GenericWorker.__init__   : MainThread, 140221684574016,
GenericWorker.run        : Dummy-1, 140221265458944,
mainwin.addBatch         : Dummy-1, 140221265458944,
mainwin.add              : Dummy-1, 140221265458944,
mainwin.add              : Dummy-1, 140221265458944,
mainwin.add              : Dummy-1, 140221265458944,
mainwin.add              : Dummy-1, 140221265458944,
mainwin.add              : Dummy-1, 140221265458944,
mainwin.add              : Dummy-1, 140221265458944,

qris.. 12

QThread中的默认run()实现为您运行一个事件循环,相当于:

class GenericThread(QThread):
    def run(self, *args):
        self.exec_()

关于事件循环的重要一点是它允许线程拥有的对象在其插槽上接收事件,这些事件将在该线程中执行.那些对象只是QObjects,而不是QThreads.

重要提示:QThread对象不属于自己的线程!它是在主线程上创建的并且存在于那里.除了run方法之外,它的所有代码都在主线程中执行.

所以你应该能够做到这一点:

class GenericWorker(QObject):
    def __init__(self, function, *args, **kwargs):
        super(GenericWorker, self).__init__()

        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.start.connect(self.run)

    start = pyqtSignal(str)

    @pyqtSlot
    def run(self, some_string_arg):
        self.function(*self.args, **self.kwargs)

my_thread = QThread()
my_thread.start()

# This causes my_worker.run() to eventually execute in my_thread:
my_worker = GenericWorker(...)
my_worker.moveToThread(my_thread)
my_worker.start.emit("hello")

另外,仔细考虑结果会发生什么self.function,目前被丢弃.你可以声明另一个信号GenericWorker,它接收结果,并让run()方法在完成后发出信号,并将结果传递给它.

一旦你掌握了它,并意识到你没有,也不应该继承QThread,生活变得更加简单直接.简单地说,永远不要在QThread中工作.你应该几乎不需要覆盖run.对于大多数用例,设置与QObject到QThread的正确关联并使用QT的信号/插槽创建了一种非常强大的多线程编程方法.小心不要让你推到你的工作线程的QObjects徘徊......

http://ilearnstuff.blogspot.co.uk/2012/09/qthread-best-practices-when-qthread.html

2 个回答
  • QThread中的默认run()实现为您运行一个事件循环,相当于:

    class GenericThread(QThread):
        def run(self, *args):
            self.exec_()
    

    关于事件循环的重要一点是它允许线程拥有的对象在其插槽上接收事件,这些事件将在该线程中执行.那些对象只是QObjects,而不是QThreads.

    重要提示:QThread对象不属于自己的线程!它是在主线程上创建的并且存在于那里.除了run方法之外,它的所有代码都在主线程中执行.

    所以你应该能够做到这一点:

    class GenericWorker(QObject):
        def __init__(self, function, *args, **kwargs):
            super(GenericWorker, self).__init__()
    
            self.function = function
            self.args = args
            self.kwargs = kwargs
            self.start.connect(self.run)
    
        start = pyqtSignal(str)
    
        @pyqtSlot
        def run(self, some_string_arg):
            self.function(*self.args, **self.kwargs)
    
    my_thread = QThread()
    my_thread.start()
    
    # This causes my_worker.run() to eventually execute in my_thread:
    my_worker = GenericWorker(...)
    my_worker.moveToThread(my_thread)
    my_worker.start.emit("hello")
    

    另外,仔细考虑结果会发生什么self.function,目前被丢弃.你可以声明另一个信号GenericWorker,它接收结果,并让run()方法在完成后发出信号,并将结果传递给它.

    一旦你掌握了它,并意识到你没有,也不应该继承QThread,生活变得更加简单直接.简单地说,永远不要在QThread中工作.你应该几乎不需要覆盖run.对于大多数用例,设置与QObject到QThread的正确关联并使用QT的信号/插槽创建了一种非常强大的多线程编程方法.小心不要让你推到你的工作线程的QObjects徘徊......

    http://ilearnstuff.blogspot.co.uk/2012/09/qthread-best-practices-when-qthread.html

    2023-02-13 14:35 回答
  • 我试图在应用程序中使用qris的示例,但一直在我的主线程中运行我的代码!这是他宣布致电的信号运行方式!

    基本上,当在对象的构造函数中连接它时,该连接将存在于主线程中的两个对象之间-因为QObject的属性属于创建它们的线程。当您将QObject移至新线程时,连接不会随之移动。删除将信号连接到运行功能的线,然后在将worker移至新线程后将其连接

    来自qris答案的相关更改:

    class GenericWorker(QObject):
        def __init__(self, function, *args, **kwargs):
            super(GenericWorker, self).__init__()
    
            self.function = function
            self.args = args
            self.kwargs = kwargs
    
        start = pyqtSignal(str)
    
        @pyqtSlot
        def run(self, some_string_arg):
            self.function(*self.args, **self.kwargs)
    
    my_thread = QThread()
    my_thread.start()
    
    # This causes my_worker.run() to eventually execute in my_thread:
    my_worker = GenericWorker(...)
    my_worker.moveToThread(my_thread)
    my_worker.start.connect(my_worker.run) #  <---- Like this instead 
    my_worker.start.emit("hello")
    

    2023-02-13 14:38 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有