Qt中的事件处理

1 Qt中的事件处理

1.1 Qt中的事件处理过程

GUI程序原理回顾,图形界面应用程序的消息处理模型如下:
在这里插入图片描述
思考:操作系统发送的消息如何转变成Qt信号?

Qt平台将系统产生的消息转换成Qt事件:

  • Qt事件是一个QEvent的对象。
  • Qt事件用于描述程序内部或外部发生的动作。
  • 任意的QObject对象都具备事件处理的能力。

在这里插入图片描述
GUI应用程序的事件处理方式:

  1. Qt事件产生后立即被分发到QWidget对象。
  2. QWidget中的event(QEvent*)进行事件处理。
  3. event()根据事件类型调用不同的事件处理函数。
  4. 在事件处理函数中发送Qt中预定义的信号。
  5. 调用信号关联的槽函数。

场景分析:按钮点击
在这里插入图片描述
(图中的序号4应该在序号5之后。)

QPushButton事件处理分析:

  1. 接收到鼠标事件。
  2. 调用event(QEvent*)成员函数。
  3. 调用mouseReleaseEvent(QMouseEvent*)成员函数。
  4. 调用click()成员函数。
  5. 触发信号SIGNAL(clicked())。

事件(QEvent)和信号(SIGNAL)的不同:

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

编程实验:自定义事件处理函数(改写按钮的点击事件)
在这里插入图片描述
QMyPushButton.h:

#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_

QMyPushButton.cpp:

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

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

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

        e->accept();

        setDown(false);
    }
    else
    {
        QPushButton::mouseReleaseEvent(e);
    }
}


Widget.h:

#ifndef _WIDGET_H_
#define _WIDGET_H_

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

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

#endif // _WIDGET_H_

Widget.cpp:

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

void onMyButtonMouseRelease(QObject* sender, QMouseEvent* e)
{
    qDebug() << "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()
{
    
}

main.cpp:

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

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

1.2 Qt中事件的传递过程

首先我们需要了解一点:事件被组件对象处理后可能传递到其父组件对象,也可能不传递到父组件对象。

QEvent中的关键成员函数:

  • void ignore():接收者忽略当前事件,事件可能会传递给父组件。
  • void accept():接收者期望处理当前事件。
  • bool isAccepted():判断当前事件是否被处理。

编程实验:事件处理的顺序
在这里插入图片描述
MyLineEdit.h:

#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H

#include <QLineEdit>

class MyLineEdit : public QLineEdit
{
    Q_OBJECT
public:
    explicit MyLineEdit(QWidget *parent = 0);
    bool event(QEvent* e);
    void keyPressEvent(QKeyEvent* e);
signals:
    
public slots:
    
};

#endif // MYLINEEDIT_H

MyLineEdit.cpp:

#include "MyLineEdit.h"
#include <QDebug>
#include <QEvent>
#include <QKeyEvent>

MyLineEdit::MyLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
}

bool MyLineEdit::event(QEvent* e)
{
    if( e->type() == QEvent::KeyPress )
    {
        qDebug() << "MyLineEdit::event";
    }

    return QLineEdit::event(e);
}

void MyLineEdit::keyPressEvent(QKeyEvent* e)
{
    qDebug() << "MyLineEdit::keyPressEvent";

    QLineEdit::keyPressEvent(e);

    // e->ignore();	// 如果调用了ignore函数,事件则会被传递到其父组件
}

Widget.h:

#ifndef WIDGET_H
#define WIDGET_H

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

class Widget : public QWidget
{
    Q_OBJECT
    
    MyLineEdit myLineEdit;
public:
    Widget(QWidget* parent = 0);
    bool event(QEvent* e);
    void keyPressEvent(QKeyEvent* e);
    ~Widget();
};

#endif // WIDGET_H

Widget.cpp:

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

Widget::Widget(QWidget *parent)
    : QWidget(parent), myLineEdit(this)
{

}

bool Widget::event(QEvent* e)
{
    if( e->type() == QEvent::KeyPress )
    {
        qDebug() << "Widget::event";
    }

    return QWidget::event(e);
}

void Widget::keyPressEvent(QKeyEvent* e)
{
    qDebug() << "Widget::keyPressEvent";

    QWidget::keyPressEvent(e);
}

Widget::~Widget()
{
    
}

main.cpp:

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

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

1.3 Qt中的事件过滤器

对于Qt中的事件过滤器:

  • 事件过滤器可以对其他组件接收到的事件进行监控。
  • 任意的QObject对象都可以作为事件过滤器使用。
  • 事件过滤器对象需要重写eventFilter()函数。

组件通过installEventFilter()函数安装事件过滤器:

  • 事件过滤器在组件之前接收到事件。
  • 事件过滤器能够决定是否将事件转发到组件对象。

在这里插入图片描述
事件过滤器的典型实现:
在这里插入图片描述
编程实验:事件过滤器的使用
大部分代码和上面的代码都相同,这里只贴出安装事件过滤器、和事件过滤器的实现:

Widget::Widget(QWidget *parent)
    : QWidget(parent), myLineEdit(this)
{
    myLineEdit.installEventFilter(this);
}

bool Widget::eventFilter(QObject* obj, QEvent* e)
{
    bool ret = true;

    if( (obj == &myLineEdit) && (e->type() == QEvent::KeyPress) )
    {
        qDebug() << "Widget::eventFilter";

        QKeyEvent* evt = dynamic_cast<QKeyEvent*>(e);

        switch(evt->key())
        {
        case Qt::Key_0:
        case Qt::Key_1:
        case Qt::Key_2:
        case Qt::Key_3:
        case Qt::Key_4:
        case Qt::Key_5:
        case Qt::Key_6:
        case Qt::Key_7:
        case Qt::Key_8:
        case Qt::Key_9:
            ret = false;
            break;
        default:
            break;
        }
    }
    else
    {
        ret = QWidget::eventFilter(obj, e);
    }

    return ret;
}

参考资料:

  1. QT实验分析教程
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值