文章目录
- 1、事件的概念
- 2、处理事件
- 3、鼠标事件
- 1、鼠标单击和双击
- 2、鼠标移动
- 3、鼠标滚轮滚动
- 4、键盘事件
- 5、定时器事件
- 6、窗口移动和大小改变事件
1、事件的概念
用户进行操作时会产生事件,事件可以关联处理函数。Qt封装了操作系统的事件机制,然后进一步封装得到了信号槽。事件是信号槽的底层机制。如果一个行为在Qt中没有对应的信号,那么就需要重写事件处理函数。事件处理函数都是虚函数,这样才能被重写。关于事件处理函数,看Qt文档。
QEvent就是事件,下面则是各种子事件。一部分常见事件:
事件分发,事件过滤属于Qt事件机制底层的逻辑,Qt对此给程序员提供了一些API可用。
事件分发重写event函数,能获取所有事件,但这样程序员有可能因此出现大错误。
事件过滤顾名思义,它是事件分发的其中一步操作,它针对的是某一类型的时间。
2、处理事件
处理也就是写处理函数。重写事件处理函数,也就利用了多态机制。创建子类,继承自Qt自带的类,在子类中重写父类的事件处理函数。
处理鼠标进入和鼠标离开事件
创建一个QWidget项目,放一个label到界面,接下来的程序在鼠标进入label区域时label文本显示鼠标进入,离开时显示鼠标离开。可以把label的frameShape属性改为Box,方便观察。
在当前项目下,创建一个C++类,继承自QLabel。
在label.h文件中引入QLabel头文件。
// label.h
#include <QWidget>
#include <QLabel>
class Label : public QLabel
{
Q_OBJECT
public:
Label(QWidget* parent);
void enterEvent(QEvent* event);
void leaveEvent(QEvent* event);
};
// label.cpp
#include "label.h"
#include <QDebug>
Label::Label(QWidget* parent) : QLabel(parent)
{
}
void Label::enterEvent(QEvent *event)
{
(void) event;
qDebug() << "enterEvent";
}
void Label::leaveEvent(QEvent *event)
{
(void) event;
qDebug() << "leaveEvent";
}
自定义的类是Label,但是界面中的label是QLabel的,所以现在这些处理函数还不起作用。解决办法就是右键label,提升为,按照自定义的类名和头文件名来填写,不选全局包含;点击添加,选中新添加的项,提升即可。
也可以不单独创建一个类,直接在Widget文件中写逻辑,那么此时就不是在label里事件发生时有处理,而是在Qt整个窗口内触发事件时都会被处理。
3、鼠标事件
在QWidget项目下,创建自定义类Label,还是用QLabel作为父类,在界面中创建一个label,提升为Label类的。
1、鼠标单击和双击
// label.h
#include <QWidget>
#include <QMouseEvent>
class Label : public QLabel
{
Q_OBJECT
public:
Label(QWidget* parent);
// 鼠标左键右键滚轮触发
void mousePressEvent(QMouseEvent* event);
};
// label.cpp
#include "label.h"
#include <QDebug>
Label::Label(QWidget* parent) : QLabel(parent)
{
}
void Label::mousePressEvent(QMouseEvent *event)
{
// 两个方式
// 以label对象左上角为原点
qDebug() << event->x() << ", " << event->y();
// 以屏幕左上角为原点
qDebug() << event->globalX() << ", " << event->globalY();
// Qt罗列了一些按键
if (event->button() == Qt::LeftButton)
qDebug() << "按下左键";
else if (event->button() == Qt::RightButton)
qDebug() << "按下右键";
}
抬起和双击
// label.h
void mouseReleaseEvent(QMouseEvent* event);
void mouseDoubleClickEvent(QMouseEvent* event);
// label.cpp
void Label::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
qDebug() << "释放左键";
else if (event->button() == Qt::RightButton)
qDebug() << "释放右键";
}
void Label::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
qDebug() << "双击左键";
else if (event->button() == Qt::RightButton)
qDebug() << "双击右键";
}
2、鼠标移动
// label.h
void mouseMoveEvent(QMouseEvent* event);
// label.cpp
void Label::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << event->x() << event->y();
}
但是实际运行后,不会打印,是因为鼠标只要一移动,会触发大量的鼠标移动事件,那么为了程序运行流畅,Qt默认不追踪这个事件,所以不会触发。解决办法就是解开这个限制即可
Label::Label(QWidget* parent) : QLabel(parent)
{
this->setMouseTracking(true);
}
3、鼠标滚轮滚动
// label.h
// 通过delta()来获取这次鼠标滚轮滚了多远
#include <QWheelEvent>
public:
void wheelEvent(QWheelEvent* event);
private:
int total;
// label.cpp
Label::Label(QWidget* parent) : QLabel(parent)
{
total = 0;
}
void Label::wheelEvent(QWheelEvent *event)
{
//qDebug() << event->delta();
// 计算总的滚动距离
total += event->delta();
qDebug() << total;
}
4、键盘事件
QWidget项目,这次不创建子类,直接在widget文件中写
// widget.h
#include <QWidget>
#include <QKeyEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void keyPressEvent(QKeyEvent *event);
private:
Ui::Widget *ui;
};
// widget.cpp
#include <QDebug>
void Widget::keyPressEvent(QKeyEvent *event)
{
// 组合键, 用修饰符modifiers来获取
// ctrl + a
if (event->key() == Qt::Key_A && event->modifiers() == Qt::ControlModifier)
qDebug() << "组合键ctrl + A";
else if (event->key() == Qt::Key_A)
qDebug() << "按下了A键";
else qDebug() << event->key();
}
5、定时器事件
QTimer实现定时器功能,它的基础是QTimerEvent定时器事件。
QWidget项目,放一个LCD Numbers到界面中
// widget.h
void timerEvent(QTimerEvent* event);
int timerId;
// widget.cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 开启定时器事件
// timerId身份标识, 类似于Linux文件标识符
timerId = this->startTimer(1000);
}
void Widget::timerEvent(QTimerEvent *event)
{
// 如果一个程序存在多个定时器, 那么每个定时器都会触发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);
}
6、窗口移动和大小改变事件
// widget.h
#include <QWidget>
#include <QMoveEvent>
#include <QResizeEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void moveEvent(QMoveEvent* event);
void resizeEvent(QResizeEvent* event);
private:
Ui::Widget *ui;
};
// widget.cpp
#include <QDebug>
void Widget::moveEvent(QMoveEvent *event)
{
qDebug() << "之前的位置: " << event->oldPos();
qDebug() << "现在的位置: " << event->pos();
}
void Widget::resizeEvent(QResizeEvent *event)
{
qDebug() << event->size();
}
结束。