Графика в 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_())