Qt изменить размер макета во время анимации свойства виджета

У меня есть существующее приложение, которое я отлаживаю, и я хочу добавить анимацию к нескольким виджетам. Анимация виджетов с помощью 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()

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()
Другие вопросы по тегам