Qt基础学习之事件

Qt-事件

1. Qt对事件的描述及分类

什么是事件
事件是由程序内部或者外部产生的事件或某种动作的统称。比如鼠标点击产生一鼠标事件,键盘按下产生一个键盘事件,窗口显示产生一个绘图事件等。事件通常是来自于底层的窗口系统,当然也可以手动发送自定义的事件,事件不同于信号,他既可以是同步的,也可以使一异步的,这取决于是使用sendEvent()还是postEvent()发送的事件。并且事件支持过滤,这在事件的处理和传递上是具有很大好处。Qt使用QEvent()及其子类处理事件,比如,QMoustEvent()处理与鼠标相关的事件。

事件的分类

  • 根据事件的来源和传递分类
    1. 自发事件:这些事件是由窗口系统生成,置于系统队列中,并在事件循环中一个一个处理。
    2. 发布的事件:这些事件由Qt和应用程序产生,并有Qt排队,经事件循环处理。
    3. 发送的事件:这些事件由Qt和应用程序产生,并直接发送到目标对象,不由事件循环处理。
  • 事件的细分类型
    事件的细分类型由QEvent中的枚举常量表示,比如鼠标事件QMouseEvent具有双击、移动、按下事件,这些事件可以使用MouseButtonDblClick、MouseMove、MouseButtonPress枚举常量表示。不同的事件表示方式可以通过 Type QEvent::type() const函数来获取。

事件继承
image

事件的传递和处理

基本规则
目标对象如果没有处理事件,那么事件会传递给父对象,如果父对象依然没有处理,再传递给爷爷对象。直到事件别处理处理或者到达顶层对象为止。

事件传递过程

  1. 第一步: Qt中的事件循环,从可能产生事件的地方捕获事件,并把事件转化为带有事件信息的对象。然后由事件处理流程发送给需要处理事件的对象来处理事件。
  2. 第二步:Qt调用QCoreApplication::notify()函数对事件进行分发。
  3. 第三步:QObject对象调用QObject::event()函数接收事件。
  4. 第四步:event()函数根据事件的类型,调用对应的事件处理函数,如果返回true,则表示事件被处理,否则需要进一步传递或者丢弃。

事件处理流程图
image

事件处理
任何QObject子类都可以处理事件,QEvent及其子对象描述事件信息,但是并不对事件进行处理。真正处理事件的是类的成员函数,通常称为事件处理函数。Qt已经为绝大多数事件提供了事件处理函数,并做了默认处理。这些默认的事件处理函数通过event()进行调用,如果默认事件处理函数不能满足要求,可以重新event()函数实现。

QWidget::event()实现
image

事件处理的五种方式

  • 重写默认事件处理函数
  • 重写QObect::event()函数,事件在到达事件处理函数之前,先被event()函数捕获,对未被明确定义的事件处理,需要调用父类的event()函数处理。
  • 在QObject()对象上安装事件过滤器,对象一旦通过installEventFilter()函数注册,所有传递给目标对象的事件都会先别监视对象的eventFilter()捕获,如果监视对象安装了多个事件过滤器,会按照逆序方式一次激活。
  • 在QApplication上安装事件过滤器,这与重新实现noitify一样强大。一旦在QApplication上注册了事件过滤器,那么每一对象每一个事件都会在发送到其他事件过滤器之前,发送到这个eventFilter()函数。
  • 重写QCoreApplication::notify()函数。

事件处理方式实例

点击查看代码
#include "widget.h"
#include <QApplication>
#include <QDebug>

class A : public QWidget
{
    bool event(QEvent *e){
        if(e->type() == QEvent::KeyPress){
            qDebug() << "key press" << endl;
        }
        return QWidget::event(e);
    }
    void mousePressEvent(QMouseEvent *e){
        qDebug() << "mouse press" << endl;
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    A ma;
    ma.resize(300,200);
    ma.show();

    return a.exec();
}

事件传递实例

点击查看代码
class A : public QWidget {
    bool event(QEvent *e){
        switch (e->type()) {
        case QEvent::KeyPress:
            qDebug() << "parent" <<"key press";
            break;
        case QEvent::MouseButtonPress:
            qDebug() << "parent" << "mouse press" <<endl;
            break;
        case QEvent::MouseButtonRelease:
            qDebug() << "parent" << "mouse release" << endl;
            break;
        default:
            break;
        }
        return QWidget::event(e);
    }

};

class C : public QPushButton {
    bool event(QEvent *e){
        if(e->type() == QEvent::KeyPress){
            qDebug()  << "key press" << endl;
            return 0;
        }
        if(e->type() == QEvent::MouseButtonPress){
            qDebug()<< "mouse press" <<endl;
            return 1;
        }
        return QWidget::event(e);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    A ma;
    C *mc = new C();
    mc->setParent(&ma);
    mc->setText("btn");
    mc->move(20,20);
    ma.resize(200,300);
    ma.show();

    return a.exec();
}
posted @   CLAY_ZQ  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
点击右上角即可分享
微信分享提示