Вопрос, с которым я сталкиваюсь при добавлении анимации в QGraphicsItem - PullRequest
1 голос
/ 23 апреля 2019

Я хочу использовать QPropertyAnimation для QGraphicsItem, надеясь, что прямоугольный элемент может перемещаться из точки (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_())

Любая помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 23 апреля 2019

Кажется, что они не знают различных систем координат Graphics View Framework .

В этой системе есть по крайней мере следующие системы координат:

  • Система координат окна (viewport ()), где (0, 0) всегда будет в верхнем левом углу окна.

  • Система координатэтой сцены, относительно некоторой предварительно установленной точки.

  • Система координат каждого элемента, эта система координат используется методом paint () для рисованияи методы boundingRect () и shape () для получения ребер элемента.

У вас также должен быть другой концепт, позиция элемента относительно родительского элементаесли он у него есть, если у него его нет, то это относится к сцене.

Аналогия

Чтобы объяснить различные системы координат, я использую аналогиюзапись сцены с помощью камеры.

  • QGraphicsView будет экраном камеры.
  • QGraphicsScene - это записываемая сцена, поэтому точка (0, 0) - это удобная точка.
  • QGraphicsItem - это элементы сцены, их положение может быть относительно других элементов или сцены, например, мы можем рассмотреть положение обуви актера относительно актера, или элемент может быть тем же актером.

На основании вышеизложенного я объясню, что происходит, и мы дадим несколько решений.

Прямоугольный элемент не имеет родителя, и по умолчанию положение элемента равно (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. </p>


Итак, если вы хотите, чтобы прямоугольник был сверху эллипса, есть как минимум 2 решения:

  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_())
1 голос
/ 23 апреля 2019

Попробуйте:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...