【问题标题】:Qt resize layout during widget property animationQt 在小部件属性动画期间调整布局大小
【发布时间】:2018-05-30 18:57:54
【问题描述】:

我有一个正在完善的现有应用程序,我想为一些小部件添加一些动画。在布局之外使用 QPropertyAnimation 动画小部件既简单又有趣,但是当它们在布局中时,我遇到了各种困难。当前让我头疼的是,当我为小部件的大小设置动画时,布局不会调整到它的新大小。

假设我有一个带有三个小部件的 QVBoxLayout:一个应该扩展到所有可用空间的标签、一个树视图和一个按钮。当我单击按钮时,我希望树折叠并且标签接管它的空间。下面是代码中的这个示例,正如您所看到的,当树对其大小进行动画处理时,什么也没有发生,然后当我在动画结束时将其隐藏时,标签会弹出以填充现在的空白空间。因此,在动画期间,布局似乎并不“知道”树正在调整大小。我想要发生的是,随着树的缩小,标签会扩大以填充它。

这可以通过标签的绝对大小而不是通过在布局上调用调整大小或类似的方式来完成吗?我问是因为我想为我的应用程序中的几个小部件设置动画,并且我想找到最好的方法来做到这一点,而不必让太多的小部件相互依赖。

示例代码:

import sys
from PyQt4 import QtGui, QtCore


class AnimatedWidgets(QtGui.QWidget):
    def __init__(self):
        super(AnimatedWidgets, self).__init__()

        layout1 = QtGui.QVBoxLayout()
        self.setLayout(layout1)

        expanding_label = QtGui.QLabel("Expanding label!")
        expanding_label.setStyleSheet("border: 1px solid red")
        layout1.addWidget(expanding_label)

        self.file_model = QtGui.QFileSystemModel(self)
        sefl.file_model.setRootPath("C:/")
        self.browse_tree = QtGui.QTreeView()
        self.browse_tree.setModel(self.file_model)
        layout1.addWidget(self.browse_tree)

        shrink_tree_btn = QtGui.QPushButton("Shrink the tree")
        shrink_tree_btn.clicked.connect(self.shrink_tree)
        layout1.addWidget(shrink_tree_btn)

        #--

        self.tree_size_anim = QtCore.QPropertyAnimation(self.browse_tree, "size")
        self.tree_size_anim.setDuration(1000)
        self.tree_size_anim.setEasingCurve(QtCore.QEasingCurve.InOutQuart)
        self.tree_pos_anim = QtCore.QPropertyAnimation(self.browse_tree, "pos")
        self.tree_pos_anim.setDuration(1000)
        self.tree_pos_anim.setEasingCurve(QtCore.QEasingCurve.InOutQuart)
        self.tree_anim_out = QtCore.QParallelAnimationGroup()
        self.tree_anim_out.addAnimation(self.tree_size_anim)
        self.tree_anim_out.addAnimation(self.tree_pos_anim)

    def shrink_tree(self):
        self.tree_size_anim.setStartValue(self.browse_tree.size())
        self.tree_size_anim.setEndValue(QtCore.QSize(self.browse_tree.width(), 0))

        tree_rect = self.browse_tree.geometry()
        self.tree_pos_anim.setStartValue(tree_rect.topLeft())
        self.tree_pos_anim.setEndValue(QtCore.QPoint(tree_rect.left(), tree_rect.bottom()))

        self.tree_anim_out.start()
        self.tree_anim_out.finished.connect(self.browse_tree.hide)

def main():
    app = QtGui.QApplication(sys.argv)
    ex = AnimatedWidgets()

    ex.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

【问题讨论】:

    标签: python pyqt pyqt4 python-2.x qpropertyanimation


    【解决方案1】:

    布局处理小部件的geometry(),因此当想要更改pos 属性时,它们会与它们的句柄交互,因此您得到这种行为是很常见的,更好的选择是使用QVariantAnimation建立固定高度:

    import sys
    from PyQt4 import QtGui, QtCore
    
    
    class AnimatedWidgets(QtGui.QWidget):
        def __init__(self):
            super(AnimatedWidgets, self).__init__()
    
            layout1 = QtGui.QVBoxLayout(self)
    
            expanding_label = QtGui.QLabel("Expanding label!")
            expanding_label.setStyleSheet("border: 1px solid red")
            layout1.addWidget(expanding_label)
    
            self.file_model = QtGui.QFileSystemModel(self)
            self.file_model.setRootPath(QtCore.QDir.rootPath())
            self.browse_tree = QtGui.QTreeView()
            self.browse_tree.setModel(self.file_model)
            layout1.addWidget(self.browse_tree)
    
            shrink_tree_btn = QtGui.QPushButton("Shrink the tree")
            shrink_tree_btn.clicked.connect(self.shrink_tree)
            layout1.addWidget(shrink_tree_btn)
            #--
            self.tree_anim = QtCore.QVariantAnimation(self)
            self.tree_anim.setDuration(1000)
            self.tree_anim.setEasingCurve(QtCore.QEasingCurve.InOutQuart)
    
        def shrink_tree(self):
            self.tree_anim.setStartValue(self.browse_tree.height())
            self.tree_anim.setEndValue(0)
            self.tree_anim.valueChanged.connect(self.on_valueChanged)
            self.tree_anim.start()
    
        def on_valueChanged(self, val):
            h, isValid = val.toInt()
            if isValid:
                self.browse_tree.setFixedHeight(h)
    
    def main():
        app = QtGui.QApplication(sys.argv)
        ex = AnimatedWidgets()
    
        ex.show()
        sys.exit(app.exec_())
    
    if __name__ == "__main__":
        main()
    

    【讨论】:

    • Tahnks eyllanesc,但 QVaraintAnimation 是抽象的,此代码会引发错误。所以我应该先把它变成一个班级吧?
    • @Spencer 现在更新代码,看来您使用的是python2。请再试一次。
    • 是的,你是对的,我在 2(抱歉未指定),但我仍然收到此错误:TypeError: PyQt4.QtCore.QVariantAnimation represents a C++ abstract class and cannot be instantiated
    • @Spencer 你用的是什么版本的 PyQt4?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-25
    • 1970-01-01
    • 2014-08-07
    相关资源
    最近更新 更多