QGraphicsScene 和 QGraphicsItem 处理程序
QGraphicsScene and QGraphicsItem handlers
我是 Qt 的新手,尤其是 PyQt5。我正在尝试使用 QGraphicsView、QGraphicsScene 和 QGraphicsPixmapItem 开发 GUI。我的 objective 是在用户单击场景时向场景添加项目(使用 QGraphicsScene 子类中的 mousePressedEvent() 实现),并且使用 mouseMoveEvent(),我能够移动元素。
然后,我发现,通过我的实现,项目可以像从边界矩形外“推动”它们一样移动。所以,为了修复它,经过一番寻找,我决定实现一个QGraphicsPixmapItem的子类来实现它自己的事件函数。
不过,我发现我的项目无法识别 mousePressed 或 mouseMove 事件,而是来自 QGraphicsScene 的事件。我的问题是:
- 在没有我遇到的第一个问题的情况下移动元素的最有效方法是什么?
- 是否可以合并场景和项目事件处理程序?我还没有完全理解事件传播。
为了说得更清楚,我将移动问题的代码留在下面:
#!/usr/bin/env python3
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class GraphicsScene(QGraphicsScene):
def __init__(self):
super(GraphicsScene, self).__init__()
self.image = 'car.png' # Image of your own
self.inserted = False
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton and not self.inserted:
img = QPixmap(self.image).scaled(50, 50, Qt.KeepAspectRatio)
pixmap = QGraphicsPixmapItem(img)
offset = pixmap.boundingRect().topLeft() - pixmap.boundingRect().center()
pixmap.setOffset(offset.x(), offset.y())
pixmap.setShapeMode(QGraphicsPixmapItem.BoundingRectShape)
pixmap.setFlag(QGraphicsItem.ItemIsSelectable, True)
pixmap.setPos(event.scenePos())
super().mousePressEvent(event)
self.addItem(pixmap)
self.inserted = True
else:
pass
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
item = self.itemAt(event.scenePos(), QTransform())
if item is None:
return
orig_cursor_position = event.lastScenePos()
updated_cursor_position = event.scenePos()
orig_position = item.scenePos()
updated_cursor_x = updated_cursor_position.x() - orig_cursor_position.x() + orig_position.x()
updated_cursor_y = updated_cursor_position.y() - orig_cursor_position.y() + orig_position.y()
item.setPos(QPointF(updated_cursor_x, updated_cursor_y))
class MainWindow(QMainWindow):
def __init__(self):
super(QMainWindow, self).__init__()
self.resize(600, 600)
self.canvas = QGraphicsView()
self.scene = GraphicsScene()
self.setCentralWidget(self.canvas)
self.canvas.setScene(self.scene)
def showEvent(self, event):
self.canvas.setSceneRect(QRectF(self.canvas.viewport().rect()))
def resizeEvent(self, event):
self.canvas.setSceneRect(QRectF(self.canvas.viewport().rect()))
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
我认为 OP 不必要地复杂,因为 QGraphicsItems(如 QGraphicsPixmapItem)已经实现了这个功能,它只剩下激活 QGraphicsItem::ItemIsMovable 标志:
class GraphicsScene(QGraphicsScene):
def __init__(self):
super(GraphicsScene, self).__init__()
self.image = "car.png" # Image of your own
self.inserted = False
def mousePressEvent(self, event):
super().mousePressEvent(event)
if event.button() == Qt.LeftButton and not self.inserted:
img = QPixmap(self.image).scaled(50, 50, Qt.KeepAspectRatio)
pixmap = QGraphicsPixmapItem(img)
pixmap.setOffset(-pixmap.boundingRect().center())
pixmap.setShapeMode(QGraphicsPixmapItem.BoundingRectShape)
pixmap.setFlag(QGraphicsItem.ItemIsSelectable, True)
pixmap.setFlag(QGraphicsItem.ItemIsMovable, True)
pixmap.setPos(event.scenePos())
self.addItem(pixmap)
self.inserted = True
不需要覆盖 mouseMoveEvent。
我是 Qt 的新手,尤其是 PyQt5。我正在尝试使用 QGraphicsView、QGraphicsScene 和 QGraphicsPixmapItem 开发 GUI。我的 objective 是在用户单击场景时向场景添加项目(使用 QGraphicsScene 子类中的 mousePressedEvent() 实现),并且使用 mouseMoveEvent(),我能够移动元素。
然后,我发现,通过我的实现,项目可以像从边界矩形外“推动”它们一样移动。所以,为了修复它,经过一番寻找,我决定实现一个QGraphicsPixmapItem的子类来实现它自己的事件函数。
不过,我发现我的项目无法识别 mousePressed 或 mouseMove 事件,而是来自 QGraphicsScene 的事件。我的问题是:
- 在没有我遇到的第一个问题的情况下移动元素的最有效方法是什么?
- 是否可以合并场景和项目事件处理程序?我还没有完全理解事件传播。
为了说得更清楚,我将移动问题的代码留在下面:
#!/usr/bin/env python3
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class GraphicsScene(QGraphicsScene):
def __init__(self):
super(GraphicsScene, self).__init__()
self.image = 'car.png' # Image of your own
self.inserted = False
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton and not self.inserted:
img = QPixmap(self.image).scaled(50, 50, Qt.KeepAspectRatio)
pixmap = QGraphicsPixmapItem(img)
offset = pixmap.boundingRect().topLeft() - pixmap.boundingRect().center()
pixmap.setOffset(offset.x(), offset.y())
pixmap.setShapeMode(QGraphicsPixmapItem.BoundingRectShape)
pixmap.setFlag(QGraphicsItem.ItemIsSelectable, True)
pixmap.setPos(event.scenePos())
super().mousePressEvent(event)
self.addItem(pixmap)
self.inserted = True
else:
pass
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
item = self.itemAt(event.scenePos(), QTransform())
if item is None:
return
orig_cursor_position = event.lastScenePos()
updated_cursor_position = event.scenePos()
orig_position = item.scenePos()
updated_cursor_x = updated_cursor_position.x() - orig_cursor_position.x() + orig_position.x()
updated_cursor_y = updated_cursor_position.y() - orig_cursor_position.y() + orig_position.y()
item.setPos(QPointF(updated_cursor_x, updated_cursor_y))
class MainWindow(QMainWindow):
def __init__(self):
super(QMainWindow, self).__init__()
self.resize(600, 600)
self.canvas = QGraphicsView()
self.scene = GraphicsScene()
self.setCentralWidget(self.canvas)
self.canvas.setScene(self.scene)
def showEvent(self, event):
self.canvas.setSceneRect(QRectF(self.canvas.viewport().rect()))
def resizeEvent(self, event):
self.canvas.setSceneRect(QRectF(self.canvas.viewport().rect()))
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
我认为 OP 不必要地复杂,因为 QGraphicsItems(如 QGraphicsPixmapItem)已经实现了这个功能,它只剩下激活 QGraphicsItem::ItemIsMovable 标志:
class GraphicsScene(QGraphicsScene):
def __init__(self):
super(GraphicsScene, self).__init__()
self.image = "car.png" # Image of your own
self.inserted = False
def mousePressEvent(self, event):
super().mousePressEvent(event)
if event.button() == Qt.LeftButton and not self.inserted:
img = QPixmap(self.image).scaled(50, 50, Qt.KeepAspectRatio)
pixmap = QGraphicsPixmapItem(img)
pixmap.setOffset(-pixmap.boundingRect().center())
pixmap.setShapeMode(QGraphicsPixmapItem.BoundingRectShape)
pixmap.setFlag(QGraphicsItem.ItemIsSelectable, True)
pixmap.setFlag(QGraphicsItem.ItemIsMovable, True)
pixmap.setPos(event.scenePos())
self.addItem(pixmap)
self.inserted = True
不需要覆盖 mouseMoveEvent。