实现了一个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