Qt学习笔记之事件处理
1. Qt事件概述
事件是對各種應用程序需要知道的由應用程序內部或者外部產生的事情或者動作的通稱。對于初學者,總會對Qt中信號和事件的概念混淆不清。其實,記住事件比信號更底層就可以了。比如說,我們用鼠標按下界面上的一個按鈕,它會發(fā)射clicked()單擊信號,但是,它怎么知道自己被按下的呢,那就是通過鼠標事件處理的。這里可以看到,鼠標事件比信號更底層。
在Qt中處理事件有多種方法,不過最常用的是重寫Qt事件處理函數(shù)。
2. Qt事件的來源
?
?
3. Qt事件機制
Qt中定義的事件是一個從QEvent類繼承而來的對象,它表示應用程序內部或外部發(fā)生了某些應用程序自身必須知道的事情。任何從QObject類派生的對象均可以通過QObject::event()方法接收事件。事件產生時,Qt會創(chuàng)建一個合適的QEvent對象或其子對象,然后通過調用QObject類的event()函數(shù)將這個事件對象傳給特定的QObject對象或其子對象。需要指出的是,event()函數(shù)自身并不處理事件,而是根據(jù)事件類型調用相應的事件處理器,其返回值告知這個事件是否被接受并進行了處理。例如,QWidget類中的event()函數(shù)實現(xiàn)將鼠標、鍵盤和重繪等常見事件交給mousePressEvent()、keyPressEvent()和paintEvent()這些特定的事件處理器進行處理。
事件處理方式順序:
- Qt事件產生后立即被分發(fā)到QWidget對象
- QWidget中的event(QEvent*)進行事件處理
- event()根據(jù)事件類型調用不同的事件處理函數(shù)
- 在事件處理函數(shù)中發(fā)送Qt中預定義的信號
- 調用信號關聯(lián)的槽函數(shù)
在Qt內部,Qt通過由函數(shù)QCoreApplication::exec()啟動的主事件循環(huán)不停抓取事件隊列中的本地窗口事件,然后將它們轉換成對應的QEvent對象,并最終將這些QEvent對象發(fā)送到目的QObject對象來完成上述一系列事件的處理動作。
需要注意的是,不應該混淆事件和信號這兩個概念。通常,在使用已有的窗口部件時,信號是十分有用的,而在自定義新的窗口部件時,事件則更為重要。舉例來講,當使用QPushButton類時,程序員往往只關注其clicked()信號,而很少關心底層的鼠標或者鍵盤事件。但當自定義一個類似QPushButton的類時,程序員就不得不編寫一定量的代碼來處理鼠標或者鍵盤事件,并在適當?shù)臅r候發(fā)送clicked()信號。從這個角度講,事件比信號更底層。
Qt的事件處理有5種級別:
1.??????重寫控件的事件處理函數(shù):如重寫keyPressEvent(),mousePressEvent()和paintEvent(),這是最常用的事件處理方法,我們已經看到過很多這樣的例子了。
2.??????重寫QObject::event(),在事件到達事件處理函數(shù)前處理它。在需要改變Tab鍵的慣用法時這樣做。也可以處理那些沒有特定事件處理函數(shù)的比較少見的事件類型(例如,QEvent::HoverEnter)。我們重寫event()時,必須要調用基類的event(),由基類處理我們不需要處理的那些情況。
3.??????給單獨的QObject對象安裝事件過濾器:對象用installEventFilter()注冊后,所有目標對象的事件都首先到達監(jiān)視對象的eventFilter()函數(shù)。如果一個對象有多個事件過濾器,過濾器按順序激活,先到達最近安裝的監(jiān)視對象,最后到達最先安裝的監(jiān)視對象。
4.??????給QApplication對象安裝事件過濾器,如果qApp(唯一的QApplication對象)安裝了事件過濾器,程序中所有對象的每個事件在被送到任何其它事件過濾器之前都要送到eventFilter()函數(shù)中。這個方法在調試的時候非常有用,在處理禁止使能狀態(tài)的控件的鼠標事件時這個方法也很常用。
5.??????繼承QApplication,重寫notify()。Qt調用QApplication::nofity()來發(fā)送事件。重寫這個函數(shù)是在其他事件過濾器接收事件前得到所有事件的唯一方法。通常事件過濾器是最有用的,因為在同一時間,可以有任意數(shù)量的事件過濾器,但是notify()函數(shù)只有一個。
4.? 鼠標事件
QKeyEvent類:描述一個鍵盤事件。當鍵盤按鍵被按下或者被釋放時,鍵盤事件便會被發(fā)送給擁有鍵盤輸入焦點的部件。
相關函數(shù):
key(); //獲取鍵盤對應的鍵值,不區(qū)分大小寫 void keyPressEvent(QKeyEvent *event);? ? //按下事件 void keyReleaseEvent(QKeyEvent *event); //抬起事件單個事件:
if (event->key() == Qt::Key_Up){ }組合事件:
if (event->modifiers() == Qt::ControlModifier){ } void Widget::keyPressEvent(QKeyEvent *event) {int x,y;if (event->modifiers() == Qt::ControlModifier) {switch (event->key()) {case Qt::Key_Down:x = m_endPt.x()+10;y = m_endPt.y()+10;m_endPt.setX(x);m_endPt.setY(y);update();m_bIsDrawing = true;break;case Qt::Key_Up:x = m_endPt.x()-10;y = m_endPt.y()-10;m_endPt.setX(x);m_endPt.setY(y);update();m_bIsDrawing = true;break;}} }void Widget::keyReleaseEvent(QKeyEvent *event) {switch (event->key()) {case Qt::Key_Down:m_bIsDrawing = false;update();break;case Qt::Key_Up:m_bIsDrawing = false;update();break;} }5.? 鍵盤事件
QMouseEvent類:表示一個鼠標事件,當在窗口部件中按下抬起鼠標或者移動鼠標指針時,都會產生鼠標事件。
相關函數(shù):
button(); //返回鼠標的事件值 buttons(); //返回鼠標的事件值(移動事件時) x(); //返回X坐標 y(); //返回Y坐標 pos(); //返回X和Y坐標 void mousePressEvent(QMouseEvent *event); //按下事件處理函數(shù) void mouseReleaseEvent(QMouseEvent *event); //彈起事件處理函數(shù) void mouseDoubleClickEvent(QMouseEvent *event);//雙擊事件處理函數(shù) void mouseMoveEvent(QMouseEvent *event); //移動事件處理函數(shù)?鼠標事件值:
QWheelEvent類:表示鼠標滾輪事件,在這個類中主要是獲取滾輪移動的方向和距離
相關函數(shù) :
delta() //獲取滾輪移動的距離函數(shù) 每當滾輪旋轉一下,默認的是15度向上滾動,delta()函數(shù)返回正值向下滾動,delta()函數(shù)返回負值 void wheelEvent(QWheelEvent *event); void Widget::mousePressEvent(QMouseEvent *event) {if (event->button() == Qt::LeftButton){m_lastPt = event->pos();m_bIsDrawing = true; //正在繪圖} }void Widget::mouseReleaseEvent(QMouseEvent *event) {if (event->button() == Qt::LeftButton){m_endPt = event->pos();m_bIsDrawing = false;update();}}void Widget::mouseMoveEvent(QMouseEvent *event) {if (event->buttons() == Qt::LeftButton){m_endPt = event->pos();update();}}6. 定時器事件
Qt中有兩種方法來使用定時器,一種是定時器事件,另一種是使用信號和槽。一般使用了多個定時器時最好使用定時器事件來處理。
6.1 多個定時器
QTimerEvent類:定時器事件類。相關函數(shù):
timerId(); // 返回定時器值 void timerEvent(QTimerEvent *event); // 定時器事件處理函數(shù) m_timerId1 = startTimer(1000);m_timerId2 = startTimer(1000);m_timerId3 = startTimer(1000);這里開啟了三個定時器,分別返回了它們的id,這個id用來區(qū)分不同的定時器。定時器的時間單位是毫秒。每當一個定時器溢出時,都會調用定時器事件處理函數(shù),我們可以在該函數(shù)中進行相應的處理。
void Widget::timerEvent(QTimerEvent *event) {if (event->timerId() == m_timerId1) {qDebug("style 2:timerId %d,hello world...",event->timerId());}else if (event->timerId() == m_timerId2){qDebug("style 2:timerId %d,hello world...",event->timerId());}else if (event->timerId() == m_timerId3){qDebug("style 2:timerId %d,hello world...",event->timerId());} }6.2 信號與槽方式
如果只是想開啟少量的定時器,也可以使用信號和槽來實現(xiàn)。?
QTimer *timer = new QTimer(this);connect(timer,SIGNAL(timeout()),this,SLOT(updateTimer()));timer->start(1000); void Widget::updateTimer() {qDebug("style 1: hello world ....."); }?
7.?事件過濾
相關函數(shù):
bool eventFilter(QObject *watched, QEvent *event); // 過濾器函數(shù) 參數(shù):1.接受事件的對象 2.事件類型 void installEventFilter(QObject *filterObj); // 安裝一個過濾器 bool myApplication::eventFilter(QObject *obj, QEvent *event) {static int k=1;if(event->type()==QEvent::MouseButtonPress||event->type()==QEvent::MouseButtonDblClick){qDebug()<<"Click"<<k;k++;return true;}return QApplication::eventFilter(obj,event);}?
?
參考資料:
1.?Qt5 事件(event)機制詳解
2.?17.QT-事件處理分析、事件過濾器、拖放事件
3.?QT基礎:66---事件處理(鍵盤事件、鼠標事件、滾輪事件、事件過濾器)
4.?Qt之事件處理機制
5.?Qt事件原理
總結
以上是生活随笔為你收集整理的Qt学习笔记之事件处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 涂鸦板练习(20200214)
- 下一篇: Qt学习笔记之数据库