QT事件处理及实例(鼠标事件、键盘事件、事件过滤)

这篇文章通过鼠标事件、键盘事件和事件过滤的三个实例介绍事件处理的实现。

鼠标事件及实例

鼠标事件包括鼠标的移动、按下、松开、单击和双击等。
创建一个MouseEvent项目,通过项目介绍如何获得和处理鼠标事件。程序效果如下图所示。
在这里插入图片描述
界面布局代码如下:

MouseEvent::MouseEvent(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle(QStringLiteral("鼠标事件"));	//设置窗体的标题
    statusLabel = new QLabel;
    statusLabel->setText(QStringLiteral("当前位置:"));
    statusLabel->setFixedWidth(100);
    MousePosLabel = new QLabel;
    MousePosLabel->setText(QStringLiteral(""));
    MousePosLabel->setFixedWidth(100);
    statusBar()->addPermanentWidget(statusLabel);
    statusBar()->addPermanentWidget(MousePosLabel);
    this->setMouseTracking(true);
    resize(400,200);
}
  • statusLabel = new QLabel:创建QLabel控件statusLabel,用于显示鼠标移动时的实时位置。
  • MousePosLabel = new QLabel:创建QLabel控件MousePosLabel,用于显示鼠标键按下或释放时的位置。
  • statusBar()->addPermanentWidget(statusLabel):在QMainWindow的状态栏中增加控件。
  • this->setMouseTracking(true):设置窗体追踪鼠标。setMouseTracking函数设置窗体是否追踪鼠标,默认为false,不追踪,在此情况下应至少有一个鼠标按下时才响应鼠标移动事件,在前面的例子中有很多类似的情况,如绘图程序。在这里需要实时显示鼠标的位置,因此设置为true,追踪鼠标。

mousePressEvent函数为鼠标按下响应函数,QMouseEvent类的button函数方法可获得发生鼠标事件的按键属性(左键、右键、中键等)。函数代码实现如下:

void MouseEvent::mousePressEvent(QMouseEvent *e)
{
    QString str="("+QString::number(e->x())+","+QString::number(e->y()) +")";
    if(e->button()==Qt::LeftButton)
    {
        statusBar()->showMessage(QStringLiteral("左键:")+str);
    }
    else if(e->button()==Qt::RightButton)
    {
        statusBar()->showMessage(QStringLiteral("右键:")+str);
    }
    else if(e->button()==Qt::MidButton)
    {
        statusBar()->showMessage(QStringLiteral("中键:")+str);
    }
}
  • e->x()、e->y():QMouseEvent类的x和y函数可以获得鼠标相对于接收事件的窗体位置,globalX和global函数可以获得鼠标相对窗口系统的位置。

mouseMoveEvent函数为鼠标移动事件响应函数,QMouseEvent类的x和y函数可以获得鼠标相对于接收事件的窗体位置。具体代码如下:

void MouseEvent::mouseMoveEvent(QMouseEvent *e)
{
    MousePosLabel->setText("("+QString::number(e->x())+","+QString::number(e->y())+")");
}

mouseReleaseEvent函数为鼠标松开事件响应函数,其具体代码如下:

void MouseEvent::mouseReleaseEvent(QMouseEvent *e)
{
    QString str="("+QString::number(e->x())+","+QString::number(e->y()) +")";
    statusBar()->showMessage(QStringLiteral("释放在:")+str,3000);
}

mouseDoubleClickEvent函数为鼠标双击事件响应函数,在此没有实现具体功能,但仍要写出函数体框架:

void MouseEvent::mouseDoubleClickEvent(QMouseEvent *e){}

键盘事件及实例

在图像处理和游戏应用程序中,有时需要通过键盘控制某个对象的移动,此功能可以通过对键盘事件的处理来实现。键盘事件的获取时通过重定义QWidget类的keyPressEvent和keyReleaseEvent来实现的。
下面通过一个KeyEvent项目,实现键盘控制图标的移动来介绍键盘事件的应用。项目效果如下图所示。
在这里插入图片描述
窗体网格绘制代码如下:

void KeyEvent::drawPix()
{
    pix->fill(Qt::white);				//重新刷新pix对象为白色底色
    QPainter *painter = new QPainter;	//创建一个QPainter对象
    QPen pen(Qt::DotLine);
    for(int i=step;i<width;i=i+step)	//按照步进值的间隔绘制纵向的网格线
    {
        painter->begin(pix);			//指定pix为绘图设备
        painter->setPen(pen);
        painter->drawLine(QPoint(i,0),QPoint(i,height));
        painter->end();
    }
    for(int j=step;j<height;j=j+step)	//按照步进值的间隔绘制横向的网格线
    {
        painter->begin(pix);
        painter->setPen(pen);
        painter->drawLine(QPoint(0,j),QPoint(width,j));
        painter->end();
    }
    painter->begin(pix);
    painter->drawImage(QPoint(startX,startY),image);
    painter->end();
}
  • QPen pen(Qt::DotLine):创建一个QPen对象,设置画笔的线型为Qt::DotLine,用于绘制网格。
  • painter->drawImage(QPoint(startX,startY),image):在pix对象中绘制可移动的小图标。

keyPressEvent函数处理键盘的按下事件处理代码如下:

void KeyEvent::keyPressEvent(QKeyEvent *event)
{
    if(event->modifiers()==Qt::ControlModifier)
    {
        if(event->key()==Qt::Key_Left)
        {
            startX=(startX-1<0)?startX:startX-1;
        }
        if(event->key()==Qt::Key_Right)
        {
            startX=(startX+1+image.width()>width)?startX:startX+1;
        }
        if(event->key()==Qt::Key_Up)
        {
            startY=(startY-1<0)?startY:startY-1;
        }
        if(event->key()==Qt::Key_Down)
        {
            startY=(startY+1+image.height()>height)?startY:startY+1;
        }
    }
    else    //对【Ctrl】键没有按下的处理
    {
        /* 首先调节图标左上顶点的位置至网格的顶点上 */
        startX=startX-startX%step;
        startY=startY-startY%step;
        if(event->key()==Qt::Key_Left)
        {
            startX=(startX-step<0)?startX:startX-step;
        }
        if(event->key()==Qt::Key_Right)
        {
            startX=(startX+step+image.width()>width)?startX:startX+step;
        }
        if(event->key()==Qt::Key_Up)	
        {
            startY=(startY-step<0)?startY:startY-step;
        }
        if(event->key()==Qt::Key_Down)
        {
            startY=(startY+step+image.height()>height)?
            startY:startY+step;
        }
        if(event->key()==Qt::Key_Home)
        {
            startX=0;
            startY=0;
        }
        if(event->key()==Qt::Key_End)
        {
            startX=width-image.width();
            startY=height-image.height();
        }
    }
    drawPix();		//根据调整后的图标位置重新在pix中绘制图像
    update();		//触发界面重画
}
  • if(event->modifiers()==Qt::ControlModifier):判断修饰键Ctrl是否按下。Qt::KeyboardModifier定义了一系列修饰键,如下所示。
    • Qt::NoModifier:没有修饰键按下。
    • Qt::ShiftModifier:Shift键按下。
    • Qt::ControlModifier:Ctrl键按下。
    • Qt::AltModifier:Alt键按下。
    • Qt::MetaModifier:Meta键按下。
    • Qt::KeypadModifier:小键盘按键按下。
    • Qt::GroupSwitchModifier:Mode switch键按下。
  • if(event->key()==Qt::Key_Left):根据按下的左方向键调节图标的左顶点的位置,按下Ctrl键时步进值1,即细微移动。没按下步进值为网格大小。
  • if(event->key()==Qt::Key_Right):根据按下的右方向键调节图标的左顶点的位置,按下Ctrl键时步进值1,即细微移动。没按下步进值为网格大小。
  • if(event->key()==Qt::Key_Up):根据按下的上方向调节图标的坐上顶点的位置,按下Ctrl键时步进值1,即细微移动。没按下步进值为网格大小。
  • if(event->key()==Qt::Key_Down):根据按下的下方向调节图标的坐上顶点的位置,按下Ctrl键时步进值1,即细微移动。没按下步进值为网格大小。
  • if(event->key()==Qt::Key_Home):如果按下Home键,则恢复图标位置为界面的左上顶点。
  • if(event->key()==Qt::Key_End):如果按下End键,则将图标位置设置为界面的右下顶点,这里注意需要考虑图标自身的大小。

界面重绘函数paintEvent,将pix绘制到界面上。函数功能代码如下:

void KeyEvent::paintEvent(QPaintEvent *)
{
    QPainter painter;
    painter.begin(this);
    painter.drawPixmap(QPoint(0,0),*pix);
    painter.end();
}

事件过滤及实例

Qt的事件模型中提供的事件过滤器功能使得一个QObject对象可以监视另一个QObject对象中的事件,通过在一个QObject对象中安装事件过滤器,可以在事件到达该对象前捕获事件,从而起到监视该对象的作用。
例如,Qt已经提供了QPushButton用于表示一个普通的按键类。如果需要实现一个动态的图片按钮,即当鼠标按下时按钮图片发生变化,则需要同时响应鼠标按下等事件。

创建一个EventFilter项目,通过事件过滤器实现动态图片按钮效果,如下图所示。
在这里插入图片描述
构造界面时对控件调用installEventFilter函数注册过滤器。过滤器代码功能实现如下:

bool EventFilter::eventFilter(QObject *watched, QEvent *event)
{
    if(watched==label1)			//首先判断当前发生事件的对象
    {
        //判断发生的事件类型
        if(event->type()==QEvent::MouseButtonPress)
        {
            //将事件event转化为鼠标事件
            QMouseEvent *mouseEvent=(QMouseEvent *)event;
            /* 以下根据鼠标的按键类型分别显示 */
            if(mouseEvent->buttons()&Qt::LeftButton)
            {
                stateLabel->setText(QStringLiteral("左键按下左边图片"));
            }
            else if(mouseEvent->buttons()&Qt::MidButton)
            {
                stateLabel->setText(QStringLiteral("中键按下左边图片"));
            }
            else if(mouseEvent->buttons()&Qt::RightButton)
            {
                stateLabel->setText(QStringLiteral("右键按下左边图片"));
            }
            /* 显示缩小的图片 */
            QMatrix matrix;
            matrix.scale(1.8,1.8);
            QImage tmpImg=Image1.transformed(matrix);
            label1->setPixmap(QPixmap::fromImage(tmpImg));
        }
        /* 鼠标释放事件的处理,恢复图片的大小 */
        if(event->type()==QEvent::MouseButtonRelease)
        {
            stateLabel->setText(QStringLiteral("鼠标释放左边图片"));
            label1->setPixmap(QPixmap::fromImage(Image1));
        }
    }
    else if(watched==label2)
    {
        if(event->type()==QEvent::MouseButtonPress)
        {
            //将事件event转化为鼠标事件
            QMouseEvent *mouseEvent=(QMouseEvent *)event;
            /* 以下根据鼠标的按键类型分别显示 */
            if(mouseEvent->buttons()&Qt::LeftButton)
            {
                stateLabel->setText(QStringLiteral("左键按下中间图片"));
            }
            else if(mouseEvent->buttons()&Qt::MidButton)
            {
                stateLabel->setText(QStringLiteral("中键按下中间图片"));
            }
            else if(mouseEvent->buttons()&Qt::RightButton)
            {
                stateLabel->setText(QStringLiteral("右键按下中间图片"));
            }
            /* 显示缩小的图片 */
            QMatrix matrix;
            matrix.scale(1.8,1.8);
            QImage tmpImg=Image2.transformed(matrix);
            label2->setPixmap(QPixmap::fromImage(tmpImg));
        }
        /* 鼠标释放事件的处理,恢复图片的大小 */
        if(event->type()==QEvent::MouseButtonRelease)
        {
            stateLabel->setText(QStringLiteral("鼠标释放中间图片"));
            label2->setPixmap(QPixmap::fromImage(Image2));
        }
    }
    else if(watched==label3)
    {
        if(event->type()==QEvent::MouseButtonPress)
        {
            //将事件event转化为鼠标事件
            QMouseEvent *mouseEvent=(QMouseEvent *)event;
            /* 以下根据鼠标的按键类型分别显示 */
            if(mouseEvent->buttons()&Qt::LeftButton)
            {
                stateLabel->setText(QStringLiteral("左键按下右边图片"));
            }
            else if(mouseEvent->buttons()&Qt::MidButton)
            {
                stateLabel->setText(QStringLiteral("中键按下右边图片"));
            }
            else if(mouseEvent->buttons()&Qt::RightButton)
            {
                stateLabel->setText(QStringLiteral("右键按下右边图片"));
            }
            /* 显示缩小的图片 */
            QMatrix matrix;
            matrix.scale(1.8,1.8);
            QImage tmpImg=Image3.transformed(matrix);
            label3->setPixmap(QPixmap::fromImage(tmpImg));
        }
        /* 鼠标释放事件的处理,恢复图片的大小 */
        if(event->type()==QEvent::MouseButtonRelease)
        {
            stateLabel->setText(QStringLiteral("鼠标释放右边图片"));
            label3->setPixmap(QPixmap::fromImage(Image3));
        }
    }
    //将事件交给上层对话框
    return QDialog::eventFilter(watched,event);
}

工程源码

文章涉及所有代码可点击工程源码下载。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

后端之路第三站(Mybatis)——入门配置

一、Mybatis是啥&#xff1f; 就是一个用java来操控数据库的框架语言 之前学的datagrip或者navicat这些软件里我们操作数据库&#xff0c;原理是我们编写完的操作语句发送到服务器传送到数据库系统&#xff0c;然后数据库执行完之后再发送给服务器返回给datagrip或者navicat显…

独立开发者系列(13)——示例理解面向对象与过程

专业术语晦涩难懂&#xff0c;特别是当你没有写过稍微大点的系统的时候&#xff0c;你要理解这里面的区别很难。 从最简单的早期我们学习开始&#xff0c;我们除了练习hello world掌握了入门函数之后&#xff0c;基本都再练习算法。比如水仙花数的获取&#xff0c;冒泡排序&…

phpMyAdmin | mysqli::real_connect(): (HY000/2002): No such file or directory

法一&#xff1a;第一次安装宝塔 第一次安装宝塔mysql服务是默认关闭的&#xff0c;需要手动打开&#xff0c;打开服务再次进入phpMyAdmin发现可以进入了 法二&#xff1a;第一种方法没解决用这种 出现mysqli::real_connect(): (HY000/2002): No such file or directory错误通…

Java | Leetcode Java题解之第206题反转链表

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode reverseList(ListNode head) {if (head null || head.next null) {return head;}ListNode newHead reverseList(head.next);head.next.next head;head.next null;return newHead;} }

ROS2自定义接口Python实现机器人移动

1.创建机器人节点接口 cd chapt3_ws/ ros2 pkg create example_interfaces_rclpy --build-type ament_python --dependencies rclpy example_ros2_interfaces --destination-directory src --node-name example_interfaces_robot_02 --maintainer-name "Joe Chen" …

20240630 每日AI必读资讯

&#x1f4da;全美TOP 5机器学习博士发帖吐槽&#xff1a;实验室H100数量为0&#xff01; - 普林斯顿、哈佛「GPU豪门」&#xff0c;手上的H100至少三四百块&#xff0c;然而绝大多数ML博士一块H100都用不上 - 年轻的研究者们纷纷自曝自己所在学校或公司的GPU情况&#xff1a…

vue开发网站--关于window.print()调取打印

1.vue点击按钮调取打印 点击按钮&#xff1a; 调取打印该页面&#xff1a; <div click"clickDown()">下载</div>methods: {//下载-调取打印clickDown() {window.print()}, }<style>/* 点击打印的样式 */media print {.clickDown {display: no…

【测试】软件测试规程(word原件)

软件测试规程的作用在于确保软件测试活动的系统性、规范性和一致性。它明确了测试的目标、范围、方法、流程以及所需资源&#xff0c;为测试人员提供了明确的指导和操作规范。通过遵循测试规程&#xff0c;可以提高测试效率&#xff0c;减少测试遗漏和错误&#xff0c;保证软件…

K8S基础简介

用于自动部署&#xff0c;扩展和管理容器化应用程序的开源系统。 功能&#xff1a; 服务发现和负载均衡&#xff1b; 存储编排&#xff1b; 自动部署和回滚&#xff1b; 自动二进制打包&#xff1b; 自我修复&#xff1b; 密钥与配置管理&#xff1b; 1. K8S组件 主从方式架…

神经网络原理

神经网络原理是一种模拟人脑的机器学习技术&#xff0c;通过大量的神经元和层次化的连接进行信息处理和学习。 图1 神经元 神经网络由许多简单的计算单元或“神经元”组成&#xff0c;这些神经元通过连接传递信息。每个连接都有一个权重&#xff0c;用于调整传递的信号强度。这…

【Red Hat】 Red Hat 系统提示未注册订阅管理,并进行阿里yum源更新的解决方案

目录 &#x1f30a;1. 问题说明 &#x1f30a;2. 解决方案 &#x1f30d;2.1 Redhat 官网注册与订阅 &#x1f30d;2.2 Redhat 登录已订阅账号 &#x1f30d;2.3 更换 Redhat 为阿里yum源 &#x1f30d;2.4 验证 &#x1f30a;1. 问题说明 使用 yum makecache 或 yum up…

内网渗透:端口转发(SSH隧道)

SSH&#xff1a;两台设备之间进行远程登录的协议&#xff08;SSH本身就是一个隧道协议&#xff09; 远程文件传输scp命令&#xff08;scp是基于SSH的&#xff09; 拓扑&#xff1a; SSH隧道搭建的条件 1.获取到跳板机权限 2.跳板机中SSH服务启动 SSH端口转发分类&#xff1…

【工具分享】SQLmap

文章目录 工具介绍安装方式环境准备安装 sqlmap 工具介绍 sqlmap 是一个非常强大的自动化 SQL 注入工具&#xff0c;主要用于渗透测试和安全审计。它能够检测和利用 SQL 注入漏洞&#xff0c;进而访问数据库服务器。 GitHub&#xff1a;https://github.com/sqlmapproject/sql…

为什么IP地址会被列入黑名单?

您是否曾经历过网站访客数量骤减或电子邮件投递失败的困扰&#xff1f;这背后或许隐藏着一个常被忽略的原因&#xff1a;您的IP地址可能已经被列入了黑名单内。尽管您并没有进行任何违法的网络操作&#xff0c;但这个问题依然可能出现。那么&#xff0c;究竟黑名单是什么&#…

通过Python脚本实现字符画

效果 讲解&#xff1a; 用于将3D视图的帧缓冲区转换为字符画&#xff0c;并将字符画输出到文本编辑器中。 首先&#xff0c;获取当前绑定的帧缓冲区、视口信息和视图像素。 然后&#xff0c;将像素矩阵转化为字符串&#xff0c;并将字符串写入到文本编辑器中。 设置文本编辑…

【Lua】第三篇:基本变量类型介绍

文章目录 一. 变量类型介绍二. 基本知识三. 基本类型介绍1. 空类型&#xff08;nil&#xff09;2. 数值类型&#xff08;number&#xff09;3. 字符串类型&#xff08;string&#xff09;4. 布尔类型&#xff08;boolean&#xff09; 一. 变量类型介绍 Lua中一共有如下8中变量…

Nosql期末复习

mongodb基本常用命令&#xff08;只要掌握所有实验内容就没问题&#xff09; 上机必考&#xff0c;笔试试卷可能考&#xff1a; 1.1 数据库的操作 1.1.1 选择和创建数据库 &#xff08;1&#xff09;use dbname 如果数据库不存在则自动创建&#xff0c;例如&#xff0c;以下…

设计模式 - 原型模式,就该这样学!

目录 开始 为什么要引入原型模式 原型模式概述 原型模式代码实现&#xff08;浅拷贝&#xff09; 浅拷贝和深拷贝的区别 原型模式代码实现&#xff08;深拷贝&#xff09; 方式一&#xff1a;直接 copy 方式二&#xff1a;序列化和反序列化&#xff08;推荐&#xff09…

ApolloClient GraphQL 与 ReactNative

要在 React Native 应用程序中设置使用 GraphQL 的简单示例&#xff0c;您需要遵循以下步骤&#xff1a; 设置一个 React Native 项目。安装 GraphQL 必要的依赖项。创建一个基本的 GraphQL 服务器&#xff08;或使用公共 GraphQL 端点&#xff09;。从 React Native 应用中的…

window下git bash设置启动后默认路径进入自己的工程

方法一&#xff1a;更改快捷方式 方法二&#xff1a;修改~/.bashrc
最新文章