【问题标题】:Graphics in PyQtGraph not updating after zoomPyQtGraph 中的图形在缩放后不更新
【发布时间】:2018-08-22 04:55:00
【问题描述】:

我有以下 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() 并不是一个真正的选择。

【问题讨论】:

    标签: python pyqt pyqt5 pyqtgraph


    【解决方案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_())
    

    【讨论】:

    • 感谢您的回答。我确实更改了代码中的绘画。我使用了一个简单的正方形来简化问题,尽管我知道这会导致混乱。我已经更新了我的问题。如果我不能简单地使用setPos(),我应该如何进行?
    • @Peque 使用 setPos() 是最好的选择,如果您希望您的项目移动,如果您提供最接近您的问题的 minimal reproducible example,我可以为您提供使用 setPos() 的选项。
    • 是的,也许在精简代码示例中包含移动不是一个明智的决定,它只是导致源代码更短。假设物体不动。它只是改变形状(即:必须重新绘制)。这就是我更新这幅画的原因。这是解决这个问题的必要条件。正如我所说,我更新了问题以使其更清楚。很抱歉对于这个误会。 :-/
    • @Peque 我假设绘图只会影响颜色,如果它不是最好的解决方案,那是因为你没有给我一个更接近你的问题的背景。我不懂保密。
    • 我无意保密。在创建 minimal 示例时,可能会减少太多,这可能会导致混乱。即使绘图改变了它的形状(如我的评论和更新的问题中所述),似乎调用.update() 可以解决问题。谢谢,我从您的回答中学到了很多东西,它也帮助我重构/清理了代码。 :-)
    猜你喜欢
    • 2016-10-13
    • 2017-11-18
    • 2020-03-19
    • 2020-08-04
    • 2019-07-20
    • 2018-04-19
    • 2022-11-12
    • 1970-01-01
    • 2019-09-17
    相关资源
    最近更新 更多