当前位置: 首页 > news >正文

Qt系统相关——事件

文章目录

    • 事件和信号槽的关系
    • 事件处理
    • 鼠标事件
      • 鼠标进入和离开
      • 鼠标点击获取位置
      • 鼠标释放
      • 鼠标双击
      • 鼠标移动
      • 鼠标滚轮
    • 键盘事件
    • 定时器事件
    • 窗口移动和窗口改变

事件和信号槽的关系

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

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

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

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

事件是信号槽的底层机制

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

事件机制,灵活度更高。

常见Qt事件:

image-20240922090528528

常见事件描述:

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

事件处理

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

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

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

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

鼠标事件

鼠标进入和离开

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

image-20240922092214568

ui界面:

image-20240922093513461

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

image-20240922094435747

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是我们自定义的实例,才会执行到这两个函数。

image-20240922095020397

GIF 2024-9-22 9-51-09

鼠标点击获取位置

image-20240922100213101

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();
}

GIF 2024-9-22 10-11-31

这个函数可以触发鼠标的各种按键,例如左键、右键、滚轮等

#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();
}

image-20240922114302874

鼠标释放

基于上面的代码,重写鼠标释放函数

image-20240922114904755

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

一次clicked,相当于鼠标一次按下事件+一次释放事件

鼠标双击

重写双击虚函数

image-20240922115103366

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

GIF 2024-9-22 11-55-06

这里双击的时候,也会触发单击的事件,这就又有可能导致意外的情况

鼠标移动

上面都是在Label控件里面进行活动,也可以直接放到Widget里面来完成。

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic: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,除非显式告诉Qt

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setMouseTracking(true);
}

鼠标滚轮

通过wheelEvent

image-20240922144016520

#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

image-20240922145245623

单个按键:

#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();
}

组合按键:

image-20240922154253465

#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关闭定时器

image-20240922155257245

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic: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窗口移动时触发的事件image-20240922155900630
  • resizeEvent窗口大小改变时触发的事件
    image-20240922160017780
#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();
}

相关文章:

  • 东华大学《2020年+2022年824自动控制原理真题》 (完整版)
  • 【Android】页面启动耗时统计流程梳理
  • Git从了解到操作
  • JavaEE: 深入探索TCP网络编程的奇妙世界(二)
  • 建立队列,插入队列,删除队列
  • scrapy之setting文件详解
  • 0基础学习PyTorch——时尚分类(Fashion MNIST)训练和推理
  • 阿里云函数计算 x NVIDIA 加速企业 AI 应用落地
  • 10.Lab Nine —— file system-上
  • 丹摩智算(damodel)部署stable diffusion实验
  • 三子棋小游戏
  • 【React】组件通信
  • Android 已经过时的方法用什么新方法替代?
  • 使用Python解决数据分析中的相关性分析
  • macOS 15 Blank OVF - macOS Sequoia 虚拟化解决方案
  • [deviceone开发]-do_Webview的基本示例
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • JavaScript 一些 DOM 的知识点
  • JavaScript创建对象的四种方式
  • oschina
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • Swoft 源码剖析 - 代码自动更新机制
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • 给第三方使用接口的 URL 签名实现
  • 基于web的全景—— Pannellum小试
  • 解析带emoji和链接的聊天系统消息
  • 想写好前端,先练好内功
  • 译米田引理
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • 阿里云服务器购买完整流程
  • ​1:1公有云能力整体输出,腾讯云“七剑”下云端
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • #pragam once 和 #ifndef 预编译头
  • #pragma once
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • $.ajax()方法详解
  • (7)摄像机和云台
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (JS基础)String 类型
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (WSI分类)WSI分类文献小综述 2024
  • (ZT)一个美国文科博士的YardLife
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (理论篇)httpmoudle和httphandler一览
  • (三)elasticsearch 源码之启动流程分析
  • (算法)Game
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • .apk 成为历史!
  • .htaccess配置常用技巧
  • .NET Core 2.1路线图
  • .net wcf memory gates checking failed
  • .NET 反射的使用