QGraphicsScene 和 QGraphicsItem 处理程序

问题描述

我是 Qt 的新手,特别是 PyQt5。我正在尝试使用 QGraphicsView、QGraphicsScene 和 QGraphicspixmapItem 开发 GUI。我的目标是在用户单击场景时向场景添加项目(使用 QGraphicsScene 子类中的 mousepressedEvent() 实现),并且使用 mouseMoveEvent() 可以移动元素。

然后,我发现,通过我的实现,项目可以像从边界矩形外“推”它们一样移动。所以,为了修复它,经过一番搜索,我决定实现 QGraphicspixmapItem 的一个子类来实现它自己的事件函数

尽管如此,我发现我的项目不能识别 mousepressed 和 mouseMove 事件,但可以识别来自 QGraphicsScene 的事件。我的问题是:

  1. 在没有我遇到的第一个问题的情况下移动元素的最有效方法是什么?
  2. 是否可以结合使用场景和项目事件处理程序?我还没有完全理解事件传播。

为了更清楚,我将我的代码放在下面用于移动问题:

#!/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。