Qt触摸屏双指缩放和单指移动界面(支持嵌入式设备)
本文介绍的QGraphicsView的双指缩放,QWidget更简单,可以参考当前内容。
方法一:(QTouchEvent事件实现)
使用场景:适用于paintevent绘制下的界面。
优点:不需要代码设置中心锚点(锚点:视图变化期间通过此点定位场景)。
缺点:界面上所有其它操作无法响应,需单独做处理才能做相应。(无法响应原因是使用了”return true“打断了”触摸点击“转化为”鼠标点击“。但是不使用”retuen true“又会造成”触摸点击“默认转化成了”鼠标点击“,触摸操作无法过度到TouchUpdate中来捕获到多点触摸了。)
使用步骤:
1、首先需要打开触摸屏功能。
this->setAttribute(Qt::WA_AcceptTouchEvents);
2、在event事件管理器中接收触摸屏的三个事件,TouchBegin、TouchUpdate和TouchEnd。
3、判断单点触摸还是多点触摸。
4、如果多点触摸,通过比较前后两次两点间触摸位置来判断是放大还是缩小。
5、多点触摸时,会存在抖动情况,需要做防抖处理。
6、如果是单点触摸,通过比较手指放上去的位置和手指拖动时的位置来设置界面滚动条的位置。
代码:
属性设置
this->setAttribute(Qt::WA_AcceptTouchEvents);
缩放和移动逻辑
bool MGraaphicsView::event(QEvent *e)
{static int index = 0;switch (e->type()) {case QEvent::TouchBegin:case QEvent::TouchUpdate:case QEvent::TouchEnd:{qDebug() <<"CProjectionPicture::event"<<e->type();QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e);QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();if (touchPoints.count() == 2) {//缩放const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();qreal currentScaleFactor = QLineF(touchPoint0.pos(), touchPoint1.pos()).length()/ QLineF(touchPoint0.startPos(), touchPoint1.startPos()).length();if (currentScaleFactor > _lastScaleFactor)index++;else if (currentScaleFactor < _lastScaleFactor)index--;if (index == 5)//超过5次放大,则认为有效.防抖操作{index = 0;zoomOnce(true);}else if (index == -5){index = 0;zoomOnce(false);}qDebug()<<index<<currentScaleFactor<<_lastScaleFactor;_lastScaleFactor = currentScaleFactor;update();}else if (touchPoints.count() == 1){//移动 const QTouchEvent::TouchPoint &touchPoint = touchPoints.first();if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchEnd)_startScenePos = mapToScene(touchPoint.pos().toPoint());if (e->type() == QEvent::TouchUpdate){QPointF endScenePos = mapToScene(touchPoint.pos().toPoint());QPointF delta = endScenePos - _startScenePos;int oposx = this->horizontalScrollBar()->value();int oposy = this->verticalScrollBar()->value();int nposx = oposx - delta.x();int nposy = oposy - delta.y();this->horizontalScrollBar()->setValue(nposx);this->verticalScrollBar()->setValue(nposy);}qDebug()<<"====="<<_startScenePos<<touchPoint.pos();}if (touchEvent->touchPointStates() & Qt::TouchPointReleased){qDebug()<<"Qt::TouchPointReleased";}return true;//一定不要调QGraphicsView::event(e);否则手指触摸会经常失效}default:break;}return QGraphicsView::event(e);
}
//缩放
void MGraaphicsView::zoomOnce(bool increase)
{if (increase)setZoom(1);elsesetZoom(-1);
}void MGraaphicsView::setZoom(int val)
{if (val > 0){m_zoom++;auto scaleValue = qPow(2, m_zoom);setTransform(QTransform::fromScale(scaleValue, scaleValue));}else{m_zoom--;auto scaleValue = qPow(2, m_zoom);setTransform(QTransform::fromScale(scaleValue, scaleValue));}
}
方法二:(QGesture事件实现)
使用场景:适用所有场景。
优点:界面上界面上所有操作都不受影响。
缺点:需要代码定位视图锚点。(QGraphicsView需要定位视图锚点,如果是QWidget则不需要定位锚点这一步,缩放大小和位置代码设置即可。)
使用步骤:
1、首先需要打开触摸屏功能和注册缩放手势。
grabGesture(Qt::PinchGesture);//”捏“手势
this->setAttribute(Qt::WA_AcceptTouchEvents);
所有手势介绍: enum GestureType {TapGesture = 1, //轻拍手势。(1个手指单击)TapAndHoldGesture = 2, //轻触并保持(长按)手势。(1个手指单击并长按)PanGesture = 3, //平移手势。(1个手指拖动)PinchGesture = 4, //捏合缩放及缩放(2个手指捏合或转动)SwipeGesture = 5, //滑动手势。(3个手指平移)CustomGesture = 0x0100, //可用于测试手势是否为用户定义的手势ID的标志。 };
自定义手势
2、在event事件管理器中接收QEvent::Gesture事件,并转化为QGestureEvent事件。
3、获取”捏“手势,并转化为QPinchGesture事件。
4、获取”捏“手势变化状态。
5、判断捏手势变化状态,根据QPinchGesture::ScaleFactorChanged状态变化计算缩放比例。
6、在GestureUpdated的变化下,根据缩放比例来处理缩小和扩大。
代码:
bool InteractiveMap::event(QEvent *e)
{static int index = 0;
#if 1if (e->type() == QEvent::Gesture){QGestureEvent* gEvent = static_cast<QGestureEvent *>(e);if (QGesture* pinch = gEvent->gesture(Qt::PinchGesture)){QPinchGesture* pEvent = static_cast<QPinchGesture *>(pinch);QPinchGesture::ChangeFlags changeFlags = pEvent->changeFlags();//旋转角度的变化记录if (changeFlags & QPinchGesture::RotationAngleChanged){
// qreal rotationDelta = pEvent->rotationAngle() - pEvent->lastRotationAngle();
// qDebug() << "pinchTriggered(): rotate by" << rotationDelta;}static qreal s_factor = 1.;//缩放比例的变化记录if (changeFlags & QPinchGesture::ScaleFactorChanged){s_factor *= pEvent->totalScaleFactor();}int id = (int)pEvent->state();switch (id){case Qt::GestureStarted:case Qt::GestureUpdated:{//视图在变换期间应如何定位场景。//QGraphicsView使用此属性来决定在变换矩阵发生变化以及视图的坐标系发生变换时如何在视口中定位场景。//默认行为AnchorViewCenter可确保视图中心的场景点在变换期间保持不变(例如,旋转时,场景将显示为围绕视图中心旋转)。setTransformationAnchor(QGraphicsView::AnchorViewCenter); //视图中心的场景点用作锚点if (s_factor > 1)index++;elseindex--;if (index == 5) //超过5次放大,则认为有效.防抖操作{index = 0;zoomOnce(true);}else if (index == -5){index = 0;zoomOnce(false);}setTransformationAnchor(QGraphicsView::AnchorUnderMouse); //鼠标下方的点用作锚点。}break;case Qt::GestureFinished:default:{s_factor = 1.;}break;}}}return QGraphicsView::event(e);
}
void MGraaphicsView::zoomOnce(bool increase)
{if (increase)setZoom(1);elsesetZoom(-1);
}void MGraaphicsView::setZoom(int val)
{if (val > 0){m_zoom++;auto scaleValue = qPow(2, m_zoom);setTransform(QTransform::fromScale(scaleValue, scaleValue));}else{m_zoom--;auto scaleValue = qPow(2, m_zoom);setTransform(QTransform::fromScale(scaleValue, scaleValue));}
}
相关文章:
Qt触摸屏双指缩放和单指移动界面(支持嵌入式设备)
本文介绍的QGraphicsView的双指缩放,QWidget更简单,可以参考当前内容。 方法一:(QTouchEvent事件实现) 使用场景:适用于paintevent绘制下的界面。 优点:不需要代码设置中心锚点(锚点…...
【Linux】虚拟机安装Linux、客户端工具,MobaXterm的使用,Linux常用命令
目录 一,安装Linux的centos7版本 具体安装步骤: 二,Linux常见的命令: 三、安装客户端工具 1、介绍 2、安装MobaXterm 3、换源 四、拍照功能 一,安装Linux的centos7版本 介绍: 具体安装步骤&#…...
springboot-scanBasePackages包扫描
目录 原因: 方式一: 方式二: 原因: 由于对rocketMq进行了一次封装,mq模块里面引用了RocketMQTemplate的bean,如果只引入jar包的依赖,启动的时候不会报错,但是在调用到 RocketMQT…...
【C语言数据结构——————排序(1万字)】
文章目录 排序的概念 常见排序算法分类冒泡排序 时间复杂度稳定性 原理实现插入排序 时间复杂度稳定性实现选择排序 时间复杂度稳定性实现希尔排序 时间复杂度稳定性希尔排序的算法思想实现 优化快速排序 时间复杂度空间复杂度稳定性实现 三数取中优化归并排序 时间复杂度空间复…...
PyTorch基础(18)-- torch.stack()方法
一、方法详解 首先,看一下stack的直观解释,动词可以简单理解为:把……放成一堆、把……放成一摞。 有了对stack方法的直观感受,接下来,我们正式解析torch.stack方法。 PyTorch torch.stack() method joins (concaten…...
从lc560“和为 K 的子数组“带你认识“前缀和+哈希表“的解题思路
1 前缀和哈希表解题的几道题目:建议集中练习 560. 和为 K 的子数组:https://leetcode.cn/problems/subarray-sum-equals-k/ 1248. 统计「优美子数组」: https://leetcode.cn/problems/count-number-of-nice-subarrays/ 1249. 和可被 K 整除的子数组(利用…...
c:变参函数:汇编解析;va_list;marco 宏:__VA_ARGS__
文章目录 参考gcc 内部的宏定义代码汇编调用在 SEI CERT C Coding Standard 这个标准里示例实例宏里的使用 参考 https://git.sr.ht/~gregkh/presentation-security/blob/3547183843399d693c35b502cf4a313e256d0dd8/security-stuff.pdf gcc 内部的宏定义 宏定义:…...
eclipse安装教程(2021版)
第一步:下载JDK (下载地址) Java SE - Downloads 第二步 根据自己电脑的系统,选择相应的版本x64代表64位,x86代表32位。点击相应的JDK进行下载 点击之后会出现一个对话框 同意之后下载。(记住下载到哪,打…...
计算机网络重点概念整理-第二章 物理层【期末复习|考研复习】
第二章 物理层 【期末复习|考研复习】 计算机网络系列文章传送门: 第一章 计算机网络概述 第二章 物理层 第三章 数据链路层 第四章 网络层 第五章 传输层 第六章 应用层 第七章 网络安全 计算机网络整理-简称&缩写 文章目录 第二章 物理层 【期末复习|考研复习…...
【计算机网络】从输入URL到页面都显示经历了什么??
文字总结 ① DNS 解析:当用户输入一个网址并按下回车键的时候,浏览器获得一个域名,而在实际通信过程中,我们需要的是一个 IP 地址,因此我们需要先把域名转换成相应 IP 地址。浏览器会首先从缓存中找是否存在域名&…...
[C++]——带你学习类和对象
类和对象——上 目录:一、面向过程和面向对象二、类的概念三、类的访问限定符和封装3.1 访问限定符3.2 封装 四、类的作用域五、类的实例化六、类的对象大小的计算七、类成员函数this指针7.1 this指针的引用7.2 this 指针的特性 目录: 类和对象是很重要…...
Docker多平台、跨平台编译打包
大多数带有Docker官方标识的镜像都提供了多架构支持。如:busybox镜像支持amd64, arm32v5, arm32v6, arm32v7, arm64v8, i386, ppc64le, and s390x。当你在amd64设备上运行容器时,会拉取amd64镜像。 当你需要构建多平台镜像时,可以用 --platf…...
LLM系列 | 22 : Code Llama实战(下篇):本地部署、量化及GPT-4对比
引言 模型简介 依赖安装 模型inference 代码补全 4-bit版模型 代码填充 指令编码 Code Llama vs ChatGPT vs GPT4 小结 引言 青山隐隐水迢迢,秋尽江南草未凋。 小伙伴们好,我是《小窗幽记机器学习》的小编:卖热干面的小女孩。紧接…...
Nginx的进程结构实例演示
可以参考《Ubuntu 20.04使用源码安装nginx 1.14.0》安装nginx 1.14.0。 nginx.conf文件中worker_processes 2;这条语句表明启动两个worker进程。 sudo /nginx/sbin/nginx -c /nginx/conf/nginx.conf开启nginx。 ps -ef | grep nginx看一下进程情况。 sudo /nginx/sbin/ng…...
【Nginx36】Nginx学习:SSI静态文件服务器端包含模块
Nginx学习:SSI静态文件服务器端包含模块 这个模块让我想到了 2009 年刚刚工作的时候。最早我是做 .NET 的,而第一家公司其实是从 ASP 向 ASP.NET 转型中,因此,还是有不少的 ASP 做的页面。在那个时候,就用到了 SSI 。 …...
StripedFly恶意软件框架感染了100万台Windows和Linux主机
导语 近日,一款名为StripedFly的恶意软件框架在网络安全研究人员的监视之外悄然感染了超过100万台Windows和Linux系统。这款跨平台的恶意软件平台在过去的五年中一直未被察觉。在去年,卡巴斯基实验室发现了这个恶意框架的真实本质,并发现其活…...
蓝桥杯每日一题2023.10.25
乘积尾零 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 由于需要相乘的数很多,所以我们不能直接进行暴力模拟,我们知道10 2 * 5, 所以我们只需要找出这个数2和5的个数,其中2和5个数小的那个则为末尾0出现的个数 #include<bi…...
【C++】详解map和set基本接口及使用
文章目录 一、关联式容器与键值对1.1关联式容器(之前学的都是序列容器)1.2键值对pairmake_pair函数(map在插入的时候会很方便) 1.3树形结构的关联式容器 二、set2.1set的基本介绍2.1默认构造、迭代器区间构造、拷贝构造࿰…...
如何学习 Linux 内核内存管理
Linux内核内存管理部分是Linux内核中第二复杂的部分,但也非常有趣。学习它的最佳方法就是阅读代码。但在不了解术语和当前 mm 部分到底发生了什么的情况下,显然不能随意开始阅读代码。因此,我想这样开始学习比较好: 了解当前的 LS…...
【计算机网络】(谢希仁第八版)第一章课后习题答案
1.计算机网络可以向用户提供哪些服务? 答:例如音频,视频,游戏等,但本质是提供连通性和共享这两个功能。 连通性:计算机网络使上网用户之间可以交换信息,好像这些用户的计算机都可以彼此直接连…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
