Skip to content
Advertisement

How to move rect in pyqtgraph

I try to have a rect which moves with the mouse pointer. However, I seem to have a problem with calling the paint method. It either doesn’t draw or creates artifacts. The only clean picture I get is with a forced redraw (zoom the graph).

Here’s my mwe

import sys

from PyQt5 import QtWidgets, QtCore, QtGui
import pyqtgraph as pg


class RectItem(pg.GraphicsObject):
    def __init__(self):
        super().__init__()
        self.rect = QtCore.QRectF(0, 0, 1, 1)
        self.picture = QtGui.QPicture()
        self.generate_picture()

    def generate_picture(self):
        painter = QtGui.QPainter(self.picture)
        painter.setPen(pg.mkPen('r'))
        painter.drawRect(self.rect)
        painter.end()

    def paint(self, painter, option, widget=None):
        print('paint')
        painter.drawPicture(0, 0, self.picture)

    def boundingRect(self):
        return QtCore.QRectF(self.picture.boundingRect())

    def move(self, x, y):
        print(f'{x} {y}')
        self.rect.moveCenter(QtCore.QPointF(x, y))
        self.generate_picture()


class PlotWidget(pg.PlotWidget):
    mouse_moved = QtCore.pyqtSignal(float, float)

    def __init__(self):
        super().__init__()
        self.sig = pg.SignalProxy(
            self.scene().sigMouseMoved,
            rateLimit=60,
            slot=self._mouse_moved,
        )

    def _mouse_moved(self, event):
        pos, = event

        mousePoint = self.plotItem.vb.mapSceneToView(pos)
        x = mousePoint.x()
        y = mousePoint.y()

        self.mouse_moved.emit(x, y)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)

    main = PlotWidget()
    rect = RectItem()
    main.mouse_moved.connect(rect.move)
    main.addItem(rect)

    main.show()

    sys.exit(app.exec_())

Advertisement

Answer

Just redrawing the contents of an internal QPicture doesn’t affect the graphics item in any way, you must call update() in order to correctly refresh the item. Also consider that since you’re actually changing the bounding rect of the item, you must also call prepareGeometryChange() before changing the geometry, otherwise you’ll see artifacts due to the previous rectangle position not correctly cleared up.

    def move(self, x, y):
        self.rect.moveCenter(QtCore.QPointF(x, y))
        self.prepareGeometryChange()
        self.generate_picture()
        self.update()

Also, if you only need a rectangle to move around with the mouse, consider using the simpler QGraphicsRectItem which doesn’t require any painting implementation.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement