QT系列教程(13) 事件系统

server/2025/3/15 4:09:32/

事件系统

Qt事件系统是非常重要事件传递机制,所有消息传递流程都离不开这个机制,这里主要从重写类的事件响应函数,事件过滤器以及重写event函数三种方式做介绍。

重写事件函数

这种方式最为直接,我们先创建项目,选择QApplication应用,类名选择Widget,基类选择QWidget
接下来在项目中添加一个C++类命名为MyEdit项目生成后,我们为MyEdit类添加声明和实现

class MyEdit : public QLineEdit
{Q_OBJECT
public:explicit MyEdit(QWidget *parent = nullptr);protected:void keyPressEvent(QKeyEvent *);
signals:public slots:
};

MyEdit类的声明中添加了keyPressEvent函数的声明,该函数主要用来重写按键点击事件。
我们接下来实现按键点击逻辑重写

void MyEdit::keyPressEvent(QKeyEvent * event){qDebug()<<"MyEdit key press event";
}

然后我们在Widget的构造函数中初始化这个edit,并添加到Widget上

Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);line_edit_ = new MyEdit(this);line_edit_->move(100,100);
}

运行程序后点击lineEdit, 然后按下键盘,发现输出了"MyEdit key press event"。
但是lineEdit的基本输入功能失效了,此时我们在keyPressEvent中添加 QLineEdit::keyPressEvent

void MyEdit::keyPressEvent(QKeyEvent * event){qDebug()<<"MyEdit key press event";QLineEdit::keyPressEvent(event);
}

作用就是调用完我们的输出后,调用QLineEdit原有的按键处理逻辑,保证QLineEdit可以正常使用。

让父窗口和子窗口都响应事件

为了让父窗口也响应按键事件,在父窗口Widget里同样实现keyPressEvent

void Widget::keyPressEvent(QKeyEvent * event){qDebug()<<"Widget key press event" << endl;
}

运行程序,我们在lineEdit中输入内容,发现此时只触发MyEdit的keyPressEvent。
如果想要触发Wdiget的keyPressEvent,需要在MyEdit的keyPressEvent添加event->ignore()

void MyEdit::keyPressEvent(QKeyEvent * event){qDebug()<<"MyEdit key press event";QLineEdit::keyPressEvent(event);event->ignore();
}

event->ignore的作用是当MyEdit处理完keyPressEvent事件后,将按键消息继续抛给其父节点,也就是Widget,这样Widget就能处理按键消息了。

万能的event

我们也可以重新实现MyEdit的event函数,这个函数的作用是所有的消息优先经过event处理,然后才根据不同的事件调用具体的事件处理函数如keyPressEvent,
所以event的调用顺序优先于keyPressEvent。

bool MyEdit::event(QEvent *pevent)
{if(pevent->type() == QEvent::KeyPress){qDebug() << tr("my edit event") << endl;}return  QLineEdit::event(pevent);
}

在event里判断事件类型为KeyPress,也就是按键事件,就打印"my edit event",然后调用QLineEdit::event,以保证其QLineEdit的原有功能。
此时在LineEdit中输入内容,就会先输出"my edit event"再输出"MyEdit key press event"。

eventFilter事件过滤器

要实现对某个控件事件的捕获,可以通过对其父窗口重写eventFilter函数,这个函数是过滤器,在这个过滤器里可以根据对象和事件类型进行。
我们在Widget类实现

bool Widget::eventFilter(QObject *object, QEvent *event)
{if(object == line_edit_){if(event->type() == QEvent::KeyPress){qDebug() << "widget eventfilter catch line_edit" << endl;return false;}}return QWidget::eventFilter(object, event);
}

在eventFilter里判断对象为line_edit_,并且事件类型为KeyPress,则打印日志,并且返回false,返回false意思是将该消息继续传递,这个按键消息会传递给MyEdit的event函数,然后是MyEdit的keyPressEvent函数。
仅仅实现eventFilter是不够的,我们需要在Widget的构造函数中加载这个过滤器。

line_edit_->installEventFilter(this);

这样再次运行程序,在lineEdit中按下键盘,会看到程序输出如下

widget eventfilter catch line_edit 
my edit event 
MyEdit key press event
Widget key press event 

可见消息捕获的顺序是 Widget::eventfilter -> MyEdit::event-> MyEdit::keyPressEvent -> MyWidget::keyPressEvent

为多个控件添加eventFilter

我们可以在父窗口为其多个子节点控件添加eventFilter。
我们在Widget中添加两个控件QTextEdit和QSpinBox, 然后再重新实现Widget的eventFilter

bool Widget::eventFilter(QObject *watched, QEvent *event){if(watched == ui->textEdit){if(event->type() == QEvent::Wheel){QWheelEvent* wheelEvent  = static_cast<QWheelEvent*>(event);if(wheelEvent->delta() > 0){qDebug() << "catch wheel event delta > 0" << endl;ui->textEdit->zoomIn();}else {qDebug() << "catch wheel event delta < 0" << endl;ui->textEdit->zoomOut();}return true;}return false;}if(watched == ui->spinBox){if(event->type() == QEvent::KeyPress){QKeyEvent * keyEvent = static_cast<QKeyEvent*>(event);if(keyEvent->key() == Qt::Key_Space){ui->spinBox->setValue(0);return true;}return false;}return false;}return QWidget::eventFilter(watched, event);
}

eventFilter 中根据不同的对象实现了不同的事件捕获,对于textEdit捕获了滚轮事件
对于spinbox,捕获了空格按键。

然后在Widget的构造函数中为两个控件安装过滤器

    ui->textEdit->installEventFilter(this);ui->spinBox->installEventFilter(this);

运行程序就可以在滚轮滚动时缩放textEdit,按下空格键就可以使spinbox清零。

总结

源码链接:

    ui->textEdit->installEventFilter(this);ui->spinBox->installEventFilter(this);

运行程序就可以在滚轮滚动时缩放textEdit,按下空格键就可以使spinbox清零。

总结

源码链接:
https://gitee.com/secondtonone1/qt-learning-notes


http://www.ppmy.cn/server/175056.html

相关文章

《灵珠觉醒:从零到算法金仙的C++修炼》卷三·天劫试炼(36)太极图化路径 - 不同路径(组合数学优化)

《灵珠觉醒:从零到算法金仙的C++修炼》卷三天劫试炼(36)太极图化路径 - 不同路径(组合数学优化) 哪吒在数据修仙界中继续他的修炼之旅。这一次,他来到了一片神秘的太极谷,谷中有一幅巨大的太极图,图中隐藏着无数路径。谷口有一块巨大的石碑,上面刻着一行文字:“欲破…

【webrtc debug tools】 rtc_event_log_to_text

一、rtc_event_log 简介 在学习分析webrtc的过程中&#xff0c;发现其内部提供了一个实时数据捕获接口RtcEventLog。通过该接口可以实时捕获进出webrtc的RTP报文头数据、音视频配置参数、webrtc的探测数据等。其内容实现可参考RtcEventLogImpl类的定义。其文件所在路径 loggin…

ArcGIS水文水资源水环境应用实战:从入门到精通!ArcGIS水文分析及流域特征提取;湖泊水库水环境监测及评价;河道水污染预测与水环境容量计算等

随着水资源日益紧缺和水环境问题日益突出&#xff0c;水文水资源领域面临着前所未有的挑战。ArcGIS 作为强大的地理信息系统平台&#xff0c;凭借其强大的空间分析、数据管理和可视化能力&#xff0c;在水文水资源领域发挥着越来越重要的作用。本文将结合最新技术&#xff0c;探…

TCP网络协议

TCP粘包 1. TCP在接收数据时&#xff0c;多包数据粘在了一起 2. 原因&#xff1a; 1. TCP发送数据时&#xff0c;没有及时发走&#xff0c;会根据缓冲区数据的情况进行重新组包&#xff1b; 2. TCP接收方&#xff0c;没有及时读走缓冲区数据&#xff0c;导致缓冲区大量数…

C#中继承的核心定义‌

1. 继承的核心定义‌ ‌继承‌ 是面向对象编程&#xff08;OOP&#xff09;的核心特性之一&#xff0c;允许一个类&#xff08;称为‌子类/派生类‌&#xff09;基于另一个类&#xff08;称为‌父类/基类‌&#xff09;构建&#xff0c;自动获得父类的成员&#xff08;字段、属…

基于SpringBoot的医院管理系统(源码+论文+部署教程)

运行环境 医院管理系统运行环境如下&#xff1a; • 前端&#xff1a;Vue • 后端&#xff1a;Java • IDE工具&#xff1a;IntelliJ IDEA&#xff08;可自行更换&#xff09; • 技术栈&#xff1a;SpringBoot Vue MySQL 主要功能 医院管理系统主要包医院含前台界面和…

服务端渲染(SSR)

服务端渲染&#xff08;Server-Side Rendering&#xff0c;SSR&#xff09;是一种将网页内容在服务器端生成并发送到客户端的技术。与传统的客户端渲染&#xff08;Client-Side Rendering&#xff0c;CSR&#xff09;相比&#xff0c;SSR 在性能、SEO 和用户体验方面具有显著优…

接口测试工具:postman详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Postman 是一款功能强大的 API 开发和测试工具&#xff0c;以下是一些高级用法的详细介绍和操作步骤。 一、环境和全局变量 环境变量允许你设置特定于环境&#…