3.11 事件
3.11.1 基本概念
事件是由程序內部或外部產生的事情或某種操作的統稱。比如,用戶按下鍵盤或鼠標,就會產生一個鍵盤事件或鼠標事件(這是由程序外部產生的事件);當窗口第一次顯示時,會產生一個繪制事件,以通知窗口需要重新繪制自身,從而使窗口可見(這是由程序內部產生的事件)。事件有兩個來源:程序外部和程序內部。
對于外部產生的事件,比如用戶的操作(單擊鼠標、按下鍵盤),首先會被操作系統內核中的設備驅動程序所感知,然后操作系統將這些消息(與所進行操作的相關信息數據)放入GUI應用程序(Qt應用程序)的消息隊列,Qt程序依次讀取這些消息,進行分發,轉化為事件類QEvent(將操作數據代碼化),再進入事件處理函數進行處理。在事件處理函數中,我們通過參數(事件類QEvent或其子類的指針對象)能夠解析出操作的詳細信息,比如鼠標按下的是左鍵還是右鍵、鍵盤按下的是哪個鍵等,有了用戶操作的詳細數據信息,我們就可以進行相應的處理了。
Qt程序內部產生的事件(比如定時器超時)也是一樣的,只不過Qt直接將事件轉為事件類,然后分發、處理。
前面兩段話有點抽象,我們將其細化一下。首先事件要被Qt程序所獲取,那么具體是誰來做這個事情呢?
Qt中的事件循環是由QApplication.exec()開始的。當該語句執行后,應用程序便建立起了一個事件循環機制,該機制不斷地從系統的消息隊列中獲取與應用程序有關的消息,并根據事件攜帶的信息將事件對應到目的窗口或控件,由于Qt中窗口和控件都是繼承自QObject類,因此具有事件處理能力(QObject類的三大核心功能之一就是事件處理)。QObject類是所有Qt類的基類,是Qt對象模型的核心。QObject類通過調用event()函數獲取事件,所有需要處理事件的類都必須繼承自QObject,通過重定義event()函數實現自定義事件的處理,或者將事件交給父類處理。
3.11.2 事件的描述
在Qt中,使用抽象類QEvent及其子類來描述事件。所有事件都是QEvent類的派生類對象,用于表示在應用程序中發生的事情,或者是應用程序需要知道的外部活動的結果。
QEvent類是所有事件類的基類。事件對象包含事件參數:基本的QEvent類只包含一個事件類型參數,QEvent子類包含了額外的描述特定事件的參數。例如,子類QMouseEvent用于描述與鼠標相關的事件,子類QKeyEvent用于描述與鍵盤相關的事件等。
Qt中常見的事件有鼠標事件(QMouseEvent)、鍵盤事件(QKeyEvent)、繪制事件(QPaintEvent)、窗口尺寸改變事件(QResizeEvent)、滾動事件(QScrollEvent)、控件顯示事件(QShowEvent)、控件隱藏事件(QHideEvent)、定時器事件(QTimerEvent)等。
3.11.3 事件的類型
事情類型用枚舉QEvent::Type來表示。這個枚舉類型定義了Qt中有效的事件類型,比如QEvent::ApplicationStateChange表示應用程序的狀態已更改、QEvent::FileOpen表示文件打開請求(QFileOpenEvent)等。
3.11.4 事件的處理
Qt的主事件循環(QCoreApplication::exec())從事件隊列中獲取本地窗口的系統事件,將它們轉化為QEvents類對象,然后將轉換后的事件發送給 QObjects類對象。函數event()不處理事件,根據傳遞的事件類型,它調用該特定類型事件的事件處理程序來進行處理。
一般來說,事件來自底層窗口系統(spontaneous()返回true),但是也可以調用QCoreApplication::sendEvent()和QCoreApplication::postEvent()(spontaneous()返回false)來手動發送事件。
QObjects類通過調用QObject::event()函數來接收事件。該函數可以在子類中重新實現,來處理自定義的事件以及添加額外的事件類型,其中QWidget::event()就是一個很著名的例子。默認情況下,像QObject::timerEvent()和QWidget::mouseMoveEvent()這樣的事件可以被發送給事件處理函數。QObject::installEventFilter()允許一個對象攔截發往另一個對象的事件。
我們不需要知道Qt是怎樣把事件轉換為QEvent類對象或其子類對象的,只需要處理這些事件或在事件函數中發出的信號即可。比如對于按下鼠標按鈕的事件,不需要知道Qt是怎樣把該事件轉換為QMouseEvent類對象的(QMouseEvent類是用于描述鼠標事件的類),只需要知道從QMouseEvent類對象的變量中獲取具體的事件即可。在處理鼠標按下事件的函數中,它的參數就是一個QMouseEvent類型的指針變量,我們可以通過該變量判斷按下的是鼠標左鍵還是鼠標右鍵,代碼如下:

3.11.5 事件的傳遞
事件的傳遞也稱事件的分發。它的基本規則是:若事件未被目標對象處理,則把事件傳遞給父對象處理;若父對象仍未處理,則傳遞給父對象的父對象處理;重復這個過程,直至事件被處理或到達頂層對象為止。注意:事件是在對象間傳遞的,這里是指對象的父子關系,而不是指類的父子關系。
在Qt中有一個事件循環,該循環負責從可能產生事件的地方捕獲各種事件,并把這些事件轉換為帶有事件信息的對象,然后由Qt的事件處理流程分發給負責處理事件的對象來處理事件。
通過調用QApplication::exec()函數啟動事件主循環。主循環從事件隊列中獲取事件,然后創建一個合適的QEvent類的對象或其子類的對象來表示該事件。在此步驟中,事件循環首先處理所有發布的事件,直到隊列為空;然后處理自發的事件;最后處理在自發事件期間產生的已發布事件。注意:發送的事件不由事件循環處理,該類事件會被直接傳遞給對象。
- Go Web編程
- 手機安全和可信應用開發指南:TrustZone與OP-TEE技術詳解
- Apache Spark 2.x Machine Learning Cookbook
- iOS開發實戰:從零基礎到App Store上架
- Mastering Unity Shaders and Effects
- FLL+WRO樂高機器人競賽教程:機械、巡線與PID
- SpringBoot從零開始學(視頻教學版)
- Android編程權威指南(第4版)
- Sitecore Cookbook for Developers
- Microsoft XNA 4.0 Game Development Cookbook
- Spring Boot 2+Thymeleaf企業應用實戰
- JavaScript編程精解(原書第3版)
- Getting Started with Hazelcast
- Advanced C++
- 你也能看得懂的Python算法書