QT的使用3:鼠标事件

这篇具有很好参考价值的文章主要介绍了QT的使用3:鼠标事件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0 事件

用户对界面中的控件进行操作后,控件需要进行响应,响应一般有两种方式,一种是之前学过的槽函数,另一种是事件,部分操作无法通过槽函数响应,只能通过事件,例如鼠标移动,键盘输入等。
当某个事件(鼠标、键盘)发生的时候,相关控件就会收到这个事件,并且调用相应的事件处理函数进行相应,事件处理函数的命名都是以Event结尾的。

1 需求

在窗口内的任意位置点击,然后窗口会有一个标签(使用QLabel)显示鼠标所在位置的坐标:随着鼠标在窗口内不同位置进行点击,标签显示的坐标也在变换。效果如下图所示:
qt鼠标事件,Qt Creator,qt,计算机外设,ui

2 查看控件的事件处理函数

在帮助界面搜索QWidget,然后点击Protected Functions
qt鼠标事件,Qt Creator,qt,计算机外设,ui
可以看到很多以“Event”结尾的函数,这些函数的参数都是各个事件,并且这些函数都使用了virtual修饰,即他们都是虚函数,继承时表现为多态特性。
qt鼠标事件,Qt Creator,qt,计算机外设,ui
我们可以往下滑,找到鼠标事件
qt鼠标事件,Qt Creator,qt,计算机外设,ui
截图中红色方框框出来的几个分别为:鼠标单击、鼠标移动、鼠标点击、鼠标释放,说明这个控件可以对这四种鼠标事件进行响应,它们的参数均为鼠标事件指针(QMouseEvent *)。

3 UI设计

打开QT设计师,在Display Widgets中选择Label,将其拖到窗口中:qt鼠标事件,Qt Creator,qt,计算机外设,ui
给主窗口来个布局
qt鼠标事件,Qt Creator,qt,计算机外设,ui
右下角可以看到类的继承层次结构,我们刚刚拖到窗口中的控件,类型是QLabel
在QFrame的frameShape属性中选择Box
qt鼠标事件,Qt Creator,qt,计算机外设,ui
窗口中会出现黑色的框线
qt鼠标事件,Qt Creator,qt,计算机外设,ui

4 新建一个类,继承QLabel

设计好UI后,之所以还要新建类去继承已有类,是因为原先的事件处理函数无法满足需求,我们需要重写相应的事件处理函数(这部分稍后会说)。
由于新建类的时候,父类选项没有QLabel,所以这里新建类的时候先选择继承QWidget(也可以选其他),产生代码后手动改父类
qt鼠标事件,Qt Creator,qt,计算机外设,ui
打开新建类的头文件,将父类由QWidget改成QLabel
qt鼠标事件,Qt Creator,qt,计算机外设,ui
对应的cpp文件也要改,在构造函数的初始化列表中,将父类改过来
qt鼠标事件,Qt Creator,qt,计算机外设,ui

5 对已有对象进行类型提升

在UI设计界面的对象树中,右击我们刚刚在UI设计阶段,拖到窗口中的空间(QLabel对象),然后点击“提升为”
qt鼠标事件,Qt Creator,qt,计算机外设,ui
在弹出的对话框中,填写提升的类名称,然后点击添加
qt鼠标事件,Qt Creator,qt,计算机外设,ui
再次填写提升的类名称,然后点击提升
qt鼠标事件,Qt Creator,qt,计算机外设,ui
此时可以看到,我们刚刚拖到窗口中的控件,类型变成了MyLabel
qt鼠标事件,Qt Creator,qt,计算机外设,ui
然后Ctrl+R,看看有没有错。

6 重写事件处理函数

MyLabel.h内容如下:

#ifndef MYLABEL_H
#define MYLABEL_H

#include <QWidget>
#include <QLabel>

class MyLabel : public QLabel
{
    Q_OBJECT
public:
    explicit MyLabel(QWidget *parent = nullptr);

signals:

public:
    void mousePressEvent(QMouseEvent *event);
};

#endif // MYLABEL_H

输入完函数声明后,按下alt+回车,会显示提示消息,然后选择“在mylabel.cpp添加定义”,就能在mylabel.cpp中自动生成函数头,十分方便。
qt鼠标事件,Qt Creator,qt,计算机外设,ui

MyLabel.cpp内容如下:

#include "mylabel.h"
#include "QMouseEvent"

MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{

}

void MyLabel::mousePressEvent(QMouseEvent *event)
{
    //获取鼠标事件的一些信息
    //获取坐标
    int x = event->x();
    int y = event->y();

    //格式化显示坐标,并居中
    QString str = QString("<h1><center>[%1, %2]</center></h1>").arg(x).arg(y);
    this->setText(str);
}

这里QString str = QString("<h1><center>[%1, %2]</center></h1>").arg(x).arg(y);是将字符串进行格式化匹配,QString中是可以使用html语法的,随后的this->setText(str)是输出指定的字符串。

现在我们按下Ctrl+R运行,然后点击窗口中的任意一点,然后就能看到坐标了
qt鼠标事件,Qt Creator,qt,计算机外设,ui
至此,大功告成。

我们这个项目的结构如下图所示:
qt鼠标事件,Qt Creator,qt,计算机外设,ui
项目中的main.cpp、widget.h和widget.cpp都没有修改,这几个文件一般很少去动,除非要和后端进行联动。

7 项目进一步拓展

(1)获取鼠标按键

在mylabel.cpp中输入event->button();,然后移动光标到函数上,按两遍F1(笔记本电脑可能和某些屏幕、声音设置的快捷键冲突,这种情况下需要按住键盘左下角的fn键,然后按两遍F1)
qt鼠标事件,Qt Creator,qt,计算机外设,ui
可以看到这个函数的返回值类型是Buttons,点击QT::MouseButton
qt鼠标事件,Qt Creator,qt,计算机外设,ui
QT 5.14.2的帮助文档中,button()返回值是Qt3DInput::QMouseEvent::Buttons类型,而用这个类来定义event->button的返回值却报错,我不知道怎么回事,所以上面使用的是QT 5.9文档内容。也就是说,5.14.2并不是稳定版本,编译器和帮助文档有冲突,我们以后查看返回值类型的时候,用ctrl,然后鼠标点击要查看的函数,找到源码查看返回值类型,然后再调用帮助文档。

可以看到QT::MouseButton枚举类型(一般Qt后面跟两个冒号的,都是枚举类型),红框框出来的为需要掌握的键,分别是:未按下、任意键、左键、右键、中键(滚轮)、中键,最后两个含义相同。
qt鼠标事件,Qt Creator,qt,计算机外设,ui
将mylabel.cpp的代码修改如下:

#include "mylabel.h"
#include "QMouseEvent"

MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{

}

void MyLabel::mousePressEvent(QMouseEvent *event)
{
    //获取鼠标事件的一些信息
    //获取坐标
    int x = event->x();
    int y = event->y();

    //获取鼠标按键
    Qt::MouseButton btn = event->button();
    QString strButton ="" ;
    if(btn == Qt::LeftButton)
    {
        strButton = "LeftButton";
    }
    if(btn == Qt::RightButton)
    {
        strButton = "RightButton";
    }
    if(btn == Qt::MidButton)
    {
        strButton = "MidButton";
    }

    //格式化显示坐标,并居中
    QString str = QString("<h1><center>[%1, %2][%3]</center></h1>").
            arg(x).arg(y).arg(strButton);
    this->setText(str);

    qDebug()<<"press";
}

运行结果如下:
qt鼠标事件,Qt Creator,qt,计算机外设,ui

(2)鼠标移动

在MyLabel类中新增一个函数,定义如下(mylabel.h中也要声明,这里不再赘述):

void MyLabel::mouseMoveEvent(QMouseEvent *ev)
{
    //获取坐标
    int x = ev->x();
    int y = ev->y();

    QString str=QString("<h1><center>Move[%1, %2][%3]</center></h1>").arg(x).arg(y);
    this->setText(str);
}

点击运行后,按下鼠标,会调用mousePressEvent,移动鼠标会调用mouseMoveEvent
qt鼠标事件,Qt Creator,qt,计算机外设,ui

(3)显示多个按键

对于按下按键后(不松开)拖动的情况,会先调用mousePressEvent,然后调用mouseMoveEvent,我们希望标签能显示Move和坐标的同时,也显示按下了哪个按钮,例如Move[300, 300][LeftButton],对于鼠标移动过程中,同时按下左键和右键的情况,我们也希望能够检测到。则可以对mouseMoveEvent做如下修改:

void MyLabel::mouseMoveEvent(QMouseEvent *ev)
{
    //获取坐标
    int x = ev->x();
    int y = ev->y();

    //获取鼠标按键
    Qt::MouseButtons btns = ev->buttons();  //可以一次获取多个按键
    QString strButton ="" ;
    if(btns & Qt::LeftButton)               //按位与操作
    {
        strButton += "LeftButton ";			//+是字符串拼接,因为有可能按了多个键
    }
    if(btns & Qt::RightButton)
    {
        strButton += "RightButton ";		//+是字符串拼接,因为有可能按了多个键
    }
    if(btns & Qt::MidButton)
    {
        strButton += "MidButton ";
    }

    QString str=QString("<h1><center>Move[%1, %2][%3]</center></h1>").
            arg(x).arg(y).arg(strButton);
    this->setText(str);
}

这里需要注意的是,ev->buttons()返回一个数,我们用二进制的角度来看,假如它返回的是000101,那么它是000100(MidButton)和000001(LeftButton)按位与的结果,表示同时按下了两个按键。
后面的几个if判断条件,其实是按位与运算。因为每一种Qt::MouseButton常量,只有某一位是1,其他位都为0,因此要从ev->buttons()的返回值中将某一位抽取出来,可以使用按位与运算,例如要判断是否按下了RightButton(000010),可以用RightButton与返回值进行按位与运算,结果为0则表示没按下,非0则表示按下了,假设返回值为000011,000010&000011结果是000010,结果非0,因此按下了。

运行后,按下鼠标拖动如下:
qt鼠标事件,Qt Creator,qt,计算机外设,ui
在按下鼠标(左键)拖动的那一瞬间,是否调用了mousePressEvent?可以在mousePressEvent函数中增加一行打印功能,来查看是否调用。
我自己尝试了,点下的那一瞬间,确实是先调用mousePressEvent,然后调用mouseMoveEvent,即点下的一瞬间先相应mousePressEvent,随后移动鼠标时相应mouseMoveEvent,此时由于鼠标左键还没松开,因此能被ev->buttons()检测到。

对于同时按下多个按键进行拖动,也能正常显示
qt鼠标事件,Qt Creator,qt,计算机外设,ui

(4)设置默认鼠标跟踪

上面的程序,在开始的时候,没有跟踪鼠标,也就是下面这个样子:
qt鼠标事件,Qt Creator,qt,计算机外设,ui
只有点击了窗口以后,才会显示“Move+坐标+按键名称”

如果我们想在窗口打开后,鼠标移动到窗口中(未点击)就开始跟踪鼠标的移动,那么可以在构造函数中进行设置

MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{
    //默认情况下,窗口不会主动跟踪鼠标
    //只有当某个鼠标按键按下的情况下才开始跟踪
    //如果想一开始跟踪,就要使用以下函数
    this->setMouseTracking(true);
}

8 QT事件分发机制

为什么我们点击了鼠标,就会调用mousePressEvent,移动了鼠标就会调用mouseMoveEvent?
当某个事件(鼠标、键盘)发生的时候,相应的控件就会收到这个事件,并且根据事件的类型调用相应的事件处理函数,这个过程都在一个名为event的事件中,这个函数可以在帮助文档中查看,它是一个虚函数,可以被子类重写。

qt鼠标事件,Qt Creator,qt,计算机外设,ui
一般情况下,不会去重写这个函数,我们能这里为了了解事件分发机制,因此对其进行重写。

这里仅仅以鼠标移动为例

bool MyLabel::event(QEvent *e)
{
    //返回值:true表示该事件得到处理,如果是false,没被处理,事件会继续传递到父窗口
    //QEvent就是所有Event类的父类,这里其实是使用了多态
    //判断event的类型
    if(e->type()==QEvent::MouseMove)    //e->type()返回的是鼠标事件的类型
    {
        this->mouseMoveEvent(static_cast<QMouseEvent *>(e));	//这句如果注释掉,则鼠标移动将不会有反应
        return true;
    }

    //其他类型的事件,交给父类的event函数去处理
    return QLabel::event(e);    //父类的event函数因为被覆盖了,所以需要域作用符
}

如果将this->mouseMoveEvent(static_cast<QMouseEvent *>(e));注释掉,则当鼠标移动时将不会有反应,此时就把鼠标移动给拦截过滤了。

事件的机制,可以用下面这张图来总结,事件过滤器这里没讲,这个并不重要:
qt鼠标事件,Qt Creator,qt,计算机外设,ui文章来源地址https://www.toymoban.com/news/detail-543705.html

到了这里,关于QT的使用3:鼠标事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • QT6 C++获取Window系统计算机的主机BIOS序列号源代码

    这是自己用QT6 C++编程语言开发的获取主机BIOS序列号的程序。经过调试,可以在Window10系统和Win7系统运行。

    2024年02月09日
    浏览(46)
  • Qt 事件 < 二 >鼠标键盘事件

    Qt 是一个流行的 C++ 框架,用于构建跨平台的图形用户界面应用程序。在 Qt 中,处理键盘事件和鼠标事件是常见的任务,因为用户输入在交互式应用程序中至关重要。下面是关于 Qt 键盘事件和鼠标事件的学习总结: 键盘事件 (QKeyEvent)使用入门: 事件处理函数: 键盘事件通过

    2024年01月18日
    浏览(12)
  • 【QT】鼠标常用事件

    【QT】鼠标常用事件

    新建项目 加标签控件 当鼠标进去,显示【鼠标进入】,离开时显示【鼠标离开】 将QLable提升成自己的控件,然后再去捕获 添加文件 改继承的类名 提升类 同一个父类,可以提升 效果 现在代码就和Qlabel对应起来了。 在.h中声明,.cpp中实现 测试 鼠标的移动、按下、松开事件

    2024年02月06日
    浏览(9)
  • Qt开发-鼠标事件

    Qt开发-鼠标事件

    个人认为,事件机制是Qt最难以理解且最为精妙的一部分。事件主要分为两种: 在与用户交互时发生 。比如按下鼠标(mousePressEvent),敲击键盘(keyPressEvent)等。 系统自动发生 ,比如计时器事件(timerEvent)等。 在发生事件时(比如说上面说的按下鼠标),就会产生一个

    2024年02月09日
    浏览(8)
  • qt鼠标事件

    鼠标移动事件,只要移动鼠标,就会触发这个函数,其中,正常情况下,只有当鼠标在QWidget界面点击鼠标后,才会捕捉到鼠标的坐标,那如何实现,在不点击鼠标的情况下,也可以捕捉到鼠标移动事件呢? 代码如下: 比如在主窗口QWidget下有一个父窗口Lable,在鼠标进入Lab

    2024年02月09日
    浏览(18)
  • Qt5鼠标事件

    判断鼠标按下了哪个键 本文福利, 莬 费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击 莬 费领取

    2024年02月12日
    浏览(12)
  • Qt 鼠标进入离开事件

    QEvent::Enter ​ 鼠标进入事件,当鼠标进入到窗口/控件内部时,触发该事件,它对应的子类是 QEnterEvent QEvent::Leave ​ 鼠标离开事件,当鼠标离开到窗口/控件内部时,触发该事件 自定义一个标签控件 LabelX ,让它继承自 QLabel ,然后重写父类的 enterEvent 和 leaveEvent 。 代码如下:

    2024年01月24日
    浏览(16)
  • qt鼠标常用事件

    qt鼠标常用事件

    和上一个案例相同,也是做了提升,换了相同父类,但是方式有所不同 先在widget.ui中加入label标签,此时其父类为QLabel,然后想实现鼠标在QLabel上的捕获。所以我们需要把QLabel提升为自己的框架,然后自定义框架后,我们就可以自己捕获信息了。然后添加新文件mylabel.h和mylabel.cpp,

    2024年02月02日
    浏览(10)
  • qt 禁止点击 屏蔽鼠标事件

    我开了一个线程上传文件夹,用一个进度条显示进度 测试 就在界面随便点击 ,也没有出泵任何控件,没有引发槽函数,直接就崩了! 不知道为什么崩了,所以直接禁止点击,蔽鼠标事件! 主界面 进度条 Qt::WidgetAttribute::WA_TransparentForMouseEvents 该属性的含义是“透明掉鼠标事

    2024年02月15日
    浏览(12)
  • Qt知识笔记(八)—— 鼠标和事件

    默认情况下,触发事件需要点击一下,才能触发。可设置为自动触发: setMouseTracking(true); 鼠标事件有单机,双击,释放,移动,滑轮 单机:void mousePressEvent(QMouseEvent *event); 双击:void mouseDoubleClickEvent(QMouseEvent *event); 释放:void mouseReleaseEvent(QMouseEvent *event); 移动:void mouseMove

    2024年02月16日
    浏览(7)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包