当前位置: 首页 > ai >正文

Qt小组件 - 8 图片浏览器

一个自制的图片浏览器,如果不想安装qfluentwidgetsCommandBarView可以使用QWidget+QPushButton替代

安装 qfluentwidgets

pip install PySide6-Fluent-Widgets[full]

代码示例

# coding: utf-8
from typing import Unionfrom PySide6.QtCore import Qt, QRectF, QSize, Signal, QPropertyAnimation, QEasingCurve, Property
from PySide6.QtGui import QPainter, QPixmap, QWheelEvent, QResizeEvent, QImage
from PySide6.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QGraphicsItem, QFileDialog, \QVBoxLayout
from qfluentwidgets import FluentIcon as FIF, InfoBar, CommandBarView, MaskDialogBase, Actionfrom common import imageRequestclass PictureBrowserView(QGraphicsView):"""图片查看器"""closeSignal = Signal(bool)def __init__(self, parent=None):super().__init__(parent)self._rotationAngle = 0.0self.zoomInTimes = 0self.maxZoomInTimes = 22self.displayedImageSize = QSize(0, 0)self.verticalLayout = QVBoxLayout(self)self.toolsBar = CommandBarView(self)self.graphicsScene = QGraphicsScene(self)self.pixmapItem = QGraphicsPixmapItem()self.__animation = QPropertyAnimation(self, b'rotation', self)self.__animation.setDuration(100)self.__animation.setEasingCurve(QEasingCurve.Type.InOutQuart)self.__animation.finished.connect(self.setAdaptation)self.__initWidgets()self.__initSignals()def __initWidgets(self):self.toolsBar.move(0, 0)self.toolsBar.resize(self.width(), 50)self.setAlignment(Qt.AlignmentFlag.AlignCenter)self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)  # 隐藏水平滚动条self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)  # 隐藏垂直滚动条self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)  # 以鼠标所在位置为锚点进行缩放self.pixmapItem.setTransformationMode(Qt.TransformationMode.SmoothTransformation)  # 平滑转型self.setRenderHints(QPainter.RenderHint.Antialiasing | QPainter.RenderHint.LosslessImageRendering | QPainter.RenderHint.SmoothPixmapTransform)  # 平滑像素图变换self.setContentsMargins(0, 0, 0, 0)self.setViewportMargins(0, 0, 0, 0)# 设置布局self.verticalLayout.setContentsMargins(10, 10, 10, 10)self.verticalLayout.setSpacing(0)self.verticalLayout.addWidget(self.toolsBar, 0, Qt.AlignTop | Qt.AlignRight)# 添加图片标签self.graphicsScene.addItem(self.pixmapItem)self.setScene(self.graphicsScene)# 设置控件样式self.setStyleSheet('QGraphicsView{background-color: transparent; border: none;}')def __initSignals(self):self.toolsBar.addAction(Action(FIF.ROTATE, '旋转图片', triggered=lambda: self.setRotationByAnimation()))self.toolsBar.addAction(Action(FIF.ZOOM_IN, '放大图片', triggered=lambda: self.enlargePicture()))self.toolsBar.addAction(Action(FIF.ZOOM_OUT, '缩小图片', triggered=lambda: self.shrinkPicture()))self.toolsBar.addAction(Action(FIF.SAVE, '保存图片', triggered=self.__saveImage))self.toolsBar.addAction(Action(FIF.CLOSE, '关闭窗口', triggered=self.closeSignal.emit))self.toolsBar.resizeToSuitableWidth()def __saveImage(self):fileName, t = QFileDialog.getSaveFileName(self, self.tr("保存图片"), "", self.tr("图片 (*.png)"))if fileName:self.pixmapItem.pixmap().save(fileName, 'PNG')InfoBar.success('', self.tr("图片已保存到") + fileName, self.window())def __getScaleRatio(self):"""获取显示的图像和原始图像的缩放比例:return:"""pm = self.pixmapItem.pixmap()if pm.isNull():return 1pw = pm.width()ph = pm.height()rw = min(1, self.width() / pw)rh = min(1, self.height() / ph)return min(rw, rh)def __setDragEnabled(self, isEnabled: bool):"""设置拖拽是否启动:param isEnabled: bool:return:"""if isEnabled:self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)else:self.setDragMode(QGraphicsView.DragMode.NoDrag)def __isEnableDrag(self):"""根据图片的尺寸决定是否启动拖拽功能:return:"""v = self.verticalScrollBar().maximum() > 0h = self.horizontalScrollBar().maximum() > 0return v or hdef getRotation(self) -> float:return self.pixmapItem.rotation()def setRotation(self, stepSize: Union[float, int] = 90.0):"""顺时针旋转:param stepSize: 步长,旋转角度:return:"""if self.pixmapItem.pixmap().isNull():return# self.pixmapItem.setTransformOriginPoint(self.pixmapItem.boundingRect().center())  # 指定图片旋转中心点self.pixmapItem.setRotation(stepSize)def setRotationByAnimation(self, stepSize: int = 90):"""顺时针旋转动画:param stepSize: 步长,旋转角度:return:"""if self.__animation.state() == QPropertyAnimation.State.Running:returnself.__animation.setStartValue(self._rotationAngle)self._rotationAngle += stepSizeself.__animation.setEndValue(self._rotationAngle)self.__animation.start()def resetTransform(self):"""重置变换:return:"""self.zoomInTimes = 0self.__setDragEnabled(False)super().resetTransform()def setAdaptation(self):"""缩放以适应:return:"""self.setSceneRect(QRectF(self.pixmapItem.pixmap().rect()))self.fitInView(self.pixmapItem)self.__setDragEnabled(False)self.zoomInTimes = 0def setOriginalSize(self):"""设置 1:1 大小:return:"""self.resetTransform()self.setSceneRect(QRectF(self.pixmapItem.pixmap().rect()))self.__setDragEnabled(self.__isEnableDrag())self.zoomInTimes = self.getZoomInTimes(self.pixmapItem.pixmap().width())def enlargePicture(self, anchor=QGraphicsView.ViewportAnchor.AnchorUnderMouse):"""放大图片:return:"""if self.zoomInTimes == self.maxZoomInTimes:returnself.setTransformationAnchor(anchor)self.zoomInTimes += 1self.scale(1.1, 1.1)self.__setDragEnabled(self.__isEnableDrag())# 还原 anchorself.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)def shrinkPicture(self, anchor=QGraphicsView.ViewportAnchor.AnchorUnderMouse):"""缩小图片:return:"""if self.zoomInTimes == 0 and not self.__isEnableDrag():returnself.setTransformationAnchor(anchor)self.zoomInTimes -= 1# 原始图像的大小pm = self.pixmapItem.pixmap()pw = pm.width()ph = pm.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(QGraphicsView.ViewportAnchor.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.pixmapItem.pixmap().size()self.zoomInTimes = 0def resizeEvent(self, event: QResizeEvent):"""重写 resizeEvent 事件,调整图片大小:param event::return:"""# super().resizeEvent(event)if self.zoomInTimes > 0:return# 调整图片大小ratio = self.__getScaleRatio()self.displayedImageSize = self.pixmapItem.pixmap().size() * ratioif ratio < 1:self.fitInView(self.pixmapItem)else:self.resetTransform()def wheelEvent(self, e: QWheelEvent):"""滚动鼠标滚轮缩放图片:param e::return:"""if e.angleDelta().y() > 0:self.enlargePicture()else:self.shrinkPicture()def setPixmap(self, pixmap: Union[str, QPixmap, QImage]):"""设置图片:param pixmap::return:"""if not pixmap:returnif isinstance(pixmap, str):pixmap = QPixmap(pixmap)elif isinstance(pixmap, QImage):pixmap = QPixmap.fromImage(pixmap)# 设置图片, 并设置场景大小self.pixmapItem.setPixmap(pixmap)# 缩放图片ratio = self.__getScaleRatio()self.displayedImageSize = pixmap.size() * ratioself.pixmapItem.setTransformOriginPoint(self.pixmapItem.boundingRect().center())self.setSceneRect(QRectF(pixmap.rect()))self.setAdaptation()def setUrl(self, url: str):imageRequest(self, url)rotation = Property(float, getRotation, setRotation)class PictureBrowserDialog(MaskDialogBase):"""图片浏览器"""def __init__(self, parent=None):super().__init__(parent)self.vBoxLayout = QVBoxLayout(self.widget)self.view = PictureBrowserView(self.widget)self.view.closeSignal.connect(self.close)self.vBoxLayout.setContentsMargins(0, 0, 0, 0)self._hBoxLayout.setContentsMargins(0, 0, 0, 0)self.vBoxLayout.addWidget(self.view)self.setClosableOnMaskClicked(True)def setUrl(self, url: str):self.view.setUrl(url)
main.py

QImageQPixmap不太支持大文件浏览,或者未知图片类型,使用pillow嵌套使用

# coding: utf-8
import sys
from PIL import Image
from PIL.ImageQt import toqpixmap
from PySide6.QtWidgets import QApplicationfrom components import PictureBrowserViewapp = QApplication(sys.argv)
view = PictureBrowserView()
# view.setPixmap(r"G:\手机\壁纸\20250616153644.png")
view.setPixmap(toqpixmap(Image.open(r"G:\手机\壁纸\0250616153644.png")))
view.show()
sys.exit(app.exec())

在这里插入图片描述

http://www.xdnf.cn/news/16392.html

相关文章:

  • go‑cdc‑chunkers:用 CDC 实现智能分块 强力去重
  • SpringBoot轻松集成豆包AI
  • 精简 RT-Thread 工程并查找占用空间大的模块
  • 中国汽车能源消耗量(2010-2024年)
  • java里List链式编程
  • 【智慧物联网平台】安装部署教程——仙盟创梦IDE
  • Jenkins流水线部署+webhook2.0
  • 四、计算机组成原理——第7章:输入/输出系统
  • 命令执行漏洞
  • EAP(基于事件的异步编程模式)
  • 思途SQL学习 0728
  • SIM2REAL记录
  • 初识 docker [下] 项目部署
  • 亚马逊地址关联暴雷:新算法下的账号安全保卫战
  • 通过具有一致性嵌入的大语言模型(LMMs)实现端到端乳腺癌放射治疗计划制定|文献速递-医学影像算法文献分享
  • 反欺诈系统:Oracle 到 ES 迁移实战
  • 形参表不匹配(BUG)
  • R语言常用扩展包
  • 【自动化运维神器Ansible】Ansible常用模块之unarchive模块详解
  • YOLO11 改进、魔改|低分辨率自注意力机制LRSA ,提取全局上下文建模与局部细节,提升小目标、密集小目标的检测能力
  • 10、Docker Compose 安装 MySQL
  • 动/静态库的原理及制作
  • 鸿蒙打包签名
  • Linux:线程同步与线程互斥
  • Vue 工程化
  • 重构vite.config.json
  • Linux Shell 命令
  • 设计模式(九)结构型:组合模式详解
  • 卷积神经网络研讨
  • 设计模式(三)创建型:抽象工厂模式详解