【Qt】事件處理、事件分發器、事件過濾器

事件處理

  • 一. 事件
    • 事件處理
    • 鼠標事件處理
    • 按鍵事件處理
    • 定時器事件處理
    • 窗口事件處理
  • 二. 事件分發器
  • 三. 事件過濾器

雖然 Qt 是跨平臺的 C++ 開發框架,Qt 的很多能力其實是操作系統提供的,只不過 Qt 封裝了系統 API,程序是運行在操作系統上的,需要系統給我們提供支撐。如:事件、文件操作、多線程編程、網絡編程、多媒體。

一. 事件

  • 信號槽:用戶進行的各種操作,就可能會產生出信號,可以給某個信號指定槽函數,當信號觸發的時候,就能夠自動的執行到對應的槽函數。
  • 事件:用戶進行的各種操作,也會產生事件,程序員同樣可以給事件關聯上處理函數 (處理的邏輯),當事件觸發的時候,就能夠執行到對應的代碼。
    • 事件本身是操作系統提供的機制,Qt 也同樣把操作系統事件機制進行了封裝,拿到了 Qt 中,但是由于事件對應的代碼編寫起來不是很方便。
    • Qt 對于事件機制又進一步的封裝,就得到了信號槽,信號槽就是對于事件的進一步封裝,事件是信號槽的低層機制。
    • 實際 Qt 開發程序的過程中,絕大部分和用戶之間進行的交互都是通過 “信號槽” 來完成的,有些特殊情況下,信號槽不一定能搞定 (某個用戶的動作行為,Qt 沒有提供對應的信號),此時就需要通過重寫事件處理函數,來手動處理事件的響應邏輯。
    • 開發事件機制給我們程序員,我們就可以根據實際的需要進行更深度的定制化 DIY (自己動手做) 操作了。
    • 用戶進行了很多操作,就會產生很多的事件,當然也會產生出很多的信號。

Qt 中使用個對象來表示一個事件,所有的 Qt 事件均繼承抽象類 QEvent。

  • 事件是由系統或者 Qt 平臺本身在不同的時刻發出的,當用戶按鼠標、敲下鍵盤,或者是窗口需要重新繪制的時候,都會發出一個相應的事件。
  • 一些事件是在用戶操作時發出,如鍵盤事件、鼠標事件等,另一些事件則是由系統本身自動發出,如定時器事件。

常見的 Qt 事件如下:

在這里插入圖片描述

常見事件描述:

在這里插入圖片描述

事件處理

事件的處理:讓一段代碼和某個事件關聯起來,當事件觸發的時候,就能夠執行這段代碼。

  • 之前信號槽這里通過 connect 來完成上述關聯的。
  • 對于事件來說不一樣,讓當前的類,重寫某個事件處理函數,這里用到的是 “多態” 機制,創建子類,繼承 Qt 已有的類,在子類中重寫父類的事件處理函數,后續事件觸發的過程中,就會通過多態這樣的機制,執行到我們自己寫的子類的函數。
  • 事件處理一般常用的方法為:重寫相關的 Event 函數。在 Qt 中,幾乎所有的 Event 函數都是虛函數,所以可以重新實現。如:在實現鼠標的進入和離開事件時,直接重新實現 enterEvent() 和 leaveEvent() 即可。

enterEvent() 和 leaveEvent() 函數原型如下:

在這里插入圖片描述

代碼:鼠標進入和離開控件

給 ui 文件設置 QLabel,并添加上邊框,為了方便觀察當前鼠標是否進入和離開,如下:

在這里插入圖片描述

這里需要創建 QLabel 的子類,重寫 enterEvent 和 leaveEvent,如下:

在這里插入圖片描述

要想重寫父類的函數,就需要確保你這邊寫的函數名字和函數的參數列表都完全一致 (形參名無所謂),謹防單詞拼寫錯,正常來說 Qt Create 應該要能夠提示出來的,但實際上沒有提示。

在這里插入圖片描述
在這里插入圖片描述

運行代碼后,發現鼠標進入或者離開 QLabel 時,應用程序輸出中并沒有打印出 enterEvent 和 leaveEvent,如下:

在這里插入圖片描述

原因分析:我們在 ui 文件中使用的控件是 QLabel,而 QLabel 默認不處理 enterEvent 和 leaveEvent,而且要啟用鼠標跟蹤功能也需要額外的操作。

我們需要在 ui 文件中,使用自己定義的 Label,如下:

在這里插入圖片描述
在這里插入圖片描述

通過 “提升為” 這樣的方式,就可以把 Qt Designed 中拖上去的控件的類型轉換為自定義的控件類型,如下:

在這里插入圖片描述

運行程序后,此時就說明當前的 enterEvent 和 leaveEvent 這兩個事件就被我們給捕捉到了,如下:

在這里插入圖片描述

鼠標事件處理

在 Qt 中,鼠標事件是用 QMouseEvent 類來實現的。

  • 當在窗口中 “按下鼠標” 或者 “移動鼠標” 時,都會產生鼠標事件。
  • 利用 QMouseEvent 類可以獲取鼠標的哪個鍵被按下了以及鼠標的當前位置等信息。
  • 在 Qt 幫助文檔中,可以查找 QMouseEvent 類,如下:

在這里插入圖片描述

代碼:鼠標點擊事件

在 Qt 中,鼠標按下時,通過執行虛函數 QWidget::mousePressEvent(QMouseEvent *event) 來捕獲的。而其中鼠標可以通過 “左鍵”、“右鍵”、“滾輪” 等等按下,如何區分?通過 event->button() 函數的返回值區分。

  • 鼠標左鍵:Qt::LeftButton
  • 鼠標左鍵:Qt::RightButton
  • 鼠標滾輪:Qt::MidButton

同理將 QLabel 提升為我們自定義的 Label,如下:

在這里插入圖片描述

修改 label.h 和 label.cpp 文件,如下:

在這里插入圖片描述

在這里插入圖片描述

代碼:鼠標釋放事件

鼠標釋放事件是通過虛函數 QWidget::mouseReleaseEvent(QMouseEvent *event) 來捕獲的。

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

代碼:鼠標雙擊事件

鼠標雙擊事件是通過虛函數 QWidget::mouseDoubleClickEvent(QMouseEvent *event) 來實現的。

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

注意:這里第二次按下的時候,才能夠識別時 “雙擊”,比如:程序可能有一些單擊邏輯、有另一些雙擊邏輯,如果我們沒注意到,可能雙擊操作就會觸發單擊的邏輯,可能就有 bug

代碼:鼠標移動事件

  • 鼠標移動事件是通過虛函數 QWidget::mouseMoveEvent(QMouseEvent *event) 來實現的。
  • 同時為了實時捕獲鼠標位置信息,需要通過函數 setMouseTracking(bool enable) 來追蹤鼠標的位置。
    • 說明:setMouseTracking() 函數默認是 false,需要設置為 true,才能實時捕獲鼠標位置信息。否則只有當鼠標按下時才能捕獲其位置信息。

剛才重寫鼠標事件的操作,都是在自定義的 Label 中完成的,此時鼠標只有在 Label 范圍內進行動作的時候,才能捕獲到,也可以把這些操作直接放到 Widget (QWidget 的子類) 來完成,這樣的話,鼠標在整個窗口中進行的各種動作都能獲取到了。如下:

在這里插入圖片描述
在這里插入圖片描述

注意:

  • 鼠標移動不同于鼠標按下,隨便移動一下鼠標,就會產生大量的鼠標移動事件,當你進行捕獲事件的時候,久其是在這里再進行一些復雜邏輯的時候,程序負擔就很重,很容易產生卡頓之類的情況。
  • Qt 為了保證程序的流暢性,默認情況下不會對鼠標移動進行追蹤,鼠標移動的時候不會調用 mouseMoveEvent(),除非顯示告訴 Qt 就要追蹤鼠標位置。

如下:

在這里插入圖片描述

代碼:鼠標滾輪事件

在 Qt 中,鼠標滾輪事件是通過 QWindow::wheelEvent(QWheelEvent *event) 函數來實現的。滾輪滑動的距離可以通過 event->delta() 函數獲取。

  • 返回值:滾輪滑動的距離,正數表示滾輪相對于用戶向前滑動,負數表示滾輪相對于用戶向后滑動。

在這里插入圖片描述

在這里插入圖片描述

可以通過滾輪可以實現縮放字體的大小!

按鍵事件處理

  • 要想獲取到用戶的鍵盤按鍵,可以通過 QShortCut,這是信號槽機制封裝過,獲取鍵盤按鍵的方式,站在更底層的角度,也可以通過事件獲取到當前用戶鍵盤按鍵按下的情況。
  • Qt 中的按鍵事件是通過 QKeyEvent 類來實現的。當鍵盤上的按鍵被按下或者被釋放時,鍵盤事件便會觸發。在幫助文檔中查找 QKeyEvent 類如下:

在這里插入圖片描述

代碼:按下單個按鍵

按下單個按鍵是通過虛函數 QWidget::keyPressEvent(QKeyEvent *event) 來實現的,搭配 event->key() 函數,來獲取哪個按鍵被按下,如下:

在這里插入圖片描述

在這里插入圖片描述

代碼:按下組合按鍵

在 Qt 助手中搜索:Qt::KeyboardModifier,如下圖示:

在這里插入圖片描述

Qt::KeyboardModifier 中定義了在處理鍵盤事件時對應的修改鍵。在 Qt 中,鍵盤事件可以與修改鍵一起使用,以實現一些復雜的交互操作。KeyboardModifier 中修改鍵的具體描述如下:

在這里插入圖片描述

通過 event->modifiers() 函數,判斷按下了哪一個修改鍵,如下:

在這里插入圖片描述

定時器事件處理

Qt 中在進行窗口程序的處理過程中,經常要周期性的執行某些操作,或者制作一些動畫效果,使用定時器就可以實現。所謂定時器就是在間隔一定時間后,去執行某一個任務。定時器在很多場景下都會使用到,如彈窗自動關閉之類的功能等。

Qt 中的定時器分為 QTimerEvent 和 QTimer 這兩個類:

  • QTimerEvent 類,用來描述一個定時器事件。在使用時需要通過 QObject::startTimer() 函數來開啟一個定時器,這個函數需要輸入一個以毫秒為單位的整數作為參數來表明設定的時間,它返回的整型值代表這個定時器。當定時器溢出時 (即定時時間到達) 就可以在 QObject::timerEvent() 函數中獲取該定時器的編號來進行相關操作。
  • QTimer 類,用來實現一個定時器,背后是 QTimerEvent 定時器事件進行支撐的,它提供了更高層次的編程接口,例如:可以使用信號和槽,還可以設置只運行一次的定時器。

代碼:基于 QTimerEvent 定時器,實現倒計時

通過 QObject::startTimer(int msec) 這個虛函數,開啟定時器,返回一個身份標識符,用于標識這個定時器,功能就是每隔一段時間,執行 QObject::timerEvent(QTimerEvent *event) 函數,通過 event->timerId() 函數來獲取定時器標識符,通過 QObject::killTimer(int id) 函數來取消某個定時器,如下:

在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述

代碼:基于 QTimer 定時器,實現倒計時

通過創建 QTimer 對象,調用其中的 start(int msec) 函數來啟動定時器,每隔一段時間定時器對象就會發出 QTimer::timeout 信號,此時需要將該信號和處理定時器的槽函數建立連接,通過 stop() 函數來停止定時器,如下:

在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述

總結:使用 timerEvent 比 QTimer 還是要更復雜一些,需要手動管理 timerId,還需要區分這次函數調用是哪個 timerId 引起的,后續實際開發中,使用 QTimer 即可。

代碼:獲取系統日期及時間

  • 在 Qt 中,獲取系統的日期及實時時間可以通過 QTimer 類 和 QDateTime 類,QDateTime 類提供了字符串格式的時間。
  • 字符串形式的時間輸出格式由 toString() 方法中的 format 參數列表決定,可用的參數列表如下:

在這里插入圖片描述

在 ui 文件中,放置一個 QLabel 控件,用來顯示日期及時間,同時放置兩個按鈕 “開始” 和 “停止”,如下:

在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述

窗口事件處理

  • 通過 QWidget::moveEvent(QMoveEvent *event) 虛函數,是窗口移動時,觸發的事件。
  • 通過 QWidget::resizeEvent(QResizeEvent *event) 虛函數,是窗口大小改變時,觸發的事件。

在這里插入圖片描述
在這里插入圖片描述

代碼:窗口移動、窗口大小改變,事件的處理

在這里插入圖片描述
在這里插入圖片描述

二. 事件分發器

事件分發器概述:

  • 在 Qt 中,事件分發器 (Event Dispatcher) 是一個核心概念,用于處理 GUI 應用程序中的事件。
  • 事件分發器負責將事件從一個對象傳遞到另一個對象,直到事件被處理或被取消。
  • 每個繼承 QObject 類 或 QObject 類本身,都可以在本類中重寫 bool event(QEvent *event) 函數,來實現相關事件的捕獲和攔截。

事件分發器工作原理:

  • 在 Qt 中,我們發送的事件都是傳給了 QObject 對象,更具體點是傳給了 QObject 對象的 event() 函數。
  • 所有的事件都會進入到 event() 函數里面,那么我們處理事件就要重寫這個 event() 函數。
  • event() 函數本身不會去處理事件,而是根據 事件類型 (type值) 調用不同的事件處理函數。
  • 事件分發器就是工作在應用程序向下分發事件的過程中,如下圖:

在這里插入圖片描述

如上圖,事件分發器用于分發事件。在此過程中,事件分發器也可以做攔截操作。事件分發器主要是通過 bool event(QEvent *event) 函數來實現。其返回值為布爾類型,若為 ture 代表攔截,不向下分
發。

Qt 中的事件是封裝在 QEvent 類中,在 Qt 助手中輸入 QEvent 可以查看其所包括的事件類型,如下圖示:

在這里插入圖片描述
在這里插入圖片描述

代碼:鼠標點擊事件 和 事件分發器

在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述

事件處理順序:

  • 當鼠標按下事件發生時,系統首先調用 event() 方法,判斷事件類型是否為 QEvent::MouseButtonPress:
    • 如果是:則返回 true 表示事件已被處理,不會繼續分發給 mousePressEvent()
    • 如果不是: event() 返回 QWidget::event(event),表示交給父類處理,結果就是,事件會繼續分發到 mousePressEvent(),處理鼠標按下事件。

三. 事件過濾器

在 Qt 中,一個對象可能經常要查看或攔截另外?個對象的事件,如對話框想要攔截按鍵事件,不讓別的組件接收到,或者修改按鍵的默認值等。通過上面,已經知道,Qt 創建了 QEvent 事件對象之后,會調用 QObject::event() 函數來處理事件的分發。

顯然,我們可以在 event() 函數中實現攔截的操作,由于 event() 函數是 protected 的,因此需要繼承已有類。如果組件很多,就需要重寫很多個 event() 函數。這當然相當麻煩,更不用說重寫 event() 函數還得小心一堆問題。好在 Qt 提供了另外一種機制來達到這一目的:事件過濾器。

事件過濾器是在應用程序分發到 event 事件分發器之前,再做一次更高級的攔截,如下圖示:

在這里插入圖片描述

事件過濾器的一般使用步驟:安裝事件過濾器、重寫事件過濾器函數 eventfilter()

void QObject::installEventFilter(QObject *filterObj)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/913113.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/913113.shtml
英文地址,請注明出處:http://en.pswp.cn/news/913113.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

廣東省省考備考(第三十八天7.4)——言語理解:邏輯填空(題目訓練)

錯題解析 本題可從第二空入手,橫線處搭配“理論”,且根據“使得”可知,橫線處與前文構成因果關系,即“遺傳學的空白和古生物證據的缺乏”導致他的理論在某些方面存在不足,A項“捉襟見肘”指拉一拉衣襟,就露…

5G網絡切片技術

5G中的網絡切片技術是一種通過虛擬化將單一物理網絡劃分為多個獨立、可定制的虛擬網絡的技術,旨在滿足不同應用場景對網絡性能、帶寬、時延等需求的差異化要求。以下從技術原理、核心價值、應用場景、實現方式及未來趨勢五個維度展開分析:一、技術原理&a…

算法學習筆記:7.Dijkstra 算法——從原理到實戰,涵蓋 LeetCode 與考研 408 例題

在計算機科學領域,圖論算法一直占據著重要地位,其中 Dijkstra 算法作為求解單源最短路徑問題的經典算法,被廣泛應用于路徑規劃、網絡路由等多個場景。無論是算法競賽、實際項目開發,還是計算機考研 408 的備考,Dijkstr…

匯編 函數調用棧

前言 網上很多對函數棧的解釋,說的不是很清楚感覺,尤其是對到底是誰的棧,以及指令的微小但是很致命的細節沒說,特寫本文,一是幫助自己記憶,二是為了幫助大家,如有疏忽錯誤請指正。 核心概念 首先…

基于Apache MINA SSHD配置及應用

Apache MINA SSHD 是一個基于 Java 的 SSH 服務器和客戶端實現,它是 Apache MINA 項目的一部分,提供了完整的 SSH 協議支持。 主要特性 SSH 協議支持: 支持 SSH2 協議 兼容大多數 SSH 客戶端 支持多種加密算法和密鑰交換方法 服務器功能…

Excel 如何讓數據自動按要求排序或篩選?

讓數據按要求排序和篩選是Excel數據處理的基礎核心功能,也是進行有效分析前必做的準備工作。下面我們分開講解這兩個功能。 一、排序 (Sort):讓數據井井有條 排序的目的是重新排列數據行的順序,以便更好地觀察和比較。 1. 快速單列排序 (最…

Django 安裝使用教程

一、Django 簡介 Django 是一個高級 Python Web 框架,鼓勵快速開發和簡潔實用的設計。它內置 ORM、認證系統、后臺管理、表單處理、路由控制等功能,廣泛用于開發企業級網站、內容管理系統、電商平臺等。 二、環境準備 2.1 安裝 Python Django 基于 Py…

前沿交叉:Fluent與深度學習驅動的流體力學計算體系

基礎模塊 流體力學方程求解 1、不可壓縮N-S方程數值解法(有限差分/有限元/偽譜法) Fluent工業級應用:穩態/瞬態流、兩相流仿真(圓柱繞流、入水問題) Tecplot流場可視化與數據導出 2、CFD數據的AI預處理 基于P…

五、Flutter動畫

目錄1. Flutter 中動畫的基本概念是什么?2. 解釋 AnimationController 和 Tween 的作用3. 如何實現一個補間(Tween)動畫?4. 什么是隱式動畫?舉例說明5. 如何實現自定義復雜動畫?1. Flutter 中動畫的基本概念…

全網唯一/Qt結合ffmpeg實現手機端采集攝像頭推流到rtsp或rtmp/可切換前置后置攝像頭/指定分辨率幀率

一、前言說明 之前已經實現了Qt結合ffmpeg在安卓上運行,所有在win上的功能,在安卓上都已經實現,比如編碼保存到MP4文件,正常解碼音視頻文件播放等,唯獨還差一個功能,盡管用的不多,但是還是有一…

Install Ubuntu 24.04 System

1.制作安裝鏡像盤(U盤) 下載rufus制作工具(網址:https://www.xiaomoxz.com/nexus/bi1/rufus4.shtml?bd_vid8643969197265870719) 2. 設置U盤啟動: F2進入BIOS 3. Install Ubuntu 24.04 Ubuntu下載地址:…

solidjs 處理復雜類型的響應式

solidjs 處理復雜類型的響應式 在 solidjs 里響應式一般直接用 createSignal 就可以,但 createSignal 一般用于基礎數據類型。 雖然復雜類型也是可以使用,但基于起細粒度響應性的特性。 一般復雜的數據使用 createSignal 就不是那么友好了。 所以 cre…

爬蟲技術-獲取瀏覽器身份認證信息(如 Cookie、Token、Session 等)

方法一:通過瀏覽器開發者工具查看和提取 Cookie / Token 📌 示例場景: 你在使用一個網站時已經登錄了,想看看這個網站是如何保存你的身份憑證的。 🔧 操作過程: 打開瀏覽器(例如 Chrome&#xf…

[密碼學實戰]GMT 0136-2024《密碼應用HTTP接口規范》解析

[密碼學實戰]GM/T 0136-2024《密碼應用HTTP接口規范》解析國家密碼管理局于2025年7月1日正式實施GM/T 0136-2024標準,該規范首次統一了密碼服務的HTTP接口設計,為國產密碼技術的規模化應用鋪平道路。本文結合標準原文,深入剖析其技術細節并給…

Docker 國內鏡像列表(免費長期)

Docker 可用鏡像源列表(7月1日更新-長期維護)_dockerhub國內鏡像源列表-CSDN博客

BlenderFBXExporter 導出fbx被修改問題

1) 解決增加A節點的問題 https://github.com/A-Ribeiro/CustomBlenderFBXExporter 2)找出blendshape 不一致,生成blendshape key name映射map 文件compare.txt C:\Users\49938\Documents\DazToUnreal\zhang01\UpdatedFBX\zhang01_fix7.fbx…

AI時代下的IT服務管理轉型:趨勢、挑戰與破局之道

近年來,人工智能(AI)與自動化技術的迅猛發展,正以前所未有的速度重塑企業運營的各個層面。特別是在IT服務管理(ITSM)領域,AI的介入不僅提高了問題響應效率,也推動了組織從“被動響應…

三體融合實戰:Django+訊飛星火+Colossal-AI的企業級AI系統架構

目錄 技術棧關鍵詞:Django 5.0 訊飛星火4.0Ultra Colossal-AI 1.2 WebSocket 聯邦學習 ? 核心架構設計 🛠? 一、Django深度集成訊飛星火API(免費版) 1. 獲取API憑證 2. 流式通信改造(解決高并發阻塞&#xff09…

多模態數據融合預警:從IoT傳感器到衛星監測的可視化方案升級

你有沒有想過,為什么有些城市在暴雨來臨時能提前數小時發布內澇預警,而有些地方卻只能“等水來了才反應”? 背后的關鍵,就是多模態數據融合預警系統——它把來自IoT傳感器、無人機、地面雷達、氣象站、甚至衛星的數據整合在一起&a…

面試八股---css

2、css 2.1 說說你對盒子模型的理解 是什么 當對一個文檔進行布局(layout)的時候,瀏覽器的渲染引擎會根據標準之一的 CSS 基礎框盒模型(CSS basic box model),將所有元素表示為一個個矩形的盒子&#xf…