PyQt5图片浏览器

PyQt5图片浏览器

  • 实现方式
    • 功能实现
    • 具体代码
  • 界面实现
    • `pillow`源码修改
    • `ImageQt`错误
    • 主页面布局
  • 项目开源地址

分享一个图片浏览器

实现方式

qt本身有一个QGraphicsView类用来当做视图框架。
具体参考:如何在pyqt中使用 QGraphicsView 实现图片查看器
不过大佬给的例子,功能有点少,因此需要添加一下其他的功能

功能实现

  1. 图片旋转(顺时针/逆时针)
  2. 设置 1:1 大小
  3. 缩放以适应

代码示例:

    def setOriginalSize(self):"""设置 1:1 大小:return:"""self.resetTransform()self.setSceneRect(QRectF(self.pixmap.rect()))self.__setDragEnabled(self.__isEnableDrag())self.zoomInTimes = self.getZoomInTimes(self.pixmap.width())def setAdaptation(self):"""缩放以适应:return:"""self.setSceneRect(QRectF(self.pixmap.rect()))self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)self.__setDragEnabled(False)self.zoomInTimes = 0def rotationAngle(self):return self._rotationAngledef rotateClockwise(self, stepSize: int = 90):"""顺时针旋转:param stepSize: 步长,旋转角度:return:"""if self.pixmap.fileName() is None:returnself._rotationAngle = self._rotationAngle + stepSizeself.__rotation(self._rotationAngle)def __rotation(self, stepSize: int):"""指定图片中心并旋转:return:"""self.pixmapItem.setTransformOriginPoint(self.pixmapItem.boundingRect().center())  # 指定图片旋转中心点self.pixmapItem.setRotation(stepSize)self.setAdaptation()

具体代码

# coding:utf-8
from PyQt5.QtCore import QRectF, QSize, Qt
from PyQt5.QtGui import QPainter, QPixmap, QWheelEvent, QResizeEvent
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsPixmapItem, QGraphicsItemclass Pixmap(QPixmap):def __init__(self, fileName: str, *args, **kwargs):super().__init__(fileName, *args, **kwargs)self._fileName = fileNamedef fileName(self):return self._fileNameclass ImageGraphicsView(QGraphicsView):"""图片查看器"""def __init__(self, fileName: str = None, parent=None):super().__init__(parent)self._rotationAngle = 0self.zoomInTimes = 0self.maxZoomInTimes = 22self.pixmap = Pixmap(fileName)self.pixmapItem = QGraphicsPixmapItem()self.graphicsScene = QGraphicsScene()self.displayedImageSize = QSize(0, 0)self.__initWidget()def __initWidget(self):"""初始化小部件:return:"""self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)  # 隐藏水平滚动条self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)  # 隐藏垂直滚动条self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)  # 以鼠标所在位置为锚点进行缩放self.pixmapItem.setTransformationMode(Qt.TransformationMode.SmoothTransformation)  # 平滑转型self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)  # 平滑像素图变换self.pixmapItem.setPixmap(self.pixmap)self.graphicsScene.addItem(self.pixmapItem)self.setScene(self.graphicsScene)self.setStyleSheet('background-color: #ffffff;')def setImage(self, fileName: str):"""设置显示的图片:param fileName::return:"""self.resetTransform()del self.pixmapself.pixmap = Pixmap(fileName)self.pixmapItem.setPixmap(self.pixmap)self.zoomInTimes = 0# 调整图片大小self.setSceneRect(QRectF(self.pixmap.rect()))ratio = self.__getScaleRatio()self.displayedImageSize = self.pixmap.size() * ratioif ratio < 1:self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)self.pixmapItem.setTransformOriginPoint(self.pixmapItem.boundingRect().center())def setOriginalSize(self):"""设置 1:1 大小:return:"""self.resetTransform()self.setSceneRect(QRectF(self.pixmap.rect()))self.__setDragEnabled(self.__isEnableDrag())self.zoomInTimes = self.getZoomInTimes(self.pixmap.width())def setAdaptation(self):"""缩放以适应:return:"""self.setSceneRect(QRectF(self.pixmap.rect()))self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)self.__setDragEnabled(False)self.zoomInTimes = 0def rotationAngle(self):return self._rotationAngledef rotateClockwise(self, stepSize: int = 90):"""顺时针旋转:param stepSize: 步长,旋转角度:return:"""if self.pixmap.fileName() is None:returnself._rotationAngle = self._rotationAngle + stepSizeself.__rotation(self._rotationAngle)def __rotation(self, stepSize: int):"""指定图片中心并旋转:return:"""self.pixmapItem.setTransformOriginPoint(self.pixmapItem.boundingRect().center())  # 指定图片旋转中心点self.pixmapItem.setRotation(stepSize)self.setAdaptation()def __isEnableDrag(self):"""根据图片的尺寸决定是否启动拖拽功能:return:"""v = self.verticalScrollBar().maximum() > 0h = self.horizontalScrollBar().maximum() > 0return v or hdef __setDragEnabled(self, isEnabled: bool):"""设置拖拽是否启动:param isEnabled: bool:return:"""if isEnabled:self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)else:self.setDragMode(QGraphicsView.DragMode.NoDrag)def __getScaleRatio(self):"""获取显示的图像和原始图像的缩放比例:return:"""if self.pixmap.isNull():return 1pw = self.pixmap.width()ph = self.pixmap.height()rw = min(1, self.width() / pw)rh = min(1, self.height() / ph)return min(rw, rh)def enlargePicture(self, anchor=QGraphicsView.AnchorUnderMouse):"""放大图片:return:"""if self.zoomInTimes == self.maxZoomInTimes:returnself.setTransformationAnchor(anchor)self.zoomInTimes += 1self.scale(1.1, 1.1)self.__setDragEnabled(self.__isEnableDrag())# 还原 anchorself.setTransformationAnchor(self.AnchorUnderMouse)def shrinkPicture(self, anchor=QGraphicsView.AnchorUnderMouse):"""缩小图片:return:"""if self.zoomInTimes == 0 and not self.__isEnableDrag():returnself.setTransformationAnchor(anchor)self.zoomInTimes -= 1# 原始图像的大小pw = self.pixmap.width()ph = self.pixmap.height()# 实际显示的图像宽度w = self.displayedImageSize.width() * 1.1 ** self.zoomInTimesh = self.displayedImageSize.height() * 1.1 ** self.zoomInTimesif pw > self.width() or ph > self.height():# 在窗口尺寸小于原始图像时禁止继续缩小图像比窗口还小if w <= self.width() and h <= self.height():self.fitInView(self.pixmapItem)else:self.scale(1 / 1.1, 1 / 1.1)else:# 在窗口尺寸大于图像时不允许缩小的比原始图像小if w <= pw:self.resetTransform()else:self.scale(1 / 1.1, 1 / 1.1)self.__setDragEnabled(self.__isEnableDrag())# 还原 anchorself.setTransformationAnchor(self.AnchorUnderMouse)def getZoomInTimes(self, width: int, step: int = 100):for i in range(0, self.maxZoomInTimes):if width - self.displayedImageSize.width() * 1.1 ** i <= step:return ireturn self.maxZoomInTimesdef fitInView(self, item: QGraphicsItem, mode=Qt.AspectRatioMode.KeepAspectRatio):"""缩放场景使其适应窗口大小:param item::param mode::return:"""super().fitInView(item, mode)self.displayedImageSize = self.__getScaleRatio() * self.pixmap.size()self.zoomInTimes = 0def resizeEvent(self, event: QResizeEvent):if self.zoomInTimes > 0:return# 调整图片大小ratio = self.__getScaleRatio()self.displayedImageSize = self.pixmap.size() * ratioif ratio < 1:self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)else:self.resetTransform()def resetTransform(self):"""重置变换:return:"""self.zoomInTimes = 0self.__setDragEnabled(False)super().resetTransform()def wheelEvent(self, e: QWheelEvent):"""滚动鼠标滚轮缩放图片:param e::return:"""if e.angleDelta().y() > 0:self.enlargePicture()else:self.shrinkPicture()

该函数可以显示图片实现图片下旋转、放大、缩小等功能

界面实现

pillow源码修改

在实现图片列表时,如果全部加载出来会直接爆内存,因此需要借助pillow生成缩略图,但是pillow最新版本没有适配PyQt5,如果使用需要改源码。

ImageQt.py中修改源码
在这里插入图片描述
将红框中的代码加上就行了。
在这里插入图片描述

ImageQt错误

如果你使用了pillow这个库直接转为QPixmap你就会发现很多问题。

PyQt5+pillow实现缩略图,代码示例:

import sys
from PyQt5.Qt import *
import res.res_rc
from PIL import Image, ImageQtclass Window(QWidget):def __init__(self, parent=None):super().__init__(parent)self.vBox = QVBoxLayout(self)self.vBox.setContentsMargins(0, 0, 0, 0)self.vBox.setSpacing(0)file = r"G:\手机\壁纸\电脑壁纸\1689637545648.png"img = Image.open(file)img.thumbnail((200, 120))label = QLabel()label.setPixmap(ImageQt.toqpixmap(img))self.vBox.addWidget(label)if __name__ == '__main__':QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)app = QApplication(sys.argv)app.setQuitOnLastWindowClosed(True)demo = Window()demo.resize(800, 600)demo.show()sys.exit(app.exec_())

运行结果:

运行后,你会发现基本上所有图片都会变成花屏,于是就直接放弃了,那么只能生成本地图片,然后在显示出来,于是使用本地sqlite数据库,为了使方便引入了SQLAlchemy来管理数据库,别问为什么,问就是不想写SQL,这要也方便了后期拓展

def CreateThumbnail(fileName, saveFile, *, size=(200, 120), **kwargs):"""创建缩略图"""img = Image.open(fileName)img.thumbnail(size=size, **kwargs)img.save(saveFile)

在这里插入图片描述

主页面布局

在这里插入图片描述

项目开源地址

https://gitee.com/chiyaun/picture-browser.git

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序 uniapp+vue餐厅美食就餐推荐系统

本论文根据系统的开发流程以及一般论文的结构分为三个部分&#xff0c;第一个部分为摘要、外文翻译、目录&#xff1b;第二个部分为正文&#xff1b;第三个部分为致谢和参考文献。其中正文部分包括&#xff1a; &#xff08;1&#xff09;绪论&#xff0c;对课题背景、意义、目…

eBPF实践篇之基础概念

文章目录 前言基本概念eBPF的生命周期之旅最后 前言 eBPF 是一门革命性的技术&#xff0c;可以在不修改内核源代码或者加载内核模块的情况下&#xff0c;安全和高效地拓展和增强Linux内核的功能&#xff0c;我们主要聚焦在eBPF在网络传输上的应用和实践&#x1f680; 基本概念…

AI时代显卡如何选择,B100、H200、L40S、A100、H100、V100 含架构技术和性能对比

AI时代显卡如何选择&#xff0c;B100、H200、L40S、A100、H100、V100 含架构技术和性能对比。 英伟达系列显卡大解析B100、H200、L40S、A100、A800、H100、H800、V100如何选择&#xff0c;含架构技术和性能对比带你解决疑惑。 近期&#xff0c;AIGC领域呈现出一片繁荣景象&a…

企业型多域名SSL证书

多域名SSL证书是目前市场上用的比较多的一种&#xff0c;主要解决多个不同规则的域名申请&#xff0c;但不适合主域名&#xff08;根域名&#xff09;相同的域名&#xff0c;因为这种域名直接申请通配符。 企业型其实就是OV类型或者EV类型&#xff0c;由于在CA/B产品名称规范中…

【k8s资源调度-HPA(自动扩缩容)】

1、HPA可以做什么&#xff1f; 通过观察pod的cpu、内存使用率或自定义metrics指标进行自动的扩容或缩容pod的数量。通常用于Deployment&#xff0c;不适用于无法扩/缩容的对象&#xff0c;如DaemonSet。控制管理器每隔30s(可以通过-horizontal-pod-autoscaler–sync-period修改…

Ubuntu20.04和Windows11下配置StarCraft II环境

1.Ubuntu20.04 根据下面这篇博客就可以顺利安装&#xff1a; 强化学习实战(九) Linux下配置星际争霸Ⅱ环境https://blog.csdn.net/weixin_39059031/article/details/117247635?spm1001.2014.3001.5506 Ubuntu下显示游戏界面目前还没有解决掉。 大家可以根据以下链接看看能…

Jenkins详解

目录 一、Jenkins CI/CD 1、 Jenkins CI/CD 流程图 2、介绍 Jenkins 1、Jenkins概念 2、Jenkins目的 3、特性 4、产品发布流程 3、安装Jenkins 1、安装JDK 2、安装tomcat 3.安装maven 4安装jenkins 5.启动tomcat&#xff0c;并页面访问 5.添加节点 一、Jenkins CI/…

[深度学习]yolov9+bytetrack+pyqt5实现目标追踪

【简介】 目标追踪简介 目标追踪是计算机视觉领域中的一个热门研究方向&#xff0c;它涉及到从视频序列中实时地、准确地跟踪目标对象的位置和运动轨迹。随着深度学习技术的快速发展&#xff0c;基于深度学习的目标追踪方法逐渐展现出强大的性能。其中&#xff0c;YOLOv9&…

web安全学习笔记【16】——信息打点(6)

信息打点-语言框架&开发组件&FastJson&Shiro&Log4j&SpringBoot等[1] #知识点&#xff1a; 1、业务资产-应用类型分类 2、Web单域名获取-接口查询 3、Web子域名获取-解析枚举 4、Web架构资产-平台指纹识别 ------------------------------------ 1、开源-C…

K线实战分析系列之一:标准K线图的识别

K线实战分析系列之一&#xff1a;标准K线图的识别 一、阳线和阴线二、光头K线三、光脚K线四、光头光脚大阳线五、纺锤线六、十字线 一、阳线和阴线 二、光头K线 如果某根K线没有上影线&#xff0c;就叫它光头k线 三、光脚K线 某一根K线没有下影线就叫它光脚K线 四、光头光…

广联达Linkworks GetAllData 信息泄露漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

【CSS-语法】

CSS-语法 ■ CSS简介■ CSS 实例■ CSS id 和 class选择器■ CSS 样式表■ 外部样式表(External style sheet)■ 内部样式表(Internal style sheet)■ 内联样式(Inline style)■ 多重样式 ■ CSS 文本■ CSS 文本颜色■ CSS 文本的对齐方式■ CSS 文本修饰■ CSS 文本转换■ CS…

力扣1290. 二进制链表转整数

Problem: 1290. 二进制链表转整数 文章目录 题目描述思路复杂度Code 题目描述 思路 1.记录一个变量res初始化为0&#xff0c;指针p指向链表头&#xff1b; 2.循环每次res res * 2 p -> val;p p -> next;&#xff08;充分利用二进制数的特性&#xff1b;其中利用指针先…

Flutter开发进阶之Package

Flutter开发进阶之Package 通常我们在Flutter开发中需要将部分功能与整体项目隔离&#xff0c;一般有两种方案Plugin和Package&#xff0c;Application是作为主体项目&#xff0c;Module是作为原生项目接入Flutter模块。 当独立模块不需要与原生项目通讯只需要Plugin就可以&a…

Python + Google AI 自动修复 Sonar Bug 实践

前言 在工作中总会遇到种种不期而至的需求&#xff0c;比如前段时间突然要修复所有 Sonar Bug&#xff0c;涉及各种琐碎的代码风格问题&#xff0c;包括但不限于语法不规范、废弃注释等问题。这些项目都已经持续开发几年了&#xff0c;Sonar 上的问题层出不穷&#xff0c;各种…

记一次生产jvm oom问题

前言 jvm添加以下参数&#xff0c;发生OOM时自动导出内存溢出文件 -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/opt 内存分析工具&#xff1a; MAT, 下载地址&#xff1a;Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation&#xff0c; 注意工具地址…

【多线程】volatile 关键字、wait 和 notify方法详解

volatile 、wait 和 notify &#x1f332;volatile关键字&#x1f6a9;保证内存可见性&#x1f6a9;volatile 不保证原⼦性 &#x1f333;wait 和 notify方法&#x1f6a9;wait()&#x1f6a9;notify()&#x1f6a9;notifyAll()方法 ⭕wait 和 sleep 的对比&#xff08; 面试题…

中国农业无人机行业市场现状分析与投资前景预测研究报告

全版价格&#xff1a;壹捌零零 报告版本&#xff1a;下单后会更新至最新版本 交货时间&#xff1a;1-2天 第一章农业无人机行业发展综述 第一节农业无人机行业定义及分类 一、农业无人机行业的定义 农业无人机是一种无人驾驶的飞行器来帮助优化农业经营&#xff0c;增加作…

深入理解基于 eBPF 的 C/C++ 内存泄漏分析

对于 C/C 程序员来说&#xff0c;内存泄露问题是一个老生常谈的问题。排查内存泄露的方法有很多&#xff0c;比如使用 valgrind、gdb、asan、tsan 等工具&#xff0c;但是这些工具都有各自的局限性&#xff0c;比如 valgrind 会使程序运行速度变慢&#xff0c;gdb 需要了解代码…

政府采购网有哪些回款方式

政府采购网的回款方式多种多样&#xff0c;具体取决于采购项目的性质、规模以及采购单位与供应商之间的约定。以下是一些常见的政府采购网回款方式&#xff1a; 线上支付&#xff1a;随着电子商务的发展&#xff0c;越来越多的政府采购项目采用线上支付方式。这种方式方便快捷&…