目录
[3.1 鼠标单击事件](#3.1 鼠标单击事件)
[3.2 鼠标释放事件](#3.2 鼠标释放事件)
[3.3 鼠标双击事件](#3.3 鼠标双击事件)
[3.4 鼠标移动事件](#3.4 鼠标移动事件)
[3.5 滚轮事件](#3.5 滚轮事件)
[4.1 单个按键](#4.1 单个按键)
[4.2 组合按键](#4.2 组合按键)
[5.1 QTimerEvent类](#5.1 QTimerEvent类)
[5.2 QTimer类](#5.2 QTimer类)
[5.3 获取系统日期及时间](#5.3 获取系统日期及时间)
一、介绍
事件是应用程序内部或者外部产生的事情或者动作的统称。在Qt中使用一个对象来表示一个事件。所有的Qt事件均继承于抽象类QEvent。事件是由系统或者Qt平台本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制时,都会发出一个相应的事件。一些事件是在用户操作时发出,如键盘事件、鼠标事件等,另一些事件则是由系统本身自动发出,如定时器事件
常见的Qt事件如下:

二、进入离开事件
事件处理一般常用的方法为:重写相关的Event函数
在Qt中,几乎所有的Event函数都是虚函数,所以可以重新实现。如:在实现鼠标的进入和离开事件时,直接重新实现 enterEvent() 和 leaveEvent() 即可
enterEvent() 和 leaveEvent() 函数原型如下:

代码示例
新建Qt项目,基类选择QWidget,同时勾选UI界面文件,如下图示:

设计UI文件,如下图示:

在项目中新添加一个类:MyLabel,先选中项目名称QEvent,点击鼠标右键,选择add new...,弹出如下对话框:

选择:Choose....,弹出如下界面:

此时项目中会新添加以下两个文件:

项目文件"mylabel.h"

重写enterEvent()方法

在UI文件中选中Label,右键 -> 提升为...

当点击"提升为..."之后,弹出如下对话框:

修改基类


三、鼠标事件
在Qt中,鼠标事件是用QMouseEvent类来实现的。当在窗口中按下鼠标或者移动鼠标时,都会产生鼠标事件。利用QMouseEvent类可以获取鼠标的哪个键被按下了以及鼠标的当前位置等信息
在Qt帮助文档中查找QMouseEvent类,如下图示:

3.1 鼠标单击事件
在Qt中,鼠标按下是通过虚函数mousePressEvent()来捕获的
mousePressEvent()函数原型如下:
cpp
[virtual protected] void QWidget::mousePressEvent(QMouseEvent *event)
- Qt::LeftButton 鼠标左键
- Qt::RightButton 鼠标右键
- Qt::MidButton 鼠标滚轮
**代码示例:**mousePressEvent()
在上述代码的基础上(进入离开事件),在mylabel.h中声明mousePressEvent()方法

在mylabel.cpp中重写mousePressEvent()方法

**代码示例:**鼠标左键点击时,打印对应的坐标值,鼠标右键点击时,打印基于屏幕的坐标

3.2 鼠标释放事件
鼠标释放事件是通过虚函数mouseReleaseEvent()来捕获的
mouseReleaseEvent()函数原型如下:
cpp
[virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event)
**代码示例:**鼠标左键释放

3.3 鼠标双击事件
鼠标双击事件是通过虚函数:mouseDoubleClickEvent()来实现的
mouseDoubleClickEvent()函数原型如下:
cpp
[virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event)
**代码示例:**鼠标双击左键

3.4 鼠标移动事件
鼠标移动事件是通过虚函数:mouseMoveEvent()来实现的。同时为了实时捕获鼠标位置信息,需要通过函数setMouseTracking()来追踪鼠标的位置
cpp
[virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event)
cpp
void setMouseTracking(bool enable)
注意:
setMouseTracking()函数默认是false,需要设置为true,才能实时捕获鼠标位置信息。否则只有当鼠标按下时才能捕获其位置信息。一般情况下不会开启,若用户鼠标移动过快,会导致资源消耗较大
**代码示例:**追踪鼠标移动


3.5 滚轮事件
在Qt中,鼠标滚轮事件是通过QWheelEvent类来实现的。滚轮滑动的距离可以通过delta()函数获取
cpp
int QGraphicsSceneWheelEvent::delta() const
其中返回值代表滚轮滑动的距离。正数表示滚轮相对于用户向前滑动,负数表示滚轮相对于用户向后滑动
代码示例


四、按键事件
Qt中的按键事件是通过QKeyEvent类来实现的。当键盘上的按键被按下或者被释放时,键盘事件便
会触发
4.1 单个按键
**代码示例:**当某个按键被按下时,输出某个按键被按下了
新建项目,在头文件"widget.h"中声明虚函数keyPressEvent()

在"widget.cpp"文件中重写keyPressEvent()虚函数

4.2 组合按键
在Qt助手中搜索:Qt::KeyboardModifier

Qt::KeyboardModifier中定义了在处理键盘事件时对应的修改键。在Qt中,键盘事件可以与修改键⼀起使用,以实现一些复杂的交互操作
KeyboardModifier中修改键的具体描述如下:

**代码示例:**Ctrl + A

五、定时器
Qt中在进行窗口程序的处理过程中,经常要周期性的执行某些操作,或者制作一些动画效果,使用定时器就可以实现。所谓定时器就是在间隔一定时间后,去执行某一个任务。定时器在很多场景下都会使用到,如弹窗自动关闭之类的功能等
Qt中的定时器分为 QTimerEvent 和 QTimer 这2个类:
- QTimerEvent类用来描述一个定时器事件。在使用时需要通过startTimer()函数来开启一个定时器,这个函数需要输入一个以毫秒为单位的整数作为参数来表明设定的时间,它返回的整型值代表这个定时器。当定时器溢出时(即定时时间到达)就可以在 timerEvent() 函数中获取该定时器的编号来进行相关操作
- QTimer类来实现一个定时器,它提供了更高层次的编程接口,如:可以使用信号和槽,还可以设置只运行一次的定时器
5.1 QTimerEvent类
**代码示例:**在UI界面上放置两个Label,一个1秒数字累加一次,一个2秒数字累加一次

在"widget.h"头文件中声明timerEvent()函数,并定义两个整型变量
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTimerEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
//重写定时器事件
void timerEvent(QTimerEvent* event);
private:
Ui::Widget *ui;
int timerId1 = 0;
int timerId2 = 0;
};
#endif // WIDGET_H
在"widget.cpp"文件中重写timerEvent()函数
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//启动定时器
timerId1 = startTimer(1000);
timerId2 = startTimer(2000);
}
Widget::~Widget()
{
delete ui;
}
void Widget::timerEvent(QTimerEvent *event)
{
if(event->timerId() == timerId1) {
static int count1 = 1;
ui->label->setText(QString::number(count1++));
}
if(event->timerId() == timerId2) {
static int count2 = 1;
ui->label_2->setText(QString::number(count2++));
}
}
5.2 QTimer类
在UI界面放置一个Label标签,两个按钮,分别是"开始"和"停止",当点击"开始"按钮时,开始每隔1秒计数一次,点击"停止"按钮时,暂停计数

cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QTimer* timer = new QTimer(this);
connect(ui->pushButtonStart, &QPushButton::clicked, [=]() {
timer->start(1000);
});
connect(timer, &QTimer::timeout, [=](){
static int num = 1;
ui->label->setText(QString::number(num++));
});
connect(ui->pushButtonStop, &QPushButton::clicked, [=](){
timer->stop();
});
}
Widget::~Widget()
{
delete ui;
}
5.3 获取系统日期及时间
在Qt中,获取系统的日期及实时时间可以通过QTimer类和QDateTime类。QDateTime类提供了字符串格式的时间。字符串形式的时间输出格式由toString()方法中的format参数列表决定

**代码示例:**获取系统日期及实时时间
设计UI界面文件;放置一个Label控件,用来显示日期及时间,放置两个按钮"开始"和"停止"

在"widget.h"头文件中声明更新时间的槽函数

在"widget.cpp"文件中实现对应功能

六、事件分发器
在Qt中,事件分发器(Event Dispatcher)是一个核心概念,用于处理GUI应用程序中的事件。事件分
发器负责将事件从一个对象传递到另一个对象,直到事件被处理或被取消。每个继承自QObject类或QObject类本身都可以在本类中重写bool event(QEvent *e)函数,来实现相关事件的捕获和拦截
事件分发器工作原理
在Qt中,发送的事件都是传给了QObject对象,更具体点是传给了QObject对象的event()函数。所有的事件都会进入到这个函数中,那么处理事件就要重写这个event()函数。event()函数本身不会去处理事件,而是根据事件类型**(type值)**调用不同的事件处理函数
事件分发器就是工作在应用程序向下分发事件的过程中,如下图:

在此过程中,事件分发器也可以做拦截操作。事件分发器主要是通过 bool event(QEvent *e) 函数来实现。其返回值为布尔类型,若为ture,代表拦截,不向下分发

代码示例
在"widget.h"头文件中声明鼠标按下事件和事件分发器

在"widget.cpp"文件中实现功能
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
qDebug() << "鼠标左键被按下";
}
bool Widget::event(QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress) {
qDebug() << "事件分发器捕捉到鼠标按下事件";
return true;//拦截
}
if(event->type() == QEvent::MouseButtonDblClick) {
qDebug() << "事件分发器捕捉到鼠标双击事件";
return true;//拦截
}
//其他事件交给父类处理(默认处理)
return QWidget::event(event);
}
七、事件过滤器
在Qt中,一个对象可能经常要查看或拦截另外一个对象的事件,如对话框想要拦截按键事件,不让别的组件接收到,或者修改按键的默认值等
Qt创建了QEvent事件对象之后,会调用QObject的event()函数处理事件的分发。可以在event()函数中实现拦截的操作。由于event()函数是protected的,因此需要继承已有类。若组件很多,就需要重写很多个event()函数
这当然相当麻烦,更不用说重写event()函数还得小心一堆问题。好在Qt提供了另一种机制来达到这一目的 :事件过滤器
事件过滤器是在应用程序分发到event事件分发器之前,再做一次更高级的拦截。如下图示:

事件过滤器的一般使用步骤:
- 安装事件过滤器
- 重写事件过滤器函数:eventfilter()
代码示例
在"widget.h"中声明鼠标按下事件和事件分发器

在"widget.cpp"文件中实现鼠标点击事件和事件分发器

在"widget.h"头文件中声明事件过滤器函数

在"widget.cpp"文件中实现事件过滤器的两个步骤


