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.用戶在使用抓面應用程序時,不大可能同時激活多個窗口且同時進行操作,因此窗口事件的併發量不大,集中式的處理方式利於管理。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章