我读了这篇文章《如何真正地,真正地使用QThreads》。完整说明,它说而不是子类qthread和重新实现run(),应使用moveToThread(QThread
*)使用moveToThread将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,
QThread中的默认run()实现为您运行一个事件循环,等效于:
class GenericThread(QThread):
def run(self, *args):
self.exec_()
事件循环的重要之处在于,它允许线程 拥有的 对象在其插槽上接收事件,这些事件将 在该线程中
执行。这些对象只是QObject,而不是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中工作。您几乎应该永远不需要覆盖运行。对于大多数使用情况,设置与QObject到QThread的适当关联并使用QT的信号/插槽为进行多线程编程提供了一种非常强大的方法。请注意不要让推送到工作线程的QObject徘徊…
http://ilearnstuff.blogspot.co.uk/2012/09/qthread-best-practices-when-
qthread.html
问题内容: 我正在阅读有关PyQt5的一些文档,以提出一种简单的信号插槽机制。由于设计方面的考虑,我停了下来。 考虑以下代码: 为了跟踪对滑块所做的更改,我仅打印并记录所做的更改。我对代码不满意的是,我需要调用三次插槽以将相同的信息发送到3个不同的插槽。 是否可以创建自己的将整数发送到单个插槽的函数。插槽功能又会发出需要进行的更改吗? 也许我不完全了解它的目的,因为在PyQt Signal-Slo
问题内容: 我的应用程序具有以下结构: 我有一个包含一些脚本的功能文件夹,以及一个在ui.py文件上包含PyQt生成的代码的ui文件夹。 还有一个main.py文件,该文件加载ui.py以显示界面,并且ui.py从根目录的“ images”文件夹中加载一些图像。 如果我直接在python上执行脚本(main.py文件中为double clic),则图像不会显示。 但是,如果将终端与“ python
问题内容: 我正在尝试学习如何在PyQt Gui应用程序中使用QThreads。我有一些可以运行一段时间的东西,(通常)可以在其中更新Gui的点,但是我想将主要工作拆分为自己的线程(有时东西会卡住,最终有一个取消/重试按钮,如果Gui被冻结(因为主循环被阻塞),则该按钮显然不起作用)。 我已阅读https://mayaposch.wordpress.com/2011/11/01/how-to-re
问题内容: 我正在构建一个运行生产者(工人)的小型GUI应用程序,该GUI按需使用输出并将其绘制(使用pyqtgraph)。 由于生产者是一个阻塞函数(需要一段时间才能运行),我(据说)将其移到了自己的线程中。 从生产者调用QThread.currentThreadId()时,它输出与主GUI线程相同的数字。因此,首先执行worker,然后执行所有绘图函数调用(因为它们正在排队在同一线程的事件队列
问题内容: 从官方教程中: 在卸载和销毁组件之前立即调用。使用此方法执行任何必要的清除,例如使计时器无效,取消网络请求或清除在其中创建的所有DOM元素。 我了解“使计时器无效”。可以用终止。但是我不理解“清理在中创建的任何DOM元素”,我可以看到这种情况的示例吗? 问题答案: 如果网络请求发送库支持中止正在进行的网络请求调用,则绝对可以在方法中调用该请求。 但是,与清理元素有关。根据目前的经验,我
问题内容: 我一直在尝试在Node.js中调用D3。我首先尝试使用脚本标签从D3的网站导入d3.v2.js D3的作者建议一个人应该“ npm install d3” …我做到了,我可以在节点控制台中成功调用它: 但是,当尝试使用“ node app.js”从app.js调用它时,我得到: 我意识到,D3的作者在其他地方已经明确规定了应该使用画布: https://github.com/mbost