一、多线程与界面组件的通信
1、子线程更改界面组件状态的本质
(1)、子线程发射信号通知主线程界面更新请求
(2)、主线程根据具体信号以及信号参数对界面组件进行修改
2、另一种子线程通知主线程的方式 :发送自定义事件
(1)、自定义事件用于描述界面更新细节
(2)、在主窗口类中重写事件处理函数event
(3)、使用postEvent函数(异步方式)发送自定义事件类对象(抛到应用程序的事件队列,然后分发出去)
A、子线程指定接收消息的对象为主窗口对象
B、在event事件处理函数中更新界面状态
自定义事件StringEvent.h
#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
自定义事件StringEvent.h
自定义事件StringEvent.cpp
#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()";
}
自定义事件StringEvent.cpp
子线程UpdataThread.h
#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
子线程UpdataThread.h
子线程UpdataThread.cpp
#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"));
}
子线程UpdataThread.cpp
Widget.h
#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
Widget.h
Widget.cpp
#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()
{
}
Widget.cpp
main.cpp
#include <QtGui/QApplication>
#include "Widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
main.cpp
二、小结
(1)、Qt可以发送自定义事件在子线程中操作界面组件
(2)、必须使用postEvent函数发送自定义事件(异步方式)
(3)、发送的事件对象必须在堆上创建
(4)、子线程创建时必须附带模板对象的地址信息