乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      qt 事件機制

       職業(yè)醬油仔 2013-05-20
      什么是自發(fā)事件?哪些類型的事件可以被propagated 或compressed? posting and sending 事件之間有何不同?什么時候應(yīng)該調(diào)用 accept() 或是ignore() ? 如果這些問題你還不是很了解,那么繼續(xù)看下去。

      事件起源:

      基于事件如何被產(chǎn)生與分發(fā),可以把事件分為三類:
      * Spontaneous 事件,由窗口系統(tǒng)產(chǎn)生,它們被放到系統(tǒng)隊列中,通過事件循環(huán)逐個處理。
      * Posted 事件,由Qt或是應(yīng)用程序產(chǎn)生,它們被Qt組成隊列,再通過事件循環(huán)處理。
      * Sent  事件,由Qt或是應(yīng)用程序產(chǎn)生,但它們被直接發(fā)送到目標(biāo)對象。
      當(dāng)我們在main()函數(shù)的末尾調(diào)用QApplication::exec()時,程序進入了Qt的事件循環(huán),大概來講,事件循環(huán)如下面所示:
      while (!exit_was_called)
      {
        while(!posted_event_queue_is_empty)
             {
               process_next_posted_event();
             }
        while(!spontaneous_event_queue_is_empty)
            {
               process_next_spontaneous_event();
            }
        while(!posted_event_queue_is_empty)
            {
              process_next_posted_event();
            }
      }
      首先,事件循環(huán)處理所有的posted事件,直到隊列空。然后再處理所有的spontaneous事件,最后它處理所有的因為處理spontaneous事件而產(chǎn)生的posted事件。send 事件并不在事件循環(huán)內(nèi)處理,它們都直接被發(fā)送到了目標(biāo)對象。現(xiàn)在看一下實踐中的paint 事件是如何工作的。當(dāng)一個widget第一次可見,或是被遮擋后再次變?yōu)榭梢姡?br>窗口系統(tǒng)產(chǎn)生一個(spontaneous) paint事件,要求程序重畫widget,事件循環(huán)最終從事件隊列中撿選這個事件并把它分發(fā)到那個需要重畫的widget。
      并不是所有的paint事件都是由窗口系統(tǒng)產(chǎn)生的。當(dāng)你調(diào)用QWidget::update()去強行重畫widget,這個widget會post 一個paint 事件給自己。這個paint事件被放入隊列,最終被事件循環(huán)分發(fā)之。
      假如你很不耐煩,等不及事件循環(huán)去重畫一個widget, 理論上,你應(yīng)該直接調(diào)用paintEvent()強制進行立即的重畫。但實際上這不總是可行的,因為paintEvent()函數(shù)是protected的(很可能訪問不了)。它也繞開了任何存在的事件過濾器。因為這些原因,Qt提供了一個機制,直接sending事件而不是posting 。
      QWidget::repaint()就使用了這個機制來強制進行立即重畫。
      posting 相對于sending的一個優(yōu)勢是,它給了Qt一個壓縮(compress)事件的機會。假如你在一個widget上連續(xù)地調(diào)用update() 十次,因update()而產(chǎn)生的這十個事件,將會自動地被合并為一個單獨的事件,但是QPaintEvents事件附帶的區(qū)域信息也合并了??蓧嚎s的事件類型包括:paint,move,resize,layout hint,language change。
      最后要注意,你可以在任何時候調(diào)用QApplication::sendPostedEvent(),強制Qt產(chǎn)生一個對象的posted事件。

      人工合成的事件

      QT應(yīng)用程序可以產(chǎn)生他們自己的事件,或是預(yù)定義類型,或是自定義類型。 這可以通過創(chuàng)建QEvent類或它的
      子類的實例,并且調(diào)用QApplication:postEvent()或QApplication::sendEvent()來實現(xiàn)。
      這兩個函數(shù)需要一個 QObject* 與一個QEvent * 作為參數(shù),假如你調(diào)用postEvent(),你必須用 new 操作符來創(chuàng)建事件對象,Qt會它被處理后幫你刪除它。假如你用sendEvent(), 你應(yīng)該在棧上來創(chuàng)建事件。下面舉兩個例子:
      一是posting 事件:
      QApplication::postEvent(mainWin, new QKeyEvent(QEvent::KeyPress,Key_X,'X',0));
      二是sending 事件:
          QKeyEvent event(QEvent::KeyPress, Key_X, 'X', 0);
          QApplication::sendEvent(mainWin, &event);
      Qt應(yīng)用程序很少直接調(diào)用postEvent()或是sendEvnet(),因為大多數(shù)事件會在必要時被Qt或是窗口系統(tǒng)自動產(chǎn)生
      。在大多數(shù)的情況下,當(dāng)你想發(fā)送一個事件時,Qt已經(jīng)為了準備好了一個更高級的函數(shù)來為你服務(wù)。(例如
      update()與repaint())。

      定制事件類型

      qt允許你創(chuàng)建自己的事件類型,這在多線程的程序中尤其有用。在單線程的程序也相當(dāng)有用,它可以作為
      對象間的一種通訊機制。為什么你應(yīng)該用事件而不是其他的標(biāo)準函數(shù)調(diào)用,或信號、槽的主要原因是:事件既可用于同步也可用于異步(依賴于你是調(diào)用sendEvent()或是postEvents()),函數(shù)調(diào)用或是槽調(diào)用總是同步的。事件的另外一個好處是它可以被過濾。
      演示如何post一個定制事件的代碼片段:
      const QEvent::Type MyEvent = (QEvent::Type)1234;
        ...
      QApplication::postEvent(obj, new QCustomEvent(MyEvent));
      事件必須是QCustomEvent類型(或子類)的。構(gòu)造函數(shù)的參數(shù)是事件的類型,1024以下被Qt保留。其他可被程序使用。為處理定制事件類型,要重新實現(xiàn)customEvent()函數(shù):
      void MyLineEdit::customEvent(QCustomEvent *event)
          {
              if (event->type() == MyEvent) {
                  myEvent();
              } else {
                  QLineEdit::customEvent(event);
              }
          }
      QcustomEvent類有一個void *的成員,可用于特定的目的。你也可以子類化QCustomEvent,加上別的成員,但是你也需要在customEvent()中轉(zhuǎn)換QCustomeEvent到你特有的類型。

      事件處理與過濾

      Qt中的事件可以在五個不同的層次上被處理
      1,重新實現(xiàn)一個特定的事件handler
       QObjectQWidget提供了許多特定的事件handlers,分別對應(yīng)于不同的事件類型。(如paintEvent()對應(yīng)paint事件)
      2,重新實現(xiàn)QObject::event()
       event()函數(shù)是所有對象事件的入口,QObject和QWidget中缺省的實現(xiàn)是簡單地把事件推入特定的事件handlers。
      3,在QObject安裝上事件過濾器
        事件過濾器是一個對象,它接收別的對象的事件,在這些事件到達指定目標(biāo)之間。
      4,在aApp上安裝一個事件過濾器,它會監(jiān)視程序中發(fā)送到所有對象的所有事件
      5,重新實現(xiàn)QApplication:notify(),Qt的事件循環(huán)與sendEvent()調(diào)用這個函數(shù)來分發(fā)事件,通過重寫它,你可以在別人之前看到事件。

      一些事件類型可以被傳遞。這意味著假如目標(biāo)對象不處理一個事件,Qt會試著尋找另外的事件接收者。用新的目標(biāo)來調(diào)用QApplication::notify()。舉例來講,key事件是傳遞的,假如擁有焦點的Widget不處理特定鍵,Qt會分發(fā)相同的事件給父widget,然后是父親的父親,直到最頂層widget。

      接受或是忽略?

      可被傳遞的事件有一個accept()函數(shù)和一個ignore()函數(shù),你可以用它們來告訴Qt,你“接收”或是“忽略”這個事件。假如事件handler調(diào)用accept(),這個事件將不會再被傳遞。假如事件handler調(diào)用ignore(),Qt會試著查找另外的事件接收者。像大多數(shù)的開發(fā)者一樣,你可能不會被調(diào)用accept()或是ignore()所煩惱。缺省情況下是“接收”,在QWidget中的缺省實現(xiàn)是調(diào)用ignore(),假如你希望接收事件,你需要做的是重新實現(xiàn)事件handler,避免調(diào)用QWidget的實現(xiàn)。假如你想“忽略”事件,只需簡單地傳遞它到QWidget的實現(xiàn)。下面的代碼演示了這一點:
      void MyFancyWidget::keyPressEvent(QKeyEvent *event)
          {
              if (event->key() == Key_Escape) {
                  doEscape();
              } else {
                  QWidget::keyPressEvent(event);
              }
          }
      在上面的例子里,假如用戶按了"ESC"鍵,我們會調(diào)用doEscape()并且事件被“接收”了(這是缺省的情況),
      事件不會被傳遞到父widget,假如用戶按了別的鍵,則調(diào)用QWidget的缺省實現(xiàn)。
      void QWidget::keyPressEvent(QKeyEvent *event)
          {
              event->ignore();
          }
      應(yīng)該感謝ignore(),事件會被傳遞到父widget中去。
      討論到目前為至,我們都假設(shè)基類是QWidget,然而,同樣的規(guī)則也可以應(yīng)用到別的層次中,只要用QWidget
      代替基類即可。舉例來說:
       void MyFancyLineEdit::keyPressEvent(QKeyEvent *event)
          {
              if (event->key() == Key_SysReq) {
                  doSystemRequest();
              } else {
                  QLineEdit::keyPressEvent(event);
              }
          }
      由于某些原因,你會在event()中處理事件,而不是在特定的handler中,如keyPressEvent(),這個過程會有些不同。event() 會返回一個布爾值,來告訴調(diào)用者是否事件被accept或ignore,(true表示accept),從event()中調(diào)用accept()或是 ignore()是沒有意義的。“Accept”標(biāo)記是event()與特定事件handler之間的一種通訊機制。而從event()返回的布爾值卻是用來與QApplication:notify()通訊的。在QWidgetk中缺省的event()實現(xiàn)是轉(zhuǎn)換“Accept”標(biāo)記為一個布爾值,如下所示:
      bool QWidget::event(QEvent *event)
          {
              switch (e->type()) {
              case QEvent::KeyPress:
                  keyPressEvent((QKeyEvent *)event);
                  if (!((QKeyEvent *)event)->isAccepted())
                      return false;
                  break;
              case QEvent::KeyRelease:
                  keyReleaseEvent((QKeyEvent *)event);
                  if (!((QKeyEvent *)event)->isAccepted())
                      return false;
                  break;
                  ...
              }
              return true;
          }

      到現(xiàn)在為至,我們所說的內(nèi)容不僅僅適用于key事件,也適用于mouse,wheel,tablet,context menu等事件
      Close事件有點不同,調(diào)用QCloseEvent:ignore()取消了關(guān)閉操作,而accept()告訴Qt繼續(xù)執(zhí)行正常的關(guān)閉操作。為了避免混亂,最好是在closeEvent()的新實現(xiàn)中明確地進行accept()與ignore()的調(diào)用:
       void MainWindow::closeEvent(QCloseEvent *event)
          {
              if (userReallyWantsToQuit()) {
                  event->accept();
              } else {
                  event->ignore();
              }
          }vv

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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多