Python+PyQt5制作一个图片查看器

 更新时间:2022年03月25日 10:30:27   作者:之一Yo  
在PyQt中可以使用很多方式实现照片查看器,本文将利用QGraphicsView类来实现图片查看器的制作,感兴趣的小伙伴快跟随小编一起动手试一试

前言

在 PyQt 中可以使用很多方式实现照片查看器,最朴素的做法就是重写 QWidget 的 paintEvent()mouseMoveEvent 等事件,但是如果要在图像上多添加一些形状,那么在对图像进行缩放旋转等仿射变换时需要对这些形状也这些变换,虽然不难,但是从头实现这些变换还有形状还是挺讨厌的。好在 Qt 提供了图形视图框架,关于这个框架的基本使用可以参见 深入了解PyQt5中的图形视图框架,下面进入正题。

实现方式

一个最基本的照片查看器应该具有以下功能:

  • 载入图像
  • 缩放图像
  • 在窗口尺寸小于图像时允许拖拽图像

载入图像可以使用 QGraphicsPixmapItem 来解决,缩放图像使用 QGraphicsView 的 scale(sx, sy) 解决,移动图像只需将 QGraphicsView 的 dragMode 设置为 QGraphicsView.ScrollHandDrag 即可。因为常常使用鼠标滚轮来缩放图像,所以还需要重写重写以下 QGraphicsView 的 wheelEvent

实际上由于窗口的缩放导致视口大小变化,还有一些细枝末节需要处理。具体代码如下:

# coding:utf-8
import sys

from PyQt5.QtCore import QRect, QRectF, QSize, Qt
from PyQt5.QtGui import QPainter, QPixmap, QWheelEvent
from PyQt5.QtWidgets import (QApplication, QGraphicsItem, QGraphicsPixmapItem,
                             QGraphicsScene, QGraphicsView)


class ImageViewer(QGraphicsView):
    """ 图片查看器 """

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.zoomInTimes = 0
        self.maxZoomInTimes = 22

        # 创建场景
        self.graphicsScene = QGraphicsScene()

        # 图片
        self.pixmap = QPixmap(r'D:\hzz\图片\硝子\硝子 (2).jpg')
        self.pixmapItem = QGraphicsPixmapItem(self.pixmap)
        self.displayedImageSize = QSize(0, 0)

        # 初始化小部件
        self.__initWidget()

    def __initWidget(self):
        """ 初始化小部件 """
        self.resize(1200, 900)

        # 隐藏滚动条
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        # 以鼠标所在位置为锚点进行缩放
        self.setTransformationAnchor(self.AnchorUnderMouse)

        # 平滑缩放
        self.pixmapItem.setTransformationMode(Qt.SmoothTransformation)
        self.setRenderHints(QPainter.Antialiasing |
                            QPainter.SmoothPixmapTransform)

        # 设置场景
        self.graphicsScene.addItem(self.pixmapItem)
        self.setScene(self.graphicsScene)

    def wheelEvent(self, e: QWheelEvent):
        """ 滚动鼠标滚轮缩放图片 """
        if e.angleDelta().y() > 0:
            self.zoomIn()
        else:
            self.zoomOut()

    def resizeEvent(self, e):
        """ 缩放图片 """
        super().resizeEvent(e)

        if self.zoomInTimes > 0:
            return

        # 调整图片大小
        ratio = self.__getScaleRatio()
        self.displayedImageSize = self.pixmap.size()*ratio
        if ratio < 1:
            self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)
        else:
            self.resetTransform()

    def setImage(self, imagePath: str):
        """ 设置显示的图片 """
        self.resetTransform()

        # 刷新图片
        self.pixmap = QPixmap(imagePath)
        self.pixmapItem.setPixmap(self.pixmap)

        # 调整图片大小
        self.setSceneRect(QRectF(self.pixmap.rect()))
        ratio = self.__getScaleRatio()
        self.displayedImageSize = self.pixmap.size()*ratio
        if ratio < 1:
            self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)

    def resetTransform(self):
        """ 重置变换 """
        super().resetTransform()
        self.zoomInTimes = 0
        self.__setDragEnabled(False)

    def __isEnableDrag(self):
        """ 根据图片的尺寸决定是否启动拖拽功能 """
        v = self.verticalScrollBar().maximum() > 0
        h = self.horizontalScrollBar().maximum() > 0
        return v or h

    def __setDragEnabled(self, isEnabled: bool):
        """ 设置拖拽是否启动 """
        self.setDragMode(
            self.ScrollHandDrag if isEnabled else self.NoDrag)

    def __getScaleRatio(self):
        """ 获取显示的图像和原始图像的缩放比例 """
        if self.pixmap.isNull():
            return 1

        pw = self.pixmap.width()
        ph = self.pixmap.height()
        rw = min(1, self.width()/pw)
        rh = min(1, self.height()/ph)
        return min(rw, rh)

    def fitInView(self, item: QGraphicsItem, mode=Qt.KeepAspectRatio):
        """ 缩放场景使其适应窗口大小 """
        super().fitInView(item, mode)
        self.displayedImageSize = self.__getScaleRatio()*self.pixmap.size()
        self.zoomInTimes = 0

    def zoomIn(self, viewAnchor=QGraphicsView.AnchorUnderMouse):
        """ 放大图像 """
        if self.zoomInTimes == self.maxZoomInTimes:
            return

        self.setTransformationAnchor(viewAnchor)

        self.zoomInTimes += 1
        self.scale(1.1, 1.1)
        self.__setDragEnabled(self.__isEnableDrag())

        # 还原 anchor
        self.setTransformationAnchor(self.AnchorUnderMouse)

    def zoomOut(self, viewAnchor=QGraphicsView.AnchorUnderMouse):
        """ 缩小图像 """
        if self.zoomInTimes == 0 and not self.__isEnableDrag():
            return

        self.setTransformationAnchor(viewAnchor)

        self.zoomInTimes -= 1

        # 原始图像的大小
        pw = self.pixmap.width()
        ph = self.pixmap.height()

        # 实际显示的图像宽度
        w = self.displayedImageSize.width()*1.1**self.zoomInTimes
        h = self.displayedImageSize.height()*1.1**self.zoomInTimes

        if 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())

        # 还原 anchor
        self.setTransformationAnchor(self.AnchorUnderMouse)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = ImageViewer()
    w.show()
    sys.exit(app.exec_())

测试

来看一下实际的使用效果:

到此这篇关于Python+PyQt5制作一个图片查看器的文章就介绍到这了,更多相关PyQt5图片查看器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python学习之集合的常用方法总结

    Python学习之集合的常用方法总结

    集合并不是一种数据处理类型,而是一种中间类型。集合(set)是一个无序、不重复的元素序列,经常被用来处理两个列表进行交并差的处理性。本文将详细讲解集合的一些常用方法,感兴趣的可以了解一下
    2022-03-03
  • Python集成C#实现界面操作下载文件功能的全过程

    Python集成C#实现界面操作下载文件功能的全过程

    使用脚本进行下载的需求很常见,下面这篇文章主要给大家介绍了关于Python集成C#实现界面操作下载文件功能的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-03-03
  • python安装twisted的问题解析

    python安装twisted的问题解析

    我们在这篇文章中给大家详细整理了python安装twisted时遇到的问题以及解决方法,有需要的朋友们参考下。
    2018-08-08
  • 在python tkinter界面中添加按钮的实例

    在python tkinter界面中添加按钮的实例

    今天小编就为大家分享一篇在python tkinter界面中添加按钮的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03
  • python 不同方式读取文件速度不同的实例

    python 不同方式读取文件速度不同的实例

    今天小编就为大家分享一篇python 不同方式读取文件速度不同的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-11-11
  • Python练习之操作MySQL数据库

    Python练习之操作MySQL数据库

    这篇文章主要介绍了Python练习之操作MySQL数据库,文章通过如何创建MySQL数据表?如何向MySQL表中插入数据?如何查询MySQL中的数据?的三个问题展开了详细的内容介绍
    2022-06-06
  • python把转列表为集合的方法

    python把转列表为集合的方法

    在本篇文章里小编给大家分享了关于python把转列表为集合的方法以及相关实例内容,有兴趣的朋友们学习下。
    2019-06-06
  • Python可视化神器pyecharts绘制桑基图

    Python可视化神器pyecharts绘制桑基图

    这篇文章主要介绍了Python可视化神器pyecharts绘制桑基图,即桑基能量分流图,也叫桑基能量平衡图,更多相关介绍具有一定的参考价值,需要的朋友可以参考一下
    2022-07-07
  • Python实现创建快速剪映草稿轨道自动生成视频

    Python实现创建快速剪映草稿轨道自动生成视频

    这篇文章主要为大家详细介绍了如何使用Python实现创建快速剪映草稿轨道并自动生成视频,文中的示例代码讲解详细,需要的可以参考一下
    2023-08-08
  • 在Python的Django框架上部署ORM库的教程

    在Python的Django框架上部署ORM库的教程

    这篇文章主要介绍了在Python的Django框架上部署ORM库的教程,文中还给出了几个ORM库之间的对比,需要的朋友可以参考下
    2015-04-04

最新评论