在QGraphicsItem上添加动画时遇到的一个问题

2024-06-28 19:43:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我想在QGraphicsItem上使用QPropertyAnimation,希望rect项可以从点(100,30)移动到点(100,90)。但是为什么矩形在窗口的右侧移动呢?x坐标100应该使矩形根据场景的大小在中间移动。你知道吗

这是我的密码:

import sys
from PyQt5.QtCore import QPropertyAnimation, QPointF, QRectF
from PyQt5.QtWidgets import QApplication, QGraphicsEllipseItem, QGraphicsScene, QGraphicsView, \
                            QGraphicsObject


class CustomRect(QGraphicsObject):
    def __init__(self):
        super(CustomRect, self).__init__()

    def boundingRect(self):
        return QRectF(100, 30, 100, 30)

    def paint(self, painter, styles, widget=None):
        painter.drawRect(self.boundingRect())


class Demo(QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 300)

        self.scene = QGraphicsScene()
        self.scene.setSceneRect(0, 0, 300, 300)

        self.rect = CustomRect()
        self.ellipse = QGraphicsEllipseItem()
        self.ellipse.setRect(100, 180, 100, 50)

        self.scene.addItem(self.rect)
        self.scene.addItem(self.ellipse)

        self.setScene(self.scene)

        self.animation = QPropertyAnimation(self.rect, b'pos')
        self.animation.setDuration(1000)
        self.animation.setStartValue(QPointF(100, 30))
        self.animation.setEndValue(QPointF(100, 90))
        self.animation.setLoopCount(-1)
        self.animation.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

任何帮助都将不胜感激。你知道吗


Tags: fromrectimportselfinitdemodefsys
2条回答

试试看:

import sys
from PyQt5.QtCore import QPropertyAnimation, QPointF, QRectF
from PyQt5.QtWidgets import QApplication, QGraphicsEllipseItem, QGraphicsScene, QGraphicsView, \
                            QGraphicsObject


class CustomRect(QGraphicsObject):
    def __init__(self):
        super(CustomRect, self).__init__()

    def boundingRect(self):
#        return QRectF(100, 30, 100, 30)
        return QRectF(0, 0, 100, 30)                          # +++

    def paint(self, painter, styles, widget=None):
        painter.drawRect(self.boundingRect())


class Demo(QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 300)

        self.scene = QGraphicsScene()
        self.scene.setSceneRect(0, 0, 300, 300)

        self.rect = CustomRect()
        self.ellipse = QGraphicsEllipseItem()
        self.ellipse.setRect(100, 180, 100, 50)

        self.scene.addItem(self.rect)
        self.scene.addItem(self.ellipse)

        self.setScene(self.scene)

        self.animation = QPropertyAnimation(self.rect, b'pos')
        self.animation.setDuration(3000)
        self.animation.setStartValue(QPointF(100, 30))
        self.animation.setEndValue(QPointF(100, 90))
        self.animation.setLoopCount(-1)
        self.animation.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

enter image description here

他们似乎不知道Graphics View Framework的不同坐标系。你知道吗

在该系统中,至少有以下坐标系:

  • 窗口(viewport())的坐标系,其中(0,0)始终位于窗口的左上角。

  • 场景的坐标系,这是关于某个预先建立的点。

  • 每个项目的坐标系,此坐标系由paint()方法用于绘制,而boundingRect()和shape()方法用于获取项目的边。

你还必须有另一个概念,一个项目的位置是相对于父项的,如果他有它,如果他没有它,它是相对于场景的。你知道吗

类比

为了解释不同的坐标系,我用了一个用相机记录场景的类比。你知道吗

  • QGraphicsView就是摄像机的屏幕。你知道吗
  • qgraphicscene是记录的场景,因此点(0,0)是一些方便的点。你知道吗
  • QGraphicsItem是场景的元素,它们的位置可以相对于其他项目或场景,例如我们可以考虑演员的鞋子相对于演员的位置,或者项目可以是同一个演员。你知道吗

基于以上我将解释发生了什么,我们将给出几个解决方案。你知道吗

rect项没有父项,默认情况下,项的posicon是(0,0),因此此时项的坐标系和场景重合,因此boundingRect将直观地定义位置,并且当您放置QRectF(100,30,100,30)时,将在场景中重合的相同位置绘制。但应用动画时,首先要做的是将项目的位置设置为(100,30),这样由于场景和项目的坐标系不匹配,一个从另一个移动,因此boundingRect不再匹配场景的QRectF(100,30,100,30),但将以相同的因子移动(仅因为存在位移,不存在缩放或旋转),矩形将为QRectF(200、60、100、30),并且相对于始终在QRect(100、180、100、50)中的椭圆,因此矩形从200>;100开始在右侧,从60<;180开始向上。你知道吗


因此,如果您希望矩形位于椭圆的顶部,则至少有两种解决方案:

  1. 修改boundingRect,使其处于位置0,0,以便与动画引起的位移匹配:
import sys
from PyQt5 import QtCore, QtWidgets


class CustomRect(QtWidgets.QGraphicsObject):
    def boundingRect(self):
        return QtCore.QRectF(0, 0, 100, 30)  # < -

    def paint(self, painter, styles, widget=None):
        painter.drawRect(self.boundingRect())


class Demo(QtWidgets.QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 300)

        self.scene = QtWidgets.QGraphicsScene()
        self.scene.setSceneRect(0, 0, 300, 300)

        self.rect = CustomRect()
        self.ellipse = QtWidgets.QGraphicsEllipseItem()
        self.ellipse.setRect(100, 180, 100, 50)
        self.scene.addItem(self.rect)
        self.scene.addItem(self.ellipse)

        self.setScene(self.scene)

        self.animation = QtCore.QPropertyAnimation(
            self.rect,
            b"pos",
            duration=1000,
            startValue=QtCore.QPointF(100, 30),
            endValue=QtCore.QPointF(100, 90),
            loopCount=-1,
        )
        self.animation.start()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())
  1. 修改动画,使其不会生成置换:
import sys
from PyQt5 import QtCore, QtWidgets


class CustomRect(QtWidgets.QGraphicsObject):
    def boundingRect(self):
        return QtCore.QRectF(100, 30, 100, 30)

    def paint(self, painter, styles, widget=None):
        painter.drawRect(self.boundingRect())


class Demo(QtWidgets.QGraphicsView):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 300)

        self.scene = QtWidgets.QGraphicsScene()
        self.scene.setSceneRect(0, 0, 300, 300)

        self.rect = CustomRect()
        self.ellipse = QtWidgets.QGraphicsEllipseItem()
        self.ellipse.setRect(100, 180, 100, 50)
        self.scene.addItem(self.rect)
        self.scene.addItem(self.ellipse)

        self.setScene(self.scene)

        self.animation = QtCore.QPropertyAnimation(
            self.rect,
            b"pos",
            duration=1000,
            startValue=QtCore.QPointF(0, 0), # < -
            endValue=QtCore.QPointF(0, 60), # < -
            loopCount=-1,
        )
        self.animation.start()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

相关问题 更多 >