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

embedded/2025/3/14 17:09:03/

事件系统

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/embedded/172531.html

相关文章

使用RabbitMQ实现流量削峰填谷

原理 流量削峰填谷是指在面对突发的高流量时&#xff0c;通过消息队列将瞬时大量请求暂时存储起来&#xff0c;并逐步处理这些请求&#xff0c;从而避免系统过载。RabbitMQ 作为消息中间件可以很好地支持这一需求&#xff0c;特别是结合其延时消息插件&#xff08;rabbitmq_de…

C++程序设计语言笔记——基本功能:源文件与程序

0 用头文件表达接口、强调逻辑结构。 我们以 C 语言为例&#xff0c;展示如何通过头文件组织模块化设计&#xff1a; 示例场景&#xff1a;日志模块接口设计 文件结构 include/log.h // 公共接口log_config.h // 配置参数log_internal.h // 内部实现细节&#xf…

什么是大模型微调?

在大模型&#xff08;如GPT、BERT、LLaMA等&#xff09;广泛应用的今天&#xff0c;“微调”&#xff08;Fine-Tuning&#xff09;已成为释放模型潜力的关键技术。它通过针对特定任务调整预训练模型&#xff0c;使其从“通才”变为“专才”。本文将从概念、原理到实践&#xff…

C语言 进阶指针学习笔记

文章目录 字符指针指针数组数组指针数组名数组传参 函数指针函数指针数组指向函数指针数组的指针 回调函数Qsort 的使用通过冒泡排序模拟实现 qsort 大部分的内容都写在代码注释中 指针有类型&#xff0c;指针的类型决定了指针的整数的步长&#xff0c;指针解引用操作的时候的权…

Spring Boot中实现多租户架构

Spring Boot中实现多租户架构 在当今的企业级应用开发中&#xff0c;多租户架构已经成为一项关键技术&#xff0c;尤其是对于需要服务多个客户群体的 SaaS&#xff08;软件即服务&#xff09;系统。多租户架构的核心思想是通过共享资源来降低运营成本&#xff0c;同时确保各个…

如何安全处置旧设备?

每年&#xff0c;数百万台旧设备因老化、故障或被新产品取代而被丢弃&#xff0c;这些设备上存储的数据可能带来安全风险。 如果设备没有被正确删除数据&#xff0c;这些数据往往仍可被恢复。因此&#xff0c;安全处置旧设备至关重要。 旧设备可能包含的敏感数据 旧设备中可能…

产城融合典范:树莓科技如何助力宜宾数字经济腾飞​

宜宾在推动数字经济发展的征程中&#xff0c;树莓科技扮演着至关重要的角色&#xff0c;堪称产城融合的典范。 树莓科技入驻宜宾后&#xff0c;积极与当地政府合作&#xff0c;以产业发展带动城市建设&#xff0c;以城市功能完善促进产业升级。在产业布局上&#xff0c;树莓科…

docker使用robot用户登录harbor

此前一直使用 docker login harbor.devops.baga.life -u ‘robot:$baga’ -p ‘xxxxxxpassword’ 这次登录就报错了 Error response from daemon: Get "https://harbor.devops.tantin.com/v2/": unauthorized:可能是docker版本发生变化&#xff0c;robot用户识别方…