国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Qt事件機制

這篇具有很好參考價值的文章主要介紹了Qt事件機制。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

概述


 Qt程序是事件驅(qū)動的, 程序的每個動作都是由內(nèi)部某個事件所觸發(fā)。事件系統(tǒng)在Qt總扮演了十分重要的角色,其事件的生成與事件的派發(fā)對GUI 程序起到了核心的作用。Qt事件處理流程圖和時序圖大致如下, 下面對于整個事件循環(huán)系統(tǒng)進行詳細的講解。

qt事件,qt,開發(fā)語言,ui,linux,Powered by 金山文檔
qt事件,qt,開發(fā)語言,ui,linux,Powered by 金山文檔

1. 事件生成


Qt中事件主要來源于兩類,一類是平臺插件,另一類是用戶自己發(fā)送的事件。

  • 平臺插件事件

用鼠標事件舉例,一個鼠標事件,首先肯定是從驅(qū)動中傳遞上來,uos采用Xorg作為圖形服務(wù)器,Xorg會加載驅(qū)動程序庫,并從中獲取事件轉(zhuǎn)發(fā)到client上,Qt中通過QXcbConnect 連接XServer,并且在prossXcbEvents中使用了while 循環(huán),不斷的處理xcb消息并轉(zhuǎn)發(fā)出去,Qt客戶端中最原始的鼠標事件便來自于這里。那么我們從這里出發(fā)看看鼠標事件是怎么從平臺插件接收到消息并傳遞到上層的。

qt事件,qt,開發(fā)語言,ui,linux,Powered by 金山文檔

該函數(shù)比較簡單,首先進入函數(shù)先判斷連接有錯誤就退出程序,然后是一個while 循環(huán)中不斷的從 m_eventQueue 中讀取事件,compressEvent是壓縮事件的意思,最后通過調(diào)用handleXcbEvent函數(shù)處理事件。在handleXcbEvent中會根據(jù)對應(yīng)事件類型 調(diào)用qxcbwindow中具體的事件處理函數(shù) QXcbWindow::handleMouseEvent 。在該函數(shù)中調(diào)用了靜態(tài)函數(shù)QWindowSystemInterface::handleMouseEvent,代碼如下:

QWindowSystemInterface 類可以看作一個中間層,用于隔離上層的Application和下層的平臺插件。Qt是跨平臺的,上層需要對下層的具體平臺API屏蔽,采用提供QPlatform* 類采用虛接口的方式調(diào)用,下層應(yīng)該盡量減少對上層的依賴。消息就通過QWindowSystemInterface這樣一個中間層進行傳遞。

qt事件,qt,開發(fā)語言,ui,linux,Powered by 金山文檔

繼續(xù)看windowSysteminterface的代碼,在handleMouseEvent函數(shù)中構(gòu)造了MouseEvent對象并且通過handleWindowSystemEvent 函數(shù)發(fā)送,值得注意的是這里雖然構(gòu)造了鼠標消息,單這并不是真正的QMouseEvent消息,我們繼續(xù)往下看。

在 handleWindowSystemEvent 函數(shù)中,調(diào)用了模板類型的 handleWindowSystemEvent,通過synchronousWindowSystemEvents 判斷是調(diào)用同步事件處理還是異步事件處理,異步處理方式就加入到事件隊列中,同步處理就直接采用函數(shù)調(diào)用的方式。我們繼續(xù)分析這兩種方式的處理流程。

同步調(diào)用比較簡單,在同步調(diào)用函數(shù)首先判斷是否為主線程調(diào)用,如果非主線程調(diào)用那么就走異步調(diào)用,如果是當前線程是主線程,那么調(diào)用QGuiApplicationPrivate::processWindowSystemEvent(ev 戒指傳遞到上層,代碼如下。

下面是關(guān)鍵函數(shù)調(diào)用堆棧(還是以mouseEvent為例).

在QGuiApplicationPrivate::processMouseEvent 函數(shù)中調(diào)用 sendSpontaneousEvent函數(shù),進行發(fā)送事件這里可以和上面的用戶事件堆棧代碼進行對比。sendSpontaneousEvent的和sendEvent 的區(qū)別是 前者將事件標記為 Spontaneous,意思是事件起源于應(yīng)用程序外部,一般來說由平臺插件調(diào)用。我們自己發(fā)送事件就調(diào)用sendEvent 。sendSpontaneousEvent函數(shù)調(diào)用后調(diào)用notify 函數(shù)然后直接發(fā)送到對應(yīng)類的event函數(shù)中。notifyInternal 函數(shù)的作用是通知全局回調(diào)函數(shù)?;卣{(diào)函數(shù)被定義為typedef bool (*qInternalCallback)(void **); 該函數(shù)定義可以很方便的與其他的語言進行交互,例如腳本、java等。當然也可以通過這個函數(shù)捕獲所有的Qt事件。notify函數(shù)是一個虛函數(shù),自定義的Application可以通過重新實現(xiàn)該函數(shù),達到事件過濾的效果。 notify_helper 的任務(wù)同樣也是事件過濾的作用,在notify_helper 函數(shù)中,會分別給安裝在 Application 和receiver 對象中的事件過濾器發(fā)送事件??梢钥吹絈t 可以過濾事件的地方還是很多。

在異步調(diào)用中,把事件添加到Qt 的事件循環(huán)隊列中,然后通過事件循環(huán)處理事件,然后發(fā)送到上層(也就是圖上的QGuiApplication層),異步調(diào)用代碼如下:

總結(jié)一下,結(jié)合前面的流程圖這里的平臺事件整個流程就比較清晰了。有兩個地方是值得注意的。第一個就是QXcbConnect::prossXcbEvents。這里是有一個while循環(huán)不斷的讀取xcb事件,我們知道一個事件循環(huán)一般就是一個while循環(huán)不斷的取事件并進行分發(fā)處理,那么這里是就是整個Qt的事件循環(huán)嗎? 第二個值得注意的是,handleWindowSystemEvent的異步調(diào)用,它將事件加入到事件循環(huán)中,這個循環(huán)是整個Qt的事件循環(huán)嗎,那它又是在哪里派發(fā)事件? 我們先記住這兩點,再來看看用戶事件。

  • 用戶事件
    用戶事件比較簡單,在單元測試中尤為常見,通過QCoreapplication的postEvent和sendEvent 發(fā)送事件。值得注意的是postEvent 是把事件添加到事件循環(huán)中,而sendEvent則是直接發(fā)送事件。

先看postEvent函數(shù),部分代碼如下,第一個參數(shù)是消息接收者,第二個參數(shù)為具體消息,第三個參數(shù)為消息優(yōu)先級。postEvent 主要是把事件添加到 postEventList 這樣一個容器中,然后調(diào)用事件分發(fā)器的wakeUp。再往下走就走不通了,那么,這個消息進入事件循環(huán)后,在哪里進行分發(fā)的呢? 稍后我們再討論事件循環(huán)的時候再講它。

sendEvent就沒啥好說了,函數(shù)參數(shù)比postEvent少了一個優(yōu)先級,我們直接看它的調(diào)用堆棧就一目了然.前面講平臺事件的時候已經(jīng)介紹了這些函數(shù)的作用,就不多講了

到此位置,Qt事件的發(fā)生也就是圖中紅框這一部分基本都介紹完了。

qt事件,qt,開發(fā)語言,ui,linux,Powered by 金山文檔

2. 事件循環(huán)與分發(fā)


  • 事件循環(huán)

我們都知道,創(chuàng)建一個Qt程序的時候,總會在main函數(shù)中調(diào)用QGuiapplication::exec 函數(shù),只有當調(diào)用了QGuiapplication::exit 函數(shù)的時候,它才會退出,否這永遠會”卡”在這個函數(shù)中。這個函數(shù)被稱為事件循環(huán)函數(shù)。

在這一節(jié)我們先來看看事件循環(huán)長什么樣子,然后結(jié)合前面事件的發(fā)生來分析事件分發(fā)的過程。先來看看exec函數(shù)堆棧。

從main函數(shù)開始,依次調(diào)用了QApplication、GUI、CORE的exec函數(shù)。這三者區(qū)別在Qt 官方文檔中有詳細的描述。我們主要關(guān)注兩個點 QEventLoop和 QXcbGlibEventDispatcher。

QEventLoop是 事件循環(huán)的關(guān)鍵,從堆棧中可以發(fā)現(xiàn)在QEventLoop的processEvents中調(diào)用了QXcbGlibEventDispatcher::processEvents。而QXcbGlibEventDispatcher繼承于QAbstractEventDispatcher類,QAbstractEventDispatcher是事件分發(fā)的抽象類,根據(jù)不同的平臺,有不同的事件分發(fā)派生類,例如在windows下使用的就是標準的 Windows 消息機制,在linux下一般是采用glib進行事件分發(fā),關(guān)鍵代碼如下:

這個函數(shù)應(yīng)該很熟悉的,在我們調(diào)試一些簡單的Qt程序的時候,按下暫停斷點一般都會停在這里,該函數(shù)也是一個while循環(huán)一直被循環(huán)執(zhí)行,直至退出。而該函數(shù)內(nèi)部則使用了Glib的GMainContext對象,并調(diào)用g_main_context_iteration()函數(shù),該函數(shù)將能夠遍歷一次GMainContext提供的主循環(huán),并有參數(shù)確定如果沒有事件準備好是否需要的等待。那么GMainContext對象包含什么內(nèi)容,又是如何創(chuàng)建的呢?

首先在QEventDispatcherGlibPrivate構(gòu)造函數(shù)中,新建GMainContext對象。 然后使用函數(shù)g_source_new()創(chuàng)建GSource事件源對象,這里需要傳入一組回調(diào)函數(shù)指針GSourceFuncs,一般包括prepare/check/dispatch這3種回調(diào)函數(shù),用于獲知事件狀態(tài)。主循環(huán)調(diào)用 prepare/check 接口, 詢問事件是否準備好如果 prepare 與 check接口的返回值均為 TRUE, 那么此時主事件循環(huán)會調(diào)用 dispatch 接口分發(fā)消息。并使用g_source_attach()將GSource對象綁定到GMainContext對象。 最后如前面所講,g_main_context_iteration()函數(shù)會對GMainContext對象進行檢查,會調(diào)用前面定義的回調(diào)函數(shù), 這里涉及到glib中事件循環(huán)的機制,不多展開描述。

在Qt中,QXcbGlibEventDispatcher 創(chuàng)建了XcbEventSource 事件源對象用于處理xcb事件,另外該類繼承QEventDispatcherGlib,在父對象的構(gòu)造函數(shù)中 分別創(chuàng)建了post event,socket notification,normal timer,和idle timer這幾種事件源對象,總共也就是 5類事件源對象,并將其綁定到GMainContext對象中。

qt事件,qt,開發(fā)語言,ui,linux,Powered by 金山文檔
  • 事件分發(fā)

也就是這里,在Qt中利用了Glib的事件分發(fā)機制,將事件與g_source 綁定,使用一個while循環(huán)的機制不斷的分發(fā)出去。那么Glib的事件是怎么和Qt中對應(yīng)起來的,又是怎么從事件隊列中分發(fā)的,以前面用戶事件QCoreApplication::postEvent 為例。

回顧一下之前的postEvent 函數(shù)的代碼,當調(diào)用 data->postEventList.addEvent(QPostEvent(receiver, event, priority)); 之后,將事件和對應(yīng)的接收者打包放在postEventList 容器中,最后調(diào)用了一個事件調(diào)度器的wakeUp函數(shù) dispatcher->wakeUp();

在該函數(shù)中講 postEventSource 的 序列號serialNumber 增加 ref表示原子性+1 和 serialNumber++ 類似,并調(diào)用了 g_main_context_wakeup函數(shù)喚醒poll。這時候g_main_context_iteration 輪詢各事件源,檢查有沒有需要調(diào)用的事件,主循環(huán)調(diào)用 prepare/check 接口, 詢問事件是否準備好如果 prepare 與 check接口的返回值均為 TRUE, 那么此時主事件循環(huán)會調(diào)用 dispatch 接口分發(fā)消息。我們查看在prepare 與 check的代碼,postEventSourceFuncs 的postEventSourcePrepare函數(shù)關(guān)鍵實現(xiàn)如下:

如果當前序列號與最后一次調(diào)用的序列號不同的話,就把 wakeUpCalled 設(shè)置為 true 并返回。canWait 表示如果沒有掛起的事件,則等待。check 函數(shù)同樣也調(diào)用的 prepare 函數(shù),那么如果我們有postEvent函數(shù)加入進來,prepare 和 check 返回為true。接下來Glib庫就對調(diào)用 dispatch 函數(shù)分發(fā)事件。

在dispatch 函數(shù)中調(diào)用了 QCoreApplication::sendPostedEvents 發(fā)送事件,并且把最后一次序列號 lastSerialNumber 設(shè)置為當前的序列號。

在 QCoreApplication::sendPostedEvents 函數(shù)中,也是一個while 循環(huán),將我們開始放在 postEventList 容器中的事件,然后調(diào)用 QCoreApplication::sendEvent(r, e)全部發(fā)送出去。sendEvent就前面已經(jīng)給詳細講解過了,該函數(shù)是直接的函數(shù)調(diào)用,和事件循環(huán)無關(guān)了。關(guān)鍵代碼如下:

所以在linux下整個事件循環(huán)的流程圖如下,通過上面5中接口,向事件循環(huán)中添加事件,事件隊列由自己維護,gllib事件分發(fā)機制通過回調(diào)函數(shù)查詢是否有需要處理的事件,并調(diào)用下面的5種函數(shù)接口,對事件隊列中的事件pop然后進行處理。

qt事件,qt,開發(fā)語言,ui,linux,Powered by 金山文檔

回到開始將平臺插件的地方,平臺插件的事件異步調(diào)用的時候在QWindowSystemInterface 的時候被加入到事件循環(huán)中,我們看回顧開始的代碼,可以看到該事件循環(huán)就是獲取的QCoreApplication 中的事件循環(huán)。那它的事件分發(fā)在哪里呢? 前面講到的5類事件源對象其中的 XcbEventSource 就是處理這里的事件。在Prepare/check查詢函數(shù)中永遠返回了true。也就是只要有xcb事件就會進行處理。

在 dispatch事件分發(fā)函數(shù)中調(diào)用了QWindowSystemInterface::sendWindowSystemEvents函數(shù)。然后在該函數(shù)調(diào)用了 QGuiApplicationPrivate::processWindowSystemEvent 將事件傳遞到上層處理

值得注意的是在dispatch 函數(shù)中還調(diào)用了 processXcbEvents 函數(shù),這個函數(shù)是xcb消息起源的函數(shù)。前面已經(jīng)提到了,該函數(shù)中也是有個while 循環(huán)從 一個隊列中取數(shù)據(jù),并轉(zhuǎn)化為 xcb 消息。那么該事件隊列的數(shù)據(jù)來自于哪里? Qt主線程負責界面繪制、刷新、事件等任務(wù),而平臺消息基于socket,實時性要求較高,所以在平臺插件的內(nèi)部有專門的一個線程QXcbEventQueue負責處理xcb的消息。QXcbEventQueue 繼承于QThread,在QxcbConnect中創(chuàng)建,run函數(shù)中調(diào)用 xcb_wait_for_event 函數(shù)等待 xcb消息,并將其加入到 QXcbEventQueue中供 processXcbEvents 處理。

3. QA


到此結(jié)束,事件循環(huán)就講解完了,有幾個問題

Q: 需要等待100 ms,又不想阻塞主線程,下面代碼的原理是什么?

A:當執(zhí)行到exec 的代碼的時候,程序不再往下繼續(xù)執(zhí)行,因為進入了 事件分發(fā)器dispatch 函數(shù)的while 循環(huán)中,如果這時候事件隊列中有事件,那么就繼續(xù)處理事件,如果這時候沒有事件,就暫停在這里 100ms 后繼續(xù)執(zhí)行后面代碼。

Q:QDialog的exec 也調(diào)用了exec。其原理是什么?為什么會阻塞其他widget的消息

A:QDialog的exec 原理和第一個問題一樣。同樣是創(chuàng)建了QEventloop對象,這時候xcb事件隊列中仍然會收到QWidget 的消息,并且進入事件循環(huán),QWidget的消息轉(zhuǎn)發(fā)到上層的時候,在QGuiapplication中被 blockedByModalWindow變量攔截。不再進行傳遞、文章來源地址http://www.zghlxwxcb.cn/news/detail-610924.html

到了這里,關(guān)于Qt事件機制的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【Qt 底層之事件驅(qū)動系統(tǒng)】深入理解 Qt 事件機制:主事件循環(huán)與工作線程的交互探究,包括 QML 的視角

    【Qt 底層之事件驅(qū)動系統(tǒng)】深入理解 Qt 事件機制:主事件循環(huán)與工作線程的交互探究,包括 QML 的視角

    在探討 Qt 的世界時,我們不僅是在討論一種編程框架,更是在探索一種將復雜技術(shù)細節(jié)隱藏于幕后、讓開發(fā)者專注于創(chuàng)造性工作的藝術(shù)形式。正如著名的計算機科學家 Edsger Dijkstra 所言:“簡潔是復雜性的先決條件?!?在這一章節(jié)中,我們將探討 Qt 事件機制的基礎(chǔ)概念,這

    2024年02月22日
    瀏覽(27)
  • DAY4,Qt(事件處理機制的使用,Qt中實現(xiàn)服務(wù)器的原理)

    DAY4,Qt(事件處理機制的使用,Qt中實現(xiàn)服務(wù)器的原理)

    ---chatser.h---頭文件 ---chatser.cpp---函數(shù)實現(xiàn)文件 ---main.cpp---測試文件 結(jié)果展示---? ? ?

    2024年02月15日
    瀏覽(20)
  • QT 之基礎(chǔ)(一) 詳解UI文件設(shè)計與運行機制

    QT 之基礎(chǔ)(一) 詳解UI文件設(shè)計與運行機制

    一、項目文件組成 1.1 創(chuàng)建一個項目文件 ? ? ? ?建立好項目如下 ? (1)項目組織文件【untitled.pro】 存儲項目設(shè)置文件 (2)主程序入口文件【main.cpp】 實現(xiàn)函數(shù)main()函數(shù)程序文件? ?(3)窗體界面文件【mainwindow.ui】 一個XML格式存儲的窗體上的元件及其布局文件。 任何界面窗

    2024年02月16日
    瀏覽(19)
  • QT基礎(chǔ)之——ui文件以及信號和槽機制

    QT基礎(chǔ)之——ui文件以及信號和槽機制

    ? ? ? ? 上一節(jié)我們講了除界面文件ui文件其他的所有文件,這一節(jié)我們來介紹一下ui文件:在文件目錄中我們能看到界面文件這一欄,點擊展開我們可以看到一個以\\\".ui\\\"結(jié)尾的文件,雙擊我們會看到如下界面: ? ? ? ? 我們在右側(cè)選中l(wèi)abel和PushButton拖入到工作臺上的窗口中,

    2024年04月08日
    瀏覽(23)
  • Qt UI上的按鈕和創(chuàng)建的按鈕綁定 click 點擊事件

    Qt UI上的按鈕和創(chuàng)建的按鈕綁定 click 點擊事件

    如果在ui 上 的按鈕 綁定點擊事件,按鈕鼠標右鍵轉(zhuǎn)到槽,點擊clicked(),即可創(chuàng)建函數(shù)。 動態(tài)創(chuàng)建的按鈕需要 用 connect 連接

    2024年02月15日
    瀏覽(26)
  • Qt開發(fā)-鼠標事件

    Qt開發(fā)-鼠標事件

    個人認為,事件機制是Qt最難以理解且最為精妙的一部分。事件主要分為兩種: 在與用戶交互時發(fā)生 。比如按下鼠標(mousePressEvent),敲擊鍵盤(keyPressEvent)等。 系統(tǒng)自動發(fā)生 ,比如計時器事件(timerEvent)等。 在發(fā)生事件時(比如說上面說的按下鼠標),就會產(chǎn)生一個

    2024年02月09日
    瀏覽(28)
  • C++ Qt開發(fā):Charts折線圖綁定事件

    C++ Qt開發(fā):Charts折線圖綁定事件

    Qt 是一個跨平臺C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺窗體應(yīng)用程序,在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實現(xiàn)圖形化開發(fā)極大的方便了開發(fā)效率,本章將重點介紹 QCharts 折線圖的常用方法及靈活運用。 在上一篇文章中筆者介紹了關(guān)于 QChart

    2024年02月04日
    瀏覽(25)
  • Qt實現(xiàn)全局鼠標事件監(jiān)聽器-Linux

    Qt實現(xiàn)全局鼠標事件監(jiān)聽器-Linux

    更多精彩內(nèi)容 ??個人內(nèi)容分類匯總 ?? ??Qt自定義模塊、工具?? Qt版本:V5.12.5 兼容系統(tǒng): Windows:這里測試了Windows10,其它的版本沒有測試; Linux:這里測試了ubuntu18.04、20.04,其它的沒有測試; Mac:等啥時候我有了Mac電腦再說。 有時候我們想獲取到【系統(tǒng)全局鼠標事件】

    2024年02月11日
    瀏覽(17)
  • 【QT開發(fā)筆記-基礎(chǔ)篇】| 第四章 事件QEvent | 4.5 鍵盤事件

    【QT開發(fā)筆記-基礎(chǔ)篇】| 第四章 事件QEvent | 4.5 鍵盤事件

    本章要實現(xiàn)的整體效果如下: QEvent::KeyPress ? 鍵盤按下時,觸發(fā)該事件,它對應(yīng)的子類是 QKeyEvent QEvent::KeyRelease ? 鍵盤抬起時,觸發(fā)該事件,它對應(yīng)的子類是 QKeyEvent 本節(jié)通過兩個案例來講解這 2 個事件: 鍵盤按下、釋放事件的基本使用 通過鍵盤的上下左右箭頭,控制標簽

    2024年02月07日
    瀏覽(24)
  • Qt教程 — 2.1 如何使用Qt Designer 開發(fā)UI程序

    Qt教程 — 2.1 如何使用Qt Designer 開發(fā)UI程序

    目錄 1?Qt Designer簡介 2 編輯UI界面 2.1?在 UI 界面添加一個Label 2.2 在 UI 界面添加一個按鈕 2.3 在 UI 文件里連接信號與槽 方法一:通過信號和槽編輯欄 方法二:通過導航區(qū)信號和槽編按鈕 方法三:通過跳轉(zhuǎn)編輯代碼實現(xiàn)—通過按鈕輸出文字 Qt Designer 是屬于 Qt Creator 的一個功能

    2024年03月22日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包