实现QT元类型和QT线程通信是本文将要介绍的内容,不多说废话,先来看内容。今天调试QT线程通信的程序时,突然发现如下消息:
其中PEOPLE只是我定义的枚举类型即enum PEOPLE。然后在Qt的信号-槽函数的参数中使用了这个枚举型,在发送信号时就出现了上述警告。上面警告的大概意思是信号队列中无法使用PEOPLE类型,要使用qRegisterMetaType()注册该类型后方可使用。
通常使用的connect,实际上最后一个参数使用的是Qt::AutoConnection类型:(友们,点击之后,就会放大,不好意思,影响你视觉了)
Qt支持6种连接方式,其中3中最主要:
Qt::DirectConnection(直连方式)
当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。(信号与槽函数关系类似于函数调用,同步执行)
Qt::QueuedConnection(排队方式)
当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,调用相应的槽函数。emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信,异步执行)
Qt::AutoConnection(自动方式)
Qt的默认连接方式,如果信号的发出和接收这个信号的对象同属一个线程,那个工作方式与直连方式相同;否则工作方式与排队方式相同。
我的项目中的确跨线程使用了PEOPLE为参数类型的信号,因此使用的应当是排队方式的信号-槽机制,出现“队列中无法使用PEOPLE类型”的警告信息就可以理解了。放狗搜了一圈,有篇文章提供了个这样的解决方案:
- connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
- this,SLOT(sendRes(QUuid,QByteArray,bool)));
改为:
- connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
- this,SLOT(sendRes(QUuid,QByteArray,bool)));
这样做的确能使警告信息消失,因为Qt官方文档写了:
- With queued connections, the parameters must be of types that are known to Qt's meta-object system,
- because Qt needs to copy the arguments to store them in an event behind the scenes.
即使用排队方式的信号-槽机制,Qt的元对象系统(meta-object system)必须知道信号传递的参数类型。这里手动改为直连方式,Qt的元对象系统就不必知道参数类型了,于是警告信息消失。但这样做是不安全的,见Qt官方文档:
- Be aware that using direct connections when the sender and receiver live in different threads is unsafe if
- an event loop is running in the receiver's thread, for the same reason that calling any function on an obje
- ct living in another thread is unsafe.
因此,咱还是老老实实地用qRegisterMetaType()注册类型吧
我写的线程通讯方法是采用信号槽机制,通常情况下,信号和槽机制可以同步操作,这就意味着在发射信号的时候,使用直接函数即可以立刻调用连接到一个信号上的多个槽。然而,当连接位于不同线程中的对象时,这一机制就会变得不同步起来,可以通过刚才介绍的,修改QObject::connect()的第5个可选参数而改变。
connect的第五个参数Qt::QueuedConnection表示槽函数由接受信号的线程所执行,如果不加表示槽函数由发出信号的次线程执行。当传递信号的参数类型不是QT的元类型时要先注册,关于QT的元类型可以参看QT文档。
QMetaType这个类里面列举了所有的元类型。
以枚举PEOPLE为例,注册时首先Q_DECLARE_METATYPE(PEOPLE);
然后,int id=qRegisterMetaType<PEOPLE>("PEOPLE");
加上这两句就注册成功了。
贴个示例的代码,次线程不断更改一个PEOPLE{boy,girl}的信息传给GUI主线程,主线程在GUI界面上显示。
- mythread.h
- #ifndef MYTHREAD_H
- #define MYTHREAD_H
- #include <QThread>
- enum PEOPLE{boy,girl};
- class MyThread : public QThread
- {
- Q_OBJECT
- public:
- MyThread();
- ~MyThread();
- protected:
- void run();
- signals:
- void changeText(PEOPLE pe);
- };
- #endif // MYTHREAD_H
- mainwindow.h
- view plaincopy to clipboardprint?
- #ifndef MAINWINDOW_H
- #define MAINWINDOW_H
- #include "mythread.h"
- #include <QMainWindow>
- namespace Ui {
- class MainWindow;
- }
- class MainWindow : public QMainWindow {
- Q_OBJECT
- public:
- MainWindow(QWidget *parent = 0);
- ~MainWindow();
- private slots:
- void labelSetText(PEOPLE qstr);
- protected:
- void changeEvent(QEvent *e);
- private:
- Ui::MainWindow *ui;
- };
- #endif // MAINWINDOW_H
- #ifndef MAINWINDOW_H
- #define MAINWINDOW_H
- #include "mythread.h"
- #include <QMainWindow>
- namespace Ui {
- class MainWindow;
- }
- class MainWindow : public QMainWindow {
- Q_OBJECT
- public:
- MainWindow(QWidget *parent = 0);
- ~MainWindow();
- private slots:
- void labelSetText(PEOPLE qstr);
- protected:
- void changeEvent(QEvent *e);
- private:
- Ui::MainWindow *ui;
- };
- #endif // MAINWINDOW_H
- mythread.cpp
- view plaincopy to clipboardprint?
- #include "mythread.h"
- MyThread::MyThread()
- : QThread()
- {
- }
- MyThread::~MyThread()
- {
- }
- void MyThread::run(){
- static int i=1;
- while(true)
- {
- if(i==1)emit changeText(boy);
- else emit changeText(girl);
- ii=i*(-1);
- QThread::sleep(1);
- }
- }
- mainwindow.cpp
- #include "mainwindow.h"
- #include "ui_mainwindow.h"
- #include "mythread.h"
- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
- MyThread *mythread = new MyThread;
- int id=qRegisterMetaType<PEOPLE>("PEOPLE");
- connect(mythread,SIGNAL(changeText(PEOPLE)),this,SLOT(labelSetText(PEOPLE)),Qt::QueuedConnection);
- mythread->start();
- }
- MainWindow::~MainWindow()
- {
- delete ui;
- }
- void MainWindow::changeEvent(QEvent *e)
- {
- QMainWindow::changeEvent(e);
- switch (e->type()) {
- case QEvent::LanguageChange:
- ui->retranslateUi(this);
- break;
- default:
- break;
- }
- }
- void MainWindow::labelSetText(PEOPLE qstr){
- switch(qstr)
- {
- case boy:
- ui->label->setText("BOY");break;
- case girl:
- ui->label->setText("GIRL");break;
- }
- }
小结:实现QT元类型和QT线程通信的内容到这就介绍完了,希望本文能帮你解决问题
转载于:http://mobile.51cto.com/symbian-272638.htm