sceneRect().translated(x,y) 不适用于缩放
sceneRect().translated(x,y) doesn't work properly with zoom
一个月前我在问,如何翻译场景,我得到了很大的帮助并了解了它是如何工作的,在与 it/adding 工作人员一起工作一个月后,我注意到当你放大得非常近时几何或其他地方,翻译越来越有价值。
您必须放大到非常接近几何图形才能看到问题。这是一些代码:
from PyQt5.QtGui import QColor, QPolygonF, QPen, QBrush
from PyQt5.QtCore import Qt, QPointF, QPoint, pyqtSignal
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsPolygonItem, QApplication, \
QFrame, QSizePolicy
points_list = [[60.1, 19.6, 0.0], [60.1, 6.5, 0.0], [60.1, -6.5, 0.0], [60.1, -19.6, 0.0], [60.1, -19.6, 0.0],
[20.0, -19.6, 0.0], [-20, -19.6, 0.0], [-60.1, -19.6, 0.0], [-60.1, -19.6, 0.0], [-60.1, -6.5, 0.0],
[-60.1, 6.5, 0.0], [-60.1, 19.6, 0.0], [-60.1, 19.6, 0.0], [-20.0, 19.6, 0.0], [20.0, 19.6, 0.0],
[60.1, 19.6, 0.0]]
class MainWindow(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self, parent=parent)
self.create()
def create(self, **kwargs):
main_layout = QVBoxLayout()
graphics = MainGraphicsWidget()
main_layout.addWidget(graphics)
self.setLayout(main_layout)
class MainGraphicsWidget(QGraphicsView):
zoom_signal = pyqtSignal(bool)
def __init__(self, parent=None):
super(MainGraphicsWidget, self).__init__(parent)
self._scene = QGraphicsScene(backgroundBrush=Qt.gray)
self.__zoom = 0
self.setScene(self._scene)
self.setTransformationAnchor(QGraphicsView.NoAnchor)
#self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setBackgroundBrush(QBrush(QColor(30, 30, 30)))
self.setFrameShape(QFrame.NoFrame)
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
# self.sceneRect = self._scene.sceneRect()
self.testButton = GraphicsButton()
self._scene.addItem(self.testButton)
self.startPos = None
def mousePressEvent(self, event):
if event.modifiers() & Qt.AltModifier and event.button() == Qt.LeftButton:
self.startPos = event.pos()
else:
super(MainGraphicsWidget, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
modifierPressed = QApplication.keyboardModifiers()
if self.startPos is not None:
delta = self.startPos - event.pos()
transform = self.transform()
deltaX = delta.x() / transform.m11()
deltaY = delta.y() / transform.m22()
self.setSceneRect(self.sceneRect().translated(deltaX, deltaY))
self.startPos = event.pos()
else:
super(MainGraphicsWidget, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.startPos = None
super(MainGraphicsWidget, self).mouseReleaseEvent(event)
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
factor = 1.25
self.__zoom += 1
else:
factor = 0.8
self.__zoom -= 1
self.scale(factor, factor)
self.zoom_signal.emit(self.__zoom < 10)
class GraphicsButton(QGraphicsPolygonItem):
def __init__(self, parent=None):
super(GraphicsButton, self).__init__(parent)
self.myPolygon = QPolygonF([QPointF(v1, v2) for v1, v2, v3 in points_list])
self.setPen(QPen(QColor(0, 0, 0), 0, Qt.SolidLine, Qt.FlatCap, Qt.MiterJoin))
self.setPolygon(self.myPolygon)
self.setBrush(QColor(220, 40, 30))
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.setGeometry(500, 100, 500, 900)
window.show()
sys.exit(app.exec_())
(翻译开始使用 Alt + 左键单击 )
我想问题是当你放大得太近时,你的光标仍然沿着相同的坐标移动(它们不会变小)并且它开始平移得更慢,我不考虑计算我的代码。但为什么有时我的 sceneRect().translated()
会完全停止移动?我是否放大到至少我的光标(1x,1y)没有穿过的点?
所以我的问题是,如果我的理论正确,有人可以告诉我如何计算 delta
、放大和缩小吗?谢谢你,对不起我的英语
编辑:这是您需要放大多少倍才能看到问题的屏幕截图。
sceneRect
位于场景坐标中,而不是视图坐标中,因此对于您的计算,您必须使用 mapToScene 方法将鼠标点转换为场景坐标。此修改也应应用于场景中投影的视口矩形,因为它不等于 sceneRect
class MainGraphicsWidget(QGraphicsView):
zoom_signal = pyqtSignal(bool)
def __init__(self, parent=None):
# ...
self.startPos = QPointF()
def mousePressEvent(self, event):
if event.modifiers() & Qt.AltModifier and event.button() == Qt.LeftButton:
self.startPos = self.mapToScene(event.pos())
else:
super(MainGraphicsWidget, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if not self.startPos.isNull():
delta = self.startPos - self.mapToScene(event.pos())
r = self.mapToScene(self.viewport().rect()).boundingRect()
self.setSceneRect(r.translated(delta))
else:
super(MainGraphicsWidget, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.startPos = QPointF()
super(MainGraphicsWidget, self).mouseReleaseEvent(event)
def wheelEvent(self, event):
# ...
以上答案部分正确。我的看法是,您的方法是尝试通过考虑视口比例来平移 sceneRect。 “m11 和 m22”。但是,当您放大时,您的视口比例将小于 1。
平移函数不接受小于 1 的值。尝试在放大时打印出 DeltaX,您会看到只有当 DeltaX > 1 时场景才会移动。
您可以采取的两种方法是:
A) 当 Delta 轴大于 0 时,手动向上舍入到 1.1 之类的值,即大于 1。
transform = self.transform()
deltaX = delta.x() / transform.m11()
deltaY = delta.y() / transform.m22()
if 1 > deltaX > 0.1:
deltaX = 1.1
if 1 > deltaY > 0.1:
deltaY = 1.1
B) 像上面提到的 eyllanesc 一样,将视口投影到场景中,因此所做的任何转换都将在相对于视口 space 的场景 space 中。此外,为了使缩放位置保持一致,您还可以在缩放场景时将鼠标位置转换为场景 space。最后,eyllanesc 添加了一行代码,该代码是多余的并且可以正确翻译。按下鼠标键时不需要重新设置鼠标原点位置。
因此你可以得到这样的东西。
def __init__(self, parent):
super(GraphicsThingy, self).__init__(parent)
self.setTransformationAnchor(QGraphicsView.NoAnchor)
self.setResizeAnchor(QGraphicsView.NoAnchor)
self.installEventFilter(self)
self.mousePos = None
def wheelEvent(self, event):
if event.modifiers() & Qt.ControlModifier:
scaleDelta = event.angleDelta().y() / 35
factor = pow(self.zoomMultiplier, scaleDelta)
originalPos = self.mapToScene(event.pos())
self.scale(factor, factor)
newPos = self.mapToScene(event.pos())
deltaPos = newPos - originalPos
self.translate(deltaPos.x(), deltaPos.y())
event.accept()
def mousePressEvent(self, event):
if event.button() == Qt.MiddleButton:
self.mousePos = self.mapToScene(event.pos())
event.accept()
def mouseMoveEvent(self, event):
if self.movePos is not None:
delta = self.mousePos - self.mapFromScene(event.pos())
# Keeps scrolling speed consistent with zoom. Max(v,1) Ensures that the scale value will not multiply the scrolling speed.
delta.setX(delta.x() / max(self.transform().m11(),1))
delta.setY(delta.y() / max(self.transform().m22(),1))
# Change scene scene rect position based on delta
rect = self.mapToScene(self.viewport().rect()).boundingRect()
self.setSceneRect(rect.translated(delta))
self.update()
event.accept()
def mouseReleaseEvent(self, event):
self.mousePos = None
一个月前我在问,如何翻译场景,我得到了很大的帮助并了解了它是如何工作的,在与 it/adding 工作人员一起工作一个月后,我注意到当你放大得非常近时几何或其他地方,翻译越来越有价值。
您必须放大到非常接近几何图形才能看到问题。这是一些代码:
from PyQt5.QtGui import QColor, QPolygonF, QPen, QBrush
from PyQt5.QtCore import Qt, QPointF, QPoint, pyqtSignal
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsPolygonItem, QApplication, \
QFrame, QSizePolicy
points_list = [[60.1, 19.6, 0.0], [60.1, 6.5, 0.0], [60.1, -6.5, 0.0], [60.1, -19.6, 0.0], [60.1, -19.6, 0.0],
[20.0, -19.6, 0.0], [-20, -19.6, 0.0], [-60.1, -19.6, 0.0], [-60.1, -19.6, 0.0], [-60.1, -6.5, 0.0],
[-60.1, 6.5, 0.0], [-60.1, 19.6, 0.0], [-60.1, 19.6, 0.0], [-20.0, 19.6, 0.0], [20.0, 19.6, 0.0],
[60.1, 19.6, 0.0]]
class MainWindow(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self, parent=parent)
self.create()
def create(self, **kwargs):
main_layout = QVBoxLayout()
graphics = MainGraphicsWidget()
main_layout.addWidget(graphics)
self.setLayout(main_layout)
class MainGraphicsWidget(QGraphicsView):
zoom_signal = pyqtSignal(bool)
def __init__(self, parent=None):
super(MainGraphicsWidget, self).__init__(parent)
self._scene = QGraphicsScene(backgroundBrush=Qt.gray)
self.__zoom = 0
self.setScene(self._scene)
self.setTransformationAnchor(QGraphicsView.NoAnchor)
#self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setBackgroundBrush(QBrush(QColor(30, 30, 30)))
self.setFrameShape(QFrame.NoFrame)
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
# self.sceneRect = self._scene.sceneRect()
self.testButton = GraphicsButton()
self._scene.addItem(self.testButton)
self.startPos = None
def mousePressEvent(self, event):
if event.modifiers() & Qt.AltModifier and event.button() == Qt.LeftButton:
self.startPos = event.pos()
else:
super(MainGraphicsWidget, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
modifierPressed = QApplication.keyboardModifiers()
if self.startPos is not None:
delta = self.startPos - event.pos()
transform = self.transform()
deltaX = delta.x() / transform.m11()
deltaY = delta.y() / transform.m22()
self.setSceneRect(self.sceneRect().translated(deltaX, deltaY))
self.startPos = event.pos()
else:
super(MainGraphicsWidget, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.startPos = None
super(MainGraphicsWidget, self).mouseReleaseEvent(event)
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
factor = 1.25
self.__zoom += 1
else:
factor = 0.8
self.__zoom -= 1
self.scale(factor, factor)
self.zoom_signal.emit(self.__zoom < 10)
class GraphicsButton(QGraphicsPolygonItem):
def __init__(self, parent=None):
super(GraphicsButton, self).__init__(parent)
self.myPolygon = QPolygonF([QPointF(v1, v2) for v1, v2, v3 in points_list])
self.setPen(QPen(QColor(0, 0, 0), 0, Qt.SolidLine, Qt.FlatCap, Qt.MiterJoin))
self.setPolygon(self.myPolygon)
self.setBrush(QColor(220, 40, 30))
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.setGeometry(500, 100, 500, 900)
window.show()
sys.exit(app.exec_())
(翻译开始使用 Alt + 左键单击 )
我想问题是当你放大得太近时,你的光标仍然沿着相同的坐标移动(它们不会变小)并且它开始平移得更慢,我不考虑计算我的代码。但为什么有时我的 sceneRect().translated()
会完全停止移动?我是否放大到至少我的光标(1x,1y)没有穿过的点?
所以我的问题是,如果我的理论正确,有人可以告诉我如何计算 delta
、放大和缩小吗?谢谢你,对不起我的英语
编辑:这是您需要放大多少倍才能看到问题的屏幕截图。
sceneRect
位于场景坐标中,而不是视图坐标中,因此对于您的计算,您必须使用 mapToScene 方法将鼠标点转换为场景坐标。此修改也应应用于场景中投影的视口矩形,因为它不等于 sceneRect
class MainGraphicsWidget(QGraphicsView):
zoom_signal = pyqtSignal(bool)
def __init__(self, parent=None):
# ...
self.startPos = QPointF()
def mousePressEvent(self, event):
if event.modifiers() & Qt.AltModifier and event.button() == Qt.LeftButton:
self.startPos = self.mapToScene(event.pos())
else:
super(MainGraphicsWidget, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if not self.startPos.isNull():
delta = self.startPos - self.mapToScene(event.pos())
r = self.mapToScene(self.viewport().rect()).boundingRect()
self.setSceneRect(r.translated(delta))
else:
super(MainGraphicsWidget, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.startPos = QPointF()
super(MainGraphicsWidget, self).mouseReleaseEvent(event)
def wheelEvent(self, event):
# ...
以上答案部分正确。我的看法是,您的方法是尝试通过考虑视口比例来平移 sceneRect。 “m11 和 m22”。但是,当您放大时,您的视口比例将小于 1。 平移函数不接受小于 1 的值。尝试在放大时打印出 DeltaX,您会看到只有当 DeltaX > 1 时场景才会移动。
您可以采取的两种方法是:
A) 当 Delta 轴大于 0 时,手动向上舍入到 1.1 之类的值,即大于 1。
transform = self.transform()
deltaX = delta.x() / transform.m11()
deltaY = delta.y() / transform.m22()
if 1 > deltaX > 0.1:
deltaX = 1.1
if 1 > deltaY > 0.1:
deltaY = 1.1
B) 像上面提到的 eyllanesc 一样,将视口投影到场景中,因此所做的任何转换都将在相对于视口 space 的场景 space 中。此外,为了使缩放位置保持一致,您还可以在缩放场景时将鼠标位置转换为场景 space。最后,eyllanesc 添加了一行代码,该代码是多余的并且可以正确翻译。按下鼠标键时不需要重新设置鼠标原点位置。
因此你可以得到这样的东西。
def __init__(self, parent):
super(GraphicsThingy, self).__init__(parent)
self.setTransformationAnchor(QGraphicsView.NoAnchor)
self.setResizeAnchor(QGraphicsView.NoAnchor)
self.installEventFilter(self)
self.mousePos = None
def wheelEvent(self, event):
if event.modifiers() & Qt.ControlModifier:
scaleDelta = event.angleDelta().y() / 35
factor = pow(self.zoomMultiplier, scaleDelta)
originalPos = self.mapToScene(event.pos())
self.scale(factor, factor)
newPos = self.mapToScene(event.pos())
deltaPos = newPos - originalPos
self.translate(deltaPos.x(), deltaPos.y())
event.accept()
def mousePressEvent(self, event):
if event.button() == Qt.MiddleButton:
self.mousePos = self.mapToScene(event.pos())
event.accept()
def mouseMoveEvent(self, event):
if self.movePos is not None:
delta = self.mousePos - self.mapFromScene(event.pos())
# Keeps scrolling speed consistent with zoom. Max(v,1) Ensures that the scale value will not multiply the scrolling speed.
delta.setX(delta.x() / max(self.transform().m11(),1))
delta.setY(delta.y() / max(self.transform().m22(),1))
# Change scene scene rect position based on delta
rect = self.mapToScene(self.viewport().rect()).boundingRect()
self.setSceneRect(rect.translated(delta))
self.update()
event.accept()
def mouseReleaseEvent(self, event):
self.mousePos = None