【Qt】消息机制和事件

news2024/9/22 21:16:32

文章目录

  • 事件
  • event()
  • 事件过滤器
  • 案例:检测鼠标事件
  • 案例:定时器

事件

事件(event)是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件

一些事件在对用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件


回顾

Qt 程序需要在main()函数创建一个QApplication对象,然后调用它的exec()函数,这个函数就是开始 Qt 的事件循环,在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。

当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent,在事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数


event()

event()函数主要用于事件的分发,所以如果希望在事件分发之前做一些操作,就可以重写这个event()函数

  • 如果传入的事件已被识别并且处理,则需要返回 true,否则返回 false
  • 如果返回值是 true,那么 Qt 会认为这个事件已经处理完毕,不会再将这个事件发送给其它对象,而是会继续处理事件队列中的下一事件,并且在event()函数中,调用事件对象的accept()和ignore()函数是没有作用的,不会影响到事件的传播

event()函数中实际是通过事件处理器来响应一个具体的事件。这相当于event()函数将具体事件的处理“委托”给具体的事件处理器。而这些事件处理器是 protected virtual 的,因此,我们重写了某一个事件处理器,即可让 Qt 调用我们自己实现的版本。

  • 由此可见,event()是一个集中处理不同类型的事件的地方

事件过滤器

在程序将事件分发到事件分发器前,可以利用过滤器做拦截

QObject有一个eventFilter()函数,用于建立事件过滤器

virtual bool QObject::eventFilter ( QObject * watched, QEvent * event )

事件过滤器会检查接收到的事件。如果这个事件是我们感兴趣的类型,就进行我们自己的处理;如果不是,就继续转发。这个函数返回一个 bool 类型,如果不想让它继续转发,就返回 true,否则返回 false

安装过滤器需要调用QObject::installEventFilter()函数

void QObject::installEventFilter ( QObject * filterObj )

注意事项

1.事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效

2.事件过滤器在目标对象接收到事件之前进行处理,如果我们将事件过滤掉,目标对象根本不会见到这个事件


案例:检测鼠标事件

前置工作

1.项目 => Add New =>C++ class

image-2023100520492631

2.在mianWindow.ui文件当中创建一个Label控件 => 提升为

image-20231005205126983

3.可以更改控件的格式 看的更明显

image-20231005205210158


注意:在第二步当中可以发现:基类名称为 Q L a b e l QLabel QLabel,所以生成的myLabel.h和myLabel.cpp文件要改动:

//.h文件
#include <QLabel>
class myLabel : public QLabel//改为继承QLabel
    
//.cpp文件
myLabel::myLabel(QWidget *parent) : QLabel(parent) //父类对象从QWidget(parent)  =》 QLabel(parent)  

myLabel.h

//鼠标进入事件
void enterEvent(QEvent *event);  //从父类继承的函数

//鼠标离开事件
void leaveEvent(QEvent *);

//鼠标按下
virtual void mousePressEvent(QMouseEvent *ev);

//鼠标释放
virtual void mouseReleaseEvent(QMouseEvent *ev);

//鼠标移动
virtual void  mouseMoveEvent(QMouseEvent *ev);

//通过event事件分发器 拦截 鼠标按下事件
bool event(QEvent *e);

myLabel.cpp

//鼠标进入事件
void myLabel::enterEvent(QEvent *event)
{
   qDebug() << "鼠标进入了";
}

//鼠标离开事件
void myLabel::leaveEvent(QEvent *)
{
   qDebug() << "鼠标离开了";
}


//鼠标按下
void myLabel::mousePressEvent(QMouseEvent *ev)
{

    //当鼠标左键按下  提示信息
    if( ev->button() ==  Qt::LeftButton)
    {
        //arg:参数  global的含义:基于窗口的距离 普通的x,y:基于控件的距离
        QString str = QString( "鼠标按下了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug() << str;
    }
}

//鼠标释放
void myLabel::mouseReleaseEvent(QMouseEvent *ev)
{

    if( ev->button() ==  Qt::LeftButton)
    {
        QString str = QString( "鼠标释放了 x = %1   y = %2  globalX = %3 globalY "  \
                               "= %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug() << str;
    }
}

//鼠标移动
void myLabel::mouseMoveEvent(QMouseEvent *ev)
{
    // 当鼠标左键按下  提示信息  buttons:返回按键类型 ev->buttons() &   Qt::LeftButton:如果是左键才为真
    if( ev->buttons() &   Qt::LeftButton )  //移动是持续的过程!
    {
        QString str = QString( "鼠标移动了 x = %1   y = %2  globalX = %3 globalY " \
                               "= %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug() << str;
   }
}

bool myLabel::event(QEvent *e)
{
    //如果是鼠标按下 ,在event事件分发中做拦截操作
    if(e->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent * ev  = static_cast<QMouseEvent *>(e); //QEvent是QMouseEvent的父类
        QString str = QString( "Event函数中::鼠标按下了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug() << str;

        return true; //true代表用户自己处理这个事件,不向下分发 => 不会触发mousePressEvent函数
    }

    //其他事件 交给父类处理 =>默认处理
    return QLabel::event(e);
}

注意:

1.QString的arg()函数可以自动替换掉QString中出现的占位符。其占位符以 % 开始,后面是占位符的位置,例如 %1,%2 这种

QString("[%1, %2]").arg(x).arg(y); =>x替换 %1,y替换 %2  QString为[x, y]

2.要点击鼠标之后才能在 m o u s e M o v e E v e n t mouseMoveEvent mouseMoveEvent函数中显示鼠标坐标值,原因如下:

  • QWidget中有一个mouseTracking属性,该属性用于设置是否追踪鼠标只有鼠标被追踪时,mouseMoveEvent()才会发出。
  • 如果mouseTracking是 false(默认即是),组件在至少一次鼠标点击之后,才能够被追踪,也就是能够发出mouseMoveEvent()事件如果mouseTracking为 true,则mouseMoveEvent()直接可以被发出。

如果想不点击鼠标也能在 m o u s e M o v e E v e n t mouseMoveEvent mouseMoveEvent函数中显示鼠标坐标值,在构造函数当中:

myLabel::myLabel(QWidget *parent) : QLabel(parent)
{
    //设置鼠标追踪状态   默认为false
    setMouseTracking(true);
}

3.$ev->button() $可以判断所有按键 Q t : : L e f t B u t t o n Qt::LeftButton Qt::LeftButton Q t : : R i g h t B u t t o n Qt::RightButton Qt::RightButton

e v − > b u t t o n s ( ) ev->buttons() ev>buttons()判断组合按键 判断move时候的左右键 结合 & 操作符


案例:定时器

创建方式1:

利用事件 void timerEvent ( QTimerEvent * ev),启动定时器: s t a r t T i m e r ( 1000 ) startTimer(1000) startTimer(1000) 单位是毫秒,$timerEvent 的返回值是定时器的唯一标示可以和 的返回值是定时器的唯一标示 可以和 的返回值是定时器的唯一标示可以和ev->timerId $做比较

创建方式2:

1.利用定时器类 QTimer => 创建定时器对象 QTimer * timer = new QTimer(this)

2.启动定时器 timer->start(毫秒)

3.每隔一定毫秒发送信号 timeout ,进行监听

4.暂停 : timer->stop


前置内容

1.先预先创建4个 L a b e l Label Label

image-20231006102712863

创建定时器方法1:需要重写定时器的事件

//widget.h
//重写定时器的事件
void timerEvent(QTimerEvent *);

int id1; //定时器1的唯一标示
int id2; //定时器2的唯一标示
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //启动定时器  => 会返回定时器的标识符
    id1 = startTimer(1000); //参数:时间间隔,单位是毫秒
    id2 = startTimer(2000);
}

void MainWindow::timerEvent(QTimerEvent* ev)
{
    if(ev->timerId() == id1)//label1 每隔1秒+1
    {
        static int num = 1;
        ui->label_1->setText( QString::number(num++));
    }

    if(ev->timerId() == id2) //label2  每隔2秒 +1
    {
        static int num2 = 1;
        ui->label_2->setText( QString::number(num2++));
    }
}

第二种方式创建定时器

在ui界面当中多增加两个按钮用于停止和恢复定时器:

image-20231006104029330

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //定时器第二种方式
    QTimer * timer = new QTimer(this);
    //启动定时器
    timer->start(500);
    connect(timer,&QTimer::timeout,[=](){   //label3 每隔0.5秒+1
        static int num = 1;
        ui->label_3->setText(QString::number(num++));
    });


    //点击暂停按钮 实现停止定时器
    connect(ui->stop_btn,&QPushButton::clicked,[=](){
        timer->stop();
        qDebug() <<"定时器已暂停" ;
    });

    //点击恢复按钮 重写启动定时器
    connect(ui->start_btn,&QPushButton::clicked,[=](){
        timer->start(500);
        qDebug() <<"定时器已恢复" ;
    });
}

定时器的事件过滤器

重写 bool eventFilter(QObject *, QEvent *);

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    //步骤1:给控件label_4 安装事件过滤器
    ui->label_4->installEventFilter(this);
}


// 步骤2  重写 eventfilter事件
bool MainWindow::eventFilter(QObject * obj , QEvent * e)
{
   if(obj == ui->label_4)//控件判断  因为可能很多控件都安装了事件过滤器
   {
       if(e->type() == QEvent::MouseButtonPress)//如果是label的鼠标按下
       {
           QMouseEvent * ev  = (QMouseEvent*)e;
           QString str = QString( "事件过滤器中::鼠标按下了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
           qDebug() << str;
           qDebug() <<"事件过滤器拦截成功";
           return true; //true代表用户自己处理这个事件,不向下分发
       }
   }

   //其他默认处理
   return QWidget::eventFilter(obj,e);
}

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

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

相关文章

微信小程序进阶——后台交互个人中心授权登录

目录 一、小程序登录微信登录接口演示 1.1 项目导入 1.2 method1 1.3 method2 二、小程序授权登录 2.1 登录过程 2.1.1 详解 2.1.2 图解 2.2 后端代码导入 2.3 前端代码导入 ​编辑 2.4 案例演示 前端代码如下&#xff1a; 2.4.1 前端调用接口地址 2.4.2 个人中…

Power BI 傻瓜入门 5. 准备数据源

本章内容将介绍&#xff1a; 定义Power BI支持的数据源类型探索如何在Power BI中连接和配置数据源了解选择数据源的最佳做法 现代组织有很多数据。因此&#xff0c;不用说&#xff0c;微软等企业软件供应商已经构建了数据源连接器&#xff0c;以帮助组织将数据导入Power BI等…

瑞萨e2studio(27)----使用EZ-CUBE3烧录

瑞萨e2studio.27--使用EZ-CUBE3烧录 概述视频教学样品申请引脚配置EZ-CUBE3 仿真器开关设置对RA族MCU进行Flash编程蓝色 LED 指示灯的状态信息 概述 EZ-CUBE3&#xff08;CYRCNEZCUBE03&#xff09;是具有Flash存储器编程功能的片上调试仿真器&#xff0c;可以用于调试MCU程序…

合同管理怎么做?套用Excel合同管理台账模板,真可以省心省力!

对于从事日常行政办公管理的人来说&#xff0c;最难受得就是各种合同乱糟糟&#xff0c;合同数据又多又杂&#xff0c;一不小心就会出错&#xff0c;而且有的合同数据到期了我们太忙也不知道&#xff0c;所以就很麻烦…… 想做好合同台账&#xff0c;其实很简单&#xff0c;今天…

基于stm32控制的ESP8266在设备模式下通讯

一、文章中要用的指令 指令作用ATUART115200,8,1,0,0之前的51通讯是9600&#xff0c;这里的321用的是115200&#xff0c;需要改一下波特率ATCWMODEXX是1代表station&#xff08;设备&#xff09;模式 &#xff0c;X是2代表AP&#xff08;路由&#xff09;模式 &#xff0c;X是…

微信小程序之个人中心授权登录

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 1.了解微信授权登录 微信登录官网&#xff1a; 小程序登录https://developers.weixin.qq.com/miniprogram/d…

YOLOv5源码中的参数超详细解析(2)— 配置文件yolov5s.yaml(包括源码+网络结构图)

前言:Hello大家好,我是小哥谈。配置文件yolov5s.yaml在YOLOv5模型训练过程中发挥着至关重要的作用,属于初学者必知必会的文件!在YOLOv5-6.0版本源码中,配置了5种不同大小的网络模型,分别是YOLOv5n、YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x,其中YOLOv5n是网络深度和宽度最小…

5G技术的飞速发展:连接未来

随着科技的日益进步&#xff0c;5G通讯技术已经成为了全球科技领域的热门话题。5G&#xff0c;即第五代移动通信技术&#xff0c;带来的不仅仅是更快的网络速度&#xff0c;它的高带宽和低延迟特性将为未来的数字世界奠定基础。 速度与效率的飞跃: 5G技术的最大亮点是它极高的下…

App分发的策略和注意事项

当今的数字化时代中&#xff0c;移动应用程序已经成为了人们生活中不可或缺的一部分。随着智能手机的普及和移动互联网的快速发展&#xff0c;应用程序的分发方式也变得越来越多样化。 App分发是指将移动应用程序通过特定的渠道传递给终端用户的过程。在应用程序开发完成后&am…

js轮转数组

给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4…

OpenCV+QT实现的数字图像处理算法合集

源码下载地址&#xff1a; 基于OpenCV和QT的图像处理源码 图像预处理 灰度处理 灰度直方图 灰度均衡 梯度锐化 Laplace锐化 边缘检测 Roberts Sobel Laplace Prewitt canny Krisch 噪声 椒盐噪声 高斯噪声 滤波 均值滤波 中值滤波 双边滤波 形态学滤波 高斯滤波 图像变…

牛客网刷题-(1)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

工作中几个问题的思考

对于需要并行多公司并行处理的任务&#xff0c;方案是什么&#xff1f; 多线程、并行流、并发库&#xff08;ExecutorService、Futrue、Callable&#xff09;&#xff0c;分布式计算&#xff08;1&#xff09;按照公司ID分片 &#xff08;2&#xff09;按照业务类型分片 处理…

当我让文心一言写个代码来庆祝1024程序员节,它写的代码是……

先让它写个自我介绍吧~ 大家好&#xff0c;我是一个人工智能语言模型&#xff0c;我的中文名是文心一言&#xff0c;英文名是ERNIE Bot。我可以协助您完成范围广泛的任务并提供有关各种主题的信息&#xff0c;比如回答问题&#xff0c;提供定义和解释及建议。如果您有任何问题…

单链表的实现(全注释promax版)

目录 前言&#xff1a; 哨兵位&#xff1a; 链表的概念 链表的相关操作&#xff1a; 链表的创建&#xff1a; 打印链表&#xff1a; 申请新节点&#xff1a; 链表的尾插&#xff1a; &#xff01;&#xff01;&#xff01;对于传参中二级指针的解释&#xff1a; 链表的…

解决使用WebTestClient访问接口报[185c31bb] 500 Server Error for HTTP GET “/**“

解决使用WebTestClient访问接口报[185c31bb] 500 Server Error for HTTP GET "/**" 问题发现问题解决 问题发现 WebTestClient 是 Spring WebFlux 框架中提供的用于测试 Web 请求的客户端工具。它可以不用启动服务器&#xff0c;模拟发送 HTTP 请求并验证服务器的响…

【UCAS自然语言处理作业一】利用BeautifulSoup爬取中英文数据,计算熵,验证齐夫定律

文章目录 前言中文数据爬取爬取界面爬取代码 数据清洗数据分析实验结果 英文数据爬取爬取界面动态爬取 数据清洗数据分析实验结果 结论 前言 本文分别针对中文&#xff0c;英文语料进行爬虫&#xff0c;并在两种语言上计算其对应的熵&#xff0c;验证齐夫定律github: ShiyuNee…

Java Static关键字 单例设计模式

类变量 类变量&#xff08;静态变量&#xff09;&#xff1a;有static修饰&#xff0c;属于类&#xff0c;在计算机中只有一份&#xff0c;被类的所有对象共享 可以通过类名访问&#xff0c;也可以通过对象名访问&#xff0c;但是推荐用类名访问类变量一般用public修饰&#xf…

Maven 生命周期clean default size含义

clean 负责清理工作&#xff0c;清理上一次项目构建产生的一些文件&#xff0c;如编译后的字节码文件&#xff0c;打包后的jar包文件 default 整一个项目构建的核心工作&#xff0c;如编译&#xff0c;测试&#xff0c;打包&#xff0c;安装&#xff0c;部署等等 size 生成报告…

springBoot--web--函数式web

函数式web 前言场景给容器中放一个Bean&#xff1a;类型是 RouterFunction<ServerResponse>每个业务准备一个自己的handler使用集合的时候加注解请求的效果 前言 springmvc5.2 以后允许我们使用函数式的方式&#xff0c;定义web的请求处理流程 函数式接口 web请求处理的…