gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 01:00:40 24 4
gpt4 key购买 nike

我想在 QGraphicsItem 上使用 QPropertyAnimation,希望矩形项目可以从点(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_())

最佳答案

看来他们不知道Graphics View Framework的不同坐标系.

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

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

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

  • 每个item的坐标系,paint()方法使用这个坐标系进行绘制,boundingRect()和shape()方法用来获取item的边缘。

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

类比

为了解释不同的坐标系,我使用使用相机记录场景的类比。

  • QGraphicsView 将是相机的屏幕。
  • QGraphicsScene 是记录的场景,因此点 (0, 0) 是一些方便的点。
  • QGraphicsItem是场景的元素,它们的位置可以相对于其他项目或场景,例如我们可以考虑 Actor 鞋子相对于 Actor 的位置,或者项目可以是同一个 Actor .
<小时/>

根据上述内容,我将解释发生的情况,并给出几种解决方案。

矩形项目没有父级,默认情况下项目的位置图标是 (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_())
  • 修改动画,使其不产生位移:
  • 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_())

    关于python - 在QGraphicsItem上添加动画时遇到的一个问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55814638/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com