Qt 事件(event)

2018-10-05 14:51 更新

事件(event)

前面說(shuō)了幾個(gè)標(biāo)準(zhǔn)對(duì)話(huà)框,下面不打算繼續(xù)說(shuō)明一些組件的使用,因?yàn)檫@些使用很難講完,很多東西都是與實(shí)際應(yīng)用相關(guān)的。實(shí)際應(yīng)用的復(fù)雜性決定了我們根本不可能把所有組件的所有使用方法都說(shuō)明白。這次來(lái)說(shuō)說(shuō) Qt 相對(duì)高級(jí)一點(diǎn)的特性:事件。

事件(event)是有系統(tǒng)或者 Qt 本身在不同的時(shí)刻發(fā)出的。當(dāng)用戶(hù)按下鼠標(biāo),敲下鍵盤(pán),或者是窗口需要重新繪制的時(shí)候,都會(huì)發(fā)出一個(gè)相應(yīng)的事件。一些事件是在對(duì)用戶(hù)操作做出響應(yīng)的時(shí)候發(fā)出,如鍵盤(pán)事件等;另一些事件則是由系統(tǒng)自動(dòng)發(fā)出,如計(jì)時(shí)器事件。

一般來(lái)說(shuō),使用 Qt 編程時(shí),我們并不會(huì)把主要精力放在事件上,因?yàn)樵?Qt 中,需要我們關(guān)心的事件總會(huì)發(fā)出一個(gè)信號(hào)。比如,我們關(guān)心的是 QPushButton 的鼠標(biāo)點(diǎn)擊,但我們不需要關(guān)心這個(gè)鼠標(biāo)點(diǎn)擊事件,而是關(guān)心它的 clicked()信號(hào)。這與其他的一些框架不同:在 Swing 中,你所要關(guān)心的是JButton 的 ActionListener 這個(gè)點(diǎn)擊事件。

Qt 的事件很容易和信號(hào)槽混淆。這里簡(jiǎn)單的說(shuō)明一下,signal 由具體對(duì)象發(fā)出,然后會(huì)馬上交給由connect 函數(shù)連接的 slot 進(jìn)行處理;而對(duì)于事件,Qt 使用一個(gè)事件隊(duì)列對(duì)所有發(fā)出的事件進(jìn)行維護(hù),當(dāng)新的事件產(chǎn)生時(shí),會(huì)被追加到事件隊(duì)列的尾部,前一個(gè)事件完成后,取出后面的事件進(jìn)行處理。但是,必要的時(shí)候,Qt 的事件也是可以不進(jìn)入事件隊(duì)列,而是直接處理的。并且,事件還可以使用“事件過(guò)濾器”進(jìn)行過(guò)濾??偟膩?lái)說(shuō),如果我們使用組件,我們關(guān)心的是信號(hào)槽;如果我們自定義組件,我們關(guān)心的是事件。因?yàn)槲覀兛梢酝ㄟ^(guò)事件來(lái)改變組件的默認(rèn)操作。比如,如果我們要自定義一個(gè) QPushButton,那么我們就需要重寫(xiě)它的鼠標(biāo)點(diǎn)擊事件和鍵盤(pán)處理事件,并且在恰當(dāng)?shù)臅r(shí)候發(fā)出 clicked()信號(hào)。

還記得我們?cè)?main 函數(shù)里面創(chuàng)建了一個(gè) QApplication 對(duì)象,然后調(diào)用了它的 exec()函數(shù)嗎?其實(shí),這個(gè)函數(shù)就是開(kāi)始 Qt 的事件循環(huán)。在執(zhí)行 exec()函數(shù)之后,程序?qū)⑦M(jìn)入事件循環(huán)來(lái)監(jiān)聽(tīng)?wèi)?yīng)用程序的事件。當(dāng)事件發(fā)生時(shí),Qt 將創(chuàng)建一個(gè)事件對(duì)象。Qt 的所有事件都繼承于 QEvent 類(lèi)。在事件對(duì)象創(chuàng)建完畢后,Qt 將這個(gè)事件對(duì)象傳遞給 QObject 的 event()函數(shù)。event()函數(shù)并不直接處理事件,而是按照事件對(duì)象的類(lèi)型分派給特定的事件處理函數(shù)(event handler)。關(guān)于這一點(diǎn),我們會(huì)在以后的章節(jié)中詳細(xì)說(shuō)明。

在所有組件的父類(lèi) QWidget 中,定義了很多事件處理函數(shù),如 keyPressEvent()、keyReleaseEvent()、mouseDoubleClickEvent()、mouseMoveEvent ()、mousePressEvent()、mouseReleaseEvent()等。這些函數(shù)都是 protected virtual 的,也就是說(shuō),我們應(yīng)該在子類(lèi)中重定義這些函數(shù)。下面來(lái)看一個(gè)例子。

#include <QApplication> 
#include <QWidget> 
#include <QLabel> 
#include <QMouseEvent> 

class EventLabel : public QLabel 
{ 

protected: 
        void mouseMoveEvent(QMouseEvent *event); 
        void mousePressEvent(QMouseEvent *event); 
        void mouseReleaseEvent(QMouseEvent *event); 
}; 

void EventLabel::mouseMoveEvent(QMouseEvent *event) 
{ 
        this->setText(QString("<center><h1>Move: (%1, %2)</h1></center>") 
                                                        .arg(QString::number(event->x()), QString::number(event->y()))); 
} 

void EventLabel::mousePressEvent(QMouseEvent *event) 
{ 
        this->setText(QString("<center><h1>Press: (%1, %2)</h1></center>") 
                                                        .arg(QString::number(event->x()), QString::number(event->y()))); 
} 

void EventLabel::mouseReleaseEvent(QMouseEvent *event) 
{ 
        QString msg; 
        msg.sprintf("<center><h1>Release: (%d, %d)</h1></center>", 
                                event->x(), event->y()); 
        this->setText(msg); 
} 

int main(int argc, char *argv[]) 
{ 
        QApplication app(argc, argv); 
        EventLabel *label = new EventLabel; 
        label->setWindowTitle("MouseEvent Demo"); 
        label->resize(300, 200); 
        label->show(); 
        return app.exec(); 
}

這里我們繼承了 QLabel 類(lèi),重寫(xiě)了 mousePressEvent、mouseMoveEvent 和 MouseReleaseEvent 三個(gè)函數(shù)。我們并沒(méi)有添加什么功能,只是在鼠標(biāo)按下(press)、鼠標(biāo)移動(dòng)(move)和鼠標(biāo)釋放(release)時(shí)把坐標(biāo)顯示在這個(gè) Label 上面。注意我們?cè)?mouseReleaseEvent 函數(shù)里面有關(guān) QString 的構(gòu)造。我們沒(méi)有使用 arg 參數(shù)的方式,而是使用 C 語(yǔ)言風(fēng)格的 sprintf 來(lái)構(gòu)造 QString 對(duì)象,如果你對(duì) C 語(yǔ)法很熟悉(估計(jì)很多 C++程序員都會(huì)比較熟悉的吧),那么就可以在 Qt 中試試熟悉的 C 格式化寫(xiě)法啦!

本文出自 “豆子空間” 博客,請(qǐng)務(wù)必保留此出處 http://devbean.blog.51cto.com/448512/194031

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)