文章目录
- 事件和信号槽的关系
- 事件处理
- 鼠标事件
- 鼠标进入和离开
- 鼠标点击获取位置
- 鼠标释放
- 鼠标双击
- 鼠标移动
- 鼠标滚轮
- 键盘事件
- 定时器事件
- 窗口移动和窗口改变
事件和信号槽的关系
Qt信号槽机制: 用户进行的操作就可能产生信号,可以给某个信号指定槽函数,当信号触发的时候,就能够执行到对应的槽函数。
对于事件,和信号槽类似,用户进行的各种操作,也会产生事件,可以给事件关联处理函数,当事件触发的时候,就能够执行到对应的代码。
事件本身是由操作系统提供的机制,Qt将操作系统事件机制进行封装。
但是事件对应的代码编写起来不方便,Qt对事件机制又继续了进一步封装,就得到了信号槽。
即事件是信号槽的底层机制
大部分情况都是采用信号槽,但对于有些行为,Qt没有提供对应的信号,此时就需要重写事件处理函数,来手动处理事件的响应逻辑了。
事件机制,灵活度更高。
常见Qt事件:

常见事件描述:
| 事件名称 | 描述 | 
|---|---|
| 鼠标事件 | 鼠标左键、鼠标右键、鼠标滚轮、鼠标的移动、鼠标按键的按下和松开 | 
| 键盘事件 | 按键类型、按键按下、按键松开 | 
| 定时器事件 | 定时时间到达 | 
| 进入离开事件 | 鼠标的进入和离开 | 
| 滚轮事件 | 鼠标滚轮滚动 | 
| 绘屏事件 | 重绘屏幕的某些部分 | 
| 显示隐藏事件 | 窗口的显示和隐藏 | 
| 移动事件 | 窗口位置的变化 | 
| 窗口事件 | 是否为当前窗口 | 
| 大小改变事件 | 窗口大小改变 | 
| 焦点事件 | 键盘焦点移动 | 
| 拖拽事件 | 用鼠标进行拖拽 | 
事件处理
事件处理就是让一段代码和某个事件关联起来,当事件触发的时候,就能指定到这段代码。
之前信号槽是通过
connect来完成上述关联的;对于事件,让当前的类,重写某个事件处理函数。
属于多态机制,创建子类,继承Qt自己的类,然后重新父类的事件处理函数。
鼠标事件
鼠标进入和离开
处理一下鼠标的进入和离开事件

ui界面:

创建QLabel的子类,然后重写enterEvent和leaveEvent

label.h:
#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:
#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:
#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();
}

这个函数可以触发鼠标的各种按键,例如左键、右键、滚轮等
#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(); }
鼠标释放
基于上面的代码,重写鼠标释放函数

void Label::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        qDebug() << "左键释放";
    }
    else if(event->button() == Qt::RightButton)
    {
        qDebug() << "右键释放";
    }
}
一次clicked,相当于鼠标一次按下事件+一次释放事件
鼠标双击
重写双击虚函数

void Label::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        qDebug() << "左键双击";
    }
    else if(event->button() == Qt::RightButton)
    {
        qDebug() << "右键双击";
    }
}

这里双击的时候,也会触发单击的事件,这就又有可能导致意外的情况
鼠标移动
上面都是在Label控件里面进行活动,也可以直接放到Widget里面来完成。
widget.h:
#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:
#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,除非显式告诉QtWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setMouseTracking(true); }
鼠标滚轮
通过wheelEvent

#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

单个按键:
#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();
}
组合按键:

#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:
#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:
#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窗口大小改变时触发的事件
  
#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();
}





















