您好,我正在努力实现缩放到鼠标位置的简单图像小部件。我结合了放大/缩小摩尔点的示例?和 https://doc.qt.io/qt-5/qtwidgets-widgets-imageviewer-example.html。但是,图像未按预期缩放,比例尺也不会正确更新。这是我的代码:
import sys
from PySide6 import QtWidgets
from PySide6.QtCore import Qt
from PIL.ImageQt import ImageQt
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import QDialog, QVBoxLayout, QLabel, QScrollArea
class MyScrollArea(QScrollArea):
def __init__(self, imageWidget):
# initialize widget
super().__init__()
self.setWidget(imageWidget)
self.myImageWidget = imageWidget
self.oldScale = 1
self.newScale = 1
def wheelEvent(self, event) -> None:
if event.angleDelta().y() < 0:
# zoom out
self.newScale = 0.8
else:
# zoom in
self.newScale = 1.25
# compute scrollbar positions
scrollBarPosHorizontal = self.horizontalScrollBar().value()
scrollBarPosVertical = self.verticalScrollBar().value()
deltaToPos = (event.position() / self.oldScale) - (self.myImageWidget.pos() / self.oldScale)
delta = deltaToPos * self.newScale - deltaToPos * self.oldScale
# resize image
self.myImageWidget.resize(self.myImageWidget.size() * self.newScale)
# set scrollbars
self.horizontalScrollBar().setValue(scrollBarPosHorizontal+delta.x())
self.verticalScrollBar().setValue(scrollBarPosVertical+delta.y())
# save old scale
self.oldScale = self.newScale
class ImageViewer(QDialog):
def __init__(self, img):
# initialize widget
super().__init__()
self.setWindowTitle('Zoom example')
self.imageWidget = QLabel()
self.imageWidget.installEventFilter(self)
self.imageWidget.setAlignment(Qt.AlignCenter)
self.pixmap = QPixmap.fromImage(img)
self.imageWidget.setPixmap(self.pixmap)
# create scroll area
self.scrollArea = MyScrollArea(self.imageWidget)
# insert to layout
self.layout = QVBoxLayout()
self.layout.addWidget(self.scrollArea)
self.setLayout(self.layout)
if __name__ == '__main__':
# prepare app
app = QtWidgets.QApplication(sys.argv)
# prepare image
image = ImageQt("test.png")
# create viewer widget
MyWidget = ImageViewer(image)
MyWidget.show()
# close app
sys.exit(app.exec())
图像根本不缩放到鼠标点。我做错了什么?
主要问题是,默认情况下,当调整QLabel大小时,pixmap不会调整大小,因此必须使用setScaledContent(True)。
请注意,用于缩放和平移的算法效果不佳,因为它没有正确考虑滚动条范围的变化。
我提出了一个替代版本,它实际上缩放鼠标类似于常见图像查看器/编辑器和地图查看器中发生的情况。诀窍是将鼠标位置映射到标签,并根据缩放位置获取增量:
class MyScrollArea(QScrollArea):
def __init__(self, imageWidget):
# ...
imageWidget.setScaledContents(True)
# ...
def wheelEvent(self, event) -> None:
if event.angleDelta().y() < 0:
# zoom out
self.newScale = 0.8
else:
# zoom in
self.newScale = 1.25
widgetPos = self.myImageWidget.mapFrom(self, event.position())
# resize image
self.myImageWidget.resize(self.myImageWidget.size() * self.newScale)
delta = widgetPos * self.newScale - widgetPos
self.horizontalScrollBar().setValue(
self.horizontalScrollBar().value() + delta.x())
self.verticalScrollBar().setValue(
self.verticalScrollBar().value() + delta.y())
self.oldScale = self.newScale
请注意,QLabel不太适合此类目的(尤其是对于大图像和高缩放值)。我强烈建议您考虑切换到图形视图框架。