user2831602
user2831602

Reputation: 148

Changing a rectangle's X value does not actually move it in the GUI

I'm working on a GUI in Python with PySide2. I have a GraphicsView, where I'll put an image, and I'd like to draw and move a polygon around on that image. I've found many examples of simply drawing polygons, circles, etc. in PySide, PySide2, or PyQt 4/5 in Python. However, I haven't been able to figure out why my graphics items do not move on an event without deleting and redrawing.

I'm using the keyboard to change the X value on a PySide2 QRectF. The X value is clearly changing, but the rectangle does not actually move.

Here is a minimal example:

from PySide2 import QtCore, QtGui, QtWidgets
from functools import partial

class DebuggingDrawing(QtWidgets.QGraphicsView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # initialize the scene and set the size
        self._scene = QtWidgets.QGraphicsScene(self)
        self._scene.setSceneRect(0,0,500,500)
        self.setScene(self._scene)

        # make a green pen and draw a 10 wide, 20 high rectangle at x=20, y=30
        self.pen = QtGui.QPen(QtCore.Qt.green, 0)
        self.draw_rect = QtCore.QRectF(20, 30, 10, 20)
        # add the rectangle to our scene
        self._scene.addRect(self.draw_rect, self.pen)

    def move_rect(self, dx: int):
        # method for moving the existing rectangle
        # get the x value
        x = self.draw_rect.x()
        print('x: {} dx: {}'.format(x, dx))
        # use the moveLeft method of QRectF to change the rectangle's left side x value
        self.draw_rect.moveLeft(x + dx)
        self.update()


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()
        self.labelImg = DebuggingDrawing()

        # Get a keyboard shortcut and hook it up to the move_rect method
        next_shortcut = QtWidgets.QShortcut(QtGui.QKeySequence('Right'), self)
        next_shortcut.activated.connect(partial(self.labelImg.move_rect, 1))

        # get the left key shortcut, move_rect one pixel left
        back_shortcut = QtWidgets.QShortcut(QtGui.QKeySequence('Left'), self)
        back_shortcut.activated.connect(partial(self.labelImg.move_rect, -1))

        self.setCentralWidget(self.labelImg)

        self.setMaximumHeight(480)
        self.update()

if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    testing = MainWindow()
    testing.show()
    app.exec_()

Here's what the output looks like:

enter image description here

You clearly can't see in the image, but even though the rectangle's x value is changing according to our print calls, nothing moves around in the image. I've confirmed it's not just my eyes, because if I draw new rectangles in move_rect, they clearly show up.

Upvotes: 1

Views: 209

Answers (1)

eyllanesc
eyllanesc

Reputation: 243897

draw_rect is a QRectF is an input to create an item(QGraphicsRectItem) that is returned by the addRect() method similar to pen, that is, it takes the information but then no longer uses it. The idea is to move the item using setPos():

class DebuggingDrawing(QtWidgets.QGraphicsView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # initialize the scene and set the size
        self._scene = QtWidgets.QGraphicsScene(self)
        self._scene.setSceneRect(0, 0, 500, 500)
        self.setScene(self._scene)

        # make a green pen and draw a 10 wide, 20 high rectangle at x=20, y=30
        pen = QtGui.QPen(QtCore.Qt.green, 0)
        draw_rect = QtCore.QRectF(20, 30, 10, 20)
        # add the rectangle to our scene
        self.item_rect = self._scene.addRect(draw_rect, pen)

    def move_rect(self, dx: int):
        p = self.item_rect.pos()
        p += QtCore.QPointF(dx, 0)
        self.item_rect.setPos(p)

If you still want to use draw_rect then you have to set it again in the item:

    self.pen = QtGui.QPen(QtCore.Qt.green, 0)
    self.draw_rect = QtCore.QRectF(20, 30, 10, 20)
    # add the rectangle to our scene
    self.item_rect = self._scene.addRect(self.draw_rect, self.pen)

def move_rect(self, dx: int):
    # method for moving the existing rectangle
    # get the x value
    x = self.draw_rect.x()
    print('x: {} dx: {}'.format(x, dx))
    # use the moveLeft method of QRectF to change the rectangle's left side x value
    self.draw_rect.moveLeft(x + dx)
    self.item_rect.setRect(self.draw_rect)

It is recommended that "Graphics View Framework" be read so that the QGraphicsItems, QGraphicsView and QGraphicsScene work.

Upvotes: 2

Related Questions