事件过滤器及不规则窗体
事件過濾器及不規則窗體
文章目錄
- 事件過濾器及不規則窗體
- 一、事件過濾器
- 二、不規則窗體
一、事件過濾器
有時候, 對象需要查看、 甚至要攔截發送到另外對象的事件。 例如, 對話框可能
想要攔截按鍵事件, 不讓別的組件接收到; 或者要修改回車鍵的默認處理。
我們已經知道, Qt 創建了 QEvent 事件對象之后, 會調用 QObject的 event()函數處理事件的分發。 顯然, 我們可以在 event()函數中實現攔截的操作。
由于 event()函數是 protected 的, 因此, 需要繼承已有類。 如果組件很多, 就需
要重寫很多個 event()函數。 這當然相當麻煩, 更不用說重寫 event()函數還得小心
一堆問題。 好在 Qt 提供了另外一種機制來達到這一目的: 事件過濾器。
1. 事件過濾器
QObject 有一個 eventFilter()函數, 用于建立事件過濾器。 函數原型如下
virtual bool QObject::eventFilter ( QObject * watched, QEvent * event );這個函數正如其名字顯示的那樣, 是一個“事件過濾器”。 所謂事件過濾器, 可以
理解成一種過濾代碼。 事件過濾器會檢查接收到的事件。 如果這個事件是我們感興趣的類型, 就進行我們自己的處理; 如果不是, 就繼續轉發。 這個函數返回一個 bool 類型, 如果你想將參數 event 過濾出來, 比如, 不想讓它繼續轉發, 就返回 true, 否則返回 false。 事件過濾器的調用時間是目標對象(也就是參數里面的 watched 對象) 接收到事件對象之前。 也就是說, 如果你在事件過濾器中停止了某個事件, 那么, watched 對象以及以后所有的事件過濾器根本不會知道這么一個事件。
我們來看一段簡單的代碼:
class MainWindow : public QMainWindow { public:MainWindow(); protected:bool eventFilter(QObject *obj, QEvent *event); private:QTextEdit *textEdit; };MainWindow::MainWindow() {textEdit = new QTextEdit;setCentralWidget(textEdit);textEdit->installEventFilter(this); } bool MainWindow::eventFilter(QObject *obj, QEvent *event) {if (obj == textEdit) {if (event->type() == QEvent::KeyPress) {QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);qDebug() << "Ate key press" << keyEvent->key();return true;} else{return false;}} else{// pass the event on to the parent classreturn QMainWindow::eventFilter(obj, event);} }- MainWindow 是我們定義的一個類。 我們重寫了它的 eventFilter()函數。 為了過濾特定組件上的事件, 首先需要判斷這個對象是不是我們感興趣的組件, 然后判斷這個事件的類型。 在上面的代碼中, 我們不想讓 textEdit 組件處理鍵盤按下的事件。 所以, 首先我們找到這個組件, 如果這個事件是鍵盤事件,則直接返回true, 也就是過濾掉了這個事件, 其他事件還是要繼續處理, 所以返回 false。 對于其它的組件, 我們并不保證是不是還有過濾器, 于是最保險的辦法是調用父類的函數
- eventFilter()函數相當于創建了過濾器, 然后我們需要安裝這個過濾器。 安裝過濾器需要調用 QObject::installEventFilter()函數。 函數的原型如下:
- 這個函數接受一個 QObject *類型的參數。 記得剛剛我們說的, eventFilter()函 數是 QObject的一個成員函數, 因此, 任意 QObject 都可以作為事件過濾器(問 題在于, 如果你沒有重寫eventFilter()函數, 這個事件過濾器是沒有任何作用 的 , 因 為 默 認 什 么 都 不 會 過 濾 ) 。 已 經存 在 的 過 濾 器 則 可 以 通 過 QObject::removeEventFilter()函數移除
- 我 們 可 以 向 一 個 對 象 上 面 安 裝 多 個 事 件 處 理 器 , 只 要 調 用 多 次installEventFilter()函數。 如果一個對象存在多個事件過濾器, 那么, 最后一個
安裝的會第一個執行, 也就是后進先執行的順序
現在, 我們可以給出一個使用事件過濾器的版本:
bool FilterObject::eventFilter(QObject *object, QEvent *event) {if (object == target && event->type() == QEvent::KeyPress){QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);if (keyEvent->key() == Qt::Key_Tab) {qDebug() << "You press tab.";return true;} else {return false;}}return false; }- 事件過濾器的強大之處在于, 我們可以為整個應用程序添加一個事件過濾器。 記得, installEventFilter()函數是 QObject 的函數, QApplication 或者 QCoreApplication對象都是 QObject 的子類, 因此, 我們可以向 QApplication 或QCoreApplication添加事件過濾器。 這種全局的事件過濾器將會在所有其它特性對象的事件過濾器之前調用。 盡管很強大, 但這種行為會嚴重降低整個應用程序的事件分發效率。
- 注意,
事件過濾器和被安裝過濾器的組件必須在同一線程, 否則, 過濾器將不起作用。
另外, 如果在安裝過濾器之后, 這兩個組件到了不同的線程, 那么, 只有等到二者重新回到同一線程的時候過濾器才會有效
二、不規則窗體
常見的窗體是各種方形的對話框,但有時候也需要非方形的窗體,如圓形,橢圓甚至是不規則形狀的對話框。
實現步驟:
- 新建一個項目, 比如項目名稱叫做“ShapeWidget”, 給此項目添加一個類
“ShapeWidget”, 基類選擇“QWidget”。 - 為了使該不規則窗體可以通過鼠標隨意拖拽, 在類中重定義鼠標事件:
mousePressEvent()、 mouseMoveEvent()、 以及繪制函數 paintEvent() - “ShapeWidget”的構造函數部分是實現該不規則窗體的關鍵, 添加具體代碼如
下
- 重新實現鼠標事件和繪制函數
總結
以上是生活随笔為你收集整理的事件过滤器及不规则窗体的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计器的使用及常用控件
- 下一篇: C++方向复习总结