使用QGraphicsView思想做一个简单图片查看器

使用QGraphicsView思想做一个简单图片查看器

如果要做一个图片查看器,支持放大、滚动操作,比较直接的方法是,使用QWidget来显示完整图片,将QWidget放入QScrollArea。缩放时调整QWidget的尺寸,QScrollArea会自动调整滚动范围,超出视口区域图片自然就不会显示。

如果要使用QGraphicsView的思想呢?

原理

QGraphicsScenes是固定不变的,QGraphicsView使用一个变换矩阵来实现QWidget区域与QGraphicsScene区域之间的转换。缩放和滚动相对直接,任意角度旋转涉及到的问题还是挺麻烦的,这里不考虑。
场景和视口关系
所以只要能实现图像坐标、区域,到QWidget的坐标、区域转换,和反向转换,剩下就非常简单了。只考虑缩放和滚动,只需要维护变换矩阵(QTransform)和滚动距离,交互上还需要考虑滚动范围,避免超出。

主要代码

以下代码全部使用了浮点值,防止精度损失和溢出

  1. 根据缩放,重设变换矩阵

    void resetView()
    {// QSizeF scrollRange; //缓存滚动范围// qreal scale; //当前缩放QRectF rect(this->rect());scrollRange = imageRect.size() / scale - rect.size();QPointF offset(0, 0);	// 当图片显示小于视口,用于居中if(scrollRange.width() < 0){// 水平居中offset.rx() = - scrollRange.rwidth() / 2;scrollRange.rwidth() = 0;}if(scrollRange.height() < 0){// 垂直居中offset.ry() = - scrollRange.height() / 2;scrollRange.rheight() = 0;}// 变换矩阵transform = QTransform().scale(scale, scale).translate(-offset.x(), -offset.y());
    }
    
  2. 坐标与矩阵映射
    QGraphicsView内部,滚动范围值是场景区域经过变换后的区域范围,并非从0起始。
    由于滚动代表实际的偏移位置,直接写入transform不方便

    // 	QPointF scrollValue; // 当前滚动,为了方便使用坐标点
    QPointF mapToImage(QPointF pos){return transform.map(pos + scrollValue);
    }
    QPointF mapFromImage(QPointF pos){return transform.inverted().map(pos) - scrollValue;
    }
    QRectF mapToImage(QRectF rect){rect.moveTopLeft(rect.topLeft() + scrollValue);return transform.mapRect(rect);
    }
    QRectF mapFromImage(QRectF rect){rect = transform.inverted().mapRect(rect);rect.moveTopLeft(rect.topLeft() - scrollValue);return rect;
    }
    
  3. 绘制图片

    QRectF rect(this->rect());
    QRectF img_rect = mapToImage(rect).intersected(imageRect);
    QRectF paint_rect = mapFromImage(img_rect);QPainter painter(this);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.drawImage(paint_rect, image, img_rect);
    

    绘制时,先将窗口区域变换到图片区域,求取交集,再反算到视口区域。QPainter支持将图片重某区域绘制到指定区域。

  4. 滚动和缩放图片
    滚动相对简单,监听鼠标事件,修改当前滚动。
    缩放直接修改scale,调用resetView重新计算滚动范围、变换矩阵。

    void scollView(QPointF dp){scrollValue.rx() = qBound(0.0, scrollValue.x() + dp.x(), scrollRange.width());scrollValue.ry() = qBound(0.0, scrollValue.y() + dp.y(), scrollRange.height());
    }
    

最终效果

在这里插入图片描述

其他细节

上述代码基本包含了主要逻辑,一些细节可能需要根据实际需要再增加逻辑。

  1. 缩放限制
    尽管浮点数的运算能最大程度保留精度,但最好考虑在修改scale时,限定范围。

  2. 缩放时同步缩放图片
    很少有软件会做这样的支持,毕竟支持滚动了。
    但Windows自带的照片有这样功能,具体原理可以再研究。

  3. 缩放或者调整窗口时,锚定某个坐标不动
    当变换矩阵变化、窗口resize时,QGraphicsView支持锚定某个坐标在视口中不变。具体可以文档QGraphicsView::ViewportAnchor。
    可以简单这样实现:

    // QPointF view_pos; //指定一个视口坐标
    QPointF anch_pos = mapToImage(view_pos);
    // ...
    // 其他触发变换矩阵变化的逻辑
    // ...
    // 调整前后差异,重新滚动对齐
    QPointF new_pos = mapFromImage(anch_pos);
    scollView(new_pos - view_pos);
    
  4. 旋转、翻转
    如果只支持90°倍数旋转,直接对原图修改应该比较简单(变换矩阵是否可以做到)

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

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

相关文章

MBR20200FCT-ASEMI智能AI专用MBR20200FCT

编辑&#xff1a;ll MBR20200FCT-ASEMI智能AI专用MBR20200FCT 型号&#xff1a;MBR20200FCT 品牌&#xff1a;ASEMI 封装&#xff1a;TO-220F 批号&#xff1a;最新 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;20A 最大循环峰值反向电压&#xff08;VRRM&a…

别再问了!微信小程序的那些事儿,一文搞定

微信小程序是一种无需下载安装即可使用的应用&#xff0c;它嵌入在微信生态中&#xff0c;用户通过微信扫一扫或搜索即可快速访问。 无论是购物、订餐、预约服务&#xff0c;还是玩个小游戏、看篇文章&#xff0c;都不需要下载额外的APP&#xff0c;直接就能在微信里搞定。不会…

联想电脑如何查看ip地址?详细介绍几种方法

随着互联网的普及和技术的飞速发展&#xff0c;IP地址已成为我们日常网络活动中不可或缺的一部分。无论是访问网站、远程办公还是进行网络游戏&#xff0c;IP地址都扮演着重要的角色。对于联想电脑用户来说&#xff0c;了解如何查看自己的IP地址是一项基本技能。虎观代理小二将…

JSON Web Token (JWT): 理解与应用

JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间以JSON对象的形式安全地传输信息。JWT通常用于身份验证和授权目的&#xff0c;因为它可以使用JSON对象在各方…

【向量数据库】Ubuntu编译安装FAISS

参考官方的安装指导&#xff1a;https://github.com/facebookresearch/faiss/blob/main/INSTALL.md&#xff0c;不需要安装的可以跳过 ~$ wget https://github.com/facebookresearch/faiss/archive/refs/tags/v1.8.0.tar.gz ~$ tar -zxvf v1.8.0.tar.gz ~$ cd faiss-1.8.0 ~$ …

易基因:RNA修饰N4-乙酰胞苷(ac4C)的调控机制、检测方法及其在癌症中的作用最新研究进展|新方向

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 N4-乙酰胞苷&#xff08;ac4C&#xff09;是一种高度保守的化学修饰&#xff0c;广泛存在于真核和原核生物RNA中&#xff0c;如tRNA、rRNA和mRNA。这种修饰与多种人类疾病显著相关&#…

vuex的原理和使用方法

简介 Vuex 是 Vue.js 应用的状态管理模式&#xff0c;它为应用内的所有组件提供集中式的状态&#xff08;数据&#xff09;管理。可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。 Vuex的构成 state&#xff1a;state 是 Vuex 的数据中心&#xff0c;也就是说state是用来…

职业院校云计算实训室建设方案全景剖析

在信息化社会的今天&#xff0c;云计算作为一项关键技术&#xff0c;正在迅速改变着教育和培训的方式。本文旨在探讨如何通过"职业院校云计算实训室建设方案"&#xff0c;为学生提供一个现代化、高效的学习和研究环境&#xff0c;以适应云计算技术的发展和市场需求。…

软件测试---接口测试

一、接口及接口测试概念 &#xff08;1&#xff09;接口的类型 &#xff08;2&#xff09;接口测试的概念 &#xff08;3&#xff09;接口测试的原理 &#xff08;4&#xff09;接口测试的特点 &#xff08;5&#xff09;接口测试的实现方式 二、HTTP协议 &#xff08;1&#…

Qt 实现抽屉效果

1、实现效果和UI设计界面 2、工程目录 3、mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QToolButton> #include <QPushButton> #include <vector> using namespace std;QT_BEGIN_NAMESPACE namespace…

生成式:PolyGen: An Autoregressive Generative Model of 3D Meshes【附件】

论文:PolyGen: An Autoregressive Generative Model of 3D Meshes OBJ坐标变换: # Transpose so that z-axis is vertical.vertices = vertices[:, [2, 0, 1]]变换前: 对应数据:

C++模板(初阶)

1.引入 在之前的笔记中有提到&#xff1a;函数重载&#xff08;特别是交换函数&#xff08;Swap&#xff09;的实现&#xff09; void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(double& left, double& right) {do…

小程序开发_02

一、项目的基本结构 二、小程序的页面组成部分 三、json配置文件 ① project.config.json文件 作用&#xff1a;项目的配置文件&#xff0c;用来记录对小程序开发工具所作的个性化配置 ② sitemap.json 作用&#xff1a;是否允许被微信引擎搜索,不希望被搜索dis ③ app.jso…

基于C51和OLED12864实现贪吃蛇小游戏

引言 在微电子技术飞速发展的今天&#xff0c;单片机作为智能控制的核心&#xff0c;广泛应用于各种电子设备中。C51系列单片机以其高效、稳定的特性&#xff0c;成为众多电子爱好者和工程师的首选平台。而OLED显示屏以其轻薄、低功耗、响应速度快等优点&#xff0c;在显示设备…

springcloud接入seata管理分布式事务

下载安装包 链接: seata 配置seata-server 文件上传Linux解压 压缩包我放在/usr/local/seata中 tar -zxvf seata-server-2.0.0.tar.gz修改配置文件 设置nacos为注册和配置中心 进入文件夹 cd /usr/local/seata/seata/conf修改application.yml文件 ...... ...... cons…

CST软件如何进行参数化扫描?

在用CST进行仿真设计的过程中&#xff0c;经常需要对某一些参数进行参数化设置&#xff0c;并对这些参数进行仿真对比。这一期&#xff0c;我们介绍下如何进行参数化扫描。 还是借用&#xff0c;之前已经对馈电位置、贴片的长和宽都进行了参数设置&#xff0c;如下图所示&…

计算机网络HTTP全讲解,让你透彻掌握HTTP协议(三)http长短连接/代理/网关/缓存/内容协商机制/断点续传

HTTP HTTP的长连接与短连接短链接长链接HTTP代理代理的作用HTTP网关web网关常见的网关类型HTTP缓存HTTP缓存头部字段HTTP缓存工作方式缓存改进方案cdn缓存工作方式浏览器操作对http缓存的影响HTTP内容协商机制客户端驱动服务器驱动请求首部集近似匹配透明协商断点续传和多线程下…

springboot投票管理系统-计算机毕业设计源码33128

摘 要 本文介绍了基于微信小程序和Spring Boot的投票管理系统的设计与实现。该系统结合了移动互联网技术和后端开发框架&#xff0c;旨在为各类组织或活动提供一个高效、便捷、用户友好的在线投票平台。 系统采用微信小程序作为前端展示与交互界面&#xff0c;用户无需下载安装…

学校如何筹办一场汉字听写大赛

汉字作为中国最宝贵的文化遗产&#xff0c;在五千年的历史长河里&#xff0c;汉字以其浩瀚广博抒写着华夏历史&#xff0c;以其灵秀展示着炎黄之精神。传承汉字文明是我们的使命和主责任。随着科技的发展&#xff0c;现在人们很少用笔书写汉字&#xff0c;导致汉字听写能力普遍…

unity2D游戏开发16弹弓动画

清理动画器 选中PlayerObject,打开Animator,删除原来的四个状态 右键选择Create State |from New Blend Tree; 冲命名为Walk Tree 双击Walk Tree查看Blend Tree Graph 设置属性为2D Simple Directional,再点击加号选择Add Motion Field 添加四个,如图 点击Base Layer