儘管 Qt 已經提供了不少事件,但對於更加變幻無窮的需求來講,有限的事件都是不夠的。例如,我要支持一種新的設備,這個設備提供一種嶄新的交互方式,那麼,這種事件如何處理呢?因此,容許建立本身的事件 類型也就勢在必行。即使是不說那種很是極端的例子,在多線程的程序中,自定義事件也是尤爲有用。固然,事件也並非侷限在多線程中,它能夠用在單線程的程序中,做爲一種對象間通信的機制。那麼,爲何我須要使用事件,而不是信號槽呢?主要緣由是,事件的分發既能夠是同步的,又能夠是異步的,而函數的調用或者說是槽的回調老是同步的。事件的另一個好處是,它可使用過濾器。安全
Qt 自定義事件很簡單,同其它類庫的使用很類似,都是要繼承一個類進行擴展。在 Qt 中,你須要繼承的類是QEvent
。多線程
繼承QEvent
類,最重要的是提供一個QEvent::Type
類型的參數,做爲自定義事件的類型值。回憶一下,這個 type 是咱們在處理事件時用於識別事件類型的代號。好比在event()
函數中,咱們使用QEvent::type()
得到這個事件類型,而後與咱們定義的實際類型對比。異步
QEvent::Type
是QEvent
定義的一個枚舉。所以,咱們能夠傳遞一個 int 值。可是須要注意的是,咱們的自定義事件類型不能和已經存在的 type 值重複,不然會有不可預料的錯誤發生。由於系統會將你新增長的事件當作系統事件進行派發和調用。在 Qt 中,系統保留 0 – 999 的值,也就是說,你的事件 type 要大於 999。這種數值固然很是難記,因此 Qt 定義了兩個邊界值:QEvent::User
和QEvent::MaxUser
。咱們的自定義事件的 type 應該在這兩個值的範圍之間。其中,QEvent::User
的值是 1000,QEvent::MaxUser
的值是 65535。從這裏知道,咱們最多能夠定義 64536 個事件。經過這兩個枚舉值,咱們能夠保證咱們本身的事件類型不會覆蓋系統定義的事件類型。可是,這樣並不能保證自定義事件相互之間不會被覆蓋。爲了解決這個問題,Qt 提供了一個函數:registerEventType()
,用於自定義事件的註冊。該函數簽名以下:函數
static int QEvent::registerEventType ( int hint = -1 );
這個函數是 static 的,所以可使用QEvent
類直接調用。函數接受一個 int 值,其默認值是 -1;函數返回值是向系統註冊的新的 Type 類型的值。若是 hint 是合法的,也就是說這個 hint 不會發生任何覆蓋(系統的以及其它自定義事件的),則會直接返回這個值;不然,系統會自動分配一個合法值並返回。所以,使用這個函數便可完成 type 值的指定。這個函數是線程安全的,沒必要另外添加同步。post
咱們能夠在QEvent
子類中添加本身的事件所須要的數據,而後進行事件的發送。Qt 中提供了兩種事件發送方式:線程
static bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event);
1. 直接將event
事件發送給receiver
接受者,使用的是QCoreApplication::notify()
函數。函數返回值就是事件處理函數的返回值。在事件被髮送的時候,event
對象並不會被銷燬。一般咱們會在棧上建立event
對象,例如:code
QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0); QApplication::sendEvent(mainWindow, &event);
static void QCoreApplication::postEvent(QObject *receiver, QEvent *event);
2. 將event
事件及其接受者receiver
一同追加到事件隊列中,函數當即返回。orm
由於 post 事件隊列會持有事件對象,而且在其 post 的時候將其 delete 掉,所以,咱們必須在堆上建立event
對象。當對象被髮送以後,再試圖訪問event
對象就會出現問題(由於 post 以後,event
對象就會被 delete)。對象
當控制權返回到主線程循環時,保存在事件隊列中的全部事件都經過notify()
函數發送出去。繼承
事件會根據 post 的順序進行處理。若是你想要改變事件的處理順序,能夠考慮爲其指定一個優先級。默認的優先級是Qt::NormalEventPriority
。
這個函數是線程安全的。
Qt 還提供了一個函數:
static void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type);
這個函數的做用是,將事件隊列中的接受者爲receiver
,事件相似爲 event_type 的全部事件當即發送給 receiver 進行處理。須要注意的是,來自窗口系統的事件並不禁這個函數進行處理,而是processEvent()
。詳細信息請參考 Qt API 手冊。
如今,咱們已經可以自定義事件對象,已經可以將事件發送出去,還剩下最後一步:處理自定義事件。處理自定義事件,同前面咱們講解的那些處理方法沒有什麼區別。咱們能夠重寫QObject::customEvent()
函數,該函數接收一個QEvent
對象做爲參數:
void QObject::customEvent(QEvent *event);
咱們能夠經過轉換 event 對象類型來判斷不一樣的事件:
void CustomWidget::customEvent(QEvent *event) { CustomEvent *customEvent = static_cast<CustomEvent *>(event); // ... }
固然,咱們也能夠在event()
函數中直接處理:
bool CustomWidget::event(QEvent *event) { if (event->type() == MyCustomEventType) { CustomEvent *myEvent = static_cast<CustomEvent *>(event); // processing... return true; } return QWidget::event(event); }