QT中事件處理器和事件過濾器實現實例


Qt中事件處理的方式,最常用的就是使用事件處理器(event handler)和事件過濾器(event filter)這兩種方法。接下來,我們就來看看事件處理器和事件過濾器是怎么使用的。

事件處理器

Qt中針對每一種常見的事件類型都提供了相應的事件處理器,我們如果想捕獲某種類型的事件並進行自定義處理,那么只需要實現重寫這些事件處理器就行。常見的事件類型和對應的事件處理器如下圖所示:

用戶自定義事件定義如下:

 

在日常使用中,我們最常使用的鼠標事件:

新建一個基於QWidget的應用程序,在QWidget的頭文件中找到鼠標操作事件處理器虛函數如下:

 

我們將其在我們的QWidget子類中重寫實現:

 

到這里這個功能就實現了,大家看看上面的頭文件就知道這里還實現了其它類型事件的處理,其實都是一樣的思路,找到欲處理的事件類型,找到對應的事件處理器,重寫事件處理器中處理事件的方法即可。這個看起來比較簡單!

 

 

事件過濾器

Qt事件模型中一項非常強大的功能就是一個QObject實例可以監視另一個QObject實例中的事件,實現方法是在目標對象中安裝事件過濾器。

假設我們有一個Dialog控件,由一些QLineEdit控件組成。我們希望使用Space鍵得到下一個QLineEdit的輸入焦點。

一個最直接的方法是繼承QLineEdit重寫keyPressEvent()函數,當點擊了Space鍵時,調用focusNextChild():

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
 
void  MyLineEdit::keyPressEvent(QKeyEvent *event)
{
    
if  (event->key() == Qt::Key_Space)
    {
        focusNextChild();
    }
    
else
    {
        QLineEdit::keyPressEvent(event);
    }
}

這個方法有一個最大的缺點:如果我們在窗體中使用了很多不同類型的控件(QComboBox,QSpinBox等等),我們也要繼承這些控件,重寫它們的keyPressEvent()。

一個更好的解決方法是讓Dialog監視其子控件的鍵盤事件,在監視代碼處實現以上功能。

這就是事件過濾的方法。實現一個事件過濾包括兩個步驟:

1、在目標對象上調用installEventFilter(),注冊監視對象。

2、在監視對象的eventFilter()函數中處理目標對象的事件。

 Dialog.h 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
#include  <QDialog>

class  QLineEdit;
class  Dialog :  public  QDialog
{
    Q_OBJECT

public :
    Dialog(QWidget *parent = 
0 );
    ~Dialog();

protected :
    
virtual   bool  eventFilter(QObject *target, QEvent *event);

private :
    QLineEdit*      firstNameEdit ;
    QLineEdit*      lastNameEdit;
    QLineEdit*      cityEdit;
    QLineEdit*      phoneNumberEdit;
};

注冊監視對象的位置是在CustomerInfoDialog的構造函數中:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    QFormLayout* formLayout =  new  QFormLayout;
    firstNameEdit    = 
new  QLineEdit();
    lastNameEdit     = 
new  QLineEdit();
    cityEdit         = 
new  QLineEdit();
    phoneNumberEdit  = 
new  QLineEdit();
    formLayout->addRow(tr(
"&FirstName:" ), firstNameEdit);
    formLayout->addRow(tr(
"&LastName:" ), lastNameEdit);
    formLayout->addRow(tr(
"&City:" ), cityEdit);
    formLayout->addRow(tr(
"&PhoneNumber:" ), phoneNumberEdit);
    setLayout(formLayout);

    
// 給QLineEdit安裝事件過濾器
    firstNameEdit->installEventFilter( this );
    lastNameEdit->installEventFilter(
this );
    cityEdit->installEventFilter(
this );
    phoneNumberEdit->installEventFilter(
this );
}

事件過濾器注冊后,發送到firstNameEdit,lastNameEdit,cityEdit,phoneNumberEdit控件的事件首先到達CustomerInfoDialog::eventFilter()函數,然后在到達最終的目的地。

下面是eventFilter()函數的代碼:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
bool  Dialog::eventFilter(QObject *target, QEvent *event)
{
    
if  (target == firstNameEdit ||
        target == lastNameEdit ||
        target == cityEdit ||
        target == phoneNumberEdit)
    {
        
if  (event->type() == QEvent::KeyPress)
        {
            QKeyEvent *keyEvent = 
static_cast <QKeyEvent *>(event);
            
if  (keyEvent->key() == Qt::Key_Space)
            {
                focusNextChild();
                
return   true ;
            }
        }
    }
    
return  QDialog::eventFilter(target, event);
}

首先,我們看是目標控件是否為QLineEdit,如果事件為鍵盤事件,把QEvent轉換為QKeyEvent,確定被敲擊的鍵。如果為Space鍵,調用focusNextChild(),把焦點交給下一個控件,返回true通知Qt已經處理了這個事件,如果返回false,Qt將會把事件傳遞給目標控件,把一個空格字符插入到QLineEdit中。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM