Qt事件机制的小实验

7 篇文章 0 订阅

Qt事件机制的小实验

实验一:QCoreApplication::sendEvent

mymessageevent.h

#ifndef MYEVENT
#define MYEVENT

#include<QEvent>
#include<QString>

class MyMessageEvent:public QEvent
{

public:
    MyMessageEvent() :QEvent(static_cast<Type>(m_type)){}

    void setMessage(QString _m){ m_message=_m; }
    QString getMessage(){ return m_message; }   

private:
    QString m_message;
    int m_type = static_cast<int>(QEvent::User) + 1;
};
#endif // !MYEVENT

messageui.h

#ifndef MESSAGEUI
#define MESSAGEUI

#include <QtWidgets/QApplication>
#include <QLabel>
#include <QGridLayout>
#include <QThread>
#include <thread>
#include <chrono>
#include "mymessageevent.h"


class MessageUI : public QWidget
{
    Q_OBJECT

public:
    MessageUI(QWidget *parent = 0) :QWidget(parent), m_pLabel(nullptr), m_layout(this){
        setGeometry(600, 200, 50, 200);
        m_pLabel = new QLabel(this);
        m_pLabel->setText("");
        m_layout.addWidget(m_pLabel);
        setLayout(&m_layout);
    }

protected:
    void customEvent(QEvent * event){
        MyMessageEvent *mevent = dynamic_cast<MyMessageEvent*>(event);
        m_pLabel->setText(mevent->getMessage());
    }
private:
    QGridLayout m_layout;
    QLabel  *m_pLabel;
};

class clasMessageThread : public QThread
{

    void run() Q_DECL_OVERRIDE{

        if (m_pUI)
        {
            MyMessageEvent e_on_stack;
            e_on_stack.setMessage("I am a stack message");

            //send it right away and do not delete it
            QCoreApplication::sendEvent(m_pUI, &e_on_stack);
        }

       //事件循环 
        exec();
    }

public:
    void setMessageUI(MessageUI * _ui){ m_pUI = _ui; }

private:
    MessageUI * m_pUI=nullptr;

};

#endif

main

#include <QtWidgets/QApplication>
#include "messageui.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    //创建一个ui
    MessageUI ui;
    ui.show();

    //创建一个线程并启动
    clasMessageThread t;
    t.setMessageUI(&ui);
    t.start();

    return a.exec();
}

运行这个程序,期望线程t的run方法能够直接将栈上的消息发送给GUI线程创建的ui:

void run() Q_DECL_OVERRIDE{

        if (m_pUI)
        {
            MyMessageEvent e_on_stack;
            e_on_stack.setMessage("I am a stack message");

            //send it right away and do not delete it
            QCoreApplication::sendEvent(m_pUI, &e_on_stack);
        }

       //事件循环 
        exec();
}

可得到的却是这样一个断言:


qt-sendEvent-006

断言上说,不能直接将事件发送给一个不属于当前线程的对象。

是的!

不能直接将事件发送给一个不属于当前线程的对象。

qt库保证一个对象的事件处理器以及非直接连接的槽函数都只能在拥有这个对象的线程中执行,如果一个对象不属于某一个线程,那就不允许这个线程执行它的这些函数。


qt-sendEvent-005

checkReceiverThread会检查Receiver所属的线程,若不是当前线程,就引发上面的断言。

实验二:QCoreApplication::postEvent

我们改改run方法,这次不使用sendEvent,而是使用postEvent,看看有什么不一样:

    void run() Q_DECL_OVERRIDE{

        if (m_pUI)
        {
            MyMessageEvent *e_on_heap = new MyMessageEvent;
            e_on_heap->setMessage("I am a heap message");
        // post the event to the post event queue of thread m_pUI belongs to. 
        // The event must be allocated on the heap since the post event queue will 
        // take ownership of the event and delete it once it has been posted.
        // It is not safe to access the event after it has been posted.
            QCoreApplication::postEvent(m_pUI, e_on_heap);
        }

        exec();
    }

运行结果:


qt-postEvent-007

所以,postEvent完美的实现了线程间的事件的传送。

postEvent能够完成事件的传送是因为他完全遵守上面所说的qt的设计原则:

qt库保证一个对象的事件处理器以及非直接连接的槽函数都只能在拥有这个对象的线程中执行,如果一个对象不属于某一个线程,那就不允许这个线程执行它的这些函数。

当前线程调用postEvent时,只是将事件挂在了receiver所在线程的事件队列里,然后就返回了,事件的处理是异步的,receiver所在的线程在他的事件循环中会处理当前线程post上去的这个事件。

当前线程调用sendEvent时,会直接将事件一路传递到最终的处理器进行处理,处理完成后返回,事件的处理是同步的,如果receiver所在的线程和当前线程不是同一个线程,则会触发上面的断言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值