Pyside6实现的ImageView类

实现了一个ImageView类,继承自QGraphicsView,主要overwrite鼠标和滚轮事件,实现基本的拖拽,以鼠标中心点进行缩放。

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
                            QMetaObject, QObject, QPoint, QRect,
                            QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
                           QFont, QFontDatabase, QGradient, QIcon,
                           QImage, QKeySequence, QLinearGradient, QPainter,
                           QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QAbstractScrollArea, QApplication, QGraphicsView, QMainWindow,
                               QMenuBar, QSizePolicy, QStatusBar, QVBoxLayout,
                               QWidget)
from PySide6 import QtGui, QtWidgets

import copy
import numpy as np


class QImageView(QGraphicsView):
    def __init__(self, parent):
        super(QImageView, self).__init__(parent)
        self.setMouseTracking(True)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        #self.setCacheMode(QGraphicsView.CacheBackground)
        #self.setDragMode(QGraphicsView.ScrollHandDrag)
        #self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        #self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)

        self.scene = QtWidgets.QGraphicsScene()
        self.img = QtGui.QPixmap()
        self.img_sz = []

        self.scale_current = 1
        self.scale_fill = 1
        self.scale_index = 0
        self.scale_lut_base = [0.01, 0.02, 0.05, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.25, 1.5, 1.75,
                               2.0, 3.0, 5.0, 7.0, 10.0, 20.0, 30.0, 50.0]
        self.scale_lut = self.scale_lut_base.copy()

        self.startpos = QPoint(0, 0)  # 鼠标中键按下时起始点
        self.endpos = QPoint(0, 0)  # 鼠标中键弹起时终点

        self.nposx = 0  # 视图移动参数x
        self.nposy = 0  # 视图移动参数y

    def set_shown_image(self, img):
        #self.img.load(filename)
        self.img = img
        self.img_sz = self.img.size()
        self.scene.setSceneRect(0, 0, self.img_sz.width(), self.img_sz.height())
        self.scene.addItem(QtWidgets.QGraphicsPixmapItem(self.img))
        self.setScene(self.scene)
        self.setTransform(QtGui.QTransform())

        # init scale lut
        size = self.size()
        scale_fill_h = size.height() / self.img_sz.height()
        scale_fill_w = size.width() / self.img_sz.width()
        self.scale_fill = min(scale_fill_w, scale_fill_h)
        self.scale_lut = self.scale_lut_base.copy()
        if scale_fill_h not in self.scale_lut:
            self.scale_lut.append(scale_fill_h)
        if scale_fill_w not in self.scale_lut:
            self.scale_lut.append(scale_fill_w)
        self.scale_lut.sort()
        self.scale_index = self.scale_lut.index(self.scale_fill)
        self.scale_current = self.scale_lut[self.scale_index]

        img_center = QPoint(self.img_sz.width() // 2, self.img_sz.height() // 2)
        self.setTransform(QtGui.QTransform(self.scale_fill, 0, 0, 0, self.scale_fill, 0, 0, 0, 1))
        self.centerOn(img_center)

    def wheelEvent(self, event):
        self.setTransformationAnchor(QGraphicsView.NoAnchor)
        self.setResizeAnchor(QGraphicsView.NoAnchor)
        if event.angleDelta().y() > 0.5 and self.scale_index < len(self.scale_lut) - 1:  # zoom in
            self.scale_index = self.scale_index + 1
        elif event.angleDelta().y() < 0.5 and self.scale_index > 0:  # zoom out
            self.scale_index = self.scale_index - 1
        self.scale_current = self.scale_lut[self.scale_index]

        oldpos = self.mapToScene(QPoint(event.position().x(), event.position().y()))
        self.setTransform(QtGui.QTransform(self.scale_current, 0, 0, 0, self.scale_current, 0, 0, 0, 1))
        newpos = self.mapToScene(QPoint(event.position().x(), event.position().y()))
        delta = newpos - oldpos
        self.translate(delta.x(), delta.y())

    def mousePressEvent(self, event):
        button = event.button()
        # 按住ctrl时变更鼠标样式
        if button == Qt.LeftButton:
            self.setCursor(Qt.OpenHandCursor)
            self.startpos = self.mapToScene(event.pos())

    def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None:
        button = event.buttons()

        if button == Qt.LeftButton:
            self.endpos = self.mapToScene(event.pos())
            delta = self.endpos - self.startpos
            delta = delta * self.transform().m11()  # 乘以缩放比
            self.centerOn(self.mapToScene(QPoint(self.viewport().rect().width() / 2 - delta.x(),
                                                 self.viewport().rect().height() / 2 - delta.y())))

    def mouseReleaseEvent(self, event):
        button = event.button()
        # 鼠标中键弹起时进行视图移动
        if button == Qt.LeftButton:
            # 变更鼠标样式
            self.setCursor(Qt.ArrowCursor)
            # 记录当前点进行视图移动
            self.endpos = self.mapToScene(event.pos())
            delta = self.endpos - self.startpos
            delta = delta * self.transform().m11() # 乘以缩放比
            self.centerOn(self.mapToScene(QPoint(self.viewport().rect().width()/2-delta.x(),
                                                 self.viewport().rect().height()/2-delta.y())))

参考连接:

用 Pyqt5 打造一个精美 图片浏览器_pyqt5 预览图片-CSDN博客

PyQt(PySide6)实现QGraphicsView滚轮缩放与拖动 | OrdosX

QGraphicsView 显示图片 – 知乎 (zhihu.com)

QGraphicsView架构学习总结(1) – 知乎 (zhihu.com)

https://www.cnblogs.com/xxhbdk/p/15938805.htm

PyCharm下安装配置PySide6开发环境(Qt Designer、PyUIC和PyRCC)_pycharm pyside6_SZ深呼吸的博客-CSDN博客

QT中QMainWindow、QWidget、QDialog – 超酷小子 – 博客园 (cnblogs.com)

PyQt5 QMainWindow主界面跳转实现_qt只有mainwindow跳转-CSDN博客

图形视图(03):【类】QGraphicsView [官翻]_hitzsf的博客-CSDN博客

PyQt graphicsView自适应显示图像 – willwuss – 博客园 (cnblogs.com)

qt,QGraphicsView实现鼠标中键拖动图片,鼠标滚轮缩放、两个窗口联动左键选点等功能(c++&pyqt两个版本)_qt滚轮放大缩小事件_踌躇向前的博客-CSDN博客

QGraphicsScene中Item缩放问题_qgraphicsscene缩放-CSDN博客

https://stackoverflow.com/questions/40680065/qgraphicsscene-view-scale-understanding

【[Qt]基于QGraphicsView的图像显示控件,支持放大、缩小、鼠标拖动】_qt图片控件_xiaohuihuihuige的博客-CSDN博客

QGraphicsView如何使图片以鼠标为中心进行放缩_qgraphicsview放大缩小移动-CSDN博客

https://stackoverflow.com/questions/68597852/zooming-in-on-mouse-position-with-qgraphicsview-scene

发表评论