脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - Python+PyQt5制作一个图片查看器

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

2022-11-14 09:36之一Yo Python

在PyQt中可以使用很多方式实现照片查看器,本文将利用QGraphicsView类来实现图片查看器的制作,感兴趣的小伙伴快跟随小编一起动手试一试

前言

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

实现方式

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# 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制作一个图片查看器

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

原文链接:https://www.cnblogs.com/zhiyiYo/p/15676079.html

延伸 · 阅读

精彩推荐