使用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地址是一项基本技能。虎观代理小二将…

跟国外客户的谈判总是难以掌控?那是因为你还不具备这7种特质

更多外贸干货及开发客户的方法&#xff0c;尽在微信【千千外贸干货】 谈判&#xff0c; 既可以是权力的游戏&#xff0c;也可以是想象的游戏。 有些人熟练地玩游戏而有些人只是模糊地参与着。成功的销售谈判者通常会很巧妙地运用自己的知识&#xff0c;经验和技能来让客户说“Y…

笑出腹肌!Ubuntu:如果连猫都会用,那你呢?‍

目录 &#x1f50d; 初见Ubuntu&#xff1a;喵星人的眼神也亮了 &#x1f50d; &#x1f4bb; Ubuntu&#xff1a;喵星人也能成为技术宅&#xff1f; &#x1f4bb; &#x1f431;‍&#x1f4bb; 喵星人的Ubuntu日常&#xff1a;从追剧到编程&#xff08;误&#xff09; &a…

微信小程序电话号码授权

前端&#xff1a; 文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html uniapp调用的时候&#xff0c;要将bind用替换 <button open-type"getPhoneNumber" getphonenumber"getPhoneNumber"…

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是用来…

关于开启SQL Server服务及其防火墙的方法步骤

一、检查SQL Server服务状态 1、打开服务管理器 可以通过“控制面板” -> “管理工具” -> “服务”来打开服务窗口。或者使用快捷键Win R&#xff0c;输入services.msc后回车&#xff0c;直接打开服务窗口。 2、查找SQL Server服务 在服务列表中&#xff0c;找到与…

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

在信息化社会的今天&#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…

notes for datawhale summer camp chemistry task2

[[appendix/Task2_RNN.ipynb|Task2_RNN.ipynb]] 本次的任务是进一步了解 AI4Science 相关知识&#xff0c;然后使用深度学习的方法建模。 你可以从中&#xff1a;了解一些相关历史、了解 SMILES 和分子指纹&#xff0c;并对 RDkit 工具包有更深的认识&#xff1b;探究深度学习…

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

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

设计模式 策略模式(Strategy Pattern) C++表达

设计模式 策略模式&#xff08;Strategy Pattern&#xff09; C表达 flyfish 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为设计模式&#xff0c;它的核心思想是将一系列相关的算法或行为封装到独立的策略类中&#xff0c;并使得这些策略可以相互替换。主要用…