青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

原文Another Look at Events 
作者: Jasmin Blanchette  譯:清源游民 gameogre@gmail.com

什么是自發事件?哪些類型的事件可以被propagated 或compressed? posting and sending 事件之間有何不同?什么時候應該調用 accept() 或是ignore() ? 如果這些問題你還不是很了解,那么繼續看下去。

事件起源:

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

人工合成的事件

QT應用程序可以產生他們自己的事件,或是預定義類型,或是自定義類型。 這可以通過創建QEvent類或它的
子類的實例,并且調用QApplication:postEvent()或QApplication::sendEvent()來實現。
這兩個函數需要一個 QObject* 與一個QEvent * 作為參數,假如你調用postEvent(),你必須用 new 操作符來創建事件對象,Qt會它被處理后幫你刪除它。假如你用sendEvent(), 你應該在棧上來創建事件。下面舉兩個例子:
一是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應用程序很少直接調用postEvent()或是sendEvnet(),因為大多數事件會在必要時被Qt或是窗口系統自動產生
。在大多數的情況下,當你想發送一個事件時,Qt已經為了準備好了一個更高級的函數來為你服務。(例如
update()與repaint())。

定制事件類型

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

事件處理與過濾

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

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

接受或是忽略?

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

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


 

posted on 2007-06-13 22:42 清源游民 閱讀(6875) 評論(4)  編輯 收藏 引用 所屬分類: Qt

FeedBack:
# re: QT中的事件機制
2007-06-14 00:17 | 黃大仙
好  回復  更多評論
  
# re: QT中的事件機制
2007-06-14 13:47 | eXile
因為Sigal/Slot可以跨線程,還可以指定執行的線程環境,,所以一般情況下沒有必要使用自定義事件。  回復  更多評論
  
# re: QT中的事件機制
2008-07-16 21:24 | NOTHING
但了解一下事件也是好的,不是嗎  回復  更多評論
  
# re: QT中的事件機制
2008-09-11 14:00 | apple
你好, 我有個問題.
因為我做一個界面是沒有鼠標的. 需要上下左右控制讓哪個wdiget來focus
我想知道目前qt自帶的焦點機制是按add的順序來postevent的嗎?
也就是按左/上方向鍵是聚焦當前widget的上一個widget, 右/下是聚焦下一個嗎? 如何制定一個比較完善的焦點機制?
比如說: 有20個widget按表格狀排列, 那么在中間的一個wdiget上, 我按向上鍵, 并不希望這個widget的左邊那個聚焦哦. 而是想讓這個widget上面的那個widget聚焦.
十分感謝!  回復  更多評論
  
<2009年5月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

留言簿(35)

隨筆分類(78)

隨筆檔案(74)

文章檔案(5)

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美激情中文不卡| 欧美激情视频一区二区三区在线播放| 欧美日精品一区视频| 欧美黄色一区| 欧美日韩在线综合| 国产乱肥老妇国产一区二 | 蜜桃av一区二区三区| 久久综合福利| 最新高清无码专区| 91久久久一线二线三线品牌| 一区二区三区精品视频| 亚洲欧美日韩另类| 鲁大师成人一区二区三区| 免费视频亚洲| 国产精品黄色| 亚洲福利视频三区| 亚洲性xxxx| 玖玖玖国产精品| 99av国产精品欲麻豆| 欧美一区二区三区免费观看| 欧美成人精品一区| 国产精品免费一区二区三区在线观看 | 国产日韩精品一区二区| 亚洲福利在线观看| 午夜精品久久久久久久| 欧美激情第10页| 亚洲欧美日韩另类| 欧美日韩一区二区三区高清| 亚洲春色另类小说| 久久精品国产精品亚洲精品| 99日韩精品| 欧美成人免费全部| 国产毛片精品国产一区二区三区| 亚洲精品日韩欧美| 老司机久久99久久精品播放免费| 一区二区高清视频在线观看| 欧美成人一区二免费视频软件| 国产一区免费视频| 午夜精品久久久久久久男人的天堂| 欧美激情亚洲自拍| 久久精品国产免费| 国产日韩欧美亚洲一区| 亚洲自拍偷拍网址| 亚洲精品视频在线观看网站| 久久一区二区视频| 狠狠色狠狠色综合| 久久精品72免费观看| 亚洲一区精品视频| 国产精品第一页第二页第三页| 日韩视频一区二区三区| 欧美高清在线精品一区| 香蕉久久一区二区不卡无毒影院| 亚洲激情在线观看视频免费| 久久精品99久久香蕉国产色戒 | 亚洲女人av| 国产精品乱码妇女bbbb| 一区二区三区高清在线| 亚洲国产一区二区三区青草影视| 久久精品久久99精品久久| 国产精品无码永久免费888| 亚洲影视在线播放| 在线综合+亚洲+欧美中文字幕| 欧美日韩国产亚洲一区| 一本大道久久a久久综合婷婷| 亚洲国产黄色| 欧美日本韩国| 午夜精品在线观看| 久久se精品一区精品二区| 一区二区视频免费在线观看| 欧美成年人视频网站| 欧美国产精品v| 亚洲综合二区| 欧美亚洲视频在线观看| 精品不卡视频| 亚洲狠狠婷婷| 国产精品二区三区四区| 欧美一区二区私人影院日本| 欧美在线视频免费| 亚洲精品久久久久| 亚洲一区二区在| 国内精品久久久久影院 日本资源| 久久婷婷麻豆| 欧美精品亚洲精品| 午夜欧美大尺度福利影院在线看| 欧美一二三视频| 91久久久亚洲精品| 亚洲一区二区三区777| 激情综合色综合久久| 亚洲精品久久久久久久久久久久久 | 午夜精品久久久久久久99热浪潮| 韩国v欧美v日本v亚洲v| 亚洲电影免费| 国产欧美日韩综合一区在线观看| 欧美成人午夜免费视在线看片| 欧美日韩天天操| 久久久噜久噜久久综合| 欧美激情中文字幕一区二区| 欧美日本在线| 欧美在线www| 另类综合日韩欧美亚洲| 亚洲欧美中文另类| 欧美极品色图| 久久综合给合久久狠狠狠97色69| 欧美色欧美亚洲另类二区| 久久人人爽国产| 国产精品家教| 91久久综合| 欧美一级视频免费在线观看| 久久人人97超碰国产公开结果| 一区二区三区回区在观看免费视频| 欧美一级片久久久久久久| 日韩网站在线看片你懂的| 欧美专区18| 午夜国产一区| 欧美日韩 国产精品| 欧美高潮视频| 极品少妇一区二区三区| 亚洲欧美成人| 亚洲一区制服诱惑| 欧美精品久久久久久久免费观看| 久久先锋影音av| 国产视频丨精品|在线观看| 一区二区黄色| 亚洲一二三四久久| 欧美日韩国产一区精品一区| 亚洲高清在线| 亚洲精品乱码久久久久久蜜桃91| 久久精品亚洲精品国产欧美kt∨| 欧美在线一二三四区| 国产精品自拍小视频| 亚洲深夜av| 香蕉视频成人在线观看| 国产精品试看| 午夜国产一区| 久久精品一区二区三区不卡牛牛| 国产精品日韩专区| 亚洲欧美成人一区二区在线电影| 午夜综合激情| 国产伦理一区| 欧美在线91| 欧美77777| 日韩视频在线一区二区| 欧美日产在线观看| 一区二区三区三区在线| 先锋亚洲精品| 一区免费在线| 鲁鲁狠狠狠7777一区二区| 欧美激情性爽国产精品17p| 日韩亚洲欧美成人一区| 欧美午夜精品| 欧美一区二区精品| 欧美国产日韩视频| 一本色道久久综合亚洲二区三区| 欧美亚一区二区| 久久久999| 在线观看亚洲一区| 久久爱www久久做| 麻豆91精品91久久久的内涵| 亚洲国产精品久久久| 欧美日韩高清在线观看| 亚洲欧美日韩国产中文在线| 美女999久久久精品视频| 亚洲国产天堂久久综合网| 欧美人牲a欧美精品| 亚洲一二三区精品| 欧美69wwwcom| 欧美在线看片a免费观看| 亚洲第一搞黄网站| 国产精品久久久久久久久久久久| 香蕉尹人综合在线观看| 亚洲国产黄色| 久久精品中文字幕一区二区三区 | 国产免费亚洲高清| 久久久噜噜噜久久中文字幕色伊伊| 亚洲免费观看高清在线观看| 亚洲欧美日韩国产一区| 欧美国产日本在线| 亚洲欧美国产精品专区久久| 黄色成人在线免费| 欧美日韩亚洲一区二区三区| 午夜欧美精品久久久久久久| 亚洲国产精品久久久久久女王| 香蕉免费一区二区三区在线观看| 亚洲国产你懂的| 国产精品一区二区在线观看| 蜜桃久久av| 欧美一区二区三区四区在线观看地址 | 久久综合国产精品| 亚洲色图自拍| 亚洲成色777777女色窝| 久久精品水蜜桃av综合天堂| 亚洲午夜精品久久| 91久久精品网| 亚洲电影免费| 国产揄拍国内精品对白| 欧美视频一区在线| 欧美黄色网络| 欧美成人首页| 久久在线视频在线| 久久精品99国产精品|