Qt5事件模型分析

qt窗口应用程序案例

code-1

#include <iostream>

#include <QApplication>

#include <QtWidgets/QWidget>

 

using namespace std;

 

class MyClass : public QWidget

{

//    Q_OBJECT

 

public:

    MyClass(QWidget *parent = 0):QWidget(parent){}

    ~MyClass(){}

    void doThings()

    {

        std::cout<<"ggg"<<std::endl;

    }

private:

    bool event(QEvent* ev)

    {

        if (ev->type() == QEvent::PolishRequest) {

            // overwrite handling of PolishRequest if any

            doThings();

            return true;

        } else  if (ev->type() == QEvent::Show) {

            // complement handling of Show if any

            doThings();

            QWidget::event(ev);

            return true;

        }

        // Make sure the rest of events are handled

        return QWidget::event(ev);

    }

};

 

int main(int argc, char *argv[])

{

    QApplication a(argc, argv);

    MyClass c;

    c.show();

    return a.exec();

}

代码中,首先派生Widget类,并复写了event()方法,用户自己处理事件。为了能够运行窗口应用程序,在main函数中,首先需要定义一个QApplication实例,然后实例化窗口对象,最后启动QApplication::exec()进入事件循环(文档中对exec函数的描述)。qt框架是事件驱动的应用程序框架,为了探究其事件模型,我们对两个对象QApplicationQWidget进行研究。

首先,我们知道,qt窗口对象最底层实际上是对各平台提供的窗口API的封装,从而实现跨平台。在win平台中,一个窗口对象对应一个线程(win窗口基于消息驱动),并且win平台也提供从线程的消息堆栈获取消息的API,所以猜测qt在win平台上的窗口线程,会不断获取系统窗口事件,然后以某种方式去处理这些事件。

至于如何处理这些事件,就就涉及另一概念,事件模型中的事件中心,以通常事件驱动模型的实现经验上看,事件中心应该由专门的Daemon线程在管理,那么这个线程在何处被创建呢?观察main函数后,不难发现,除了MyClass对象,只有QApplication对象有可能。通过阅读文档,印证了猜想。在一个qt应用程序中,创建QApplication的线程是主线程,在此主线中,调用QApplication::exec()进入事件循环,不断处理产生的事件(消息)。因此,我们可以对qt的事件模驱动模型有一个大致的认识:

  1. 程序中存在一个事件(消息)总线 event bus
  2. qt应用程序的事件来自用户对窗口的操作,窗口线程在获取这些事件后,调用postEvent()将event对象投递到event bus中
  3. event bus由Daemon线程管理,线程的事件循环核心工作便是处理这些事件

事件模型

更深入的了解qt事件驱动框架后,其简化的模型如下:

图1 qt事件驱动模型

其中,Win thread不断调用GetMessage()从win窗口线程的消息堆栈获取消息,并转化为qt消息Event对象,投递到Event Bus中。而Daemon thread则不断从Event Bus中获取Event,然后遍历事件的观察者,逐个调用其event()方法。若观察者成功处理事件,则event返回true,否则返回false。

经过调试跟踪代码发现,qt窗口事件的处理不是异步而是同步方式处理,即事件句柄的调用由Daemon thread调用。采用这种方式的原因,猜测可能的原因:

1.qt的开发者希望事件的产生和处理分离,窗口线程专注于收集/响应用户交互事件与界面绘制,事件处理则由专门线程集中处理,使得界面线程不易因为处理事件而陷入阻塞状态,满足界面响应的实时性,从而提供更好的用户交互体验;

2.用户在使用抓面应用程序时,不大可能同时激活多个窗口且同时进行操作,因此窗口事件的并发量不大,集中式的处理方式利于管理。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值