久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

QT父子窗口事件傳遞與事件過濾器

 t涂鴉 2012-02-21

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

  QT將事件封裝為QEvent實例以后,會呼叫QObject的event()方法,,并且將QEvent實例傳送給它,,在某些情況下,希望在執(zhí)行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參數(shù)表示事件發(fā)生的來源物件,,eventFilter()若返回false,則安裝該事件過濾器的對象的 event()會繼續(xù)執(zhí)行,,若返回true,,則安裝事件過濾器的對象后event()方法就不會被執(zhí)行,由此進行事件的攔截處理,。給本對象安裝事件過濾 器:

this->installEventFilter(this);

 

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

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

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

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

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

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

定時事件: 定時器到時.

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

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

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

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

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

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

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

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

 

事件的產生

事件的兩種來源:

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

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

 

事件的調度

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

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

while ( !app_exit_loop ) {

       while( !postedEvents ) {             processPostedEvents()       }

       while( !qwsEvnts ){            qwsProcessEvents();   }

       while( !postedEvents ) {             processPostedEvents()       }

}

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

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


事件的派發(fā)和處理

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

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

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


事件的轉發(fā)

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

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


實際應用

1.重載特定事件處理函數(shù)

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

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()函數(shù)

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

下面這個例子演示了如何重載event()函數(shù), 改變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來監(jiān)視過濾B的事件)

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

 然后, A要重載QObject::eventFilter()函數(shù), 在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對象)裝上過濾器,那么所有的事件在發(fā)往任何其他的過濾器時,都要先經過當前這個eventFilter(). debug的時候,這個辦法就非常有用也常常被用來處理失效了的widget的鼠標事件,通常這些事件會被QApplication::notify()丟掉. ( QApplication::notify() 是先調用qApp的過濾器再對事件進行分析以決定是否合并或丟棄)


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

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

    本站是提供個人知識管理的網絡存儲空間,,所有內容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內容中的聯(lián)系方式,、誘導購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權內容,,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多