第八十五课、多线程与界面组件的通信(下)------------------狄泰软件学院

一、多线程与界面组件的通信

1、子线程更改界面组件状态的本质

(1)、子线程发射信号通知主线程界面更新请求

(2)、主线程根据具体信号以及信号参数对界面组件进行修改

2、另一种子线程通知主线程的方式 :发送自定义事件

(1)、自定义事件用于描述界面更新细节

(2)、在主窗口类重写事件处理函数event

(3)、使用postEvent函数(异步方式)发送自定义事件类对象(抛到应用程序的事件队列,然后分发出去)

A、子线程指定接收消息的对象为主窗口对象

B、在event事件处理函数中更新界面状态

#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
#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
#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
#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
#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
#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
#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)、子线程创建时必须附带模板对象的地址信息  

posted @ 2017-03-06 21:08  lgc202  阅读(414)  评论(0编辑  收藏  举报