我有两类编辑过的
QGrapchicsView
,一类(GraphicsView
)显示线条并启用缩放和平移。第二类 (PolygonGrapchisView
) 仅根据从第一类接收到的信号更新场景矩形以匹配第一类 GraphicsView
的场景。平移事件由中间按钮触发
问题
PolygonGrapchisView
类接收来自 GraphicsView
类的信号并更新场景矩形以匹配两个类的范围。
无论位置或缩放级别如何,来自
mousePressEvent
类的 mouseReleaseEvent
、mouseMoveEvent
和 GraphicsView
函数(平移事件)的信号都正确地设置了两个类的场景。我的意思是正确的,它在两个类中设置了矩形场景,以便在事件发生后,多边形和线相对于彼此保持在相同的位置。
当我尝试对
wheelEvent
(缩放事件)做同样的事情时,它有两种行为。第一个是当滚动条已满(占据整个水平和垂直条,没有移动滚动条的空间)或我们正在缩小时完成缩放事件,这里它“正确”工作。
第二个,是我们开始放大直到滚动条激活 并开始有移动空间,匹配场景矩形的信号失败。它没有对齐两个 graphicsview 类,这意味着多边形和线不会保持在相对于彼此的相同位置,而是开始重叠或彼此分开。如果您停止移动轮子并按下中间底部和平移场景,您可以解决这个未对齐问题。
这是情节的初始状态,这是所有鼠标事件后应该保持的状态。
这是在您放大直到激活滚动条时发生故障的地方。
当我们在
PolygonGrapchisView
类中执行平移或缩放事件时,无论缩放级别或滚动条的位置如何,GraphicsView
类的场景都会“正确”更新。它在鼠标事件期间和之后保持多边形和线之间的相对距离。
代码
from PyQt5 import QtWidgets, QtGui, QtCore
import sys
class PolygonGraphicsView(QtWidgets.QGraphicsView):
def __init__(self, scene, parent=None):
super(PolygonGraphicsView, self).__init__(scene, parent)
# Set the anchor point for zooming and resizing
self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
# Disable the scrollbars
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
@QtCore.pyqtSlot(QtCore.QRectF, QtGui.QTransform)
def setBounds(self, rect_scene, transform_matrix):
#set scene rect
self.setSceneRect(rect_scene)
# Update the transformation matrix to match GraphicsView
self.setTransform(transform_matrix)
class GraphicsView(QtWidgets.QGraphicsView):
#señal para cambiar el viewport del qgrapichsview de los poligonos
scene_rect_changed = QtCore.pyqtSignal(QtCore.QRectF, QtGui.QTransform)
def __init__(self, scene, parent=None):
super(GraphicsView, self).__init__(scene, parent)
# recursivamente encontrar el qmainwindow
cond = True
self._parent = self.parentWidget()
while cond:
if isinstance(self._parent, QtWidgets.QMainWindow):
cond = False
else:
self._parent = self._parent.parentWidget()
# "variables iniciales"
self.pos_init_class = None
self.scale_factor = 1.5
# # Set the anchor point for zooming and resizing
self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
#señal para el qgrapichsview de poligonos
self.polygon_graphicsview = self._parent.findChildren(PolygonGraphicsView, 'polygon_graphicsView')[0]
self.scene_rect_changed.connect(self.polygon_graphicsview.setBounds)
#apply transparent style sheet
self.this_style_sheet = """
background-color: transparent;
selection-background-color:transparent;
"""
self.setStyleSheet(self.this_style_sheet)
self.viewport().setStyleSheet(self.this_style_sheet)
def send_polygon_graphicsView_update(self):
# Emit the scene_rect_changed signal with the transformation matrix
new_rect = self.sceneRect()
self.scene_rect_changed.emit(new_rect, self.transform())
def mousePressEvent(self, event):
pos = self.mapToScene(event.pos())
# "pan mouse"
if event.button() == QtCore.Qt.MiddleButton:
self.pos_init_class = pos
#update position
self.send_polygon_graphicsView_update()
else:
super(GraphicsView, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
# pan
if self.pos_init_class and event.button() == QtCore.Qt.MiddleButton:
self.pos_init_class = None
# update position
self.send_polygon_graphicsView_update()
else:
super(GraphicsView, self).mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.pos_init_class:
# "pan"
delta = self.pos_init_class - self.mapToScene(event.pos())
r = self.mapToScene(self.viewport().rect()).boundingRect()
self.setSceneRect(r.translated(delta))
# update position
self.send_polygon_graphicsView_update()
super(GraphicsView, self).mouseMoveEvent(event)
def wheelEvent(self, event):
old_pos = self.mapToScene(event.pos())
# Determine the zoom factor
if event.angleDelta().y() > 0:
zoom_factor = self.scale_factor
else:
zoom_factor = 1 / self.scale_factor
# Apply the transformation to the view
transform = QtGui.QTransform()
transform.translate(old_pos.x(), old_pos.y())
transform.scale(zoom_factor, zoom_factor)
transform.translate(-old_pos.x(), -old_pos.y())
# Get the current transformation matrix and apply the new transformation to it
current_transform = self.transform()
self.setTransform(transform * current_transform)
# update position
self.send_polygon_graphicsView_update()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
# geometria de la ventana
self.geometry = QtCore.QRect(0, 0, 800, 500)
self.scene_rect_value = QtCore.QRectF(721200.96, -9679800.97, 500, -500)
# central widget
self.centralwidget = self.f_centralWidget()
# polygon grapchisview widget
self.polygon_graphicsView = self.f_polygon_grapchicsviewWidget(parent=self.centralwidget)
# graphics view widget
self.graphicsView, self.scene = self.f_graphicsviewWidget(parent=self.centralwidget)
#dummy generator
self.dummy_lines_polygons()
####################################################################################################################################################################################################
# widget functions
def f_centralWidget(self):
# main window widget
self.centralwidget = QtWidgets.QWidget(self)
self.setCentralWidget(self.centralwidget)
# define geometry main window
self.setGeometry(self.geometry)
return self.centralwidget
def f_graphicsviewWidget(self, parent):
# graphics view widget
self.scene = QtWidgets.QGraphicsScene()
self.graphicsView = GraphicsView(scene=self.scene, parent=parent)
# geometry widget
self.graphicsView.setGeometry(self.geometry)
self.graphicsView.setSceneRect(self.scene_rect_value)
return self.graphicsView, self.scene
def f_polygon_grapchicsviewWidget(self, parent):
# polygon graphics view widget
self.polygon_scene = QtWidgets.QGraphicsScene()
self.polygon_graphicsView = PolygonGraphicsView(scene=self.polygon_scene, parent=parent)
self.polygon_graphicsView.setObjectName('polygon_graphicsView')
# geometry widget
self.polygon_graphicsView.setGeometry(self.geometry)
self.polygon_graphicsView.setSceneRect(self.scene_rect_value)
return self.polygon_graphicsView
def dummy_lines_polygons(self):
polygon_list = [[[721278.105, 9679978.402], [721378.918, 9679958.288], [721395.355, 9680058.781], [721294.491, 9680079.538]],
[[721398.840, 9679959.473], [721486.867, 9679930.441], [721502.381, 9680029.483], [721416.757, 9680055.152]]]
for pol in polygon_list:
polygon = QtGui.QPolygonF()
for item in pol:
x = item[0]
y = -item[1]
polygon.append(QtCore.QPointF(x, y))
polygon_item = QtWidgets.QGraphicsPolygonItem(polygon)
brush = QtGui.QBrush(QtGui.QColor(0, 0, 255))
polygon_item.setBrush(brush)
self.polygon_scene.addItem(polygon_item)
# add some lines to the line view
line_list = [[[721385.198, 9679948.971], [721404.402, 9680064.235] ], [[721404.402, 9680064.235], [721512.651, 9680035.611]]]
pen = QtGui.QPen(QtGui.QColor(255, 0, 0))
for line in line_list:
x1 = line[0][0]
y1 = -line[0][1]
x2 = line[1][0]
y2 = -line[1][1]
line = QtWidgets.QGraphicsLineItem(x1, y1, x2, y2)
line.setPen(pen)
self.scene.addItem(line)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())