pyqt add rectangle in Qgraphicsscene
Asked Answered
L

1

6

I have a scene like this

class Scene(QtWidgets.QGraphicsScene):
    def __init__(self, parent=None):
        super(Scene, self).__init__(parent)

    def mousePressEvent(self, event):
        print('scene pressed')
        self.wid = MyRect(event.pos(), event.pos())
        self.addItem(self.wid)
        self.wid.show()

I would like class MyRect(QtWidgets.QGraphicsRectItem) with painter, mouse event and so on to be a draggable rectangle. all stuff in MyRect

So then I could have many Rectangle to the scene and even after draw line between them and so on (kind of diagram app), but keeping objects related editable options in MyRect, MyLine , ....

I thought :

class MyRect(QtWidgets.QGraphicsRectItem):
    def __init__(self, begin, end, parent=None):
        super().__init__(parent)
        self.begin = begin
        self.end = end

    def paintEvent(self, event):
        print('painting')
        qp = QtGui.QPainter(self)
        qp.drawRect(QtCore.QRect(self.begin, self.end))

    def mousePressEvent(self, event):
        self.begin = event.pos()
        self.end = event.pos()
        self.update()

    def mouseMoveEvent(self, event):
        self.end = event.pos()
        self.update()

    def mouseReleaseEvent(self, event):
        self.begin = event.pos()
        self.end = event.pos()
        self.update()

But I does not work (paint event not initiated whereas mousepressed event in scene is intiated)

I did not find what I wanted through the web so started totry do it by myself. I'm pretty sure it is a must known starting point but I cannot find it

Loganloganberry answered 9/10, 2018 at 19:58 Comment(0)
S
10

First of all a QGraphicsItem is not a QWidget, so it has those events and does not handle them directly, that's what QGraphicsView and QGraphicsScene do. For example you say that you want to have a moveable rectangle because that task is simple is QGraphicsView, it is not necessary to overwrite:

from PyQt5 import QtCore, QtWidgets

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        scene = QtWidgets.QGraphicsScene(self)
        view = QtWidgets.QGraphicsView(scene)
        self.setCentralWidget(view)

        rect_item = QtWidgets.QGraphicsRectItem(QtCore.QRectF(0, 0, 100, 100))
        rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
        scene.addItem(rect_item) 


if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

If you want to change the way you paint the rectangle you must overwrite the paint() method as shown below:

from PyQt5 import QtCore, QtGui, QtWidgets


class RectItem(QtWidgets.QGraphicsRectItem):
    def paint(self, painter, option, widget=None):
        super(RectItem, self).paint(painter, option, widget)
        painter.save()
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setBrush(QtCore.Qt.red)
        painter.drawEllipse(option.rect)
        painter.restore()

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        scene = QtWidgets.QGraphicsScene(self)
        view = QtWidgets.QGraphicsView(scene)
        self.setCentralWidget(view)

        rect_item = RectItem(QtCore.QRectF(0, 0, 100, 100))
        rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
        scene.addItem(rect_item) 


if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

Update:

from PyQt5 import QtCore, QtGui, QtWidgets

class GraphicsScene(QtWidgets.QGraphicsScene):
    def __init__(self, parent=None):
        super(GraphicsScene, self).__init__(QtCore.QRectF(-500, -500, 1000, 1000), parent)
        self._start = QtCore.QPointF()
        self._current_rect_item = None

    def mousePressEvent(self, event):
        if self.itemAt(event.scenePos(), QtGui.QTransform()) is None:
            self._current_rect_item = QtWidgets.QGraphicsRectItem()
            self._current_rect_item.setBrush(QtCore.Qt.red)
            self._current_rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
            self.addItem(self._current_rect_item)
            self._start = event.scenePos()
            r = QtCore.QRectF(self._start, self._start)
            self._current_rect_item.setRect(r)
        super(GraphicsScene, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if self._current_rect_item is not None:
            r = QtCore.QRectF(self._start, event.scenePos()).normalized()
            self._current_rect_item.setRect(r)
        super(GraphicsScene, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        self._current_rect_item = None
        super(GraphicsScene, self).mouseReleaseEvent(event)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        scene =GraphicsScene(self)
        view = QtWidgets.QGraphicsView(scene)
        self.setCentralWidget(view)


if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())
Speight answered 9/10, 2018 at 20:23 Comment(2)
well I'd like to do soething like question 44468775 you previously answered but inside a scene and to add as many rectangle or whatever once I click or double clicked (I'd like to build something like simple diagrams) / I just checked your github repo diagram-scene in github but it's a bit heavy and I need simpler things to understand :) (sorry for annoying)Loganloganberry
That's it and being possible to add as many as you want, this squeleton would be very helpfull (nearly must have tuto). Agreed your github repo is quite large, just need to navigate inside. Qt doc is often in C++ and translation in python is not so easy for non programmers like me. Anyway thanks for the answersLoganloganberry

© 2022 - 2024 — McMap. All rights reserved.