目录
[1. Qt事件介绍:](#1. Qt事件介绍:)
[2. 事件的处理](#2. 事件的处理)
示例1:鼠标进入(enterEvent)与离开事件(leaveEvent)
[3. 按键事件](#3. 按键事件)
[4. 定时器](#4. 定时器)
[5. 窗口事件](#5. 窗口事件)
1. Qt事件介绍:
事件是应用程序内部或者外部产生的事情或者动作的统称。在Qt中使用⼀个对象来表示⼀个事件。所 有的Qt事件均继承于抽象类QEvent。事件是由系统或者Qt平台本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出⼀个相应的事件。⼀些事件是在用户操作时发出,如键盘事件、鼠标事件等,另⼀些事件则是由系统本身自动发出,如定时器事件。常见的Qt事件如下:

2. 事件的处理
事件处理⼀般常用的方法为:重写相关的Event函数。
示例1:鼠标进入(enterEvent)与离开事件(leaveEvent)
处理鼠标进入与离开事件
1.新建Qt项目,基类选择QWidget,同时勾选UI界面文件

- 在ui文件添加label控件

- 创建QLabel的子类,重写enterEvent和leaveEvent
①:

②:

此时项目多出两个新文件:

- 为了方便给label指定父对象,调整一下构造函数:
5.函数重写:在"label.h"中:
(注意:重写函数时,要确保函数名字和参数列表完全一致 ,谨防拼写错误,为避免错误,可以在帮助文档查找目标函数,复制粘贴即可)
cpp
class Label : public QLabel
{
Q_OBJECT
public:
Label(QWidget* parent);
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
};
- 在"label.cpp"重写enterEvent与leaveEvent方法:
(按alt+回车键转到函数定义)

cpp
void Label::enterEvent(QEvent *event)
{
(void) event;//躲避编译器警告
qDebug() << "enterEvent";
}
void Label::leaveEvent(QEvent *event)
{
(void) event;//躲避编译器警告
qDebug() << "leaveEvent";
}
此时执行程序,其实并没有起到效果,这是因为此时界面上的label并不是我们定义的Label类的实例,其仍然是系统的QLabel创建的实例。
那么问题来了,此时也只能从界面上拖动QLabel来创建实例呀!如何才能使界面上的label是来自我们自己定义的Label类呢?步骤继续:
- 回到ui界面:
效果如图:

学到了这里,我们再来回顾一下在Qt入门3------常用控件1中所写的"给女神表白的程序",当时鼠标点击的时候按钮才会移动,现在我希望鼠标进入按钮,按钮就随机移动,代码如下:
1.按照如上步骤,添加一个Button类,再将"拒绝"按钮提升为Button类
2.重写enterEvent:
cpp
#include "button.h"
Button::Button(QWidget* parent) : QPushButton(parent)
{
srand(time(0));
}
void Button::enterEvent(QEvent *event)
{
(void) event;
//获取父窗口
QWidget* parentwidget = this->parentWidget();
//获取父窗口可用区域的大小
int width = parentwidget->geometry().width();
int height = parentwidget->geometry().height();
int x = rand() % width;
int y = rand() % height;
this->move(x,y);
}
效果如图:按钮还没来得及点击就跑了:

示例2:鼠标点击事件(mousePressEvent)
当鼠标点击时,获取相应的坐标值
- 创建两个label:

-
按照示例1的7,将下面的label提升。
-
在label.h中创建一个私有变量QString类型的私有变量coordText

-
重写mousePressEvent函数:(详细步骤参考示例1)
void Label::mousePressEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::LeftButton){
coordText = QString("此处以label为准的坐标为:(%1, %2)").arg(ev->x()).arg(ev->y());
}else if(ev->button() == Qt::RightButton){
coordText = QString("此处以主窗口为准的坐标:(%1, %2)").arg(ev->globalX()).arg(ev->globalY());
}
this->setText(coordText);
}
效果如图:

鼠标释放事件(mouseReleaseEvent)与鼠标双击事件(mouseDoubleClickEvent)与示例2相同,不过是需要重写的函数不同罢了,此处不再演示。
示例3:鼠标移动事件(mouseMoveEvent)
此示例让鼠标移动事件发生在整个窗口,所以不再自定义类。
1.在ui界面创建一个label来显示鼠标移动的坐标
2.重写mouseMoveEvent:
cpp
void Widget::mouseMoveEvent(QMouseEvent *event)
{
ui->label->setText("(" + QString::number(event->x()) + "," + QString::number(event->y()) + ")");
}
此时运行程序,不会有任何反应,这是因为鼠标移动不同于鼠标按下和释放,随便移动一下鼠标就会产生大量的鼠标移动事件。当进行捕获事件时,尤其是执行一些复杂的逻辑时,程序的负担会很重,可能会产生卡顿的情况。所以默认情况下Qt不会对鼠标移动事件进行跟踪,除非显式地告诉Qt:
cpp//在构造函数中将setMouseTracking设为true this->setMouseTracking(true);
效果如图:

示例4:鼠标滚轮滑动事件(wheelEvent)
1.在ui界面创建一个label来显示鼠标移动的坐标
2.重写wheelEvent
cpp
void Widget::wheelEvent(QWheelEvent *event)
{
//delta()获取到这次事件鼠标滚轮滚动了多远
ui->label->setText(QString::number(event->delta()));
}
效果如图:滚动一次为120像素

3. 按键事件
Qt中的按键事件是通过QKeyEvent类来实现的。当键盘上的按键被按下或者被释放时,键盘事件便会触发。
可以在Qt帮助文档中查看QKeyEvent类:

组合按键:

示例:
cpp
void Widget::keyPressEvent(QKeyEvent *event)
{
//用label显示按下的按键对应的value
ui->label->setText(QString::number(event->key()));
//用label_2显示按下的单个按键
if(event->key() == Qt::Key_A){
ui->label_2->setText("按下了A键");
}
//用label_3显示按下的组合按键
if(event->key() == Qt::Key_A && event->modifiers() == Qt::ControlModifier){
ui->label_3->setText("按下了ctrl+A键");
}
}
效果如图:

4. 定时器
Qt 中在进行窗口程序的处理过程中,经常要周期性的执行某些操作,或者制作一些动画效果,使用定时器就可以实现。所谓定时器就是在间隔一定时间后,去执行某一个任务。
Qt中的定时器分为QTimerEvent和QTimer这2个类。
QTimerEvent类用来描述一个定时器事件。在使用时需要通过startTimer()函数来开启一个定时器,这个函数需要输入一个以毫秒为单位的整数作为参数来表明设定的时间,它返回的整型值代表 这个定时器。当定时器溢出时(即定时时间到达)就可以在timerEvent()函数中获取该定时器的编号来进行相关操作;
QTimer类来实现⼀个定时器,它提供了更高层次的编程接口,如:可以使用信号和槽,还可以设置只运行一次的定时器。
示例:
1.ui界面创建定时器

- 重写timerEvent
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//开启定时器事件
//此处timerId是一个定时器的身份标识
timerId = this->startTimer(1000);//timeId为此类的私有变量
}
void Widget::timerEvent(QTimerEvent *event)
{
//如果一个程序中存在多个定时器,(startTimer创建的定时器),此时每个定时器都会触发timerEvent函数
//先判断这次触发是否是我们想要的定时器触发的
if(event->timerId() != this->timerId){
//如果不是我们的定时器触发的,就直接忽略
//当前程序中只有这一个定时器
return;
}
int value = ui->lcdNumber->intValue();
if(value <= 0){
//停止定时器
this->killTimer(this->timerId);
return;
}
value -= 1;
ui->lcdNumber->display(value);
}
效果如图:

5. 窗口事件
窗口事件有窗口移动事件(moveEvent)和窗口大小改变事件(resizeEvent)。
示例:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(ui->label);
layout->addWidget(ui->label_2);
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}
void Widget::moveEvent(QMoveEvent *event)
{
QPoint pos = event->pos();
QString text = QString("窗口现在的坐标为(%1,%2)").arg(pos.x()).arg(pos.y());
ui->label->setText(text);
}
void Widget::resizeEvent(QResizeEvent *event)
{
QSize size = event->size();
QString text = QString("窗口现在的长度为:%1,宽度为:%2").arg(size.width()).arg(size.height());
ui->label_2->setText(text);
}