Qt 中的事件處理(一)


1、圖形界面應用程序的消息處理模型
特點:
  • 基於操作系統才能運行
  • GUI應用程序提供的功能必須由用戶觸發
  • 用戶操作界面時操作系統是第一個感知的 
  • 系統內核的消息通過事件處理轉變成QT的信
2. Qt中的事件處理
(1)在Qt中,事件被封裝成一個個對象,所有的事件均繼承自抽象類QEvent.    
         事件處理的核心包括事件產生、②分發、③接受和處理
事件的產生

誰來產生事件? 最容易想到的是我們的輸入設備,比如鍵盤、鼠標產生的keyPressEvent,keyReleaseEvent,mousePressEvent,mouseReleaseEvent事件(他們被封裝成QMouseEvent和QKeyEvent)。

②Qt中事件的分發

誰來負責分發事件?對於non-GUI的Qt程序,是由QCoreApplication負責將QEvent分發給QObject的子類-Receiver. 
對於Qt GUI程序,由QApplication來負責
 
③事件的接受和處理
誰來接受和處理事件?答案是QObject。
類是整個Qt對象模型的心臟,事件處理機制是QObject三大職責(內存管理、內省(intropection)與事件處理制)之一。任何一個想要接受並處理事件的對象均須繼承自QObject,可以選擇重載QObject::event()函數或事件的處理權轉給父類。
(2)Qt平台將系統產生的消息轉變成Qt事件
  • Qt事件是一個QEvent(或子類)對象
  • 有時一個事件包含多個事件類型,比如鼠標事件又可以分為鼠標按下雙擊、和移動多種操作
  • 事件類型由QEvent類的枚舉型QEvent::Type來表示,可由幫助文檔進行查詢
  • Qt事件用於描述程序內部或外部發生的對應動作描述的是操作系統發生來的消息,一個系統消息對應着一個消息事件
  • 任意QObject對象都具備時間處理的能力

 

QEvent及其子類對象

note:QEvent子類可以表示一個事件,但並不能處理這個事件

Qt 程序需要在main()函數創建一個QApplication對象,然后調用它的exec()函數。這個函數就是開始 Qt 的事件循環。在執行exec()函數之后,程序將進入事件循環來監聽應用程序的事件。當事件發生時,Qt 將創建一個事件對象。Qt 中所有事件類都繼承於QEvent。在事件對象創建完畢后,Qt 將這個事件對象傳遞給QObject的event()函數。event()函數並不直接處理事件,而是將這些事件對象按照它們不同的類型,分發給不同的事件處理器(event handler)。如上所述,event()函數主要用於事件的分發。

(3)GUI應用程序的事件處理方式
  • Qt事件產生后會立即被分發到QWidget對象(QObject的子類,如按鍵QPushButton對象等)
  • QWidget對象其內部會有一個event(QEVent*)函數被調用,進行事件處理
  • event()根據事件類型調用不同的事件處理函數(默認的子函數)
  • 在事件處理函數中發送Qt中預定義的信號
  • 調用信號關聯的槽函數

(4) QPushButton事件處理分析

 

 

①接收到鼠標事件

②QApplication調用QObject::event(QEvent*)成員函數來處理,進行事件的分派。

③調用QPushButton的mouseReleaseEvent(QMouseEvent*)成員函數

④QPushButton調用click()成員函數

⑤觸發信號SIGNAL(clicked())

 

(5)實例

實例一:自定義事件處理函數

鼠標左鍵右鍵

wigth.h

 1 #ifndef WIDGET_H  2 #define WIDGET_H
 3  4 #include <QWidget>
 5  6 class Widget : public QWidget  7 {  8  Q_OBJECT  9 protected: 10     void mousePressEvent(QMouseEvent *event); 11 public: 12     Widget(QWidget *parent = 0); 13 14     ~Widget(); 15 }; 16 17 #endif // WIDGET_H
18 19  
20  

 

widgth.cpp

 1 #include "widget.h"
 2 #include <QMouseEvent>
 3 #include <QDebug>
 4 #include <QMenu>
 5 Widget::Widget(QWidget *parent)  6  : QWidget(parent)  7 {  8 }  9 10 void Widget::mousePressEvent(QMouseEvent *event) 11 { 12     if(event->button()==Qt::LeftButton) 13  { 14         qDebug()<<"LeftButton clicked!"; 15  } 16     else if(event->button()==Qt::RightButton) 17  { 18         qDebug()<<"RightButton clicked!"; 19         
20  } 21 22 } 23 24 Widget::~Widget() 25 { 26     
27 } 28

main.cpp

 1 #include <QApplication>
 2 #include "widget.h"
 3  4 int main(int argc, char *argv[])  5 {  6  QApplication a(argc, argv);  7  Widget w;  8  w.show();  9     
10     return a.exec(); 11 } 12

 

 實例二:自定義事件處理函數
 
 
QMyPushButton.h
 
 1 #ifndef _QMYPUSHBUTTON_H_  2 #define _QMYPUSHBUTTON_H_
 3 
 4 #include <QPushButton>
 5 
 6 typedef void (QButtonListener)(QObject*,QMouseEvent*);  7 
 8 class QMyPushButton : public QPushButton  9 { 10  Q_OBJECT 11 
12 protected: 13     QButtonListener* m_listener; 14 
15     //重寫QPushButton的事件處理函數 就有可能不會產生clicked信號
16     void mouseReleaseEvent(QMouseEvent *e); 17 public: 18     explicit QMyPushButton(QWidget* parent = 0, QButtonListener* listener = 0); 19 }; 20 
21 #endif // _QMYPUSHBUTTON_H_

//QMyPushButton.cpp

 1 #include "QMyPushButton.h"
 2 #include <QMouseEvent>
 3 
 4 QMyPushButton::QMyPushButton(QWidget* parent, QButtonListener* listener):QPushButton(parent)  5 {  6     m_listener = listener;  7 }  8 
 9 //重寫改寫事件處理函數,會改變程序的行為。
10 void QMyPushButton::mouseReleaseEvent(QMouseEvent *e) 11 { 12     if(m_listener != NULL) 13  { 14         //調用自定義的事件處理函數,盡管按鈕的clicked信號被連接到onMyButtonClicked槽函數, 15         //但因自定義的m_listener函數里並不觸發clicked信號,從而槽函數不會被調用。
16         m_listener(this, e); 17         e->accept();//事件被接收,就不再傳遞到父QWidget
18 
19         setDown(false); //按鈕設置為“彈起”狀態
20  } 21     else
22  { 23         //父類的mouseReleaseEvent會去調用clicked(),並觸發SIGNAL(clicked()) 24         //從而調用到連接到該信號的槽函數(本例為onMyButtonClicked())
25         QPushButton::mouseReleaseEvent(e); //調用父類
26  } 27 }

Widget.h

 1 #ifndef _WIDGET_H_  2 #define _WIDGET_H_
 3 
 4 #include <QWidget>
 5 #include "QMyPushButton.h"
 6 
 7 class Widget : public QWidget  8 {  9  Q_OBJECT 10  QMyPushButton myButton; 11 
12 protected slots: 13     void onMyButtonClicked(); 14 
15 public: 16     Widget(QWidget *parent = 0); 17     ~Widget(); 18 }; 19 
20 #endif // _WIDGET_H_

Widget.cpp

 1 #include "Widget.h"
 2 #include <qDebug>
 3 
 4 //自定義事件處理函數
 5 void onMyButtonMouseRelease(QObject* sender, QMouseEvent* e)  6 {  7     qDebug() << "onMyButtonMouseRelease(QObject* sender, QMouseEvent* e)";  8 }  9 
10 Widget::Widget(QWidget *parent) 11     : QWidget(parent),myButton(this, onMyButtonMouseRelease) //實驗2:myButton(this, 0)
12 { 13     myButton.setText("QMyPushButton"); 14 
15     connect(&myButton, SIGNAL(clicked()), this, SLOT(onMyButtonClicked())); 16 } 17 
18 //槽函數,用於接收按鈕的clicked信號
19 void Widget::onMyButtonClicked() 20 { 21     qDebug() << "onMyButtonClicked()" ; 22 } 23 
24 Widget::~Widget() 25 { 26 }

main.cpp

#include "Widget.h" #include <QApplication>

int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }

(4)事件(QEvent)和信號(SIGNAL)的不同

 

事件(QEvent)

信號(SIGNAL)

與QObject的關系

由具體對象進行處理

由具體對象主動產生

對程序影響

改寫事件處理函數可能導致程序行為發生改變

信號是否存在對應的槽函數不會改變程序行為

兩者的聯系

一般而言,信號在具體的事件處理函數中產生

例如:單擊界面上的按鈕,那么就會產生鼠標事件QMouseEvent(不是按鈕產生的),由於按鈕被按下了,所以他會發出一個單擊信號clicked()信號(是按鈕產生的),這里只考慮單擊信號而不用考慮鼠標事件,但如果要設計一個按鈕,或者當單擊按鈕時讓它產生別的效果,此時就要考慮鼠標事件了,由此,信號和事件是兩個不同層面的東西,發出者不同,作用不同。Qt中,所有的QObject的子類實例均可對事件接收和處理! 

 

3. 小結

(1)Qt中的事件和信號不同

(2)事件由QObject對象進行處理

(3)信號由QObject對象觸發

(4)重寫事件處理函數可能改變程序行為

(5)信號的觸發不會對程序行為造成影響

(6)事件處理是在實際工程開發中應用非常普遍的


免責聲明!

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



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