dpoloa
dpoloa

Reputation: 15

QGraphicsScene and QGraphicsItem handlers

I'm new to Qt, and specially to PyQt5. I'm trying to develop a GUI using QGraphicsView, QGraphicsScene and QGraphicsPixmapItem. My objective is to add items to the scene when the user clicks on the scene (achieved using mousePressedEvent() in a QGraphicsScene subclass) and, using mouseMoveEvent(), I was able to move the element.

Then, I discovered that, with my implementation, the items could be moved like "pushing" them from outside the bounding rect. So, in order to fix it, after some searching, I decided to implement a subclass of QGraphicsPixmapItem to implement its own event functions.

Nevertheless, I found out that my item does not recognize mousePressed nor mouseMove events, but the ones from QGraphicsScene. My questions are:

  1. What is the most efficient way to move elements without having the first problem I encountered?
  2. Is it possible to combine both scene and item event handlers? I have not understood event propagation completely.

To make it more clear, I leave my code down below for the moving problem:

#!/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_())

Upvotes: 1

Views: 282

Answers (1)

eyllanesc
eyllanesc

Reputation: 243945

I think that the OP is unnecessarily complicated since the QGraphicsItems (like QGraphicsPixmapItem) already implement this functionality and it only remains to activate the QGraphicsItem::ItemIsMovable flag:

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

Override mouseMoveEvent is unnecessary.

Upvotes: 1

Related Questions