0

Let me explain my problem in detail. I have a QGraphicsRectItem as a parent in QGraphicsScene, and I have QGraphicsPolygonItems as its children. When The children are not selected and I move the parent everything's fine - they keep their positions relative to the parent and move with it. But when children are selected and I move the parent children move weirdly (I would like them to behave the same way as if they were not selected - move relative to their parent). Here's the code and a gif displaying both situations.

class Test(QWidget):
    def __init__(self, parent=None):
        super(Test, self).__init__(parent)
        self.resize(1000, 800)
        self.generalLayout = QVBoxLayout()
        self.view_ = GraphicsView()
        self.size_grip = QSizeGrip(self)

        self.generalLayout.addWidget(self.size_grip, 0, Qt.AlignBottom | Qt.AlignRight)
        self.generalLayout.addWidget(self.view_)

        self.setLayout(self.generalLayout)

    def contextMenuEvent(self, event):
        self.menu = QMenu(self)
        self.new_children_menu = QMenu("New child", self.menu)
        parentAction = QAction("New Parent", self)
        childAction = QAction('Child', self)

        click_pos = self.view_.mapToScene(event.pos())
        parent_item = self.itemUnderMouse()
        mouse_pos = self.mousePosition(click_pos, parent_item)

        parentAction.triggered.connect(lambda: self.view_.addParent(mouse_pos, parent_item))
        childAction.triggered.connect(lambda: self.view_.addButton(mouse_pos, parent_item))

        self.new_children_menu.addAction(childAction)
        self.menu.addAction(parentAction)
        self.menu.addMenu(self.new_children_menu)

        self.menu.popup(QCursor.pos())

    def mousePosition(self, click, prnt_item):
        if prnt_item is None:
            return click
        else:
            return prnt_item.mapFromScene(click)

    def itemUnderMouse(self):
        for item in self.view_.scene().items():
            if item.isUnderMouse():
                return item
            else:
                continue

class GraphicsView(QGraphicsView):
    def __init__(self):
        super(GraphicsView, self).__init__()
        self.setAttribute(Qt.WA_StyledBackground, True)
        self.setStyleSheet('background-color: white;')
        self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
        self.setMouseTracking(True)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setFrameShape(QFrame.NoFrame)

        self.setCursor(QCursor(Qt.PointingHandCursor))

        self.size_grip = QSizeGrip(self)
        self._scene = QGraphicsScene()

        self._scene.setSceneRect(0, 0, 400, 400)
        self.setScene(self._scene)
        self.fitInView(self.scene().sceneRect(), Qt.KeepAspectRatio)
        self.setDragMode(QGraphicsView.ScrollHandDrag)
        self.parent = GraphicsRectItem
        self.child = newButton

    def addParent(self, pos, prnt):
        new_parent = self.parent(0, 0, 100, 150)
        new_parent.setPos(pos)
        if prnt is None:
            self.scene().addItem(new_parent)
        else:
            new_parent.setParentItem(prnt)


    def addButton(self, pos, parent_item):
        new_button = self.child(pos)
        if parent_item is None:
            self.scene().addItem(new_button)
        else:
            new_button.setParentItem(parent_item)

class GraphicsRectItem(QGraphicsRectItem):

    def __init__(self, *args):

        super().__init__(*args)

        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, True)

class newButton(QGraphicsPolygonItem):
    def __init__(self, pos):
        super(newButton, self).__init__()
        self.newPoly = QPolygonF()
        self.newPolyPoints = (QPointF(0, 0),
                              QPointF(0, 50),
                              QPointF(50, 50),
                              QPointF(50, 0))
        for point in self.newPolyPoints:
            self.newPoly.append(point)

        self.setPolygon(self.newPoly)
        self.setBrush(QBrush(QColor("violet")))
        self.setPen(QPen(QColor("gray")))
        self.setFlags(
            self.ItemIsSelectable
            | self.ItemIsMovable
            | self.ItemIsFocusable
            | self.ItemSendsGeometryChanges
        )
        self.setAcceptHoverEvents(True)
        poly_center = self.boundingRect().center()
        self.setTransformOriginPoint(poly_center)
        self.setPos(pos)


if __name__ == '__main__':
    app = QApplication([])
    win = Test()
    win.show()
    app.exec_()

button movement issue gif

I also want the children to not go out of the parent's bounding rectangle area, but if I set the "ItemClipsChildrenToShape" flag the children disappear inside the parent. This gif illustrates that situation. ItemClipsChildrenToShape issue

musicamante
  • 41,230
  • 6
  • 33
  • 58
galaxy
  • 53
  • 1
  • 1
  • 15
  • 1
    Seems like a "bug". Or, at least, an unexpected behavior caused by the missing selectable flag on the parent. A possible workaround could be to deselect all child items (recursively). Note that you can only ask one question per post, but in any case, look at [this post](https://stackoverflow.com/q/73037018/2001654) for your other question (just adapt the answer to the *parent* bounding rect instead of the scene rect); in any case, `ItemClipsChildrenToShape` wouldn't have worked: as the documentation of that flag explains, it clips the **painting**, not their position. – musicamante Aug 06 '22 at 16:43
  • @musicamante I reimplemented the mousePressEvent() in GraphicsView class , so that items will be deselected when I press on the parent item and it worked). Thank you very much for your suggestions! – galaxy Aug 08 '22 at 08:50

0 Answers0