文章目录
事件和信号槽的关系
Qt信号槽机制: 用户进行的操作就可能产生信号,可以给某个信号指定槽函数,当信号触发的时候,就能够执行到对应的槽函数。
对于事件,和信号槽类似,用户进行的各种操作,也会产生事件,可以给事件关联处理函数,当事件触发的时候,就能够执行到对应的代码。
事件本身是由操作系统提供的机制,Qt将操作系统事件机制进行封装。
但是事件对应的代码编写起来不方便,Qt对事件机制又继续了进一步封装,就得到了信号槽。
即事件是信号槽的底层机制
大部分情况都是采用信号槽,但对于有些行为,Qt没有提供对应的信号,此时就需要重写事件处理函数,来手动处理事件的响应逻辑了。
事件机制,灵活度更高。
常见Qt事件:
常见事件描述:
事件名称 | 描述 |
---|---|
鼠标事件 | 鼠标左键、鼠标右键、鼠标滚轮、鼠标的移动、鼠标按键的按下和松开 |
键盘事件 | 按键类型、按键按下、按键松开 |
定时器事件 | 定时时间到达 |
进入离开事件 | 鼠标的进入和离开 |
滚轮事件 | 鼠标滚轮滚动 |
绘屏事件 | 重绘屏幕的某些部分 |
显示隐藏事件 | 窗口的显示和隐藏 |
移动事件 | 窗口位置的变化 |
窗口事件 | 是否为当前窗口 |
大小改变事件 | 窗口大小改变 |
焦点事件 | 键盘焦点移动 |
拖拽事件 | 用鼠标进行拖拽 |
事件处理
事件处理就是让一段代码和某个事件关联起来,当事件触发的时候,就能指定到这段代码。
之前信号槽是通过
connect
来完成上述关联的;对于事件,让当前的类,重写某个事件处理函数。
属于多态机制,创建子类,继承Qt自己的类,然后重新父类的事件处理函数。
鼠标事件
鼠标进入和离开
处理一下鼠标的进入和离开事件
ui界面:
创建QLabel
的子类,然后重写enterEvent
和leaveEvent
label.h
:
cpp
#ifndef LABEL_H
#define LABEL_H
#include <QWidget>
#include<QLabel>
class Label : public QLabel
{
Q_OBJECT
public:
Label(QWidget* parent);
void enterEvent(QEvent* event);
void leaveEvent(QEvent* event);
};
#endif // LABEL_H
label.cpp
:
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
,而界面是的是QLabel
。要确保界面上的
label
是我们自定义的实例,才会执行到这两个函数。
鼠标点击获取位置
label.cpp
:
cpp
#include "label.h"
#include<QDebug>
#include<QMouseEvent>
Label::Label(QWidget* parent)
:QLabel(parent)
{}
void Label::mousePressEvent(QMouseEvent *event)
{
//当前控件左上角为原点
qDebug() << event->x() << "," << event->y();
//屏幕左上角为原点
qDebug() << event->globalX() << "," << event->globalY();
}
这个函数可以触发鼠标的各种按键,例如左键、右键、滚轮等
cpp#include "label.h" #include<QDebug> #include<QMouseEvent> Label::Label(QWidget* parent) :QLabel(parent) {} void Label::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { qDebug() << "左键触发"; } else if(event->button() == Qt::RightButton) { qDebug() << "右键触发"; } //当前控件左上角为原点 qDebug() << event->x() << "," << event->y(); //屏幕左上角为原点 qDebug() << event->globalX() << "," << event->globalY(); }
鼠标释放
基于上面的代码,重写鼠标释放函数
cpp
void Label::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
qDebug() << "左键释放";
}
else if(event->button() == Qt::RightButton)
{
qDebug() << "右键释放";
}
}
一次clicked,相当于鼠标一次按下事件+一次释放事件
鼠标双击
重写双击虚函数
cpp
void Label::mouseDoubleClickEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
qDebug() << "左键双击";
}
else if(event->button() == Qt::RightButton)
{
qDebug() << "右键双击";
}
}
这里双击的时候,也会触发单击的事件,这就又有可能导致意外的情况
鼠标移动
上面都是在Label
控件里面进行活动,也可以直接放到Widget
里面来完成。
widget.h
:
cpp
#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();
void mouseMoveEvent(QMouseEvent* event);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QMouseEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << event->x() << event->y();
}
上面的代码,不会直接移动的时候捕获位置,因为鼠标经常移动,稍微移动一下,就会产生大量的鼠标移动事件。
在捕获事件的时候,如果这里逻辑很复杂,就会导致程序特别卡顿。
为了保证程序流畅性,默认不会对鼠标移动进行追踪,鼠标移动的时候,不会调用
mouseMoveEvent
,除非显式告诉Qt
cppWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setMouseTracking(true); }
鼠标滚轮
通过wheelEvent
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QMouseEvent>
#include<QWheelEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
total = 0;
}
Widget::~Widget()
{
delete ui;
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << event->x() << event->y();
}
void Widget::wheelEvent(QWheelEvent *event)
{
total += event->delta();
qDebug() << total;
}
键盘事件
QShortCut
定义一个快捷键,然后搭配QKeySequence
这个类,指定当前按键是什么按键序列。如果按下这个键,就触发actived
信号。这是信号槽机制封装过的,获取键盘按键的快捷方式。
也可以通过事件获取到当前用户键盘按下的情况。
重写一个父类函数,keyPressEvent
单个按键:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QKeyEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::keyPressEvent(QKeyEvent *event)
{
qDebug() << event->key();
}
组合按键:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QKeyEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_A && event->modifiers() == Qt::ControlModifier)
{
qDebug() << "alt + A";
}
}
定时器事件
可以使用QTimer
这个类来完成定时器这个功能。
QTimer
背后是QTimerEvent
定时器事件来进行支撑;
QObject
提供了timerevent
这个函数:
startTimer
启动定时器killTimer
关闭定时器
widget.h
:
cpp
#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();
void timerEvent(QTimerEvent *event);
private:
Ui::Widget *ui;
int timerId;
};
#endif // 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);
//开启定时器事件
//startTimer由QObject提供
//Widget继承QWidget
//QWidget继承QObject
//返回一个整数,定时器身份标识
timerId = this->startTimer(1000);
}
Widget::~Widget()
{
delete ui;
}
void Widget::timerEvent(QTimerEvent *event)
{
//一个程序存在多个定时器, 每个定时器都会触发这个函数
//需要判断,这次触发是否是想要的定时器触发的
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);
}
窗口移动和窗口改变
moveEvent
窗口移动时触发的事件resizeEvent
窗口大小改变时触发的事件
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QMoveEvent>
#include<QResizeEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::moveEvent(QMoveEvent *event)
{
qDebug() << event->pos();
}
void Widget::resizeEvent(QResizeEvent *event)
{
qDebug() << event->size();
}