diff --git a/Demo/ImageView.py b/Demo/ImageView.py deleted file mode 100644 index 85d1b8d..0000000 --- a/Demo/ImageView.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Created on 2020/11/12 -@author: Irony -@site: https://github.com/892768447 -@email: 892768447@qq.com -@file: ImageView -@description: 图片查看控件,支持移动、放大、缩小 -""" - -__Author__ = 'Irony' -__Copyright__ = 'Copyright (c) 2020 Irony' -__Version__ = 1.0 - -import os - -from PyQt5.QtCore import QPoint, QPointF, Qt -from PyQt5.QtGui import QPainter, QColor, QImage, QPixmap -from PyQt5.QtWidgets import QWidget - - -class ImageView(QWidget): - """图片查看控件""" - - def __init__(self, image, *args, **kwargs): - super(ImageView, self).__init__(*args, **kwargs) - self.setCursor(Qt.OpenHandCursor) - self._image = None - self._pos = QPoint(0, 0) # 移动图片偏移 - self._p_pos = None # 鼠标按下点 - self._scale = 1 # 缩放 - self._max_scale = 20 # 最大放大级别 - self._background = kwargs.pop('background', None) - self.setPixmap(image) - - def setMaxScale(self, scale): - """设置最大放大级别,默认为20 - :param scale: 最大缩放 - :type scale: int - """ - self._max_scale = scale - - def setBackground(self, color): - """设置背景颜色 - :param color: 背景颜色 - :type color: QColor or str - """ - if isinstance(color, QColor): - self._background = color - elif isinstance(color, str): - color = QColor(color) - if color.isValid(): - self._background = color - else: - return - self.update() - - def setPixmap(self, image): - """加载图片 - :param image: 图片或者图片路径 - :type image: QPixmap or QImage or str - """ - if isinstance(image, QPixmap): - self._image = image - elif isinstance(image, QImage): - self._image = QPixmap.fromImage(image) - elif isinstance(image, str) and os.path.isfile(image): - self._image = QPixmap(image) - else: - return - self._pos = QPoint(0, 0) - self._p_pos = None - self.update() - - def mousePressEvent(self, event): - """鼠标按下修改鼠标样式以及记录初始移动点""" - super(ImageView, self).mousePressEvent(event) - self.setCursor(Qt.ClosedHandCursor) - if event.button() == Qt.LeftButton: - self._p_pos = event.pos() - - def mouseReleaseEvent(self, event): - """鼠标释放修改鼠标样式""" - super(ImageView, self).mouseReleaseEvent(event) - self.setCursor(Qt.OpenHandCursor) - self._p_pos = None - - def mouseMoveEvent(self, event): - """鼠标移动图片""" - super(ImageView, self).mouseMoveEvent(event) - if event.buttons() == Qt.LeftButton and self._p_pos: - offset = event.pos() - self._p_pos - self._p_pos += offset - self._pos += offset - self.update() - - def wheelEvent(self, event): - super(ImageView, self).wheelEvent(event) - step = 0.4 if self._scale > 1.1 else 0.1 - if event.angleDelta().y() > 0: - # 放大 - self._scale += step - self._scale = min(self._scale, self._max_scale) - else: - # 缩小 - self._scale -= step - self._scale = max(self._scale, 0.1) - self.update() - - def paintEvent(self, event): - super(ImageView, self).paintEvent(event) - painter = QPainter(self) - painter.setRenderHint(QPainter.Antialiasing) - painter.setRenderHint(QPainter.SmoothPixmapTransform) - if self._background: - painter.fillRect(self.rect(), self._background) - if not self._image or self._image.isNull(): - return - # 变换坐标中心为窗口中点 - painter.translate(self.width() / 2, self.height() / 2) - # 缩放 - painter.scale(self._scale, self._scale) - painter.drawPixmap(QPointF(-self._image.width() / 2 + self._pos.x(), -self._image.height() / 2 + self._pos.y()), - self._image) - - -if __name__ == '__main__': - import sys - import cgitb - - cgitb.enable(format='text') - from PyQt5.QtWidgets import QApplication - - app = QApplication(sys.argv) - w = ImageView('ScreenShot/CallVirtualKeyboard2.png') - w.show() - sys.exit(app.exec_()) diff --git a/QGraphicsView/Data/bg.jpg b/QGraphicsView/Data/bg.jpg new file mode 100644 index 0000000..db16457 Binary files /dev/null and b/QGraphicsView/Data/bg.jpg differ diff --git a/QGraphicsView/ImageView.py b/QGraphicsView/ImageView.py new file mode 100644 index 0000000..5058e59 --- /dev/null +++ b/QGraphicsView/ImageView.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Created on 2020/11/12 +@author: Irony +@site: https://github.com/892768447 +@email: 892768447@qq.com +@file: ImageView +@description: 图片查看控件,支持移动、放大、缩小 +""" + +__Author__ = 'Irony' +__Copyright__ = 'Copyright (c) 2020 Irony' +__Version__ = 1.0 + +import os + +from PyQt5.QtCore import QPointF, Qt, QRectF, QSizeF +from PyQt5.QtGui import QPainter, QColor, QImage, QPixmap +from PyQt5.QtWidgets import QGraphicsView, QGraphicsPixmapItem, QGraphicsScene + + +class ImageView(QGraphicsView): + """图片查看控件""" + + def __init__(self, *args, **kwargs): + image = kwargs.pop('image', None) + background = kwargs.pop('background', None) + super(ImageView, self).__init__(*args, **kwargs) + self.setCursor(Qt.OpenHandCursor) + self.setBackground(background) + self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + self.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | + QPainter.SmoothPixmapTransform) + self.setCacheMode(self.CacheBackground) + self.setViewportUpdateMode(self.SmartViewportUpdate) + self._item = QGraphicsPixmapItem() # 放置图像 + self._item.setFlags(QGraphicsPixmapItem.ItemIsFocusable | + QGraphicsPixmapItem.ItemIsMovable) + self._scene = QGraphicsScene(self) # 场景 + self.setScene(self._scene) + self._scene.addItem(self._item) + rect = QApplication.instance().desktop().availableGeometry(self) + self.resize(int(rect.width() * 2 / 3), int(rect.height() * 2 / 3)) + + self.pixmap = None + self._delta = 0.1 # 缩放 + self.setPixmap(image) + + def setBackground(self, color): + """设置背景颜色 + :param color: 背景颜色 + :type color: QColor or str or GlobalColor + """ + if isinstance(color, QColor): + self.setBackgroundBrush(color) + elif isinstance(color, (str, Qt.GlobalColor)): + color = QColor(color) + if color.isValid(): + self.setBackgroundBrush(color) + + def setPixmap(self, pixmap, fitIn=True): + """加载图片 + :param pixmap: 图片或者图片路径 + :param fitIn: 是否适应 + :type pixmap: QPixmap or QImage or str + :type fitIn: bool + """ + if isinstance(pixmap, QPixmap): + self.pixmap = pixmap + elif isinstance(pixmap, QImage): + self.pixmap = QPixmap.fromImage(pixmap) + elif isinstance(pixmap, str) and os.path.isfile(pixmap): + self.pixmap = QPixmap(pixmap) + else: + return + self._item.setPixmap(self.pixmap) + self._item.update() + self.setSceneDims() + if fitIn: + self.fitInView(QRectF(self._item.pos(), QSizeF( + self.pixmap.size())), Qt.KeepAspectRatio) + self.update() + + def setSceneDims(self): + if not self.pixmap: + return + self.setSceneRect(QRectF(QPointF(0, 0), QPointF(self.pixmap.width(), self.pixmap.height()))) + + def fitInView(self, rect, flags=Qt.IgnoreAspectRatio): + """剧中适应 + :param rect: 矩形范围 + :param flags: + :return: + """ + if not self.scene() or rect.isNull(): + return + unity = self.transform().mapRect(QRectF(0, 0, 1, 1)) + self.scale(1 / unity.width(), 1 / unity.height()) + viewRect = self.viewport().rect() + sceneRect = self.transform().mapRect(rect) + x_ratio = viewRect.width() / sceneRect.width() + y_ratio = viewRect.height() / sceneRect.height() + if flags == Qt.KeepAspectRatio: + x_ratio = y_ratio = min(x_ratio, y_ratio) + elif flags == Qt.KeepAspectRatioByExpanding: + x_ratio = y_ratio = max(x_ratio, y_ratio) + self.scale(x_ratio, y_ratio) + self.centerOn(rect.center()) + + def wheelEvent(self, event): + if event.angleDelta().y() > 0: + self.zoomIn() + else: + self.zoomOut() + + def zoomIn(self): + """放大""" + self.zoom(1 + self._delta) + + def zoomOut(self): + """缩小""" + self.zoom(1 - self._delta) + + def zoom(self, factor): + """缩放 + :param factor: 缩放的比例因子 + """ + _factor = self.transform().scale( + factor, factor).mapRect(QRectF(0, 0, 1, 1)).width() + if _factor < 0.07 or _factor > 100: + # 防止过大过小 + return + self.scale(factor, factor) + + +if __name__ == '__main__': + import sys + import cgitb + + cgitb.enable(format='text') + from PyQt5.QtWidgets import QApplication + + app = QApplication(sys.argv) + w = ImageView(image='Data/bg.jpg', background=Qt.black) + w.show() + sys.exit(app.exec_()) diff --git a/QGraphicsView/README.md b/QGraphicsView/README.md index 733d782..ed9edb5 100644 --- a/QGraphicsView/README.md +++ b/QGraphicsView/README.md @@ -3,6 +3,7 @@ - 目录 - [绘制世界地图](#1绘制世界地图) - [添加QWidget](#2添加QWidget) + - [图片查看器](#3图片查看器) ## 1、绘制世界地图 [运行 WorldMap.py](WorldMap.py) @@ -17,4 +18,11 @@ 通过 `QGraphicsScene.addWidget` 添加自定义QWidget -![AddQWidget](ScreenShot/AddQWidget.png) \ No newline at end of file +![AddQWidget](ScreenShot/AddQWidget.png) + +## 3、图片查看器 +[运行 ImageView.py](ImageView.py) + +支持放大缩小和移动 + +![ImageView](ScreenShot/ImageView.gif) \ No newline at end of file diff --git a/QGraphicsView/ScreenShot/ImageView.gif b/QGraphicsView/ScreenShot/ImageView.gif new file mode 100644 index 0000000..150634c Binary files /dev/null and b/QGraphicsView/ScreenShot/ImageView.gif differ diff --git a/README.md b/README.md index e9dee55..25d438e 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,6 @@ https://pyqt.site 论坛是专门针对PyQt5学习和提升开设的网站,分 如果您觉得这里的东西对您有帮助,别忘了帮忙点一颗:star:小星星:star: -## 微信博客小程序 - - - [客户端下载](https://github.com/PyQt5/PyQtClient/releases) [自定义控件](https://github.com/PyQt5/CustomWidgets) @@ -117,6 +113,7 @@ https://pyqt.site 论坛是专门针对PyQt5学习和提升开设的网站,分 - [QGraphicsView](QGraphicsView) - [绘制世界地图](QGraphicsView/WorldMap.py) - [添加QWidget](QGraphicsView/AddQWidget.py) + - [图片查看器](QGraphicsView/ImageView.py) - [QCalendarWidget](QCalendarWidget) - [QSS美化日历样式](QCalendarWidget/CalendarQssStyle.py) - [QLCDNumber](QLCDNumber)