Qt中的事件处理

图形界面应用程序的消息处理模型

Qt中的事件处理_第1张图片

操作系统发送的消息如何转变为 Qt 信号?

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

Qt 事件是一个 QEvent 对象

Qt 事件用于描述程序内部或外部发生的动作

任意的 QObject 对象都具有事件处理的能力

Qt中的事件处理_第2张图片

GUI 应用程序的事件处理方式

1. Qt 事件产生后立即分发到 QWidget 对象

2. QWidget 中的 event(QEvent*) 进行事件处理

3. event() 根据事件的类型调用不同的事件处理函数

4. 在事件处理函数中发送 Qt 中预定义的信号

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

场景分析:按钮点击

Qt中的事件处理_第3张图片

QPushButton 事件处理分析

1. 接收到鼠标事件

2.  调用 event(QEvent*) 函数

3. 调用 mouseReleaseEvent(QMouseEvent*) 成员函数

4. 调用 click() 成员函数

5. 触发信号 SIGNAL(clicked())

自定义事件处理函数

QmyPushButton.h

#ifndef QMYPUSHBUTTON_H
#define QMYPUSHBUTTON_H

#include 
#include 

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

class QmyPushButton : public QPushButton
{
    Q_OBJECT
protected:
    QButtonListener* m_listen;

    /* 子类重写父类的虚函数 */
    void mouseReleaseEvent(QMouseEvent *e);
public:
    explicit QmyPushButton(QWidget *parent = nullptr, QButtonListener *listen = nullptr);

signals:

};

#endif // QMYPUSHBUTTON_H

QmyPushButton.cpp

#include "QmyPushButton.h"
#include 
QmyPushButton::QmyPushButton(QWidget *parent, QButtonListener *listen) : QPushButton(parent)
{
    m_listen = listen;
}

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

        /* 标记当前的事件已经被处理 */
        e->accept();

        /* 设置按钮弹起 */
        setDown(false);
    }
    else
    {
        QPushButton::mouseReleaseEvent(e);
    }
}

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 
#include "QmyPushButton.h"

class Widget : public QWidget
{
    Q_OBJECT
private slots:
    void buttonClicked();
private:
    QmyPushButton myButton;

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
};
#endif // WIDGET_H

Widget.cpp

#include "Widget.h"
#include 
#include 
#include 

void func(QWidget *w, QMouseEvent *e)
{
    qDebug() << "void func(QWidget *w, QMouseEvent *e)";
}

Widget::Widget(QWidget *parent)
    : QWidget(parent), myButton(this, func)
{
    myButton.setText("myButton");
    connect(&myButton, &QPushButton::clicked, this, &Widget::buttonClicked);
}

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

Widget::~Widget()
{
}

当 QmyPushButton 被按下后松开后,会调用其 mouseReleaseEvent 函数。

事件 (Event) 和信号 (Signal) 不同

事件由具体对象进行处理

信号由具体对象主动产生

改写事件处理函数可能导致程序行为发生改变

信号是否存在对应的槽函数不会改变程序行为

一般而言,信号在具体的事件处理函数中产生

事件的传递过程

Qt中的事件处理_第4张图片

事件被组件对象处理后可能传递到其父组件对象

QEvent 中的关键成员函数

void ignore();

  • 接收者忽略当前事件,事件可能传递给父组件

void accept();

  • 接收者期望处理当前事件

bool isAccepted();

  • 判断当前事件是否被处理

事件处理的顺序

MyLineEdit.h

#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H

#include 

class MyLineEdit : public QLineEdit
{
    Q_OBJECT
protected:
    bool event(QEvent* e);
    void keyPressEvent(QKeyEvent* e);

public:
    explicit MyLineEdit(QWidget* parent = nullptr);

signals:

};

#endif // MYLINEEDIT_H

MyLineEdit.cpp

#include "MyLineEdit.h"
#include 
#include 
#include 

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();
}

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 
#include 

class Widget : public QWidget
{
    Q_OBJECT
private:
    MyLineEdit myLineEdit;

protected:
    bool event(QEvent *e);
    void keyPressEvent(QKeyEvent *e);

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
};
#endif // WIDGET_H

Widget.cpp

#include "Widget.h"
#include 
#include 
#include 

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()
{
}

在单行文本框输入字符时,首先会调用 Event 函数,接下来 Event 函数会调用 keyPressEvent 函数。

Qt 中的事件过滤器

事件过滤器可以对其它组件接收到的事件进行监控

任意的 QObject 对象都可以作为事件过滤器使用

事件过滤器需要重写 eventFilter() 函数

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

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

Qt中的事件处理_第5张图片

事件过滤器的典型实现 Qt中的事件处理_第6张图片

事件过滤器的使用

Widget.cpp

#include "Widget.h"
#include 
#include 
#include 

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* key = dynamic_cast(e);

        switch(key->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;
}

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()
{
}

在使用事件过滤器之前,需要事件过滤的对应组件需要安装事件过滤器;然后重写 eventFilter 函数,eventFilter 返回 true 表示将当前事件过滤;返回 false 表示这个事件会正常传递到目标组件。

你可能感兴趣的:(Qt,qt)