日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

QT中父子窗口事件传递与事件过滤器

發布時間:2023/12/18 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 QT中父子窗口事件传递与事件过滤器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

 處理監控系統的時候遇到問題,在MainWidget中創建多個子Widget的時候,原意是想鼠標點擊先讓MainWidget截獲處理后再分派給子Widget去處理,但調試后發現如果子Widget重新實現了事件方法,就直接處理掉事件了,沒有進到MainWidget的處理方法中去,如果子Widget沒有accept或ignore該事件,則該事件就會被傳遞給其父親,在子Widget存在accept或ignore事件的時候,想要經過一下MainWidget的處理方法,就得用到事件處理器,因此網上找了一下,發現QT的事件處理器可以處理。

  QT將事件封裝為QEvent實例以后,會呼叫QObject的event()方法,并且將QEvent實例傳送給它,在某些情況下,希望在執行event()之前,先對一些事件進行處理或過濾,然后再決定是否呼叫event()方法,這時候可以使用事件過濾器。

  可以重新定義一個繼承自QObject(或其子類)的類的eventFilter()方法,

bool FilterObject::eventFilter(QObject *object, QEvent *event)

{?? ?

  if(event->type() == QEvent::KeyPress)

  {?? ? ? ?

    QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);?? ? ? ?

    if (keyEvent->key() == Qt::Key_Tab)?

    {

      // 處理Tab鍵 ? ? ? ? ??

      return true;?? ? ??

    }

  }?? ?

  return false;

}

eventFilter()的object參數表示事件發生的來源物件,eventFilter()若返回false,則安裝該事件過濾器的對象的event()會繼續執行,若返回true,則安裝事件過濾器的對象后event()方法就不會被執行,由此進行事件的攔截處理。給本對象安裝事件過濾器:

this->installEventFilter(this);

?

Qt事件的類型很多,?常見的qt的事件如下:

鍵盤事件:?按鍵按下和松開.

鼠標事件:?鼠標移動,鼠標按鍵的按下和松開.

拖放事件:?用鼠標進行拖放.

滾輪事件:?鼠標滾輪滾動.

繪屏事件:?重繪屏幕的某些部分.

定時事件:?定時器到時.

焦點事件:?鍵盤焦點移動.

進入和離開事件:?鼠標移入widget之內,或是移出.

移動事件: widget的位置改變.

大小改變事件: widget的大小改變.

顯示和隱藏事件: widget顯示和隱藏.

窗口事件:?窗口是否為當前窗口.

還有一些非常見的qt事件,比如socket事件,剪貼板事件,字體改變,布局改變等等.

Qt的事件和Qt中的signal不一樣.?后者通常用來"使用"widget,?而前者用來"實現" widget.?比如一個按鈕,?我們使用這個按鈕的時候,?我們只關心他clicked()的signal,?至于這個按鈕如何接收處理鼠標事件,再發射這個信號,我們是不用關心的.?但是如果我們要重載一個按鈕的時候,我們就要面對event了.?比如我們可以改變它的行為,在鼠標按鍵按下的時候(mouse press event)?就觸發clicked()的signal而不是通常在釋放的( mouse release event)時候.

?

事件的產生

事件的兩種來源:

???????一種是系統產生的;通常是window system把從系統得到的消息,比如鼠標按鍵,鍵盤按鍵等,?放入系統的消息隊列中. Qt事件循環的時候讀取這些事件,轉化為QEvent,再依次處理.

???????一種是由Qt應用程序程序自身產生的.程序產生事件有兩種方式,?一種是調用QApplication::postEvent().?例如QWidget::update()函數,當需要重新繪制屏幕時,程序調用update()函數,new出來一個paintEvent,調用QApplication::postEvent(),將其放入Qt的消息隊列中,等待依次被處理.?另一種方式是調用sendEvent()函數.?這時候事件不會放入隊列,?而是直接被派發和處理, QWidget::repaint()函數用的就是這種方式.

?

事件的調度

兩種調度方式,一種是同步的,?一種是異步.

Qt的事件循環是異步的,當調用QApplication::exec()時,就進入了事件循環.?該循環可以簡化的描述為如下的代碼:

while ( !app_exit_loop ) {

???????while( !postedEvents ) {?????????????processPostedEvents()???????}

???????while( !qwsEvnts ){????????????qwsProcessEvents();???}

???????while( !postedEvents ) {?????????????processPostedEvents()???????}

}

先處理Qt事件隊列中的事件,?直至為空.?再處理系統消息隊列中的消息,?直至為空,?在處理系統消息的時候會產生新的Qt事件,?需要對其再次進行處理.

調用QApplication::sendEvent的時候,?消息會立即被處理,是同步的.?實際上QApplication::sendEvent()是通過調用QApplication::notify(),?直接進入了事件的派發和處理環節.

?

事件的派發和處理

首先說明Qt中事件過濾器的概念.?事件過濾器是Qt中一個獨特的事件處理機制,?功能強大而且使用起來靈活方便.?通過它,?可以讓一個對象偵聽攔截另外一個對象的事件.?事件過濾器是這樣實現的:?在所有Qt對象的基類: QObject中有一個類型為QObjectList的成員變量,名字為eventFilters,當某個QObjec (qobjA)給另一個QObject (qobjB)安裝了事件過濾器之后, qobjB會把qobjA的指針保存在eventFilters中.?在qobjB處理事件之前,會先去檢查eventFilters列表,?如果非空,?就先調用列表中對象的eventFilter()函數.?一個對象可以給多個對象安裝過濾器.?同樣,?一個對象能同時被安裝多個過濾器,?在事件到達之后,?這些過濾器以安裝次序的反序被調用.?事件過濾器函數( eventFilter() )?返回值是bool型,?如果返回true,?則表示該事件已經被處理完畢, Qt將直接返回,?進行下一事件的處理;?如果返回false,?事件將接著被送往剩下的事件過濾器或是目標對象進行處理.

Qt中,事件的派發是從QApplication::notify()?開始的,?因為QAppliction也是繼承自QObject,?所以先檢查QAppliation對象,?如果有事件過濾器安裝在qApp上,?先調用這些事件過濾器.?接下來QApplication::notify()?會過濾或合并一些事件(比如失效widget的鼠標事件會被過濾掉,?而同一區域重復的繪圖事件會被合并).?之后,事件被送到reciver::event()?處理.

同樣,?在reciver::event()中,?先檢查有無事件過濾器安裝在reciever上.?若有,?則調用之.?接下來,根據QEvent的類型,?調用相應的特定事件處理函數.?一些常見的事件都有特定事件處理函數,?比如:mousePressEvent(), focusOutEvent(),??resizeEvent(), paintEvent(), resizeEvent()等等.?在實際應用中,?經常需要重載這些特定事件處理函數在處理事件.?但對于那些不常見的事件,?是沒有相對應的特定事件處理函數的.?如果要處理這些事件,?就需要使用別的辦法,?比如重載event()?函數,?或是安裝事件過濾器.

事件的轉發

?對于某些類別的事件,?如果在整個事件的派發過程結束后還沒有被處理,?那么這個事件將會向上轉發給它的父widget,?直到最頂層窗口.?如圖所示,?事件最先發送給QCheckBox,?如果QCheckBox沒有處理,?那么由QGroupBox接著處理,?如果QGroupBox沒有處理,?再送到QDialog,?因為QDialog已經是最頂層widget,?所以如果QDialog不處理, QEvent將停止轉發.

如何判斷一個事件是否被處理了呢? Qt中和事件相關的函數通過兩種方式相互通信. QApplication::notify(), QObject::eventFilter(), QObject::event()?通過返回bool值來表示是否已處理. “真”表示已經處理, “假”表示事件需要繼續傳遞.?另一種是調用QEvent::ignore()?或?QEvent::accept()?對事件進行標識.?這種方式只用于event()?函數和特定事件處理函數之間的溝通.?而且只有用在某些類別事件上是有意義的,?這些事件就是上面提到的那些會被轉發的事件,?包括:?鼠標,?滾輪,?按鍵等事件.

?

實際應用

1.重載特定事件處理函數

最常見的事件處理辦法就是重載象mousePressEvent(), keyPressEvent(), paintEvent()?這樣的特定事件處理函數.?以按鍵事件為例,?一個典型的處理函數如下:

void imageView::keyPressEvent(QKeyEvent * event)

{

switch (event->key()) {

case Key_Plus:

zoomIn();

break;

case Key_Minus:

zoomOut();

break;

case Key_Left:

// …

default:

QWidget::keyPressEvent(event);

}

}

2.重載event()函數

通過重載event()函數,我們可以在事件被特定的事件處理函數處理之前(象keyPressEvent())處理它.?比如,?當我們想改變tab鍵的默認動作時,一般要重載這個函數.?在處理一些不常見的事件(比如:LayoutDirectionChange)時,evnet()也很有用,因為這些函數沒有相應的特定事件處理函數.?當我們重載event()函數時,?需要調用父類的event()函數來處理我們不需要處理或是不清楚如何處理的事件.

下面這個例子演示了如何重載event()函數,?改變Tab鍵的默認動作: (默認的是鍵盤焦點移動到下一個控件上. )

bool CodeEditor::event(QEvent * event)

{

if (event->type() == QEvent::KeyPress) {

QKeyEvent *keyEvent = (QKeyEvent *) event;

if (keyEvent->key() == Key_Tab) {

insertAtCurrentPosition('\t');

return true;

}

}

return QWidget::event(event);

}

3.在QT對象上安裝事件過濾器

安裝事件過濾器有兩個步驟: (假設要用A來監視過濾B的事件)

首先調用B的installEventFilter( const QOject *obj ),?以A的指針作為參數.?這樣所有發往B的事件都將先由A的eventFilter()處理.

?然后, A要重載QObject::eventFilter()函數,?在eventFilter()?中書寫對事件進行處理的代碼.

用這種方法改寫上面的例子: (假設我們將CodeEditor?放在MainWidget中)

MainWidget::MainWidget()

{

???????// …

CodeEditor * ce = new CodeEditor( this, “code editor”);

ce->installEventFilter( this );

// …

}

bool MainWidget::eventFilter( QOject * target , QEvent * event )

{

???????if( target == ce ){

??????????????if( event->type() == QEvent::KeyPress ) {

?????????????????????QKeyEvent *ke = (QKeyEvent *) event;

?????????????????????if( ke->key() == Key_Tab ){

ce->insertAtCurrentPosition('\t');

return true;

?????????????????????}

??????????????}

???????}

???????return false;

}

4.給QAppliction對象安裝事件過濾器

一旦我們給qApp(每個程序中唯一的QApplication對象)裝上過濾器,那么所有的事件在發往任何其他的過濾器時,都要先經過當前這個eventFilter().?在debug的時候,這個辦法就非常有用,?也常常被用來處理失效了的widget的鼠標事件,通常這些事件會被QApplication::notify()丟掉. (?在QApplication::notify()?中,?是先調用qApp的過濾器,?再對事件進行分析,?以決定是否合并或丟棄)

?

5.繼承QApplication類,并重載notify()函數

Qt是用QApplication::notify()函數來分發事件的.想要在任何事件過濾器查看任何事件之前先得到這些事件,重載這個函數是唯一的辦法.?通常來說事件過濾器更好用一些,?因為不需要去繼承QApplication類.?而且可以給QApplication對象安裝任意個數的事件過濾器,?相比之下, notify()函數只有一個.

總結

以上是生活随笔為你收集整理的QT中父子窗口事件传递与事件过滤器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。