一、事件
1.事件与信号的区别
- 事件来自外部,是随机发生的。信号来自内部,是主动发生的。有点像外中断和内中断的区别。
- 事件:适用于处理系统级别的输入和状态变化,种类繁多,能够应对复杂的交互需求。
- 信号/槽:适用于对象间通信和状态变化响应,灵活性高,支持异步通信和多线程编程。
- 信号是单调的,而事件是丰富的。
2.事件系统QEvent
- GUI(Graphical User Interface) 应用程序是由事件(event)驱动的,点击鼠标、按下某个按键、改变窗口大小、最小化窗口等都会产生相应的事件,应用程序对这些事件进行相应的处理以实现程序的功能。
- 在大多数情况下,GUI进程和UI进程这两个术语是可以互换使用的,它们通常指的是同一个概念,即处理和管理图形用户界面(Graphical User Interface, GUI)以及用户与应用程序交互的进程。
- 代码详解
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//QApplication类是Qt应用程序的核心,负责管理应用程序的控制流和主要设置。
通过构造函数QApplication::QApplication(int &argc, char **argv)创建
一个QApplication对象。这个对象初始化应用程序的环境,并且启动事件循环。
Widget w;
w.show();
//Widget w;创建一个名为w的Widget对象(假设Widget是自定义的窗口类,继承自QWidget或其子类)。
w.show();调用QWidget的show()方法,使窗口显示在屏幕上。显示窗口后,QWidget开始接收和处理事件。
return a.exec();
//a.exec()启动Qt的主事件循环。这是一个阻塞调用,直到应用程序退出(通常是通过调用QApplication::quit()或窗口关闭事件)。
在事件循环中,QApplication会持续监控事件队列,等待并处理各种事件,如鼠标点击、键盘输入、窗口重绘请求等。
}
3. 事件过滤器
- 事件过滤器。它可以将一个对象的事件委托给另一个对象来监视并处理。例如,一个窗口可以作为其界面上的QLabel组件的事件过滤器,派发给QLabel 组件的事件由窗口去处理,这样,就不需要为了处理某种事件而新定义一个标签类。
- 要实现事件过滤器功能,需要完成两项操作。
- 被监视对象使用函数installEventFilter()将自己注册给监视对象,监视对象就是事件过滤器。
- 监视对象重新实现函数eventFilter(),对监视到的事件进行处理。作为事件过滤器的监视对象需要重新实现函数eventFilter() - 事件过滤器可以在事件到达目标对象之前进行预处理,从而提供了更多的控制和灵活性。
- 主要作用和使用场景
1. 事件拦截和预处理
- 检查和修改事件:在事件到达目标对象之前检查和修改事件。例如,可以在事件到达目标对象之前记录事件信息、修改事件数据或阻止事件的进一步传播。
- 实现自定义逻辑:在事件到达目标对象之前实现自定义逻辑。例如,可以在鼠标点击之前判断是否允许特定操作,或者在键盘输入之前进行输入验证。
2. 统一处理多个对象的事件
- 事件过滤器允许你统一处理多个对象的事件,而不需要在每个对象上实现事件处理函数。这对于管理复杂界面中的多个控件特别有用。
- 集中处理事件:将事件处理逻辑集中到一个地方(即事件过滤器),而不是在每个控件的事件处理函数中实现。
- 简化代码:减少代码重复,使代码更清晰、易于维护。
3. 实现复杂的事件处理逻辑
- 拦截和阻止事件:根据需要阻止事件的进一步传播。例如,可以阻止鼠标事件在控件之间传播,或者阻止特定的键盘输入。
- 实现全局事件处理:在整个应用程序中实现全局事件处理逻辑,例如处理所有控件的鼠标点击事件。
4. 使用场景
- 自定义控件行为:修改控件的默认行为,例如在按钮上添加额外的点击处理逻辑。
- 事件监控:记录或调试事件,例如记录所有鼠标点击事件的位置和类型。
- 跨控件事件处理:在一个地方集中处理多个控件的事件,例如处理所有按钮的点击事件。
4. 代码举例
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
bool eventFilter(QObject *watched, QEvent *event) override;
public slots:
void btnClickedSlotFun();
private:
Ui::Widget *ui;
};
#endif
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QMouseEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->label->installEventFilter(this);
ui->btn->installEventFilter(this);
ui->labHover->installEventFilter(this);
ui->labDBClick->installEventFilter(this);
connect(ui->btn,SIGNAL(clicked()),this,SLOT(btnClickedSlotFun()));
}
Widget::~Widget()
{
delete ui;
}
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
if (watched == ui->label) {
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *ev = static_cast<QMouseEvent *>(event);
qDebug() << "label press" << ev->button() << "x=" << ev->x() << "y=" << ev->y();
} else if (event->type() == QEvent::Enter) {
qDebug() << "label enter";
} else if (event->type() == QEvent::Leave) {
qDebug() << "label leave";
}
}
else if (watched == ui->btn) {
if (event->type() == QEvent::Enter) {
static int a = 1;
ui->lineEdit->setText(QString("zhangsan = %1").arg(a++));
qDebug() << "btn enter";
} else if (event->type() == QEvent::Leave) {
qDebug() << "btn leave";
}
}
else if (watched == ui->labHover) {
if (event->type() == QEvent::Enter) {
ui->labHover->setStyleSheet("background-color: rgb(170, 255, 255);");
} else if (event->type() == QEvent::Leave) {
ui->labHover->setStyleSheet("");
ui->labHover->setText("靠近我,点击我");
} else if (event->type() == QEvent::MouseButtonPress) {
ui->labHover->setText("button pressed");
} else if (event->type() == QEvent::MouseButtonRelease) {
ui->labHover->setText("button released");
}
}
else if (watched == ui->labDBClick) {
if (event->type() == QEvent::Enter) {
ui->labDBClick->setStyleSheet("background-color: rgb(85, 255, 127);");
} else if (event->type() == QEvent::Leave) {
ui->labDBClick->setStyleSheet("");
ui->labDBClick->setText("可双击的标签");
} else if (event->type() == QEvent::MouseButtonDblClick) {
ui->labDBClick->setText("double clicked");
}
}
return QWidget::eventFilter(watched, event);
}
void Widget::btnClickedSlotFun()
{
static int c = 1;
qDebug()<<"c = "<<c;
}
5. QT事件类型
Qt事件类型
事件类 | 事件类型 | 事件描述 |
---|
QMouseEvent | QEvent::MouseButtonDblClick | 鼠标双击 |
| QEvent::MouseButtonPress | 鼠标按键按下,可以是左键或右键 |
| QEvent::MouseButtonRelease | 鼠标按键释放,可以是左键或右键 |
| QEvent::MouseMove | 鼠标移动 |
QWheelEvent | QEvent::Wheel | 鼠标滚轮滚动 |
QHoverEvent | QEvent::HoverEnter | 鼠标光标移动到组件上方并悬停(hover) |
| QEvent::HoverLeave | 鼠标光标离开某个组件上方 |
| QEvent::HoverMove | 鼠标光标在组件上方移动 |
QEnterEvent | QEvent::Enter | 鼠标光标进入组件或窗口边界范围内 |
QEvent | QEvent::Leave | 鼠标光标离开组件或窗口边界范围 |
QKeyEvent | QEvent::KeyPress | 键盘按键按下 |
| QEvent::KeyRelease | 键盘按键释放 |
QFocusEvent | QEvent::FocusIn | 组件或窗口获得键盘的输入焦点 |
| QEvent::FocusOut | 组件或窗口失去键盘的输入焦点 |
| QEvent::FocusAboutToChange | 组件或窗口的键盘输入焦点即将变化 |
QShowEvent | QEvent::Show | 窗口在屏幕上显示出来,或组件变得可见 |
QHideEvent | QEvent::Hide | 窗口在屏幕上隐藏(例如窗口最小化),或组件变得不可见 |
QMoveEvent | QEvent::Move | 组件或窗口的位置移动 |
QCloseEvent | QEvent::Close | 窗口被关闭,或组件被关闭,例如QTabWidget的一个页面被关闭 |
QPaintEvent | QEvent::Paint | 界面组件需要更新重绘 |
QResizeEvent | QEvent::Resize | 窗口或组件改变大小 |
QStatusTipEvent | QEvent::StatusTip | 请求显示组件的statusTip信息 |
QHelpEvent | QEvent::ToolTip | 请求显示组件的toolTip信息 |
| QEvent::WhatsThis | 请求显示组件的whatsThis信息 |
QDragEnterEvent | QEvent::DragEnter | 在拖放操作中,鼠标光标移动到组件上方 |
QDragLeaveEvent | QEvent::DragLeave | 在拖放操作中,鼠标光标离开了组件 |
QDragMoveEvent | QEvent::DragMove | 拖放操作正在移动过程中 |
QDropEvent | QEvent::Drop | 拖放操作完成,即放下拖动的对象 |
QTouchEvent | QEvent::TouchBegin | 开始一个触屏事件序列(sequence) |
| QEvent::TouchCancel | 取消一个触屏事件序列 |
| QEvent::TouchEnd | 结束一个触屏事件序列 |
| QEvent::TouchUpdate | 触屏事件 |
QGestureEvent | QEvent::Gesture | 手势事件,能识别的手势有轻触、放大、扫屏等 |
QNativeGestureEvent | QEvent::NativeGesture | 操作系统检测到手势而产生的事件 |
QActionEvent | QEvent::ActionAdded | 运行QWidget::addAction()函数时会产生这种事件 |
| QEvent::ActionChanged | Action改变时触发的事件 |
| QEvent::ActionRemoved | 移除Action时触发的事件 |