Графика в PyQtGraph не обновляется после увеличения

У меня есть следующая программа PyQtGraph, которая заставляет красный квадрат "двигаться" при перемещении ползунка:

import sys

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QSlider
from pyqtgraph import (
    mkBrush,
    mkPen,
    GraphicsObject,
    QtGui,
    PlotWidget,
)


class SquareItem(GraphicsObject):
    def __init__(self):
        super().__init__()
        self.position_picture = QtGui.QPicture()

    def paint(self, p, *args):
        p.drawPicture(0, 0, self.position_picture)

    def boundingRect(self):
        return QtCore.QRectF(-5, -5, 20, 10)

    def update_position(self, x):
        self.position_picture = QtGui.QPicture()
        painter = QtGui.QPainter(self.position_picture)
        painter.scale(1, -1)
        painter.setBrush(mkBrush('r'))
        painter.setPen(mkPen(None))
        painter.drawRect(QtCore.QRectF(x, 0, 1, 1))
        painter.end()
        self.informViewBoundsChanged()


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle('Micromouse maze simulator')
        self.resize(600, 600)

        frame = QtWidgets.QFrame()
        layout = QtWidgets.QVBoxLayout(frame)

        self.graphics = PlotWidget()
        self.graphics.setAspectLocked()
        self.item = SquareItem()
        self.graphics.addItem(self.item)

        self.slider = QSlider(QtCore.Qt.Horizontal)
        self.slider.setSingleStep(1)
        self.slider.setPageStep(10)
        self.slider.setRange(0, 10)
        self.slider.setTickPosition(QSlider.TicksAbove)
        self.slider.valueChanged.connect(self.slider_value_changed)
        self.slider.setValue(1)

        layout.addWidget(self.graphics)
        layout.addWidget(self.slider)

        self.setCentralWidget(frame)

    def slider_value_changed(self, value):
        self.item.update_position(value)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())

Кажется, все работает нормально, но если я увеличиваю / уменьшаю масштаб, а затем снова перемещаю ползунок, положение квадрата больше не обновляется (т.е. квадрат не перерисовывается).

Как я могу это исправить?

Обновления

  • Я использую квадрат, чтобы упростить проблему. На самом деле я не только меняю положение, но и рисую различные формы, поэтому setPos() это не совсем вариант.

1 ответ

Решение

Вы не должны обновлять картину, если вы хотите изменить положение, вы должны использовать только setPos(), paint() функция занимает boundingRect() в качестве ориентира, поэтому при перемещении графика вы перемещаете его в этой системе координат вместо системы координат PlotWidget,

class SquareItem(GraphicsObject):
    def paint(self, p, *args):
        p.setBrush(mkBrush('r'))
        p.setPen(mkPen(None))
        p.drawRect(self.boundingRect())

    def boundingRect(self):
        return QtCore.QRectF(0, 0, 1, 1)

    def update_position(self, x):
        self.setPos(x, 0)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle('Micromouse maze simulator')
        self.resize(600, 600)

        frame = QtWidgets.QFrame()
        layout = QtWidgets.QVBoxLayout(frame)

        self.graphics = PlotWidget()
        self.graphics.setAspectLocked()
        self.item = SquareItem()
        self.graphics.addItem(self.item)

        self.graphics.setRange(rect=QtCore.QRectF(-10, -10, 20, 20))

        self.slider = QSlider(QtCore.Qt.Horizontal)
        self.slider.setSingleStep(1)
        self.slider.setPageStep(10)
        self.slider.setRange(0, 10)
        self.slider.setTickPosition(QSlider.TicksAbove)
        self.slider.valueChanged.connect(self.slider_value_changed)
        self.slider.setValue(1)

        layout.addWidget(self.graphics)
        layout.addWidget(self.slider)

        self.setCentralWidget(frame)

    def slider_value_changed(self, value):
        self.item.update_position(value)

Если вы не собираетесь использовать сигналы, рекомендуется использовать объекты, которые наследуются от QGraphicsItem вместо QGraphicsObjectНапример, вы могли бы использовать QGraphicsRectItem:

import sys

from PyQt5 import QtCore, QtWidgets
from pyqtgraph import (
    mkBrush,
    mkPen,
    GraphicsObject,
    QtGui,
    PlotWidget,
)

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle('Micromouse maze simulator')
        self.resize(600, 600)

        frame = QtWidgets.QFrame()
        layout = QtWidgets.QVBoxLayout(frame)

        self.graphics = PlotWidget()
        self.graphics.setAspectLocked()
        self.item = QtWidgets.QGraphicsRectItem(0, 0, 1, 1)
        self.item.setBrush(mkBrush('r'))
        self.item.setPen(mkPen(None))
        self.graphics.addItem(self.item)

        self.graphics.setRange(rect=QtCore.QRectF(-10, -10, 20, 20))

        self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.slider.setSingleStep(1)
        self.slider.setPageStep(10)
        self.slider.setRange(0, 10)
        self.slider.setTickPosition(QtWidgets.QSlider.TicksAbove)
        self.slider.valueChanged.connect(self.slider_value_changed)
        self.slider.setValue(1)

        layout.addWidget(self.graphics)
        layout.addWidget(self.slider)

        self.setCentralWidget(frame)

    def slider_value_changed(self, value):
        self.item.setPos(value, 0)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())

Обновить:

Если вы хотите перерисовать, вы должны позвонить update():

import sys

from PyQt5 import QtCore, QtWidgets

from pyqtgraph import (
    mkBrush,
    mkPen,
    GraphicsObject,
    QtGui,
    PlotWidget,
)


class SquareItem(GraphicsObject):
    colors = ['r', 'g', 'b', 'c', 'm', 'y', 'k', 'w', 'FF0', 'AA0', '0AA']
    def __init__(self):
        super().__init__()
        self.mColor = SquareItem.colors[0]

    def paint(self, p, *args):
        p.setBrush(mkBrush(self.mColor))
        p.setPen(mkPen(None))
        p.drawRect(self.boundingRect())

    def boundingRect(self):
        return QtCore.QRectF(0, 0, 1, 1)

    def update_draw(self, x):
        self.mColor = SquareItem.colors[x]
        self.update()


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle('Micromouse maze simulator')
        self.resize(600, 600)

        frame = QtWidgets.QFrame()
        layout = QtWidgets.QVBoxLayout(frame)

        self.graphics = PlotWidget()
        self.graphics.setAspectLocked()
        self.item = SquareItem()
        self.graphics.addItem(self.item)

        self.graphics.setRange(rect=QtCore.QRectF(-10, -10, 20, 20))

        self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.slider.setSingleStep(1)
        self.slider.setPageStep(10)
        self.slider.setRange(0, 10)
        self.slider.setTickPosition(QtWidgets.QSlider.TicksAbove)
        self.slider.valueChanged.connect(self.item.update_draw)
        self.slider.setValue(1)

        layout.addWidget(self.graphics)
        layout.addWidget(self.slider)

        self.setCentralWidget(frame)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())
Другие вопросы по тегам