gpt4 book ai didi

python - 如何在带有 moveToThread() 的 pyqt 中正确使用 QThread?

转载 作者:太空狗 更新时间:2023-10-29 17:06:39 24 4
gpt4 key购买 nike

我读了这篇文章 How To Really, Truly Use QThreads; The Full Explanation ,它说而不是子类 qthread,并重新实现 run(),应该使用 moveToThread 将 QObject 推到 QThread 实例上,使用 moveToThread(QThread*)

这是c++的例子,但我不知道如何将它转换成python代码。

class Worker : public QObject
{
Q_OBJECT
QThread workerThread;

public slots:
void doWork(const QString &parameter) {
// ...
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,

最佳答案

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

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

事件循环的重要之处在于它允许线程拥有的对象在它们的槽上接收事件,这些事件将在该线程中执行。这些对象只是 QObjects,而不是 QThreads。

重要说明:QThread 对象不属于它自己的线程 [ docs ]:

It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots and invoked methods will execute in the old thread [e.g. the main thread].

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

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() 方法在完成时发出该信号,并将结果传递给它。

Once you get the hang of it and realize you don't and shouldn't subclass QThread, life becomes a lot more straightforward and easier. Simply put, never do work in QThread. You should almost never need to override run. For most use cases, setting up proper associations with a QObject to a QThread and using QT's signals/slots creates an extremely powerful way to do multithreaded programming. Just be careful not to let the QObjects you've pushed to your worker threads hang around...

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

关于python - 如何在带有 moveToThread() 的 pyqt 中正确使用 QThread?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20324804/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com