缩放到鼠标位置 - pyside6
Zoom to mouse position - pyside6
您好,我正在尝试实现可缩放至鼠标位置的简单图像小部件。我在 Zooming in/out on a mouser point ? and 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 调整大小时,像素图不会调整大小,因此必须使用 setScaledContents(True)
。
请注意,用于缩放和平移的算法效果不佳,因为它没有正确考虑滚动条范围的变化。
我提出了一个替代版本,实际上 可以在鼠标上缩放,类似于在普通图像 viewers/editors 和地图查看器中发生的情况。诀窍是将鼠标位置映射到标签,并根据 scaled 位置获得增量:
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 不太适合此类用途(尤其是大图像和高缩放值)。我强烈建议您考虑切换到 Graphics View Framework.
您好,我正在尝试实现可缩放至鼠标位置的简单图像小部件。我在 Zooming in/out on a mouser point ? and 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 调整大小时,像素图不会调整大小,因此必须使用 setScaledContents(True)
。
请注意,用于缩放和平移的算法效果不佳,因为它没有正确考虑滚动条范围的变化。
我提出了一个替代版本,实际上 可以在鼠标上缩放,类似于在普通图像 viewers/editors 和地图查看器中发生的情况。诀窍是将鼠标位置映射到标签,并根据 scaled 位置获得增量:
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 不太适合此类用途(尤其是大图像和高缩放值)。我强烈建议您考虑切换到 Graphics View Framework.