溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Qt 的事件原理

發(fā)布時間:2020-06-30 04:54:02 來源:網(wǎng)絡(luò) 閱讀:696 作者:WZM3558862 欄目:開發(fā)技術(shù)

Qt的事件比如那些特定事件 ,估計大家都會使用,但是各種原理未必所有人都能理解深透,現(xiàn)在上圖

一、Qt中事件處理的方式

 

1、事件處理模式一

        首先是事件源產(chǎn)生事件,最后是事件處理器對這些事件進行處理。然而也許大家會問,

Qt中有這么多類的事件,我們怎么樣比較簡便的處理每個事件呢?設(shè)想,如果是每個事件都對應(yīng)同一個事件處理器,在該事件處理器中對不同的事件進行分類處理,這樣的弊端有兩點:第一,導(dǎo)致該事件處理器過于臃腫復(fù)雜;第二,這樣不便于擴展,當(dāng)系統(tǒng)新增加事件類型或者是我們需要使用到自定義事件時,就不得不修改Qt的源碼來達到目的。所以Qt設(shè)計者的做法是針對不同類型的事件提供不同的事件處理器與之對應(yīng)。這里又有一個問題了,Qt中是怎么讓不同類型事件與之對應(yīng)的事件處理器相關(guān)聯(lián)的呢?我們不難猜想在事件和事件處理器中間必定有一個橋梁。這個橋梁就是QObject::event()函數(shù),該函數(shù)是虛函數(shù),QObject的子類例如QWidget都實現(xiàn)了該函數(shù)。該函數(shù)的主要功能是進行事件的分發(fā),也就是將不同類型的事件與之相對應(yīng)的事件處理器相關(guān)聯(lián),該函數(shù)并不對事件進行處理,真正的事件處理是在事件處理器中進行的。

        例如:當(dāng)QWidget產(chǎn)生QPaintEvent事件后,QWidget的event函數(shù)會將該事件分發(fā)給QWidget::paintEvent()事件處理器,這樣該事件就得到處理了。

以上內(nèi)容用一個圖形表示就是:
Qt  的事件原理

2、事件處理模式二

        很多時候,我們只對某些特定的事件比較關(guān)心,例如:鼠標(biāo)單擊或者鍵盤按下等事件。其它的事件我們并不關(guān)心它是否發(fā)生,也無需對它們進行處理,這個時候最直接的想法就是將這些事件過濾掉,這樣做既可以免去對它們進行處理,也可以避免它們對程序其它部分產(chǎn)生影響。因此,處理模式二中我們引入了事件過濾器這個概念。

        如果對象安裝了事件過濾器,則事件在到達目標(biāo)對象之前先被事件過濾器截獲,進行一些處理之后再交給目標(biāo)對象,該模式總結(jié)為一個圖如下:

Qt  的事件原理
注意:這里需要區(qū)別對待,如果你是使用installEventFilter()函數(shù)給目標(biāo)對象注冊事件過濾器,那么該事件過濾器只對該目標(biāo)對象有效,只有該對象的事件需要先傳遞給eventFilter()函數(shù)進行過濾,然后調(diào)用相應(yīng)的事件處理器進行處理,非目標(biāo)對象則不受影響。如果你是給程序中唯一的QApplication對象注冊事件過濾器,那么該過濾器對程序中的每一個對象都有效,任何對象的事件都是先傳給eventFilter()函數(shù),然后再使用事件處理器進行處理。

3、事件處理模式三

        Qt調(diào)用QApplicaton來發(fā)送一個事件。所以我們可以重新實現(xiàn)QApplication中的notify()函數(shù)來獲取事件并進行處理,而且使用該函數(shù)獲取事件的時間要早于事件過濾器獲取事件的時間。但是使用事件過濾器較為簡便,因為我們可以有多個事件過濾器,但是只能有一個notify()函數(shù)。
用一個圖來總結(jié)該模式就是:

Qt  的事件原理

二、Qt中事件處理的方法

        從以上三個處理模式我們可以看出,這是一個不斷完善的過程,從3個模式的討論中我們不難找到可以進行事件處理的地方,而這幾個地方就是我們在編寫程序的時候可以控制事件處理的地方。
1、event()函數(shù)
首先是控制事件分發(fā)的event()函數(shù),我們可以改寫該函數(shù),改變事件的分發(fā)方式,這樣就可以改變事件處理的結(jié)果。
2、notify()函數(shù)
實現(xiàn)該函數(shù)可以截獲事件,并對事件加以處理,但是該方法很少用,這里不做介紹。
3、事件過濾器
實現(xiàn)自己的事件過濾器就可以改變事件處理的方法和結(jié)果,這個方法比較常用。
4、事件處理器
事件處理的最后一步,也是最重要的一步就是事件處理器,因為它才是真正進行事件處理的地方,我們可以改寫以有的事件處理器,以此改變已有事件的處理方法和處理結(jié)果,我們也可以定義自己的事件類型和相應(yīng)的事件處理器。

注意:以上四種方法中最常用的是后兩者:事件過濾器和事件處理器。


補充內(nèi)容:

1、事件的傳遞

        包括鼠標(biāo)和鍵盤事件在內(nèi)的很多事件都可以被傳遞。如果事件在到達目標(biāo)對象之前沒有被截獲處理,或者已經(jīng)傳遞給了它的目標(biāo)對象但目標(biāo)對象并沒有進行處理,那么此時,目標(biāo)對象的父對象將變成新的目標(biāo)對象,整個事件處理的過程將重復(fù)進行,直到該事件被處理或者到達最頂層對象為止。

2、event實例解析

       下面的代碼是QWidget::event()函數(shù)的代碼,從代碼中可以看出event()函數(shù)確實只進行事件的分發(fā)而不負(fù)責(zé)事件的處理。由于函數(shù)代碼過多,且都是一類型的用switch語句進行處理的,這里只貼出一部分代碼:

[cpp] view plain copy

  1. bool QWidget::event(QEvent *event)  

  2. {  

  3.     Q_D(QWidget);  

  4.   

  5.     // ignore mouse events when disabled  

  6.     if (!isEnabled()) {  

  7.         switch(event->type()) {  

  8.         case QEvent::TabletPress:  

  9.         case QEvent::TabletRelease:  

  10.         case QEvent::TabletMove:  

  11.         case QEvent::MouseButtonPress:  

  12.         case QEvent::MouseButtonRelease:  

  13.         case QEvent::MouseButtonDblClick:  

  14.         case QEvent::MouseMove:  

  15.         case QEvent::TouchBegin:  

  16.         case QEvent::TouchUpdate:  

  17.         case QEvent::TouchEnd:  

  18.         case QEvent::ContextMenu:  

  19. #ifndef QT_NO_WHEELEVENT  

  20.         case QEvent::Wheel:  

  21. #endif  

  22.             return false;  

  23.         default:  

  24.             break;  

  25.         }  

  26.     }  

  27.     switch (event->type()) {  

  28.     case QEvent::MouseMove:  

  29.         mouseMoveEvent((QMouseEvent*)event);  

  30.         break;  

  31.   

  32.     case QEvent::MouseButtonPress:  

  33.         // Don't reset input context here. Whether reset or not is  

  34.         // a responsibility of input method. reset() will be  

  35.         // called by mouseHandler() of input method if necessary  

  36.         // via mousePressEvent() of text widgets.  

  37. #if 0  

  38.         resetInputContext();  

  39. #endif  

  40.         mousePressEvent((QMouseEvent*)event);  

  41.         break;  

  42.   

  43.     case QEvent::MouseButtonRelease:  

  44.         mouseReleaseEvent((QMouseEvent*)event);  

  45.         break;  

  46.   

  47.     case QEvent::MouseButtonDblClick:  

  48.         mouseDoubleClickEvent((QMouseEvent*)event);  

  49.         break;  

  50. #ifndef QT_NO_WHEELEVENT  

  51.     case QEvent::Wheel:  

  52.         wheelEvent((QWheelEvent*)event);  

  53.         break;  

  54. #endif  

  55. #ifndef QT_NO_TABLETEVENT  

  56.     case QEvent::TabletMove:  

  57.     case QEvent::TabletPress:  

  58.     case QEvent::TabletRelease:  

  59.         tabletEvent((QTabletEvent*)event);  

  60.         break;  

  61. #endif  


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

qt
AI