Qt学习之路26--事件处理、事件重写、关闭文本编辑器操作

消息处理模型

Qt学习之路26--事件处理、事件重写、关闭文本编辑器操作_第1张图片
- GUI程序必须依赖操作系统运行
- GUI应用程序提供的功能必须由用户来触发
- 消息的产生一般是通过用户对应用程序进行了某种操作(如点击某个按钮),随之操作系统捕捉到这个操作,并让系统内核将这个操作事件转换成一个系统消息然后发送给应用程序,最后应用程序收到这个系统消息后就会调用相应的消息处理函数对这个用户操作进行最终的处理。

系统内核会将系统消息发送给应用程序,那么在Qt应用程序中系统内核是如何将发送的系统消息转换成Qt信号?

答案是通过事件处理来将系统消息转变成Qt信号

Qt中的事件处理

  • Qt平台将系统产生的消息转换成Qt事件
  • Qt事件是一个QEvent对象
  • Qt事件用于描述程序内部或外部发生的动作,这意味着QEvent对象用来描述操作系统发送回的消息
  • 一个系统消息对应着一个Qt事件,也就是一个QEvent对象
  • Qt的一个事件需要一个QObject对象来处理,并且任意的QObject对象都具备事件处理的能力
  • Qt事件相关类的继承关系图:
    Qt学习之路26--事件处理、事件重写、关闭文本编辑器操作_第2张图片

Qt事件处理方式

  • Qt事件产生后立即被分发到QWidget对象,比如点击一个按钮后就会将点击按钮这个事件发送到对应的QWidget对象上(或是一个窗口,或是一个对话框)
  • 然后这个QWidget对象调用event()这个事件处理函数,因此,event()函数也是事件处理的入口
  • event()根据事件类型(由于操作系统发送的消息类型是各不相同的,且操作系统的消息和Qt事件是一一对应的,所以Qt事件对应的事件处理函数(event()函数的子函数)也是各不相同,所以需要在event()函数中判断对应的事件类型)调用不同的事件处理函数。
  • 在事件处理函数中发送Qt中预定义的信号,最后调用信号关联的槽函数。

场景分析:按钮点击

Qt学习之路26--事件处理、事件重写、关闭文本编辑器操作_第3张图片
1、首先用户点击某个功能按钮
2、操作系统感知到后会产生一个系统消息
3、系统内核会将点击按钮这个消息发送到当前应用程序
4、应用程序会将系统消息转变成一个Qt事件,即鼠标相关事件mouseReleaseEvent()
5、Qt应用程序进行判断是哪种事件类型
6、根据事件类型将事件发送到对应的窗口部件QWidget对象
7、QWidget对象调用event()函数处理事件
8、在event函数中调用子函数click()由此产生一个Qt信号发送给对应QObject对象
9、Qobject对象处理事件,调用槽函数。

例:修改一个按钮事件的默认处理方式

在正常情况下,在Qt应用程序中点击一个按钮将会触发clicked()信号被发送,接收对象接收到这个信号后就会调用槽函数,这是默认的处理方式,接下来就通过重写Qt的mouseReleaseEvent()修改Qt对按钮点击事件的处理方式。

构造一个自定义按钮类

头文件

#ifndef QMYPUSHBUTTON_H
#define QMYPUSHBUTTON_H

#include 
#include 
#include 
typedef void (ButtonListener)(QObject*, QMouseEvent*);//重命名一个函数类型

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

    void mouseReleaseEvent(QMouseEvent *e);//重写这个事件处理函数
public:
    explicit QMyPushButton(QWidget *parent = 0, ButtonListener* listener = 0);//修改构造函数

signals: 
public slots:   
};

#endif // QMYPUSHBUTTON_H

源文件

#include "QMyPushButton.h"

QMyPushButton::QMyPushButton(QWidget *parent, ButtonListener* listener) : QPushButton(parent)
{
    m_listener = listener;
}

void QMyPushButton::mouseReleaseEvent(QMouseEvent *e)//重写事件函数
{
    if(m_listener != NULL)//修改事件的处理方式
    {
        m_listener(this, e);//初始化处理事件的QObject对象和需处理的事件类型
        e->accept();//设置事件e作为期望接受处理的事件
        setDown(false);//设置后将不会发送clicked()信号
    }
    else
    {
        QPushButton::mouseReleaseEvent(e);//调用默认事件处理函数
    }
}

构造一个包含按钮的界面类

头文件

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include "QMyPushButton.h"

class Widget : public QWidget
{
    Q_OBJECT
    QMyPushButton myButton;//自定义按钮对象
protected slots:
    void onMyButtonClicked();
public:
    Widget(QWidget *parent = 0);
    ~Widget();
};

#endif // WIDGET_H

源文件

#include "Widget.h"
#include 
#include 

void onMyButtonMouseRelease(QObject* sender, QMouseEvent* e)//重写的事件处理函数
{
    qDebug() << "onMyButtonMouseRelease(QObject* sender, QMouseEvent* e)";
}
void Widget::onMyButtonClicked()//默认的按钮槽函数
{
    qDebug() << "onMyButtonClicked()";
}

Widget::Widget(QWidget *parent) : QWidget(parent), myButton(this, onMyButtonMouseRelease)
{
    myButton.setText("QMyPushButton");
    connect(&myButton, SIGNAL(clicked()), this, SLOT(onMyButtonClicked()));//点击按钮默认会调用该槽函数
}

Widget::~Widget()
{

}
  • 通过在widget类中定义一个QMyPushButton对象,初始化成QButtonListener函数类型,所以在调用mouseReleaseEvent事件处理函数时就会调用QMyPushButton里的mouseReleaseEvent函数,进而判断m_listener是否为空来确定调用父类的事件处理函数还是重写后的事件处理函数。
  • 由于重写了事件处理函数,所以程序并不会像原先一样发送信号,所以也不会去执行对应的槽函数,而是执行m_listener这个变量初始化的函数
    Qt学习之路26--事件处理、事件重写、关闭文本编辑器操作_第4张图片
    当点击按钮时,默认会调用void Widget::onMyButtonClicked()函数,但是经过重写事件处理方式后调用的却是onMyButtonMouseRelease(QObject* sender, QMouseEvent* e)。

文本编辑器关闭操作

在点击关闭文本编辑器之前如果编辑框中有未保存的数据时则需要先保存数据再关闭编辑器,解决方法就是重写closeEvent(QCloseEvent*)事件函数,当存在未保存的数据时忽略这个事件,当不存在未保存数据时执行默认closeEvent()事件函数。

事件(QEvent)和信号(SIGNAL)的区别

  • 事件由具体对象进行处理
  • 信号由具体对象产生
  • 改写事件处理函数可能导致事件处理方式发生改变
  • 信号是否存在对应的槽函数不改变程序的行为
  • 一般而言,信号在具体的事件处理函数中产生

你可能感兴趣的:(Qt)