【Qt 事件】—— 详解Qt事件处理

news2024/11/13 12:23:36

目录

 (一)事件介绍 

(二)事件的处理

(三)按键事件 

3.1 单个按键

3.2 组合按键

(四)鼠标事件

4.1 鼠标单击事件

4.2 鼠标释放事件

 4.3 鼠标双击事件

4.4 鼠标移动事件 

4.5 滚轮事件 

(五) 定时器

5.1 QTimerEvent类

5.2 QTimer类

(六)事件分发器 

6.1 概述

6.2 事件分发器工作原理

(七)事件过滤器 

总结


【前情提示】

信号槽:

  • 用户进行的各种操作,就可能会产生出信号.可以给某个信号指定槽函数. 当信号触发时,就能够自动的执行到对应的槽函数.

事件非常类似

  • 用户进行的各种操作,也会产生事件.程序员同样可以给事件关联上处理函数(处理的逻辑),当事件触发的时候,就能够执行到对应的代码。

事件本身是操作系统提供的机制.Qt 也同样把操作系统事件机制进行了封装.但是由于事件对应的代码编写起来不是很方便.Qt 对于事件机制又进行了进一步的封装,就得到了信号槽。

⭐️⭐️ 信号槽就是对于事件的进一步封装;事件是信号槽的底层机制.

实际 Qt 开发程序过程中,绝大部分和用户之问进行的交互都是通过“信号槽”来完成的。
有些特殊情况下,信号槽不一定能搞定.(某个用户的动作行为,Qt 没有提供对应的信号….)此时就需要通过重写事件处理函数的形式,来手动处理事件的响应逻辑。

 (一)事件介绍 

事件是应用程序内部或者外部产生的事情或者动作的统称在Qt中使用⼀个对象来表示⼀个事件。所有的Qt事件均继承于抽象类QEvent。事件是由系统或者Qt平台本⾝在不同的时刻发出的。当用户 按下⿏标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出⼀个相应的事件。⼀些事件是在用户操作时发出,如键盘事件、⿏标事件等,另⼀些事件则是由系统本⾝⾃动发出,如定时器事件。常见的Qt事件如下:

 常见事件描述:

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

(二)事件的处理

事件处理⼀般常用的方法为:重写相关的Event函数

在Qt中,几乎所有的Event函数都是虚函数,所以可以重新实现。如:在实现⿏标的进⼊和离开事件 时,直接重新实现enterEvent()和 leaveEvent()即可。enterEvent()和 leaveEvent()函数原型如 下 :

示例如下:

  •  1、新建Qt项⽬,基类选择QWidget,同时勾选UI界⾯⽂件,如下图示:

  • 2、设计UI⽂件,如下图示;

 

  • 3、在项目中新添加⼀个类:MyLabel; 先选中项目名称QEvent,点击⿏标右键,选择addnew...,弹出如下对话框: 

  •  4、选择:Choose....,弹出如下界面:

  • 5、此时项目中会新添加以下两个文件: 

  • 6、在帮助文档中查找对应的内容; 

  • 7、点击"显示"之后,出现如下内容: 

  •  8、复制enterEvent(),粘贴在项目文件mylabel.h中;

  •  9、重写enterEvent()⽅法;

  •  10、在UI文件中选中Label,右键------>提升为...

  • 11、当点击"提升为..."之后,弹出如下对话框: 

  •  12、修改基类:

  •  13、执行效果如下:当鼠标进入设计好的标签之后,就会在应用程序输出栏中打印:鼠标进入(同理鼠标离开也是一样)


示例2:鼠标左键点击时,打印对应的坐标值;鼠标右键点击时,打印基于屏幕的坐标,点击完毕显示释放操作

  •  1、在上述示例的基础上,在mylabel.h中声明mousePressEvent()⽅法;
//当⿏标点击时,获取对应的坐标值
void mousePressEvent(QMouseEvent *event);
//鼠标释放操作
void mouseReleaseEvent(QMouseEvent *event);
  •  2、在mylabel.cpp中重写mousePressEvent()⽅法;
void mylabel::mousePressEvent(QMouseEvent *event)
{
    //按下右键
    if(event->button() == Qt::RightButton){
        //基于global
        qDebug() << "鼠标右键已经按下 x = "<<event->globalX();
        qDebug() << "鼠标右键已经按下 x = "<<event->globalY();
    }
    //按下左键
    if(event->button() == Qt::LeftButton){
        //基于窗口的坐标
        qDebug() << "鼠标左键已经按下 x = "<<event->x();
        qDebug() << "鼠标左键已经按下 x = "<<event->y();
    }
    //按下中间键
    if(event->button() == Qt::MidButton){
        qDebug() << "鼠标已经按下 x = "<<event->x();
        qDebug() << "鼠标已经按下 x = "<<event->y();
    }
}

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

 实现效果如下:


(三)按键事件 

在Qt框架中,处理按键事件是交互式应用程序的一个重要方面。按键事件主要涉及QKeyEvent类,它提供了关于键盘事件的信息,如按键的类型、状态等。

当键盘上的按键被按下或者被释放时,键盘事件便会触发。在帮助文档中查找QKeyEvent类如下:

查找按键事件中所有的按键类型:在帮助文档中输⼊:Qt::Key,如下图: 

 


3.1 单个按键

示例:当某个按键被按下时,输出:某个按键被按下了;

  • 1、新建项目,在头文件widget.h中声明虚函数keyPressEvent();如下图: 

  •  2、在widget.cpp⽂件中重写keyPressEvent()虚函数;


3.2 组合按键

在Qt助手中搜索:Qt::KeyboardModifier,如下图示:

Qt::KeyboardModifier 中定义了在处理键盘事件时对应的修改键。在Qt中,键盘事件可以与修改键 ⼀起使用,以实现⼀些复杂的交互操作。KeyboardModifier 中修改键的具体描述如下: 

示例如下:


(四)鼠标事件

在Qt框架中,处理鼠标事件是创建交互式图形用户界面的关键部分。鼠标事件包括鼠标点击、双击、移动、滚轮滚动等。这些事件由QMouseEvent类表示,它提供了关于鼠标事件的详细信息,如鼠标位置、按钮状态等。

利⽤QMouseEvent类可以获取⿏标的哪个键被按下了以及⿏标的当前位置等信息。在Qt帮助⽂档中 查找QMouseEvent类如下:

 


鼠标单击和释放操作代码在上述已经完成,下述就不在展示代码!!

4.1 鼠标单击事件

在Qt中,⿏标按下是通过虚函数mousePressEvent()来捕获的。mousePressEvent()函数原型如 下:

 [virtual protected] void QWidget::mousePressEvent(QMouseEvent *event)

⿏标左右键及滚的表示如下:

  • Qt::LeftButton ⿏标左键
  • Qt::RightButton ⿏标右键
  • Qt::MidButton ⿏标滚轮

4.2 鼠标释放事件

⿏标释放事件是通过虚函数mouseReleaseEvent()来捕获的。mouseReleaseEvent()函数原型如 下:

 [virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event)

 4.3 鼠标双击事件

⿏标双击事件是通过虚函数:mouseDoubleClickEvent()来实现的。mouseDoubleClickEvent() 函数原型如下:

[virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event)
void mylabel::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        qDebug() << "左键被双击";
    }else if(event->button() == Qt::RightButton){
        qDebug() << "右键被双击";
    }else if(event->button() == Qt::MidButton){
        qDebug() << "中键被双击";
   }
}

4.4 鼠标移动事件 

⿏标移动事件是通过虚函数:mouseMoveEvent()来实现的。同时为了实时捕获⿏标位置信息,需要 通过函数setMouseTracking()来追踪⿏标的位置。mouseMoveEvent()函数原型如下:

[virtual protected] void QWidget::mouseMoveEvent(QMouseEvent*event)

///
//setMouseTracking()函数原型如下:
void setMouseTracking(bool enable)

说明:
setMouseTracking() 函数默认是false,需要设置为true,才能实时捕获⿏标位置信息;
否则只有当⿏标按下时才能捕获其位置信息。

示例如下:


4.5 滚轮事件 

在Qt中,⿏标滚轮事件是通过QWheelEvent类来实现的。滚轮滑动的距离可以通过delta()函数获 取。delta()函数原型如下:

int QGraphicsSceneWheelEvent::delta() const
  • 其中返回值代表滚轮滑动的距离。正数表示滚轮相对于用户向前滑动,负数表示滚轮相对于用户向后滑动。
void Widget::wheelEvent(QWheelEvent *event)
{
    //滚轮事件
    static int x = 0;

    x += event->delta();
    if(event->delta() > 0){
        qDebug() << "滚轮向前移动了" << x;
    }
    else if(event->delta() < 0){
         qDebug() << "滚轮向后移动了" << x;
    }
}

执行效果如下: 


(五) 定时器

Qt 中在进行窗口程序的处理过程中,经常要周期性的执行某些操作,或者制作⼀些动画效果,使用定时器就可以实现。所谓定时器就是在间隔⼀定时间后,去执行某⼀个任务。定时器在很多场景下都会使用到,如弹窗自动关闭之类的功能等。

Qt中的定时器分为QTimerEventQTimer这2个类。

  • QTimerEvent类⽤来描述⼀个定时器事件。在使⽤时需要通过startTimer()函数来开启⼀个定时器,这个函数需要输⼊⼀个以毫秒为单位的整数作为参数来表明设定的时间,它返回的整型值代表 这个定时器。当定时器溢出时(即定时时间到达)就可以在timerEvent()函数中获取该定时器的编号来进行相关操作。
  • QTimer类来实现⼀个定时器,它提供了更⾼层次的编程接⼝,如:可以使⽤信号和槽,还可以设置只运⾏⼀次的定时器。

5.1 QTimerEvent类

示例:在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);
}

 实现效果如下:

 


5.2 QTimer类

示例:在UI界面放置⼀个Label标签,两个按钮,分别是"开始"和"停止",当点击"开始"按钮时, 开始每隔1秒计数⼀次,点击"停止"按钮时,暂停计数。

    ui->setupUi(this);
    
    QTimer *time = new QTimer(this);
    connect(ui->btn1 , &QPushButton::clicked,[=](){
        time->start(1000);
    });

    connect(time , &QTimer::timeout,[=](){
        static int num = 1;
        ui->label->setText(QString::number (num++));
    });

    connect(ui->btn2 , &QPushButton::clicked,[=](){
        time->stop();
    });

 实现效果如下:


(六)事件分发器 

6.1 概述

在Qt中,事件分发器(EventDispatcher)是⼀个核心概念,⽤于处理GUI应用程序中的事件。事件分发器负责将事件从⼀个对象传递到另⼀个对象,直到事件被处理或被取消。每个继承自QObject类或 QObject类本⾝都可以在本类中重写boolevent(QEvent*e)函数,来实现相关事件的捕获和拦截。

6.2 事件分发器工作原理

在Qt中,我们发送的事件都是传给了QObject对象,更具体点是传给了QObject对象的event()函 数。所有的事件都会进入到这个函数里面,那么我们处理事件就要重写这个event()函数。event()函数本身不会去处理事件,是而根据事件类型(type值)调用不同的事件处理函数。事件分发器就是工作在应用程序向下分发事件的过程中,如下图:

 如上图,事件分发器用于分发事件。在此过程中,事件分发器也可以做拦截操作。事件分发器主要是 通过boolevent(QEvent*e)函数来实现。其返回值为布尔类型,若为ture,代表拦截,不向下分发。

Qt 中的事件是封装在QEvent类中,在Qt助手中输入QEvent可以查看其所包括的事件类型,如下图示:

示例:

  • 1、在widget.h头文件中声明鼠标点击事件和事件分发器;如下图示:

  • 2、在widget.cpp文件中实现鼠标点击事件和拦截事件; 

 

 执行结果如下:


(七)事件过滤器 

在Qt中,⼀个对象可能经常要查看或拦截另外⼀个对象的事件,如对话框想要拦截按键事件,不让别的组件接收到,或者修改按键的默认值等。通过上面的学习,我们已经知道,Qt创建了QEvent事件对象之后,会调用QObject的event()函数处理事件的分发。显然,我们可以在event()函数中实现拦 截的操作。由于event()函数是protected的,因此,需要继承已有类。如果组件很多,就需要重写很多个event()函数。这当然相当麻烦,更不用说重写event()函数还得小心⼀堆问题。好在Qt提供了另外⼀种机制来达到这⼀目的:事件过滤器

 事件过滤器是在应用程序分发到event事件分发器之前,再做⼀次更高级的拦截。如下图示:

 

事件过滤器的⼀般使⽤步骤:

  • 1、安装事件过滤器;
  • 2、重写事件过滤器函数:eventfilter()。 

示例如下:

  • 1、新建Qt项目,基类选择QWidget,同时勾选UI界面⽂件,如下图; 

 

  • 2、设计UI⽂件,如下图; 

  • 3、在项目新添加⼀个类:MyLabel; 先选中项名目称QEvent,点击⿏标右键,选择addnew...,弹出如下对话框: 

  •  4、选择:Choose....,弹出如下界面:

  • 5、此时项目中会新添加以下两个文件;在UI文件中选中Label,右键------>提升为... 

  • 6、当点击"提升为..."之后,弹出如下对话框: 

  • 7、在mylabel.h中声明鼠标点击事件和事件分发器; 

  • 8、在mylabel.cpp⽂件中实现鼠标点击事件和事件分发器; 

  • 9、在widget.h头文件中声明事件过滤器函数; 

  • 10、在widget.cpp⽂件中实现事件过滤器的两个步骤;

 执行结果如下:


总结

Qt的事件处理机制非常灵活,通过事件循环、事件对象、信号与槽机制以及事件过滤器,可以高效地处理各种用户交互和系统事件。理解这些概念对于开发复杂的Qt应用程序至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2095484.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Redis】Redis 典型应⽤ - 缓存 (cache)

Redis 典型应⽤ - 缓存 cache 什么是缓存使⽤ Redis 作为缓存缓存的更新策略1) 定期⽣成2) 实时⽣成 缓存预热, 缓存穿透, 缓存雪崩 和 缓存击穿关于缓存预热 (Cache preheating)关于缓存穿透 (Cache penetration)关于缓存雪崩 (Cache avalanche)关于缓存击穿 (Cache breakdown…

OpenLayers3, 航线动画实现

文章目录 一、前言二、代码实现三、总结 一、前言 本文基于OpenLayers3&#xff0c;实现航线动画的功能。 二、代码实现 <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quo…

题解AtCoder ABC 358 F Easiest Maze

一道模拟题。 思路 最短的路线是直接竖着走下来&#xff0c;经过 n n n 个格子&#xff0c;所以 k k k 最小是 n n n。如果想要延长路线&#xff0c;可以采用九转大肠的形状&#xff0c;就像这样&#xff1a; 可以发现&#xff0c;每次向左走之后都必须走回来&#xff0c;…

关于几道计算机网络题的解答

2017年12月28日&#xff0c;星期四&#xff0c; 照片上的第一题中多项式的指数看不清&#xff0c;但没关系&#xff0c;就现在的情形&#xff0c;说一下大概的思路&#xff0c;参考着再结合题目中实际的参数&#xff0c;再套一遍就能把题目解出来了&#xff0c; 假设&#xf…

JS 如何判断是否是IE浏览器

例子 if(!!window.ActiveXObject || "ActiveXObject" in window){alert("抱歉&#xff0c;不支持IE浏览器&#xff01;");return; }

kafka使用

异步发送数据 package com.shf.kafka.producer; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.common.serializa…

算法基础-双指针算法

最长连续不重复子序列 双指针[j, i]维护的是以a[i]结尾的最长连续不重复子序列[j, i - 1]是前一步得到的最长连续不重复子序列&#xff0c;所以如果[j, i]中有重复元素&#xff0c;一定是a[i]&#xff0c;所以[j, i - 1]中一定有一个数字与a[i]重复&#xff0c;因此右移j直到a[…

【AI学习笔记】AIGC,AI绘画 ComfyUI+ComfyUI Manager安装

【AI学习笔记】ComfyUIComfyUI Manager安装 最近在面向BOSS直聘学习ComfyUI的使用&#xff0c;但是不出意外&#xff0c;因为学习者们迥异的电脑配置以及杂乱的AI软件工具包互相纠缠&#xff0c;跟人工智能相关的环境安装多少都会遇到点教程预料不到的BUG。 推荐入门教程&…

基于SpringBoot的智能医院管理系统

&#x1f4a5;&#x1f4a5;源码和论文下载&#x1f4a5;&#x1f4a5;&#xff1a;基于SpringBoot的智能医院管理系统-源码论文报告数据库文件.rar 1. 系统介绍 随着计算机科学的迅猛发展和互联网技术的不断推进&#xff0c;人们的生活方式发生了巨大的变化&#xff0c;同时也…

华为云征文 | Tomcat保姆级安装教程

简介 华为云Flexus云服务是新一代开箱即用、体验跃级、面向中小企业和开发者打造的高品价比云服务产品。Flexus云服务器X实例是华为云Flexus云服务的一个产品。 Flexus云服务器X实例是新一代面向中小企业和开发者打造的柔性算力云服务器&#xff0c;可智能感知业务负载&#…

借鉴腾讯系统架构从小到大的过程 - 如何做好一个系统设计?不限于(慧哥)慧知开源充电桩平台

推荐一套企业级开源充电桩平台&#xff1a;完整代码包含多租户、硬件模拟器、多运营商、多小程序&#xff0c;汽车 电动自行车、云快充协议&#xff1b;——(慧哥)慧知开源充电桩平台&#xff1b;https://liwenhui.blog.csdn.net/article/details/134773779?spm1001.2014.3001…

华为云征文|Flexus X实例性能测评

在数字化转型时代&#xff0c;云服务器成为企业 IT 基础设施的核心&#xff0c;其性能直接影响业务运行效率和用户体验。 面对众多云服务商提供的多样配置&#xff0c;如何选择合适的云服务器就变得尤为重要。 云服务器的性能测试对于识别潜在性能瓶颈&#xff0c;确保在高并…

安装python软件

系统是32位还是64位 “此电脑"或者"我的电脑”&#xff0c;鼠标右键——属性&#xff0c;出现如下图查看电脑系统类型&#xff08;图中显示电脑系统类型是64位系统&#xff0c;安装Python则选择其名含有"adm64"字样的文件&#xff09;: 软件安装地址 全…

AtCoder ABC 369 C 题 题解

题目传送门 C - Count Arithmetic Subarrays (atcoder.jp) 题解&#xff1a; 本题可以先预处理好 与 之间的差值。首先每个数都是一个等差数列&#xff0c;接着&#xff0c;每两个数也是一个等差数列&#xff0c;然后可以看一个数字持续了几位&#xff0c;如果持续了位&am…

layui中 子页面获取父页面的数据

父页面中 window.autosend function (obj) {//获取对应行的数据&#xff0c;var datafather obj.data;// console.log(data)layer.open({type: 2,maxmin: true,title: 选择发送时间,shade: 0.1,// area: screen(),area: [600px, 400px],content: autosend,success: function(…

Linux 背景、命令

一、嵌入式、Linux背景 1、嵌入式&#xff1a; 硬件与软件相结合 定制、为硬件设计相关代码来进行操作&#xff0c;代码测试&#xff0c;烧进板子&#xff0c;通过语音、图像、按钮等操作方式来调用。 2、操作系统种类&#xff1a; Dos&#xff0c;Windows&#xff0c;Uni…

【小白教程(无伤速通)】Visual Studio中Libtorch安装与配置

1. Libtorch下载 Download here (Release version): https://download.pytorch.org/libtorch/cpu/libtorch-win-shared-with-deps-1.8.0%2Bcpu.zipDownload here (Debug version): https://download.pytorch.org/libtorch/cpu/libtorch-win-shared-with-deps-debug-1.8.0%2B…

嵌入式Linux:信号分类

目录 1、不可靠信号与可靠信号 1.1、不可靠信号 1.2、可靠信号 2、实时信号和非实时信号 2.1、非实时信号 2.2、实时信号 在Linux系统中&#xff0c;信号可以从两个不同的角度进行分类&#xff1a;一是从可靠性方面&#xff0c;将信号分为可靠信号与不可靠信号&#xff1…

小柴带你学AutoSar系列三、标准和规范篇(3)ModeManagement

目录 ModeManagementGuide 2 Overall mechanisms and concepts 2.1 Declaration of modes 2.2 Mode managers and mode users 2.3 Modes in the RTE 2.4 Modes in the Basic Software Scheduler 2.5 Communication of modes 3 Configuration of the Basic Software Mod…

系统思考—盲点突破

最‮发近‬现服务的一些‮业企‬明明‮经已‬投入了大‮资量‬源在‮化优‬产品‮服和‬务上&#xff0c;但‮觉总‬得缺少一些‮键关‬点来‮正真‬实现突破&#xff1f;团‮每队‬天都在忙碌&#xff0c;但‮绩业‬增长却‮来越‬越缓慢&#xff0c;问‮总题‬是层出不穷&…