Qt事件机制的小实验

Posted unclerunning

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt事件机制的小实验相关的知识,希望对你有一定的参考价值。

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



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();
    

运行结果:



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

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

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

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

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

以上是关于Qt事件机制的小实验的主要内容,如果未能解决你的问题,请参考以下文章

Qt 事件处理机制

QT开发——QT事件处理机制

QT开发(六十三)——QT事件机制分析

Qt事件机制概览

Qt事件机制概览

转Qt 事件处理机制 (下篇)