<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                #(22):事件總結 Qt 的事件是整個 Qt 框架的核心機制之一,也比較復雜。說它復雜,更多是因為它涉及到的函數眾多,而處理方法也很多,有時候讓人難以選擇。現在我們簡單總結一下 Qt 中的事件機制。 Qt 中有很多種事件:鼠標事件、鍵盤事件、大小改變的事件、位置移動的事件等等。如何處理這些事件,實際有兩種選擇: 1. 所有事件對應一個事件處理函數,在這個事件處理函數中用一個很大的分支語句進行選擇,其代表作就是 win32 API 的`WndProc()`函數: ~~~ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ~~~ 在這個函數中,我們需要使用`switch`語句,選擇`message`參數的類型進行處理,典型代碼是: ~~~ switch(message) { case WM_PAINT: // ... break; case WM_DESTROY: // ... break; ... } ~~~ 2. 每一種事件對應一個事件處理函數。Qt 就是使用的這么一種機制: * `mouseEvent()` * `keyPressEvent()` * … Qt 具有這么多種事件處理函數,肯定有一個地方對其進行分發,否則,Qt 怎么知道哪一種事件調用哪一個事件處理函數呢?這個分發的函數,就是`event()`。顯然,當`QMouseEvent`產生之后,`event()`函數將其分發給`mouseEvent()`事件處理器進行處理。 `event()`函數會有兩個問題: 1. `event()`函數是一個 protected 的函數,這意味著我們要想重寫`event()`,必須繼承一個已有的類。試想,我的程序根本不想要鼠標事件,程序中所有組件都不允許處理鼠標事件,是不是我得繼承所有組件,一一重寫其`event()`函數?protected 函數帶來的另外一個問題是,如果我基于第三方庫進行開發,而對方沒有提供源代碼,只有一個鏈接庫,其它都是封裝好的。我怎么去繼承這種庫中的組件呢? 2. `event()`函數的確有一定的控制,不過有時候我的需求更嚴格一些:我希望那些組件根本看不到這種事件。`event()`函數雖然可以攔截,但其實也是接收到了`QMouseEvent`對象。我連讓它收都收不到。這樣做的好處是,模擬一種系統根本沒有那個事件的效果,所以其它組件根本不會收到這個事件,也就無需修改自己的事件處理函數。這種需求怎么辦呢? 這兩個問題是`event()`函數無法處理的。于是,Qt 提供了另外一種解決方案:事件過濾器。事件過濾器給我們一種能力,讓我們能夠完全移除某種事件。事件過濾器可以安裝到任意`QObject`類型上面,并且可以安裝多個。如果要實現全局的事件過濾器,則可以安裝到`QApplication`或者`QCoreApplication`上面。這里需要注意的是,如果使用`installEventFilter()`函數給一個對象安裝事件過濾器,那么該事件過濾器只對該對象有效,只有這個對象的事件需要先傳遞給事件過濾器的`eventFilter()`函數進行過濾,其它對象不受影響。如果給`QApplication`對象安裝事件過濾器,那么該過濾器對程序中的每一個對象都有效,任何對象的事件都是先傳給`eventFilter()`函數。 事件過濾器可以解決剛剛我們提出的`event()`函數的兩點不足:首先,事件過濾器不是 protected 的,因此我們可以向任何`QObject`子類安裝事件過濾器;其次,事件過濾器在目標對象接收到事件之前進行處理,如果我們將事件過濾掉,目標對象根本不會見到這個事件。 事實上,還有一種方法,我們沒有介紹。Qt 事件的調用最終都會追溯到`QCoreApplication::notify()`函數,因此,最大的控制權實際上是重寫`QCoreApplication::notify()`。這個函數的聲明是: ~~~ virtual bool QCoreApplication::notify ( QObject * receiver, QEvent * event ); ~~~ 該函數會將`event`發送給`receiver`,也就是調用`receiver->event(event)`,其返回值就是來自`receiver`的事件處理器。注意,這個函數為任意線程的任意對象的任意事件調用,因此,它不存在事件過濾器的線程的問題。不過我們并不推薦這么做,因為`notify()`函數只有一個,而事件過濾器要靈活得多。 現在我們可以總結一下 Qt 的事件處理,實際上是有五個層次: 1. 重寫`paintEvent()`、`mousePressEvent()`等事件處理函數。這是最普通、最簡單的形式,同時功能也最簡單。 2. 重寫`event()`函數。`event()`函數是所有對象的事件入口,`QObject`和`QWidget`中的實現,默認是把事件傳遞給特定的事件處理函數。 3. 在特定對象上面安裝事件過濾器。該過濾器僅過濾該對象接收到的事件。 4. 在`QCoreApplication::instance()`上面安裝事件過濾器。該過濾器將過濾所有對象的所有事件,因此和`notify()`函數一樣強大,但是它更靈活,因為可以安裝多個過濾器。全局的事件過濾器可以看到 disabled 組件上面發出的鼠標事件。全局過濾器有一個問題:只能用在主線程。 5. 重寫`QCoreApplication::notify()`函數。這是最強大的,和全局事件過濾器一樣提供完全控制,并且不受線程的限制。但是全局范圍內只能有一個被使用(因為`QCoreApplication`是單例的)。 為了進一步了解這幾個層次的事件處理方式的調用順序,我們可以編寫一個測試代碼: ~~~ class Label : public QWidget { public: Label() { installEventFilter(this); } bool eventFilter(QObject *watched, QEvent *event) { if (watched == this) { if (event->type() == QEvent::MouseButtonPress) { qDebug() << "eventFilter"; } } return false; } protected: void mousePressEvent(QMouseEvent *) { qDebug() << "mousePressEvent"; } bool event(QEvent *e) { if (e->type() == QEvent::MouseButtonPress) { qDebug() << "event"; } return QWidget::event(e); } }; class EventFilter : public QObject { public: EventFilter(QObject *watched, QObject *parent = 0) : QObject(parent), m_watched(watched) { } bool eventFilter(QObject *watched, QEvent *event) { if (watched == m_watched) { if (event->type() == QEvent::MouseButtonPress) { qDebug() << "QApplication::eventFilter"; } } return false; } private: QObject *m_watched; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); Label label; app.installEventFilter(new EventFilter(&label, &label)); label.show(); return app.exec(); } ~~~ 我們可以看到,鼠標點擊之后的輸出結果是: ~~~ QApplication::eventFilter eventFilter event mousePressEvent ~~~ 因此可以知道,全局事件過濾器被第一個調用,之后是該對象上面的事件過濾器,其次是`event()`函數,最后是特定的事件處理函數。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看