淺議Qt的事件處理機制 一
深入瞭解事件處理系統對於每個學習Qt人來說非常重要,可以說,Qt是以事件驅動的UI工具集。 大家熟知Signals/Slots在多執行緒的實現也依賴於Qt的事件處理機制。
在Qt中,事件被封裝成一個個物件,所有的事件均繼承自抽象類QEvent. 接下來依次談談Qt中有誰來產生、分發、接受和處理事件:
1. 誰來產生事件: 最容易想到的是我們的輸入裝置,比如鍵盤、滑鼠產生的
keyPressEvent,keyReleaseEvent,mousePressEvent,mouseReleaseEvent事件(他們被封裝成QMouseEvent和QKeyEvent),這些事件來自於底層的作業系統,它們以非同步的形式通知Qt事件處理系統,後文會仔細道來。
2. 誰來接受和處理事件:答案是QObject。在Qt的內省機制剖析一文已經介紹QObject 類是整個Qt物件模型的心臟,事件處理機制是QObject三大職責(記憶體管理、內省(intropection)與事件處理制)之一。任何一個想要接受並處理事件的物件均須繼承自QObject,可以選擇過載QObject::event()函式或事件的處理權轉給父類。
3. 誰來負責分發事件:對於non-GUI的Qt程式,是由QCoreApplication負責將QEvent分發給QObject的子類-Receiver. 對於Qt GUI程式,由QApplication來負責。
接下來,將通過對程式碼的解析來看看QT是利用event loop從事件佇列中獲取使用者輸入事件,又是如何將事件轉義成QEvents,並分發給相應的QObject處理。
- #include <QApplication>
- #include "widget.h"
- //Section 1
- int main(int argc, char *argv[])
- {
- QApplication app(argc, argv);
- Widget window; // Widget 繼承自QWidget
- window.show();
-
return
- }
- // Section 2:
- int QApplication::exec()
- {
- //skip codes
- //簡單的交給QCoreApplication來處理事件迴圈=〉section 3
- return QCoreApplication::exec();
- }
- // Section 3
- int QCoreApplication::exec()
- {
- //得到當前Thread資料
- QThreadData *threadData = self->d_func()->threadData;
- if (threadData != QThreadData::current()) {
- qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
- return -1;
- }
- //檢查event loop是否已經建立
- if (!threadData->eventLoops.isEmpty()) {
- qWarning("QCoreApplication::exec: The event loop is already running");
- return -1;
- }
- ...
- QEventLoop eventLoop;
- self->d_func()->in_exec = true;
- self->d_func()->aboutToQuitEmitted = false;
- //委任QEventLoop 處理事件佇列迴圈 ==> Section 4
- int returnCode = eventLoop.exec();
- ....
- }
- return returnCode;
- }
- // Section 4
- int QEventLoop::exec(ProcessEventsFlags flags)
- {
- //這裡的實現程式碼不少,最為重要的是以下幾行
- Q_D(QEventLoop); // 訪問QEventloop私有類例項d
- try {
- //只要沒有遇見exit,迴圈派發事件
- while (!d->exit)
- processEvents(flags | WaitForMoreEvents | EventLoopExec);
- } catch (...) {}
- }
- // Section 5
- bool QEventLoop::processEvents(ProcessEventsFlags flags)
- {
- Q_D(QEventLoop);
- if (!d->threadData->eventDispatcher)
- returnfalse;
- if (flags & DeferredDeletion)
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- //將事件派發給與平臺相關的QAbstractEventDispatcher子類 =>Section 6
- return d->threadData->eventDispatcher->processEvents(flags);
- }
- // Section 6,QTDIR/src/corelib/kernel/qeventdispatcher_win.cpp
- // 這段程式碼是完成與windows平臺相關的windows c++。 以跨平臺著稱的Qt同時也提供了對Symiban,Unix等平臺的訊息派發支援
- // 其事現分別封裝在QEventDispatcherSymbian和QEventDispatcherUNIX
- // QEventDispatcherWin32派生自QAbstractEventDispatcher.
- bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
- {
- Q_D(QEventDispatcherWin32);
- if (!d->internalHwnd)
- createInternalHwnd();
- d->interrupt = false;
- emit awake();
- bool canWait;
- bool retVal = false;
- bool seenWM_QT_SENDPOSTEDEVENTS = false;
- bool needWM_QT_SENDPOSTEDEVENTS = false;
- do {
- DWORD waitRet = 0;
- HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
- QVarLengthArray<MSG> processedTimers;
- while (!d->interrupt) {
- DWORD nCount = d->winEventNotifierList.count();
- Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
- MSG msg;
- bool haveMessage;
- if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
- // process queued user input events
- haveMessage = true;
- //從處理使用者輸入佇列中取出一條事件
- msg = d->queuedUserInputEvents.takeFirst();
- } elseif(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
- // 從處理socket佇列中取出一條事件
- haveMessage = true;
- msg = d->queuedSocketEvents.takeFirst();
- } else {
- haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
- if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents)
- && ((msg.message >= WM_KEYFIRST
- && msg.message <= WM_KEYLAST)
- || (msg.message >= WM_MOUSEFIRST
- && msg.message <= WM_MOUSELAST)
- || msg.message == WM_MOUSEWHEEL
- || msg.message == WM_MOUSEHWHEEL
- || msg.message == WM_TOUCH
- #ifndef QT_NO_GESTURES
- || msg.message == WM_GESTURE
- || msg.message == WM_GESTURENOTIFY
- #endif
- || msg.message == WM_CLOSE)) {
- // 使用者輸入事件入佇列,待以後處理
- haveMessage = false;
- d->queuedUserInputEvents.append(msg);
- }
- if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)
- && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
- // socket 事件入佇列,待以後處理
- haveMessage = false;
- d->queuedSocketEvents.append(msg);
- }
- }
- ....
- if (!filterEvent(&msg)) {
- TranslateMessage(&msg);
- //將事件打包成message呼叫Windows API派發出去
- //分發一個訊息給視窗程式。訊息被分發到回撥函式,將訊息傳遞給windows系統,windows處理完畢,會呼叫回撥函式 => section 7
- DispatchMessage(&msg);
- }
- }
- }
- } while (canWait);
- ...
- return retVal;
- }
- // Section 7 windows視窗回撥函式 定義在QTDIR/src/gui/kernel/qapplication_win.cpp
- extern"C"LRESULT QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- ...
- //將訊息重新封裝成QEvent的子類QMouseEvent ==> Section 8
- result = widget->translateMouseEvent(msg);
- ...
- }
從Section 1~Section7, Qt進入QApplication的event loop,經過層層委任,最終QEventloop的processEvent將通過與平臺相關的QAbstractEventDispatcher的子類QEventDispatcherWin32獲得使用者的使用者輸入事件,並將其打包成message後,通過標準Windows API ,把訊息傳遞給了Windows OS,Windows OS得到通知後回撥QtWndProc, 至此事件的分發與處理完成了一半的路程。
在下文中,我們將進一步討論當我們收到來在Windows的回撥後,事件又是怎麼一步步打包成QEvent並通過QApplication分發給最終事件的接受和處理者QObject::event.
下文的連結:
相關推薦
淺議Qt的事件處理機制 一
深入瞭解事件處理系統對於每個學習Qt人來說非常重要,可以說,Qt是以事件驅動的UI工具集。 大家熟知Signals/Slots在多執行緒的實現也依賴於Qt的事件處理機制。 在Qt中,事件被封裝成一個個物件,所有的事件均繼承自抽象類QEvent. 接下來
Qt ------ 事件處理機制
後處理 分發 異步 ant ont 事件循環 tar rpo 基類 簡介 在Qt中,事件被封裝成一個個對象,所有的事件均繼承自抽象類QEvent。Qt是以事件驅動UI工具集。Signals/Slots在多線程中的實現也是依賴於Qt的事件處理機制。在Qt中,事件被封裝成一個個
QT開發——QT事件處理機制
ref:https://blog.csdn.net/A642960662/article/details/66473871 一、QT事件簡介 QT程式是事件驅動的, 程式的每個動作都是由內部某個事件所觸發。QT事件的發生和處理成為程式執行的主線
Qt事件處理機制整個流程--以滑鼠在一個視窗中點選為例
轉載自:http://mobile.51cto.com/symbian-272812.htm,在此謝謝原作者的分享! ------------------------第一部分---------------------- 本篇來介紹Qt 事件處理機制 。深入瞭解事件處理系統對
Qt中的事件處理機制(event)
Qt事件也就是Qt程式中出現的一系列“事情”,包括對使用者操作做出反應時發出的滑鼠或鍵盤事件等;以及系統內部自動發出的定時器事件等。總之,出現了這些事件後就需要對這些事件進行處理,處理的方法便是“事件處理機制”。 圖1 Qt事件產生 以
控制元件巢狀中的QT滑鼠事件處理機制
想實現在層層佈局的控制元件中,對最外層的QLabel上的滑鼠事件實現tracking,即觸發mouseMoveEvent的時候,不需要一直按著 前提:自定義控制元件,繼承QLabel重寫滑鼠事件相應的方法 可參考:https://wiki.qt.io/Clickable_QLabel
淺談Android 事件分發機制(一)
get touch 需要 傳遞 cimage android ges 常見 滑動 在上一篇文章中,淺談Android 事件分發機制(一),簡要分析了一下事件分發機制的原理,總結一下就是事件層層傳遞,直到被消費,原理看似簡單,但是在實際使用過程中,場景各不相同,復雜程度也就因
事件處理(一)
blog lis 監聽 上下 strong 單擊 長按 view 處理方法 事件處理步驟: 1.註冊事件監聽器 2.根據指定的事件中編寫事件處理的代碼 3.在事件處理的代碼證完成對事件的處理 事件處理方法 1.setOnClickListener(View.OnC
從零開始理解JAVA事件處理機制(2)
extend nds 接下來 htm ref param 簡單 tostring ansi 第一節中的示例過於簡單《從零開始理解JAVA事件處理機制(1)》,簡單到讓大家覺得這樣的代碼簡直毫無用處。但是沒辦法,我們要繼續寫這毫無用處的代碼,然後引出下一階段真正有益的代碼。
事件處理機制--瀏覽器流程處理分析
style chan 一件事 cli con open() -h response xhr 事件處理機制--瀏覽器流程處理分析 js的運行是單線程的,單線程即一個時間只能做一件事。瀏覽器的運行是多線程的。 如下三種情況會進入事件隊列(任務隊列)中,但不立即執行: 1.定
初步剖析QT事件處理全過程(Windows)
職責 spa message alt cati 窗口 初步 負責 啟動 一、說起Qt事件處理,在windows平臺下,當然離不開Win32: Win32程序的基本結構: 1.註冊窗口; 2.創建窗口; 3.啟動由GetMessage和DispatchMessage構成
關於表單form元素中onsubmit事件處理機制的認識
讓我 clas 教程 是否 它的 默認方法 對象實例 action 事件處理機制 博主目前處於Js學習的初期,遇到了很多問題,比如今天的關於表單form元素中onsubmit事件問題,根據教程所述,onsubmit事件是在表單提交的時候觸發的,但是我看到教程上的onsu
wxPython事件處理機制
參數 過程 Coding vtt nbu roc pre 是我 說明 一直沒有看明白wxPython的自定義事件是如何工作的。如果要自定義事件,那麽需要明白事件源,事件類型,事件處理函數,以及事件綁定器; 但是我在整個過程中沒有看到這幾個概念是如何關聯起來的。下面舉例說明一
3.1.1 基於監聽的事件處理機制
講解 基於 example this apk imp cal href eat 3.1.1 基於監聽的事件處理機制 http://www.runoob.com/w3cnote/android-tutorial-listen-event-handle.html 本節引言:
3.2 基於回調的事件處理機制
return lan 依賴 架構 順序 們的 oncreate 兩個 運行 3.2 基於回調的事件處理機制 http://www.runoob.com/w3cnote/android-tutorial-callback-event-handle.html 1.
17.QT-事件處理分析、事件過濾器、拖放事件
期待 使用 lis 相關 事件處理 [] 支持 實現 endif Qt事件處理介紹 Qt平臺會將系統產生的消息轉換為Qt事件 Qt事件是一個QEvent的對象 Qt事件用來描述程序內部或外部發生的動作 任意的QObject對象都具備事件處理的能力 Qt常見
Node.js知識點整理之----基礎知識----事件處理機制及事件環機制
node 應用程序 nod eat 回調函數 clas 對象 繼續 知識 在event模塊中,定義了EventEmitter類,所有觸發事件的對象都是繼承了這個類的子類的實例對象。 addListener(event,listener) 對指定事件綁定事件處理函數 on
Qt事件處理
Qt事件處理 Qt事件處理的五個層次 Qt 應用程式 事件處理 的五個層次,同時也是時間流程如下圖所示: 說明如下: sendEvent()會把event直接傳送給QCoreApplication的notify(),postEvent()把event追加到事件佇列中最終也要呼叫notify(
JAVA異常處理機制(一)
異常處理機制try-catch 語法定義: try{ //可能出現異常的程式碼片段 }catch(XXXException e){ //捕獲try中出現的XXXException後的處理操作程式碼 } try-catch演示 public class Try_CatchDe
這篇文章對於瞭解Javascript的事件處理機制非常好,將它全文轉載於此,以備不時之需。
什麼是事件? 事件(Event)是JavaScript應用跳動的心臟 ,也是把所有東西粘在一起的膠水。當我們與瀏覽器中 Web 頁面進行某些型別的互動時,事件就發生了。事件可能是使用者在某些內容上的點選、滑鼠經過某個特定元素或按下鍵盤上的某些按鍵。事件還可能是 Web