Анимации, не возникающие при добавлении объектов анимации в список

#python #animation #pyqt #pyqt5

#python #Анимация #pyqt #pyqt5

Вопрос:

Я создал два фрейма и кнопку в своем приложении, я хочу анимировать изменение размера фреймов при нажатии этой кнопки. Я создал две функции * (которые должны работать одинаково) * для анимации кадров, * (см. Код ниже) *.

Если вы запустите код как есть, он анимирует фрейм так, как я хотел, но если вы используете вторую функцию * (которую я закомментировал) *, она не будет работать. Я не знаю, почему? Может кто-нибудь, пожалуйста, объясните это. Если возможно, решение.

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


class Test(QMainWindow):
    
    def __init__(self):
        super().__init__()
        self.resize(500, 500)
        self.frame_to_animate()


    # Creating items for the app
    def frame_to_animate(self):
        self.widget = QWidget()
        self.setCentralWidget(self.widget)

        # Frame to animate 1
        self.frame = QFrame(self.widget)
        self.frame.setStyleSheet('QFrame {background: red}')
        self.frame.resize(100, 100)
        
        # Frame to animate 2
        self.frame2 = QFrame(self.widget)
        self.frame2.move(0, 250)
        self.frame2.setStyleSheet('QFrame {background: yellow}')
        self.frame2.resize(100, 100)
        
        self.thing = False

        # Button to animate the frame
        self.btn = QPushButton(self.widget)
        self.btn.setText('Animate the frame')
        self.btn.move(300, 200)
        self.btn.clicked.connect(self.animation_fctn)
        # self.btn.clicked.connect(self.anim_fctn_i_want)           # This animation should be working
        
    
    # I want this way to work, but it's not working        
    def anim_fctn_i_want(self):
        anim_list = []
        for item in [self.frame, self.frame2]:
            anim_list.append(QPropertyAnimation(item, b"size"))
        
        for anim in anim_list:
            anim.setDuration(1000)
            if self.thing is False:
                anim.setEndValue(QSize(200, 200))
                self.thing = True
            else:
                anim.setEndValue(QSize(100, 100))
                self.thing = False
            anim.start()
            
            
    # Creating Animation one by one
    def animation_fctn(self):
        self.anim = QPropertyAnimation(self.frame, b"size")
        self.anim2 = QPropertyAnimation(self.frame2, b"size")
        
        self.anim.setDuration(1000)
        self.anim2.setDuration(1000)
        
        if self.thing is False:
            self.anim.setEndValue(QSize(200, 200))
            self.anim2.setEndValue(QSize(200, 200))
            self.thing = True
            
        else:
            self.anim.setEndValue(QSize(100, 100))
            self.anim2.setEndValue(QSize(100, 100))
            self.thing = False
            
        self.anim.start()
        self.anim2.start()
    
    
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Test()
    window.show()
    app.exec()
 

Проблема с моим текущим подходом * (который работает нормально) * заключается в том, что мне придется делать это для каждого элемента вручную, а в моем исходном коде это было бы громоздко из-за большого количества элементов,

Второй подход упростил бы задачу, но он не работает. Попробуйте код и, пожалуйста, укажите, что я делаю неправильно.

Сначала попробуйте, как есть. А затем с # self.btn.clicked.connect(self.anim_fctn_i_want) # This animation should be working

Ответ №1:

Проблема в том, что в этом случае область действия анимаций ограничена областью действия списка, а список — это переменная, которая будет немедленно удалена, а следовательно, и анимации, поэтому их эффект не будет виден. Решение состоит в том, чтобы продлить жизненный цикл анимации, и для этого есть несколько вариантов, таких как превращение списка в атрибут класса или передача родительского элемента анимации, поскольку они являются QObjects, в этом случае будет использоваться второй:

 def anim_fctn_i_want(self):
    for item in (self.frame, self.frame2):
        anim = QPropertyAnimation(item, b"size", parent=item)
        anim.setDuration(1000)
        anim.setEndValue(QSize(100, 100) if self.thing else QSize(200, 200))
        anim.start(QAbstractAnimation.DeleteWhenStopped)
    self.thing = not self.thing
 

С другой стороны, если вы собираетесь обрабатывать несколько анимаций параллельно, то по соображениям производительности лучше использовать QParallelAnimationGroup:

 def anim_fctn_i_want(self):
    group_animation = QParallelAnimationGroup(self)
    for item in (self.frame, self.frame2):
        anim = QPropertyAnimation(item, b"size")
        anim.setDuration(1000)
        anim.setEndValue(QSize(100, 100) if self.thing else QSize(200, 200))
        group_animation.addAnimation(anim)
    group_animation.start(QAbstractAnimation.DeleteWhenStopped)
    self.thing = not self.thing
 

Комментарии:

1. Я понял вашу точку зрения, спасибо. Я сделал список переменной класса, и он работал нормально. да, «область действия анимаций ограничена областью действия списка, а список — это переменная, которая будет удалена мгновенно, и, следовательно, также анимация» это была проблема. Спасибо, что указали.