铅笔

在你的害怕中坚持的越多,你就会越自信
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Qt 中的事件处理(一)

Posted on 2017-10-18 21:05  黑色の铅笔  阅读(17499)  评论(9编辑  收藏  举报
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来负责
 
③事件的接受和处理
Qt中的事件产生之后,谁来接受和处理事件?答案是QObject。
类是整个Qt对象模型的心脏,事件处理机制是QObject三大职责(内存管理、内省(intropection)与事件处理制)之一。任何一个想要接受并处理事件的对象均须继承自QObject,可以选择重载QObject::event()函数或事件的处理权转给父类。
(2)Qt平台将系统产生的消息转变成Qt事件
  • Qt事件是一个QEvent(或子类)对象,Qt的事件是用来替代系统的消息,每一个Qt事件都对应着一个系统消息
  • 有时一个事件包含多个事件类型,比如鼠标事件又可以分为鼠标按下双击、和移动多种操作
  • 事件类型由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中的事件和信号不同,通过事件处理函数来发出信号的,通过事件处理将系统消息转换成Qt信号

(2)事件由QObject对象进行处理

(3)信号由QObject对象触发

(4)重写事件处理函数可能改变程序行为

(5)信号的触发不会对程序行为造成影响

(6)事件处理是在实际工程开发中应用非常普遍的