交互式QGraphicsView(平移/缩放/旋转)

一 简述

Graphics View提供了一个平台,用于大量自定义 2D 图元的管理与交互,框架包括一个事件传播架构,支持场景 Scene 中的图元 Item 进行精确的双精度交互功能。Item 可以处理键盘事件、鼠标按下、移动、释放和双击事件,同时也能跟踪鼠标移动。

和 Google 地图一样,在管理大量 Item 的时候,通常需要 View 具有交互(平移/缩放/旋转)功能。

二 交互式 QGraphicsView

便于以后复用,实现一个交互式 QGraphicsView - InteractiveView。

主要功能包括:

平移:

1. 方式一:鼠标左键按下,然后移动

2.方式二:按下上/下/左/右键分别向各个方向移动

缩放:

1. 方式一:鼠标滚轮向上滚动放大,向下滚动缩小

2. 方式二:按加号键(带 Shift)进行放大,按减号键缩小

旋转:

按空格键逆时针旋转,回车键顺时针旋转

三 效果

四 源码

interactive_view.h

#ifndef INTERACTIVE_VIEW_H
#define INTERACTIVE_VIEW_H
#include <QGraphicsView>
class QWheelEvent;
class QKeyEvent;
class InteractiveView : public QGraphicsView
{Q_OBJECT
public:explicit InteractiveView(QWidget *parent = 0);// 平移速度void setTranslateSpeed(qreal speed);qreal translateSpeed() const;// 缩放的增量void setZoomDelta(qreal delta);qreal zoomDelta() const;
protected:// 上/下/左/右键向各个方向移动、加/减键进行缩放、空格/回车键旋转void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;// 平移void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;// 放大/缩小void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
public Q_SLOTS:void zoomIn();  // 放大void zoomOut();  // 缩小void zoom(float scaleFactor); // 缩放 - scaleFactor:缩放的比例因子void translate(QPointF delta);  // 平移
private:Qt::MouseButton m_translateButton;  // 平移按钮qreal m_translateSpeed;  // 平移速度qreal m_zoomDelta;  // 缩放的增量bool m_bMouseTranslate;  // 平移标识QPoint m_lastMousePos;  // 鼠标最后按下的位置qreal m_scale;  // 缩放值
};
#endif // INTERACTIVE_VIEW_H

平移速度默认为 1.0,可以使用 setTranslateSpeed() 来改变。缩放的增量大小也可以使用 setZoomDelta() 改变。

interactive_view.cpp

#include <QWheelEvent>
#include <QKeyEvent>
#include "interactive_view.h"
#define VIEW_CENTER viewport()->rect().center()
#define VIEW_WIDTH  viewport()->rect().width()
#define VIEW_HEIGHT viewport()->rect().height()
InteractiveView::InteractiveView(QWidget *parent): QGraphicsView(parent),m_translateButton(Qt::LeftButton),m_scale(1.0),m_zoomDelta(0.1),m_translateSpeed(1.0),m_bMouseTranslate(false)
{// 去掉滚动条setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);setCursor(Qt::PointingHandCursor);setRenderHint(QPainter::Antialiasing);setSceneRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX);centerOn(0, 0);
}
// 平移速度
void InteractiveView::setTranslateSpeed(qreal speed)
{// 建议速度范围Q_ASSERT_X(speed >= 0.0 && speed <= 2.0,"InteractiveView::setTranslateSpeed", "Speed should be in range [0.0, 2.0].");m_translateSpeed = speed;
}
qreal InteractiveView::translateSpeed() const
{return m_translateSpeed;
}
// 缩放的增量
void InteractiveView::setZoomDelta(qreal delta)
{// 建议增量范围Q_ASSERT_X(delta >= 0.0 && delta <= 1.0,"InteractiveView::setZoomDelta", "Delta should be in range [0.0, 1.0].");m_zoomDelta = delta;
}
qreal InteractiveView::zoomDelta() const
{return m_zoomDelta;
}
// 上/下/左/右键向各个方向移动、加/减键进行缩放、空格/回车键旋转
void InteractiveView::keyPressEvent(QKeyEvent *event)
{switch (event->key()) {case Qt::Key_Up:translate(QPointF(0, -2));  // 上移break;case Qt::Key_Down:translate(QPointF(0, 2));  // 下移break;case Qt::Key_Left:translate(QPointF(-2, 0));  // 左移break;case Qt::Key_Right:translate(QPointF(2, 0));  // 右移break;case Qt::Key_Plus:  // 放大zoomIn();break;case Qt::Key_Minus:  // 缩小zoomOut();break;case Qt::Key_Space:  // 逆时针旋转rotate(-5);break;case Qt::Key_Enter:  // 顺时针旋转case Qt::Key_Return:rotate(5);break;default:QGraphicsView::keyPressEvent(event);}
}
// 平移
void InteractiveView::mouseMoveEvent(QMouseEvent *event)
{if (m_bMouseTranslate){QPointF mouseDelta = mapToScene(event->pos()) - mapToScene(m_lastMousePos);translate(mouseDelta);}m_lastMousePos = event->pos();QGraphicsView::mouseMoveEvent(event);
}
void InteractiveView::mousePressEvent(QMouseEvent *event)
{if (event->button() == m_translateButton) {// 当光标底下没有 item 时,才能移动QPointF point = mapToScene(event->pos());if (scene()->itemAt(point, transform()) == NULL)  {m_bMouseTranslate = true;m_lastMousePos = event->pos();}}QGraphicsView::mousePressEvent(event);
}
void InteractiveView::mouseReleaseEvent(QMouseEvent *event)
{if (event->button() == m_translateButton)m_bMouseTranslate = false;QGraphicsView::mouseReleaseEvent(event);
}
// 放大/缩小
void InteractiveView::wheelEvent(QWheelEvent *event)
{// 滚轮的滚动量QPoint scrollAmount = event->angleDelta();// 正值表示滚轮远离使用者(放大),负值表示朝向使用者(缩小)scrollAmount.y() > 0 ? zoomIn() : zoomOut();
}
// 放大
void InteractiveView::zoomIn()
{zoom(1 + m_zoomDelta);
}
// 缩小
void InteractiveView::zoomOut()
{zoom(1 - m_zoomDelta);
}
// 缩放 - scaleFactor:缩放的比例因子
void InteractiveView::zoom(float scaleFactor)
{// 防止过小或过大qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();if (factor < 0.07 || factor > 100)return;scale(scaleFactor, scaleFactor);m_scale *= scaleFactor;
}
// 平移
void InteractiveView::translate(QPointF delta)
{// 根据当前 zoom 缩放平移数delta *= m_scale;delta *= m_translateSpeed;// view 根据鼠标下的点作为锚点来定位 scenesetTransformationAnchor(QGraphicsView::AnchorUnderMouse);QPoint newCenter(VIEW_WIDTH / 2 - delta.x(),  VIEW_HEIGHT / 2 - delta.y());centerOn(mapToScene(newCenter));// scene 在 view 的中心点作为锚点setTransformationAnchor(QGraphicsView::AnchorViewCenter);
}

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

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

相关文章

golang实现枚举

golang实现枚举 golang实现枚举 golang本身是没有枚举类型的&#xff0c;不像c语言&#xff0c;但是可以通过const & iota实现枚举的能力。 枚举在类似于业务状态或者少量下拉选择框中经常使用&#xff0c;比如 业务状态&#xff1a;待开始、进行中、失败、成功package ma…

福昕阅读器 PDF 文档基本操作

福昕阅读器 PDF 文档基本操作 References 转至 PDF 顶部 快捷键&#xff1a;Home. 转至 PDF 顶部 快捷键&#xff1a;End. 打开超链接 文本选择工具 -> 手形工具 (Hand Tool) -> 点击超链接 福昕阅读器 同时在多个窗口中打开多个文件 文件 -> 偏好设置 -> 文…

高中信息技术教资刷题笔记_选择题篇

1.信息技术基础 位与字节的换算 模2除法运算 网页保存 进制之间的计算 教你快速学会二进制、十进制、十六进制之间的转换 - 知乎 (zhihu.com) 原码、补码、反码计算 物联网技术 位运算 按位与&#xff1a;同位置为1&#xff0c;则为1&#xff0c;其他都是0按位或&#xff1a;有…

黑帽子学Python

黑帽子学Python Python位运算符 运算符描述示例&按位与运算符&#xff1a;参与运算的两个值&#xff0c;如果两个相应位都为1&#xff0c;则该为的结果为1&#xff0c;否则为0(a&b)输出结果12&#xff0c;二进制解释&#xff1a;0000 1100按位或运算符&#xff1a;只…

MRC是谁?- 媒体评级委员会 Media Rating Council

在在线广告的世界里&#xff0c;有许多不同的技术和实践用于提供和衡量广告。对于广告商、出版商和营销人员来说&#xff0c;了解这些技术是如何工作的以及如何有效使用这些技术很重要。在这方面发挥关键作用的一个组织是媒体评级委员会&#xff08;MRC&#xff09;。 1. 了解…

Android 项目新建问题总结

title: Android 项目新建问题总结 search: 2024-03-24 tags: “#Android 项目新建问题总结” Android 项目新建问题总结 一、gradle 项目每次都自动下载依赖包到C盘 背景&#xff1a;idea 首次打开一个 gradle 项目&#xff0c;都会在 C 盘下载项目所需的依赖包&#xff0c;但…

Automatic Prompt Engineering

让大模型自己生成prompt&#xff0c;生成提示&#xff08;prompt&#xff09;存在两种不同的操作方式。第一种方式是在文本空间中进行&#xff0c;这种提示以离散的文本形式存在。第二种方式是将提示抽象成一个向量&#xff0c;在特征空间中进行操作&#xff0c;这种提示是抽象…

React高阶组件(HOC)

高阶组件的基本概念 高阶组件&#xff08;HOC&#xff0c;Higher-Order Components&#xff09;不是组件&#xff0c;而是一个函数&#xff0c;它会接收一个组件作为参数并返回一个经过改造的新组件&#xff1a; const EnhancedComponent higherOrderComponent(WrappedCompo…

Go 实现fsnotify

【官方操作】 package mainimport ("log""github.com/fsnotify/fsnotify" )func main() {watcher, err : fsnotify.NewWatcher()if err ! nil {log.Fatal(err)}defer watcher.Close()done : make(chan bool)go func() {for {select {case event, ok : <…

使用 Docker Compose 部署 Spring Boot 应用

使用 Docker Compose 部署 Spring Boot 应用 第一步&#xff1a;创建 Spring Boot 应用的 Dockerfile 在您的 Spring Boot 项目根目录中创建一个 Dockerfile。 编辑 Dockerfile&#xff0c;添加以下内容&#xff1a; # 基础镜像使用 OpenJDK FROM openjdk:11-jdk-slim# 维护者…

Gitee删除自己本地仓库

1、打开自己的本地仓库 2、点击管理 3、选择删除仓库 4、将□的内容复制到⭕里

mysql 存储引擎 基本介绍

目录 一 存储引擎概念介绍 &#xff08;一&#xff09;存储引擎概念 &#xff08;二&#xff09;MySQL常用的存储引擎 &#xff08;三&#xff09;存储引擎运作方式 二 MyISAM 存储引擎介绍 &#xff08;一&#xff09; MyISAM 存储引擎特点 1&#xff0c;不支持…

基于51单片机数控直流电压源proteus仿真LCD显示+程序+设计报告+讲解视频

基于51单片机数控直流电压源proteus仿真LCD显示( proteus仿真程序设计报告讲解视频&#xff09; 仿真图proteus7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0072 讲解视频 基于51单片机数控直流电压源proteus仿真程序…

手机IP地址如何更换

手机IP地址的修改方法可以通过以下几种方式实现&#xff1a; 1. 手动更改IP地址&#xff1a;打开手机设置&#xff0c;进入网络设置页面&#xff0c;找到IP地址更改选项。在此页面输入新的IP地址和子网掩码&#xff0c;并启用DHCP服务器。请注意&#xff0c;并非所有手机都支持…

博途建立S7-1200PLC与HMS AB7013Profinet通讯

1、新建一个博图项目1200PLC .CPU 1214C ACDC/RIY 6ES7 214-1BG31-0x80 2、安装GSD文件 Install general station description fle (GsD) GSDMLV2.3-HMS-ABC PROFINET GSD 3、连接PLC 4、在线访问 5、增加访问子网络 6、设定IP地址 7、增加AnyBus模块 8、设定模块的IP地址及…

大语言模型(Large Language Model,LLM)简介

1. 什么是大语言模型 它是一种基于深度学习的人工智能模型&#xff0c;它从大量来自书籍、文章、网页和图像等来源的数据中学习&#xff0c;以发现语言模式和规则&#xff0c;如处理和生成自然语言文本。通常&#xff0c;大语言模型含数百亿&#xff08;或更多&#xff09;参数…

Spring Cloud Gateway Server MVC

之前你如果要用spring cloud gateway &#xff0c;就必须是webflux 的&#xff0c;也就是必须是异步响应式编程。不能和spring mvc 一起使用。现在spring cloud 新出了一个可以不用webflux的gateway。 具体使用mvc的gateway步骤如下 普通的Eureka Client的项目 如果你只是想测…

Qt程序可执行文件打包

目录 一、新建一个目录二、命令行2.1 添加临时变量2.2 打包命令 三、添加动态库四、普通 Qt 项目打包 Qml 项目打包 笔者写的python程序打包地址&#xff08;https://blog.csdn.net/qq_43700779/article/details/136994813&#xff09; 一、新建一个目录 新目录(例如test)用以…

超高并发下Redis热点数据风险破解

1 介绍 作者是互联网一线研发负责人,所在业务也是业内核心流量来源,经常参与 业务预定、积分竞拍、商品秒杀等工作。 近期参与多场新员工的面试工作,经常就 『超高并发场景下热点数据』 可用性保障与候选人进行讨论。 本文聚焦一些关键点技术进行讨论,并总结一些热点场景…

js 获取对象的属性名(key)列表

js 获取对象的属性名(key)列表 keys() 方法获取 values()可以获取键值列表 const person {name: "Bill",age: 19,eyeColor: "blue" }; const keys Object.keys(person); console.log(keys)// [name, age, eyeColor]for in 语句获取 const person {na…