Qt 事件处理

文章目录

Qt 事件概述

  • 事件(event)是由窗口系统(操作系统)或者Qt自身产生的,用以响应所发生的各类事件。QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发。QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期
  • 常见的事件如:
    • 键盘或鼠标事件, 用户按下或者松开键盘或鼠标上的按键,就可以产生一个键盘或者鼠标事件
    • 绘制事件,某个窗口第一次显示时就会产生一个绘制事件,用来告诉窗口需要重新绘制它本身,从而使得该窗口可见
    • Qt事件,Qt自身也会产生很多事件,比如QObject::startTimer()会触发QTimerEvent事件
  • 应用场景
    • 全局快捷键/热键
    • 输入验证和格式化
    • 鼠标手势和拖拽
    • 自定义控件行为

Qt事件的表示

  • QT将系统产生的消息转化为QT事件,QT事件被封装为对象,所有的QT事件均继承抽象类QEvent,用于描述程序内部或外部发生的动作
  • 特殊情况: 在复写 closeEvent 时,注意如果调用 event->ignore() ,意味着关闭事件没有被处理,窗口不关闭;不调用(默认)或者显式调用了另外一个函数 event->accept() 则代表接受事件, 窗口允许被关闭

Qt 事件的处理顺序

  • 谁来接受和处理事件:答案是QObject
  • QObject 类是整个Qt对象模型的心脏,事件处理机制是QObject三大职责(内存管理、内省(intropection)与事件处理制)之一。任何一个想要接受并处理事件的对象均须继承自QObject,可以选择重载QObject::event()函数或事件的处理权转给父窗口
  • Qt框架内部为我们提供了一系列的事件处理机制,当窗口事件产生之后,事件会经过:事件派发 -> 事件过滤->事件分发->事件处理几个阶段
  • Qt窗口中对于产生的一系列事件都有默认的处理动作,如果我们有特殊需求就需要在合适的阶段重写事件的处理动作
  • 每一个Qt应用程序都对应一个唯一的 QApplication应用程序对象,然后调用这个对象的exec()函数,这样Qt框架内部的事件检测就开始了(程序将进入事件循环来监听应用程序的事件)
cpp 复制代码
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();//开启事件循环
}
  • 事件在Qt中产生之后的分发过程如下:
    • 当事件产生之后,Qt使用用应用程序对象调用notify()函数将事件发送到指定的窗口
cpp 复制代码
[override virtual] bool QApplication::notify(QObject *receiver, QEvent *e)
复制代码
- 注意,事件在发送之前可以通过事件过滤器进行过滤,默认不对任何产生的事件进行过滤
cpp 复制代码
[virtual] bool QObject::eventFilter(QObject *watched, QEvent *event)
复制代码
- 当事件发送到指定窗口之后,窗口的事件分发器会对收到的事件进行分类
cpp 复制代码
[virtual] bool QObject::event(QEvent *e) //QWidget中重写了该方法
复制代码
- 事件分发器会将分类之后的事件(鼠标事件、键盘事件、绘图事件。。。)分发给对应的事件处理函数进行处理,每个事件处理函数都有默认的处理动作(我们也可以重写这些事件处理器函数),比如:鼠标事件
  • QWidget类是Qt中所有窗口类的基类,在这个类里边定义了很多事件处理器函数,它们都是受保护的虚函数。 各个子组件中可以覆盖这些虚函数,例如,QPushButton中:
cpp 复制代码
// /opt/Qt/6.2.4/Src/qtbase/src/widgets/widgets/qabstractbutton.cpp
void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
{
    Q_D(QAbstractButton);
    if (e->button() != Qt::LeftButton) {
        e->ignore();
        return;
    }
    d->pressed = false;
    if (!d->down) {
        // refresh is required by QMacStyle to resume the default button animation
        d->refresh();
        e->ignore();
        return;
    }
    if (hitButton(e->pos())) {
        d->repeatTimer.stop();
        d->click(); //发射 click()信号
        e->accept();
    } else {
        setDown(false);
        e->ignore();
    }
}

覆盖过滤器eventFilter

  • 实现一个事件过滤包括两个步骤:
    • 在目标对象上调用installEventFilter(),注册监视对象
    • 在监视对象的eventFilter()函数中处理目标对象的事件
cpp 复制代码
void QObject::installEventFilter(QObject *filterObj)
//filterObj, 实现了eventFilter(QObject *obj, QEvent *event)的对象
//在一个对象上安装事件过滤器filterObj
//这样发往monitoredObj对象的所有事件,都会调用filterObj.eventFilter()进行过滤
monitoredObj->installEventFilter(filterObj);
cpp 复制代码
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //给pushbutton添加过滤器
    ui->pushButton->installEventFilter(this);
}

//过滤器中覆盖默认的eventFilter
bool MainWindow::eventFilter(QObject *obj, QEvent *event){
    if(event->type() == QEvent::MouseButtonPress){
        qDebug()<<QString("%1 is press!").arg(obj->objectName());
        QPushButton *btn = static_cast<QPushButton *>(obj);
        qDebug()<<QString("%1 is press!").arg(btn->text());
        // 返回 true 表示事件已被处理,不再传递
        // 返回 false 表示继续传递
        return true;
    }
    return QWidget::eventFilter(obj, event);
}

覆盖事件处理函数

  • 覆盖closeEvent resizeEvent
cpp 复制代码
void MainWindow::closeEvent(QCloseEvent *ev){
    QMessageBox::Button btn = QMessageBox::question(this, "关闭窗口", "您确定要关闭窗口吗?");
    if(btn == QMessageBox::Yes)
    {
    // 接收并处理这个事件
        ev->accept();
    }
    else
    {
    // 忽略这个事件
        ev->ignore();
    }
}
void MainWindow::resizeEvent(QResizeEvent *ev){
    qDebug() << "oldSize: " << ev->oldSize()
    << "currentSize: " << ev->size();
}
相关推荐
我在人间贩卖青春2 小时前
Qt 多线程编程
qt·多线程编程
不想看见40415 小时前
C++/Qt 实习岗位深度解析【结合一次研发实习谈感受】
开发语言·c++·qt
羊小猪~~20 小时前
【QT】-- QMainWindow简介
开发语言·数据库·c++·后端·qt·前端框架·求职招聘
CSCN新手听安1 天前
【Qt】Qt概述(三)Qt初识,HelloWorld的创建,对象树
开发语言·qt
code_计梦星河1 天前
Qt 开发第九天:时间控件 / 正则 / Vector / 主界面优化实操
qt
小温冲冲1 天前
Qt WindowContainer 进阶指南:底层原理、性能优化与架构抉择
qt·性能优化·架构
徐某人..1 天前
基于i.MX6ULL开发板与OV5640摄像头实现QT相机应用开发
qt·学习·arm
qq_401700412 天前
Qt 数据库操作详解:从连接到增删改查
qt
天天学IT2 天前
第三章 Qt 编译及安装
开发语言·qt·qt教程·qt6教程