一、多线程与界面组件的通信
1、子线程更改界面组件状态的本质
(1)、子线程发射信号通知主线程界面更新请求
(2)、主线程根据具体信号以及信号参数对界面组件进行修改
2、另一种子线程通知主线程的方式 :发送自定义事件
(1)、自定义事件用于描述界面更新细节
(2)、在主窗口类中重写事件处理函数event
(3)、使用postEvent函数(异步方式)发送自定义事件类对象(抛到应用程序的事件队列,然后分发出去)
A、子线程指定接收消息的对象为主窗口对象
B、在event事件处理函数中更新界面状态
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#ifndef STRINGEVENT_H #define STRINGEVENT_H #include <QEvent> #include <QString> //1.继承自QEvent //2.提供全局唯一Type值 //3.初始化列表里初始化QEvent是用Type值 //4.在接收事件的地方重写事件处理函数 class StringEvent : public QEvent { QString m_data; public: //提供全局唯一的Type值 static const QEvent::Type TYPE = static_cast<QEvent::Type>(QEvent::User + 0xFF); explicit StringEvent(QString data = " "); QString data(); ~StringEvent(); }; #endif // STRINGEVENT_H
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include "StringEvent.h" #include <QDebug> StringEvent::StringEvent(QString data) : QEvent(TYPE) { m_data = data; } QString StringEvent::data() { return m_data; } StringEvent::~StringEvent() { qDebug() << "StringEvent::~StringEvent()"; }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#ifndef UPDATATHREAD_H #define UPDATATHREAD_H #include <QThread> #include "StringEvent.h" class UpdataThread : public QThread { Q_OBJECT private: void run(); public: explicit UpdataThread(QObject *parent = 0); }; #endif // UPDATATHREAD_H
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include "UpdataThread.h" #include <QApplication> UpdataThread::UpdataThread(QObject *parent) : QThread(parent) { } void UpdataThread::run() { QApplication::postEvent(parent(),new StringEvent("begin")); for(int i=0; i<10; i++) { QApplication::postEvent(parent(), new StringEvent(QString::number(i)));//事件被POST之后就会被删除 sleep(3); } QApplication::postEvent(parent(), new StringEvent("end")); }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#ifndef WIDGET_H #define WIDGET_H #include <QtGui/QWidget> #include "UpdataThread.h" #include <QEvent> #include <QPlainTextEdit> class Widget : public QWidget { Q_OBJECT UpdataThread m_thread; QPlainTextEdit m_plainTextEdit; public: Widget(QWidget *parent = 0); bool event(QEvent *evt); ~Widget(); }; #endif // WIDGET_H
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include "Widget.h" #include "StringEvent.h" Widget::Widget(QWidget *parent) : QWidget(parent) { m_plainTextEdit.setParent(this); m_plainTextEdit.resize(100,100); m_plainTextEdit.move(20,20); m_thread.setParent(this);//这是一个小技巧,为了post事件的时候能调用parent()来指定接收者 m_thread.start(); } bool Widget::event(QEvent *evt) { bool ret = true; if(evt->type() == StringEvent::TYPE) { StringEvent* se = dynamic_cast<StringEvent*>(evt); if(se != NULL) { m_plainTextEdit.appendPlainText(se->data()); } } else { ret = QWidget::event(evt); } return ret; } Widget::~Widget() { }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <QtGui/QApplication> #include "Widget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
二、小结
(1)、Qt可以发送自定义事件在子线程中操作界面组件
(2)、必须使用postEvent函数发送自定义事件(异步方式)
(3)、发送的事件对象必须在堆上创建
(4)、子线程创建时必须附带模板对象的地址信息