QT:事件
在 Qt 中,事件(Event) 是对象之间进行内部通信的底层机制,用于响应各种“发生的事”,例如窗口显示、鼠标点击、键盘输入、定时器超时等。理解事件系统是开发复杂交互式应用程序的基础。什么是事件?事件是 QEvent 或其子类的实例,封装了“发生的事情”的相关信息(如鼠标坐标、按键代码等)。任何 QObject 子类都能接收和处理事件。事件通常由操作系统产生(比如鼠标、键盘),也可以由应用程序自
概述
在 Qt 中,事件(Event) 是对象之间进行内部通信的底层机制,用于响应各种“发生的事”,例如窗口显示、鼠标点击、键盘输入、定时器超时等。理解事件系统是开发复杂交互式应用程序的基础。
什么是事件?
-
事件是 QEvent 或其子类的实例,封装了“发生的事情”的相关信息(如鼠标坐标、按键代码等)。
-
任何 QObject 子类都能接收和处理事件。
-
事件通常由操作系统产生(比如鼠标、键盘),也可以由应用程序自己生成(比如定时器事件、自定义事件)。
信号槽可以看作对特定事件的二次封装。例如 QPushButton 的 clicked()
流程
每一个Qt应用程序都对应一个唯一的QApp1ication应用程序对象,调用这个对象的exec()函数之后,Qt框架内部的事件检测就开始了(程序将进入事件循环来监听应用程序的事件)
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
Qt 的事件处理流程确实遵循事件派发 → 事件过滤 → 事件分发 → 事件处理 这几个主要阶段
[操作系统/应用程序产生事件]
↓
1️⃣ 事件派发(QApplication::notify)
- 全局入口,找到目标 QObject
↓
2️⃣ 事件过滤(事件过滤器)
- 目标对象上安装的所有 eventFilter 依次执行
- 任一过滤器返回 true,则事件被“截断”,不再继续
↓
3️⃣ 事件分发(QObject::event())
- 根据事件类型调用对应的具体事件处理函数
- 例如 QKeyEvent → keyPressEvent()
↓
4️⃣ 事件处理(具体 *Event 函数)
- 最终的业务处理,可重写实现自定义行为
1.事件派发
1当事件产生之后,Qt使用用应用程序对象调用notify()函数将事件发送到指定的窗口
[override virtual] bool QApplication::notify(Qobject *receiver, QEvent *e);
2.事件过滤
对应机制:installEventFilter() + eventFilter() 重写,需要先给窗口安装过滤器,该事件才会触发,在目标对象的处理函数(event() 函数)之前执行,只要某个过滤器返回 true,事件就被过滤/拦截,不再传递给后续过滤器以及目标对象本身,默认为不对任何事情进行过滤
[virtual] bool QApplication::eventFilter(QObject *watched, QEvent *e);
3.事件分发
当事件发送到指定窗口之后,窗口的事件分发器会对收到的事件进行分类,
事件分发器会将分类之后的事件,分发给对应的事件处理器函数进行处理。
它会根据事件的类型(例如 QEvent::KeyPress),调用对应的具体处理函数(如 keyPressEvent())。
[override virtual protected] bool Qwidget::event(QEvent *event);
4.事件处理
相应的处理函数,如 keyPressEvent(QKeyEvent*)、mousePressEvent(QMouseEvent*) 等。是虚函数,可以重写,用于实现控件自己的行为逻辑。
[virtual protected] void QWidget::keyPressEvent(QKeyEvent *event);
[virtual protected] void QWidget::mousePressEvent(QMouseEvent *event);
用户操作
用户如果想要某个事件,产生某个效果,一般对事件过滤和事件处理进行操作
1.事件处理示例
思路
这里创建一个类,继承于QTextEdit,名为mytextdit,是一个自定义控件,这里将ui的textEdit控件提升为mytextdit,
这里,通过调用基类构造函数传入 parent,使当前控件成为父 widget 的子对象,从而纳入 UI 体系,具体在.cpp文件,同时.cpp文件重写事件处理函数,实现用户在触发这个事件而想要实现的功能(其中注释也是思路补充)。
mytextdit::mytextdit(QWidget *parent):QTextEdit(parent)。
{
}
mytextdit.hh
#ifndef MYTEXTDIT_H
#define MYTEXTDIT_H
#include <QTextEdit>
class mytextdit : public QTextEdit
{
public:
mytextdit(QWidget* parent);
int ctr_key_pressed=0;//定义一个变量,用途可见.cpp注释
protected:
void wheelEvent(QWheelEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
void keyReleaseEvent(QKeyEvent *e) override;
};
#endif // MYTEXTDIT_H
#include "mytextdit.h"
#include <QWheelEvent>
#include<QDebug>
#include<QWidget>
mytextdit::mytextdit(QWidget *parent):QTextEdit(parent)//通过调用基类构造函数传入 parent,使当前控件成为父 widget 的子对象,从而纳入 UI 体系。
{
}
void mytextdit::wheelEvent(QWheelEvent *e)
{
qDebug()<<e->angleDelta().y();
if(ctr_key_pressed==1)//定义一个变量,判断按键是否按下,从实现crtl+鼠标滚轮,放大/缩小字体的功能
{
if(e->angleDelta().y()>0)//滚轮向前滚
{
zoomIn();//QTextEdit的函数,作用:放大字体
}else if(e->angleDelta().y()<0)
{
zoomOut();//减小字体
}
e->accept();//这里表示,该事件已经被当前控件处理完毕,否则会向上层父控件继续传播。
}
else
QTextEdit::wheelEvent(e);//针对事件没有被处理的情况,调用基类QTextEdit对这个事件的处理
}
void mytextdit::keyPressEvent(QKeyEvent *e)
{
if(e->key()==Qt::Key_Control)//ctrl键被按下
{
ctr_key_pressed=1;
}
QTextEdit::keyPressEvent(e);
}
void mytextdit::keyReleaseEvent(QKeyEvent *e)
{
if(e->key()==Qt::Key_Control)//ctrl键松开了
{
ctr_key_pressed=0;
}
QTextEdit::keyReleaseEvent(e);
}
2.事件过滤示例
1.文档参考


class MainWindow : public QMainWindow
{
public:
MainWindow();
bool eventFilter(QObject *obj, QEvent *ev) override;
private:
QTextEdit *textEdit;
};
MainWindow::MainWindow()
{
textEdit = new QTextEdit;
setCentralWidget(textEdit);
textEdit->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == textEdit) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
qDebug() << "Ate key press" << keyEvent->key();
return true;
} else {
return false;
}
} else {
// pass the event on to the parent class
return QMainWindow::eventFilter(obj, event);
}
}
2.示例
关键点:installEventFilter() + eventFilter() 重写

bool eventFilter(QObject *obj, QEvent *ev) override;

ui->textEdit->installEventFilter(this);//为控件,installEventFilter()

bool Widget::eventFilter(QObject *obj, QEvent *ev)
{
if (ev->type() == QEvent::Wheel) {
if (QGuiApplication::keyboardModifiers() == Qt::ControlModifier) { //事件过滤可以判断滚轮和按键事件,但是没办法联系起来
// 所以用了另外一种方式判断按键是否按下
QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(ev);//类型转换
if (wheelEvent->angleDelta().y() > 0) {
increase_font_size(); // 放大字体
} else if (wheelEvent->angleDelta().y() < 0) {
decrease_font_size(); // 缩小字体
}
return true; // 事件已处理,阻止继续传递
}
else
return false;
}
return QObject::eventFilter(obj, ev);
}
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)