使用moveToThread在Qt中将对象从一个线程移动到另一个线程是什么意思?甚至在使用moveToThread之前,一切似乎都工作,moveToThread将对象从一个线程(GUI线程)移动到另一个线程(工作),Qt:connect调用对象上的相应插槽.
由于对象所在的位置,GUI线程或工作线程,有什么区别吗?
编辑:我做了一个小程序,但我不明白QThread如何与Signal和插槽功能一起工作,如果你能解释一下moveToThread的用法,我将不胜感激
#include#include #include #include #include #include "mythread.h" //GUI calls a thread to do some job and sub update the text box once it is done int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget w; QHBoxLayout * pH = new QHBoxLayout(&w); QPushButton * pushButton = new QPushButton("asdad"); QLineEdit * lineEdit = new QLineEdit("AAA"); pH->addWidget(pushButton); pH->addWidget(lineEdit); w.setLayout(pH); w.show(); MyThread thread; qDebug("Thread id %d",(int)QThread::currentThreadId()); QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun())) ; QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString))); return a.exec(); } #ifndef MYTHREAD_H #define MYTHREAD_H #include #include class MyThread : public QThread { Q_OBJECT public: MyThread(); public slots: void callRun(); void run(); signals: void signalGUI(QString); private: QMutex mutex; }; #endif // MYTHREAD_H #include "mythread.h" #include #include #include MyThread::MyThread() { } void MyThread::callRun() { qDebug("in thread"); if(!isRunning()) { this->start(LowestPriority); exec(); } else { run(); } } void MyThread::run() { QMutexLocker fn_scope(&mutex); static int a = 0; ++a; qDebug("Thread id inside run %d",(int)QThread::currentThreadId()); this->sleep(3); static QString number; QString temp; number += temp.setNum(a); emit signalGUI(number); }
Adam W.. 37
看一下跨线程的信号和插槽.如果您始终使用信号和插槽与工作线程进行通信,Qt会根据需要为您处理moveToThread并使用正确的连接.
编辑:我猜这篇文章的作者看到了他的问题,因为他在实际创建线程之前在构造函数中调用了start.换句话说,不要盲目地信任第三方代码.
编辑:在回复您的评论时,请查看标题下的Mandelbrot示例MandelbrotWidget Class Implementation
:
对于排队连接,Qt必须存储传递给信号的参数的副本,以便稍后可以将它们传递给插槽.Qt知道如何获取许多C++和Qt类型的副本,但QImage不是其中之一.因此,在我们可以使用QImage作为排队连接中的参数之前,我们必须调用模板函数qRegisterMetaType().
我相信这有点过时,这里是有效的元类型.由于跨线程的信号和插槽使用排队连接,因此在大多数情况下您不必执行moveToThread调用.
编辑:我将尝试用类似的例子解释事情:
mythread.h:
#ifndef MYTHREAD_H #define MYTHREAD_H #include#include class MyThread : public QThread { Q_OBJECT protected: virtual void run(); signals: void signalGUI(QString); }; #endif // MYTHREAD_H
mythread.cpp:
#include "mythread.h" #includevoid MyThread::run() { qDebug("Thread id inside run %d",(int)QThread::currentThreadId()); static int run = 0; QString temp = QString("Run: %1").arg(run++); qDebug("String address inside run %p", &temp); emit signalGUI(temp); }
mylineedit.h
#ifndef MYLINEEDIT_H #define MYLINEEDIT_H #includeclass MyLineEdit : public QLineEdit { Q_OBJECT public: explicit MyLineEdit(QWidget *parent = 0); public slots: void setText(const QString &string); }; #endif // MYLINEEDIT_H
mylineedit.cpp
#include "mylineedit.h" #includeMyLineEdit::MyLineEdit(QWidget *parent) : QLineEdit(parent) { } void MyLineEdit::setText(const QString &string) { qDebug("Thread id inside setText %d",(int)QThread::currentThreadId()); qDebug("String address inside setText %p\n", &string); QLineEdit::setText(string); }
main.cpp中:
#include#include #include #include "mythread.h" #include "mylineedit.h" //GUI calls a thread to do some job and sub update the text box once it is done int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget w; QHBoxLayout * pH = new QHBoxLayout(&w); QPushButton * pushButton = new QPushButton("Run Thread", &w); MyLineEdit * lineEdit = new MyLineEdit(&w); pH->addWidget(pushButton); pH->addWidget(lineEdit); w.show(); MyThread thread; qDebug("Thread id %d",(int)QThread::currentThreadId()); QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(start())) ; QObject::connect(&thread,SIGNAL(signalGUI(const QString&)),lineEdit,SLOT(setText(const QString&))); return a.exec(); }
单击按钮后的示例输出:
Thread id 1088110320 Thread id inside run 1093176208 String address inside run 0x41288350 Thread id inside setText 1088110320 String address inside setText 0x974af58
如您所见,运行线程与主GUI线程不同.此外,即使您将const引用传递给QString,因为它跨越线程边界,它会复制它.我强烈建议您阅读Threads和QObject.
看一下跨线程的信号和插槽.如果您始终使用信号和插槽与工作线程进行通信,Qt会根据需要为您处理moveToThread并使用正确的连接.
编辑:我猜这篇文章的作者看到了他的问题,因为他在实际创建线程之前在构造函数中调用了start.换句话说,不要盲目地信任第三方代码.
编辑:在回复您的评论时,请查看标题下的Mandelbrot示例MandelbrotWidget Class Implementation
:
对于排队连接,Qt必须存储传递给信号的参数的副本,以便稍后可以将它们传递给插槽.Qt知道如何获取许多C++和Qt类型的副本,但QImage不是其中之一.因此,在我们可以使用QImage作为排队连接中的参数之前,我们必须调用模板函数qRegisterMetaType().
我相信这有点过时,这里是有效的元类型.由于跨线程的信号和插槽使用排队连接,因此在大多数情况下您不必执行moveToThread调用.
编辑:我将尝试用类似的例子解释事情:
mythread.h:
#ifndef MYTHREAD_H #define MYTHREAD_H #include#include class MyThread : public QThread { Q_OBJECT protected: virtual void run(); signals: void signalGUI(QString); }; #endif // MYTHREAD_H
mythread.cpp:
#include "mythread.h" #includevoid MyThread::run() { qDebug("Thread id inside run %d",(int)QThread::currentThreadId()); static int run = 0; QString temp = QString("Run: %1").arg(run++); qDebug("String address inside run %p", &temp); emit signalGUI(temp); }
mylineedit.h
#ifndef MYLINEEDIT_H #define MYLINEEDIT_H #includeclass MyLineEdit : public QLineEdit { Q_OBJECT public: explicit MyLineEdit(QWidget *parent = 0); public slots: void setText(const QString &string); }; #endif // MYLINEEDIT_H
mylineedit.cpp
#include "mylineedit.h" #includeMyLineEdit::MyLineEdit(QWidget *parent) : QLineEdit(parent) { } void MyLineEdit::setText(const QString &string) { qDebug("Thread id inside setText %d",(int)QThread::currentThreadId()); qDebug("String address inside setText %p\n", &string); QLineEdit::setText(string); }
main.cpp中:
#include#include #include #include "mythread.h" #include "mylineedit.h" //GUI calls a thread to do some job and sub update the text box once it is done int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget w; QHBoxLayout * pH = new QHBoxLayout(&w); QPushButton * pushButton = new QPushButton("Run Thread", &w); MyLineEdit * lineEdit = new MyLineEdit(&w); pH->addWidget(pushButton); pH->addWidget(lineEdit); w.show(); MyThread thread; qDebug("Thread id %d",(int)QThread::currentThreadId()); QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(start())) ; QObject::connect(&thread,SIGNAL(signalGUI(const QString&)),lineEdit,SLOT(setText(const QString&))); return a.exec(); }
单击按钮后的示例输出:
Thread id 1088110320 Thread id inside run 1093176208 String address inside run 0x41288350 Thread id inside setText 1088110320 String address inside setText 0x974af58
如您所见,运行线程与主GUI线程不同.此外,即使您将const引用传递给QString,因为它跨越线程边界,它会复制它.我强烈建议您阅读Threads和QObject.
该QThread::start()
方法创建线程并调用您的run()
实现.如果你要处理的线程上的事件或接收到的信号必须调用QThread::exec()
内部的run()
实现.你永远不应该run()
明确地打电话,你永远不应该exec()
在外面打电话run()
.
只有当插槽连接到连接类型不是的信号时,所有者线程才会有所不同Qt::DirectConnection
.然后Qt将确保插槽在所有者线程上运行,但为此,所有者线程必须运行事件循环QThread::exec()
.在这种情况下,调用myObj.moveToThread(myThread)
将确保myObj
在线程上运行插槽myThread
.
线程对象属于创建它的线程,而不是它所管理的线程(以及run方法将运行的位置).因此,当您将信号连接到线程对象的插槽时,该插槽将在创建线程对象的线程中运行,除非您调用moveToThread()
.