Линейная анимация с помощью QPropertyAnimation

Попытка анимировать линию, растущую от нуля до строки (0,0) до (200, 200) с помощью PyQt5 и с использованием QPropertyAnimation. Я уже прочитал много документации о Qt и попробовал несколько примеров, но я просто не могу заставить это работать. Это код, который у меня есть сейчас:

from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QPainter, QPixmap, QPainterPath
from PyQt5.QtCore import QObject, QPointF, QPropertyAnimation, pyqtProperty
from PyQt5.QtCore import QLineF
import sys


class Sample(QWidget):

    l1 = QLineF(QPointF(), QPointF())

    def __init__(self):
        super().__init__()

        self.initView()
        self.initAnimation()

    def initView(self):    
        self.show()

    def initAnimation(self):
        self.anim = QPropertyAnimation(self.l1, b'geometry')
        self.anim.setDuration(7000)
        self.anim.setStartValue(QPointF(0, 0))
        self.anim.setEndValue(QPointF(200, 200))
        self.anim.start()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Sample()
    sys.exit(app.exec_())

Не публикуя все предыдущие попытки, каждая из них терпит неудачу с другой ошибкой. У меня есть анимация затухания на виджете для работы и изображение, следующее по пути, но я могу заставить работать простой рисунок линии. Я надеялся добиться чего-то вроде этого:

Пример кода

Документация по Qt огромна, и кажется, что есть несколько способов добиться этого: рисование и таймер, анимация, вариантная анимация, но я не очень хорошо знаком с C++, и перевод на Python не всегда прост. Кроме того, образцы не так просто найти.

Я упускаю что-то очевидное?

Спасибо!


Для справки, это то, чего я добился до сих пор, но как только я раскомментирую создание QPropertyAnimation, приложение не запускается. Во всяком случае, я все еще был далек от результата в принятом ответе.

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys

class MyLine(QGraphicsLineItem, QObject):
    def __init__(self):
        super().__init__()

    def _set_start(self, point):
        self.setLine(point.x(), point.y(), self.line().p2().x(), self.line().p2().y())

    def _set_end(self, point):
        self.setLine(self.line().p1().x(), self.line().p1().y(), point.x(), point.y())

    start = pyqtProperty(QPointF, fset=_set_start)
    end = pyqtProperty(QPointF, fset=_set_end)


class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        hbox = QHBoxLayout(self)

        self.button = QPushButton("Start", self)
        self.button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        hbox.addWidget(self.button)

        hbox.addSpacing(40)

        self.line = MyLine()
        self.line.setLine(0, 0, 10, 10)
        scene = QGraphicsScene()
        scene.addItem(self.line)
        view = QGraphicsView(scene)
        hbox.addWidget(view)

        self.anim = QPropertyAnimation(self.line, b"end") # crash without error here
        # self.anim.setDuration(2500)
        # self.anim.setLoopCount(1)
        # self.anim.setStartValue(QPointF(10, 10))
        # self.anim.setEndValue(QPointF(200, 200))
        # self.button.clicked.connect(self.anim.start)

        self.setGeometry(300, 300, 380, 250)
        self.setWindowTitle('Color anim')
        self.show()


if __name__ == "__main__":

    app = QApplication([])
    ex = Example()
    ex.show()
    app.exec_()
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
1 168
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы должны использовать QGraphicsView, QGraphicsScene с QGraphicsLineItem, как показано ниже:

from PyQt5 import QtCore, QtGui, QtWidgets


class LineAnimation(QtCore.QObject):
    def __init__(self, parent=None):
        super(LineAnimation, self).__init__(parent)
        self.m_line = QtCore.QLineF()
        self.m_item = QtWidgets.QGraphicsLineItem()
        self.m_item.setLine(self.m_line)
        self.m_item.setPen(
            QtGui.QPen(
                QtGui.QColor("salmon"),
                10,
                QtCore.Qt.SolidLine,
                QtCore.Qt.SquareCap,
                QtCore.Qt.RoundJoin,
            )
        )

        self.m_animation = QtCore.QPropertyAnimation(
            self,
            b"p2",
            parent=self,
            startValue=QtCore.QPointF(0, 0),
            endValue=QtCore.QPointF(200, 200),
            duration=5 * 1000,
        )
        self.m_animation.start()

    def p1(self):
        return self.m_line.p1()

    def setP1(self, p1):
        self.m_line.setP1(p1)
        self.m_item.setLine(self.m_line)

    def p2(self):
        return self.m_line.p2()

    def setP2(self, p2):
        self.m_line.setP2(p2)
        self.m_item.setLine(self.m_line)

    p1 = QtCore.pyqtProperty(QtCore.QPointF, fget=p1, fset=setP1)
    p2 = QtCore.pyqtProperty(QtCore.QPointF, fget=p2, fset=setP2)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        scene = QtWidgets.QGraphicsScene(self)
        view = QtWidgets.QGraphicsView(
            scene, alignment=QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop
        )
        self.setCentralWidget(view)

        line_animation = LineAnimation(self)
        scene.addItem(line_animation.m_item)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

Вот и все. Спасибо! Я медленно начал двигаться в правильном направлении (см. редактирование), но все еще далек от вашего ответа.

evilmandarine 28.05.2019 22:46

@supafly PyQt не допускает двойного наследования в случаях QObject и QGraphicsItem (в некоторых случаях допускается только двойное наследование в QObjects), поэтому его программа дает сбой по этой причине, он использовал композицию вместо наследования

eyllanesc 28.05.2019 22:54

Другие вопросы по теме