Qt系统相关——事件

文章目录

事件和信号槽的关系

Qt信号槽机制: 用户进行的操作就可能产生信号,可以给某个信号指定槽函数,当信号触发的时候,就能够执行到对应的槽函数。

对于事件,和信号槽类似,用户进行的各种操作,也会产生事件,可以给事件关联处理函数,当事件触发的时候,就能够执行到对应的代码。

事件本身是由操作系统提供的机制,Qt将操作系统事件机制进行封装。

但是事件对应的代码编写起来不方便,Qt对事件机制又继续了进一步封装,就得到了信号槽。

事件是信号槽的底层机制

大部分情况都是采用信号槽,但对于有些行为,Qt没有提供对应的信号,此时就需要重写事件处理函数,来手动处理事件的响应逻辑了。

事件机制,灵活度更高。

常见Qt事件:

常见事件描述:

事件名称 描述
鼠标事件 鼠标左键、鼠标右键、鼠标滚轮、鼠标的移动、鼠标按键的按下和松开
键盘事件 按键类型、按键按下、按键松开
定时器事件 定时时间到达
进入离开事件 鼠标的进入和离开
滚轮事件 鼠标滚轮滚动
绘屏事件 重绘屏幕的某些部分
显示隐藏事件 窗口的显示和隐藏
移动事件 窗口位置的变化
窗口事件 是否为当前窗口
大小改变事件 窗口大小改变
焦点事件 键盘焦点移动
拖拽事件 用鼠标进行拖拽

事件处理

事件处理就是让一段代码和某个事件关联起来,当事件触发的时候,就能指定到这段代码。

之前信号槽是通过connect来完成上述关联的;

对于事件,让当前的类,重写某个事件处理函数。

属于多态机制,创建子类,继承Qt自己的类,然后重新父类的事件处理函数。

鼠标事件

鼠标进入和离开

处理一下鼠标的进入和离开事件

ui界面:

创建QLabel的子类,然后重写enterEventleaveEvent

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

cpp 复制代码
Widget::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();
}
相关推荐
----云烟----2 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024062 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic2 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it2 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康2 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神3 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
宅小海3 小时前
scala String
大数据·开发语言·scala
qq_327342733 小时前
Java实现离线身份证号码OCR识别
java·开发语言
锅包肉的九珍3 小时前
Scala的Array数组
开发语言·后端·scala
心仪悦悦3 小时前
Scala的Array(2)
开发语言·后端·scala