当前位置:  开发笔记 > 小程序 > 正文

跨线程的Qt信令,一个是GUI线程?

如何解决《跨线程的Qt信令,一个是GUI线程?》经验,为你挑选了2个好方法。

使用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"
#include 

void 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

#include 

class 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"
#include 

MyLineEdit::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.



1> Adam W..:

看一下跨线程的信号和插槽.如果您始终使用信号和插槽与工作线程进行通信,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"
#include 

void 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

#include 

class 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"
#include 

MyLineEdit::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.



2> Dan Berindei..:

    QThread::start()方法创建线程并调用您的run()实现.如果你要处理的线程上的事件或接收到的信号必须调用QThread::exec() 内部run()实现.你永远不应该run()明确地打电话,你永远不应该exec()在外面打电话run().

    只有当插槽连接到连接类型不是的信号时,所有者线程才会有所不同Qt::DirectConnection.然后Qt将确保插槽在所有者线程上运行,但为此,所有者线程必须运行事件循环QThread::exec().在这种情况下,调用myObj.moveToThread(myThread)将确保myObj在线程上运行插槽myThread.

    线程对象属于创建它的线程,而不是它所管理的线程(以及run方法将运行的位置).因此,当您将信号连接到线程对象的插槽时,该插槽将在创建线程对象的线程中运行,除非您调用moveToThread().

推荐阅读
放ch养奶牛
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有