《QT从基础到进阶·二十一》QGraphicsView、QGraphicsScene和QGraphicsItem坐标关系和应用
前言:
我们需要先由一个 QGraphicsView,这个是UI显示的地方,也就是装满可见原色的Scene,然后需要一个QGraphicsScene 用来管理所有可见的界面元素,要实现UI功能,我们需要用各种从QGraphicsItem拼装成UI控件,并赋予他控件的逻辑。
简单的说,QGraphicsView代表视图,QGraphicsScene 代表场景,QGraphicsItem代表图形项,QGraphicsItem放在QGraphicsScene 中,QGraphicsScene 放在QGraphicsView中。
1、坐标关系
这是QGraphicsView,始终是以左上角为(0, 0)点,单位为像素

创建场景QGraphicsScene ,并放入视图中:
QGraphicsScene* _scene = new QGraphicsScene();
ui.graphicsView->setScene(_scene);
注意:如果设置scene的坐标和宽高则不能放在构造里,不然不起效果,设置图形项宽高和坐标也不能在构造设置。
scene的坐标怎么看?
先忽略坐标看scene宽高,如果scene宽高小于view宽高,scene默认放到view正中央,
如果scene宽高大于view宽高,view视窗自动出现滚轮,保证view宽高和scene宽高一致
如果scene宽高没有设置,scene中没放图形项前宽高为0,放入图形项后scene宽高会和图形项宽高保持一致且scene宽高和左上角坐标会随着图像同步变化,scene就等同于图像,scene宽高没有设置,scene默认左上角坐标为(0, 0),原点也在左上角。scene宽高没有设置,图像左上角坐标始终与scene左上角坐标重合。

然后看scene的(x, y)坐标,(x, y)坐标为scene左上角坐标,有点特别要注意,不管scene左上角坐标如何变化,scene整体始终处于view正中央。
如果scene的(x, y)为(0, 0),scene的原点也为(0, 0)
如果scene的(x, y)为(-scene->width() / 2, -scene->height() / 2),scene的原点在view正中央。

图像坐标系也是一个独立的坐标系,图像左上角默认为(0, 0)点,把图像放入scene,图像左上角坐标默认在scene的原点,设置图像左上角坐标
pixmapItem->setPos(-scene->width() / 2, -scene->height() / 2);
这样图像左上角和scene左上角重合。
下面草图中继续说明三者坐标关系:

2、view,scene和item三者坐标转换

上图中,图片和矩形都放在QGraphicsItem里,红点为图形项零点(0, 0),因为一旦有了QGraphicsItem,scene会和item重合,所以红点处也为scene零点坐标(0, 0),但区别在于红点往左边一点,sence依然有坐标比如(-1, 0),但item直接返回空,无法计算item坐标,view视图坐标一直都是view显示框左上角为零点。
通过鼠标事件可以拿到视图view的坐标,比如触发mousePressEvent事件:
视图view坐标:
QPoint nViewPoint = event->pos();
通过视图坐标转场景scene坐标:
QPointF fScenePoint = this->mapToScene(nViewPoint);
通过场景坐标转图形项item坐标:
QGraphicsItem* pItem = this->scene()->itemAt(fScenePoint, QTransform()); //图形项指针
if (NULL != pItem)
{QPointF fItemPoint = pItem->mapFromScene(fScenePoint); //获取图形项坐标
}
注意:鼠标在不同的item上比如图片,画的多边形点击一下不仅可以拿到该图形项Item坐标,而且通过pItem拿到对应的item图形项指针!!!!!
获取场景scene中所有Item图形项指针:
QList<QGraphicsItem*> allItems = scene->items();
每个图形项都有一个type标识,可以根据这个标识判断该图形项是图片,矩形,圆等等:
if(allItems[0]->type() == QGraphicsLineItem::Type)//直线
else if(allItems[0]->type() == QGraphicsRectItem::Type)// 矩形
else if(allItems[0]->type() == QGraphicsSimpleTextItem::Type)// 文本
//......
3、在场景scene中绘制不同图形项



有时候我们会遇到这样一个问题:
当我们重新继承一个图形项的类比如QGraphicsRectItem,在自定义类中添加更多的关于矩形的功能,创建矩形对象时却一直画不出矩形?


需要把自定义类强转为QGraphicsRectItem类在设置绘制参数即可画出矩形,如下所示。

通过如上方式画矩形,QGraphicsRectItem会调用自己的paint事件画出矩形,当drawRect继承QGraphicsRectItem,同时又重写了paint方法,假如在drawRect的paint事件里直接return,用上面方法画矩形后会调用drawRect的paint方法然后直接return,当然无法画出矩形。如果重写paint方法又想在重写的paint方法中调用QGraphicsRectItem的paint方法,可以在paint方法中加上
QGraphicsRectItem::paint(painter, option, widget);
这样可以在return之前调用父类的绘画方法画出矩形。
如果在drawRect类中重写paint方法,当我实现了用鼠标画矩形的功能,画出来的矩形用鼠标在矩形上点一下却拿不到矩形的item指针(如下)

原因在于drawRect继承了QGraphicsRectItem,想要显示矩形并能拿到item指针,需要在paint中把drawRect强转为QGraphicsRectItem指针,再把更新的矩形数据QRect设置到QGraphicsRectItem中,那么paint中最后面应该加上如下代码:

另一种原因看不到绘制的图形项:

这里先创建一个矩形设置到sence中,然后再把图片设置到sence,运行后只看到图片看不到画的矩形原因在于sence中的items会根据additem的顺序展示出来,运行程序后先展示矩形,然后展示图片,但图片会覆盖矩形,所以只能看到图片,并不是矩形没有了,如果先additem图片在additem矩形,这样先展示图片,然后会在图片上画出矩形,这样可以正确显示。
4、其他一些补充:
(1)界面变化触发resizeEvent事件,想要图像实时在scene正中央需要在resizeEvent中设置:
m_Scene->setSceneRect(m_PixmapItem->boundingRect());
(2)如果在构造中创建矩形或图片并显示(图片显示m_PixmapItem->setPixmap(pixmap);),运行程序后会显示在view的左上角,这时sence和item的(0,0)点在view的左上角。

如果先创建一个矩形不设置坐标和宽高先创建出来additem到sence,然后等界面运行后通过点击按钮item->setRect(0,0,100,100),这样矩形会显示在view正中间。


(3)对一个item图元可设置焦点,设置可选中,设置可移动
item->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsSelectable |QGraphicsItem::ItemIsMovable );
(4)如果图片很大直接用QPixmap加载有可能在界面上显示不出来,可以先把图片加载成QImage类型,然后再把QImage转为QPixmap即可显示。或者设置图片缓存为0,QPixmapCache::setCacheLimit(0)这个方法有待验证。
(5)图形项的各种事件
void mousePressEvent(QGraphicsSceneMouseEvent* event)
void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
void hoverEnterEvent(QGraphicsSceneHoverEvent* event); //鼠标移入图形项
void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); //鼠标移出图形项
void contextMenuEvent(QGraphicsSceneContextMenuEvent* event); //右击菜单事件
需要注意的是图形项中的鼠标移动事件mouseMoveEvent必须鼠标在图形项上按下移动才能触发,这里没有setMouseTrack设置。使用鼠标在图形项上移入移出事件,需要在构造中加入setAcceptHoverEvents(true);
还有一点需要注意:想要图形项中的事件有相应,必须在继承GraphicsView类中写好对应的事件并在事件中调用父事件使事件透传到item,比如在界面画了一个矩形,想要在矩形上右键进入contextMenuEvent事件,必须在继承的GraphicsView类中重写contextMenuEvent事件,并在事件中调用父类事件QGraphicsView::contextMenuEvent(event);
📢博客主页: 主页
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 梦回阑珊 原创,首发于 CSDN,转载注明出处🙉
📢代码改变世界,你来改变代码!✨
相关文章:
《QT从基础到进阶·二十一》QGraphicsView、QGraphicsScene和QGraphicsItem坐标关系和应用
前言: 我们需要先由一个 QGraphicsView,这个是UI显示的地方,也就是装满可见原色的Scene,然后需要一个QGraphicsScene 用来管理所有可见的界面元素,要实现UI功能,我们需要用各种从QGraphicsItem拼装成UI控件…...
32 _ 字符串匹配基础(上):如何借助哈希算法实现高效字符串匹配?
从今天开始,我们来学习字符串匹配算法。字符串匹配这样一个功能,我想对于任何一个开发工程师来说,应该都不会陌生。我们用的最多的就是编程语言提供的字符串查找函数,比如Java中的indexOf(),Python中的find()函数等,它们底层就是依赖接下来要讲的字符串匹配算法。 字符串…...
TCP怎么实现可靠传输
链接 1,TCP头部的校验和保证获取正确数据,防篡改; 2,序列号和ACK确认机制同于管理数据包,对接收到的数据包进行确认,对没有接收到的数据包进行重传; 3,重传机制,包括超…...
C# new 和 override 的区别
在C#中子类继承抽象类的时候,new 和override都可以用来修饰子类方法,但两者之间是有区别的。 相同点: 它们都是子类在覆写基类方法时,修饰子类同名方法用的,都是为了隐藏基类的同名方法在实例化子类对象的时候&#…...
C++11『右值引用 ‖ 完美转发 ‖ 新增类功能 ‖ 可变参数模板』
✨个人主页: 北 海 🎉所属专栏: C修行之路 🎃操作环境: Visual Studio 2022 版本 17.6.5 文章目录 🌇前言🏙️正文1.右值引用1.1.什么是右值引用?1.2.move 转移资源1.3.左值引用 vs …...
在Windows以命令行方式根据文件名称搜索文件
对于cmd.exe,使用:dir /s /b filename.extension /s选项表示在子目录中搜索文件,/b选项表示仅显示文件名而不显示其他信息 对于PowerShell,使用:Get-ChildItem -Path “C:” -Recurse -Filter filename.extension -Re…...
asp.net数字档案管理系统VS开发sqlserver数据库web结构c#编程web网页设计
一、源码特点 asp.net 数字档案管理系统 是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使用c#语 言开发。 asp.net数字档案系统1 应用技…...
数据挖掘 决策树
# 编码声明,并不是注释,而是一种特殊的源文件指令,用于指定文件的字符编码格式 # -*- coding: utf-8 -*-import pandas as pd # 提供了DataFrame等数据结构 from sklearn.tree import DecisionTreeClassifier, export_graphviz # 决策树分类…...
“技能兴鲁”职业技能大赛-网络安全赛项-学生组初赛 WP
Crypto BabyRSA 共模攻击 题目附件: from gmpy2 import * from Crypto.Util.number import *flag flag{I\m not gonna tell you the FLAG} # 这个肯定不是FLAG了,不要交这个咯p getPrime(2048) q getPrime(2048) m1 bytes_to_long(bytes(flag.e…...
[Android]修改应用包名、名称、版本号、Icon以及环境判断和打包
1.修改包名 在Android Studio中更改项目的包名涉及几个步骤: 打开项目结构: 在Android Studio中,确保您处于Android视图模式(在左侧面板顶部有一个下拉菜单可以选择)。 重命名包名: 在项目视图中,找到您的包名&…...
基于风驱动算法优化概率神经网络PNN的分类预测 - 附代码
基于风驱动算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于风驱动算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于风驱动优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要:针对PNN神经网络…...
安全计算环境(设备和技术注解)
网络安全等级保护相关标准参考《GB/T 22239-2019 网络安全等级保护基本要求》和《GB/T 28448-2019 网络安全等级保护测评要求》 密码应用安全性相关标准参考《GB/T 39786-2021 信息系统密码应用基本要求》和《GM/T 0115-2021 信息系统密码应用测评要求》 1身份鉴别 1.1对登录的…...
【Hello Go】Go语言函数
Go语言函数 定义格式自定义函数无参数无返回值有参数无返回值不定参数列表有返回值有多个返回值 函数类型匿名函数和闭包延迟调用deferdefer和匿名函数结合使用 获取命令行参数 定义格式 函数是构成代码执行的逻辑结构 在Go语言中 函数的基本组成为 func关键字函数名参数列表…...
docker小技能:容器IP和宿主机IP一致( Nacos服务注册ip为内网ip,导致Fegin无法根据服务名访问 )
文章目录 I 预备知识1.1 Docker组成1.2 命名空间 (进程隔离)1.3 Docker的网络模式1.4 容器IP和宿主机IP一致1.5 容器时间和服务器时间的一致性II 常用命令2.1 案例:流水线docker 部署2.2 删除没有使用的镜像2.3 shell 不打印错误输出2.4 阿里云流水线/jenkins忽略shell步骤中…...
Android笔记:震动实现
Android震动可以通过Vibrator类实现。以下是一个简单的代码示例: 注:需要注意,震动需要在子线程中执行,所以应该在一个异步任务中执行上述代码,或者使用Handler等机制将其发送到主线程中进行执行。 1、在AndroidMani…...
CSDN每日一题学习训练——Java版(二叉搜索树迭代器、二叉树中的最大路径和、按要求补齐数组)
版本说明 当前版本号[20231115]。 版本修改说明20231115初版 目录 文章目录 版本说明目录二叉搜索树迭代器题目解题思路代码思路参考代码 二叉树中的最大路径和题目解题思路代码思路参考代码 按要求补齐数组题目解题思路代码思路参考代码 二叉搜索树迭代器 题目 实现一个二…...
WPF中有哪些布局方式和对齐方法
在WPF (Windows Presentation Foundation) 中,你可以使用多种方式来进行元素的对齐,这主要取决于你使用的布局容器类型。以下是一些最常用的对齐方式: HorizontalAlignment 和 VerticalAlignment 在大多数WPF元素上,你可以使用 Ho…...
【2012年数据结构真题】
41题 (1) 最坏情况下比较的总次数 对于长度分别为 m,n 的两个有序表的合并过程,最坏情况下需要一直比较到两个表的表尾元素,比较次数为 mn-1 次。已知需要 5 次两两合并,故设总比较次数为 X-5, X 就是以 N…...
k8s_base
应用程序在服务器上部署方式的演变,互联网发展到现在为止 应用程序在服务器上部署方式 历经了3个时代1. 传统部署 优点简单 缺点就是操作系统的资源是有限制的,比如说操作系统的磁盘,内存 比如说我8G,部署了3个应用程序,当有一天…...
2023年亚太杯APMCM数学建模大赛数据分析题MySQL的使用
2023年亚太杯APMCM数学建模大赛 以2022年C题全球变暖数据为例 数据分析: 以2022年亚太杯数学建模C题为例,首先在navicat建数据库然后右键“表”,单击“导入向导”,选择对应的数据格式及字符集进行数据导入 导入之后,…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
