深入分析QT中的事件处理(上--QT中事件处理的机制)

QT中的事件处理是QT学习过程中的一块非常重要知识点,我准备用2篇博客来深入分析一下QT中的事件处理,这篇博客是第一篇博客。

GUI应用程序的特点:1.GUI应用程序必须基于操作系统才能运行,脱离了操作系统GUI应用程序是运行不了的。2.GUI应用程序所提供的功能必须由用户触发。这个是GUI应用程序的特点。

GUI应用程序的运行模型(GUI应用程序的消息处理模型(原理)):

                   

                                                       GUI应用程序消息处理模型原理图                 

当用户想要获得应用程序功能的时候,就必须去操作应用程序的界面。 

1.当用户去操作应用程序界面的时候,操作系统内核首先会感知到用户的操作,然后操作系统内核就会把用户的操作翻译成一个系统消息。

2.这个系统消息就会发送到一个有焦点的应用程序上来,在这个有焦点的应用程序中就会去调用相应的消息处理函数,在这个消息处理函数中用户想要的功能就会被体现出来。

上述的第一步和第二步就是,一般GUI应用程序的大概运行原理。现在回到Qt应用程序中来,我们知道在Qt开发过程中主要是映射信号到槽函数。那么Qt中的信号是什么?Qt中的信号是由用户触发的,每当用户操作Qt应用程序的时候,就会产生信号。如果这个时候我们关联了信号与槽函数,这个时候如果我们操作Qt应用程序界面上的元素的时候,相应的槽函数就会被调用。对比的上述GUI应用程序消息处理模型原理图,我们可以知道Qt应用程序是符合GUI应用程序消息处理模型的基本原理的。然后这个时候再深入思考一下,QT应用程序也是基于操作系统的一个GUI应用程序,那么QT应用程序接受到的应该是系统消息,那么这个系统消息和QT中的信号是同一个概念吗?当然不是!

那么操作系统发送过来的系统消息是如何变成QT中的信号呢?这是一个值得深入思考的问题

QT平台将操作系统产生的系统消息转化为QT内部的事件

1.QT事件是一个QEvent的对象

2.QT事件用于描述程序内部或者外部发生的动作,或者说,QT事件是用来描述操作系统发送过来的消息的。一个系统消息对应一个Qt事件,它们之间是一一对应的关系的。

2.任意的QObject对象(子类对象可以当做父类对象来使用,符合父子兼容性原则)都具备事件处理的能力

下面列举一下常用的QT事件对象。

                            

                                                                  常用的Qt事件

例如:

QInputEvent:是一个输入事件,用来代表用户的输入操作的。

QDropEvent:是一个用来描述用户拖拽动作的事件。

QPaintEvent:用来描述操作系统绘制GUI图形的这个动作。

QCloseEvent:当用户去点击一个对话框或者一个主窗口的关闭按钮的时候,操作系统就会发送一个系统消息,这个系统消息映射到QT事件的时候,我们就可以得到一个QCloseEvent对象。

那么QT事件产生之后干嘛呢?QT事件产生之后肯定是要被QObject对象处理的,那么被谁处理呢?处理的过程又是怎么样的呢?来看一下GUI应用程序的事件处理方式。

1.Qt事件产生后立即被分发到QWidget(QPushbutton,QLineEdit,QLabel等等)对象

2.QWidget中的event(QEvent*)进行事件处理,event(QEvent*)事件处理函数是事件处理的入口函数

3.event()函数在内部根据事件的类型调用不同的事件处理子函数来进行处理,这里为什么要根据事件类型的不同来调用不同的事件处理子函数呢?是因为操作系统发送过来的系统消息是各种各样的,因为操作系统发送过来的系统消息和QT事件是一一对应的,所以QT事件的类型是各种各样的。

4.在事件处理函数中发送Qt中预定义的信号 ,在事件处理函数中要做的事情很多,一方面是关于界面更新的事情,另外一方面就是发送Qt中预定义的信号。(当然,QT中的信号也可以自己定义,后面的博客应该会详细介绍Qt中的信号)

5.调用信号关联的槽函数

 

下面用一个用户点击按钮的例子来具体分析一下上述所讲解的过程。

          

分析上述图形,具体的调用过程如下:

1.用户点击一个按钮,点击这个操作首先会被操作系统内核所感知到。

2.操作系统内核感受到用户的点击操作之后,就会发送一条系统消息,发送到当前的应用程序上来,当前的应用程序是由QT开发完成的,所以当前的应用程序就会做一次转化,将当前的事件分发下去,分发到用户点击的按钮对象上来。

3.按钮对象在接受到这个事件之后,就会调用自身的event()函数,在自身的event()函数的内部就会调用click()函数

4.这个click()函数的主要工作就是,发送一个QT信号,这个QT信号就会发送到其他QT对象上,那么这个时候相应的槽函数就会被调用。

 

下面通过一个程序实例来验证上面所讲解的原理。

自定义一个按钮类QMyPushButton,继承自QPushButton。然后重写void mouseReleaseEvent(QMouseEvent *e) 这个函数,观察当在事件处理函数中阻塞了信号的正常产生会是怎么样的?代码如下所示:

#ifndef QMYPUSHBUTTON_H
#define QMYPUSHBUTTON_H

#include <QPushButton>

typedef void (QButtonListener)(QObject*,QMouseEvent*);

class QMyPushButton : public QPushButton
{
    Q_OBJECT
protected:
    QButtonListener* m_listener;

    void mouseReleaseEvent(QMouseEvent *e);
public:
    explicit QMyPushButton(QWidget *parent = 0,QButtonListener* listener=0);
    
signals:
    
public slots:
    
};

#endif // QMYPUSHBUTTON_H


#include "QMyPushButton.h"
#include <QMouseEvent>

QMyPushButton::QMyPushButton(QWidget *parent,QButtonListener* listener) :QPushButton(parent)
{
      m_listener=listener;
    //m_listener=NULL;
}

void QMyPushButton::mouseReleaseEvent(QMouseEvent *e)
{
    if(m_listener!=NULL)
    {
        m_listener(this,e);

        e->accept();

        setDown(false);
    }
    else
    {
        QPushButton::mouseReleaseEvent(e);
    }
}
#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui/QWidget>
#include "QMyPushButton.h"

class Widget : public QWidget
{
    Q_OBJECT
protected:
    QMyPushButton myButton;
protected slots:
    void onMyButtonClicked();
public:
    Widget(QWidget *parent = 0);
    ~Widget();
};

#endif // WIDGET_H


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

void onMyButtonMouseRelease(QObject* sender,QMouseEvent* e)
{
    qDebug()<<"void onMyButtonMouseRelease(QObject* sender,QMouseEvent* e)";
}

Widget::Widget(QWidget *parent): QWidget(parent),myButton(this,onMyButtonMouseRelease)
{
    myButton.setText("QMyPushButton");

    connect(&myButton,SIGNAL(clicked()),this,SLOT(onMyButtonClicked()));
}

void Widget::onMyButtonClicked()
{
    qDebug()<<"onMyButtonClicked()";
}

Widget::~Widget()
{
    
}

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

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

程序的运行结果如下所示:点击三次按钮之后的结果

          

可以看出虽然正常的关联了信号与槽函数,但是点击按钮之后打印的内容并不是槽函数里面的内容。这个是因为我们重写了事件处理函数,所以在事件处理函数中就不会像以往那样正常的去触发信号,从而正常的去调用槽函数了,而是调用我们重写的事件处理函数。

 

 

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

repinkply

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值