简体   繁体   中英

Qt layout does not reflect groupbox size change

I am trying to make UI with animated collapsible groupBox , using PyQt5 and QT Creator.

If groupBox is unchecked its height shrinks to some small value, if groupBox is checked its height expands to sizeHint().height()

The problem is when another groupBox is present in layout. The another groupBox position does not reflect that collapsed groupBox size changed.

Is there way how to force bottom groupBox to move with collapsing groupBox ?

Here how it looks like:

在此处输入图片说明


Additional information

UI layout: 在此处输入图片说明

groupBox resizing implementation:

my_ui._ui.groupBox.toggled.connect(my_ui.group_box_size_change)

def group_box_size_change(self):
    duration = 1000
    self.animaiton_gb = QtCore.QPropertyAnimation(self._ui.groupBox, b"size")
    self.animaiton_gb.setDuration(duration)

    self.animaiton_gb.setStartValue(QtCore.QSize(self._ui.groupBox.width(),  self._ui.groupBox.height()))

    if self._ui.groupBox.isChecked():
        self.animaiton_gb.setEndValue(QtCore.QSize(self._ui.groupBox.width(), self._ui.groupBox.sizeHint().height()))
    else:
        self.animaiton_gb.setEndValue(QtCore.QSize(self._ui.groupBox.width(), 49))

    self.animaiton_gb.start()

Considering my old answer to a question where a similar widget was required, the following is the solution. In that case, the strategy is to use a QScrollArea as a container and use the minimumHeight and maximumHeight properties.

from PyQt5 import QtCore, QtGui, QtWidgets


class CollapsibleBox(QtWidgets.QGroupBox):
    def __init__(self, title="", parent=None):
        super(CollapsibleBox, self).__init__(title, parent)
        self.setCheckable(True)
        self.setChecked(False)
        self.toggled.connect(self.on_pressed)
        self.toggle_animation = QtCore.QParallelAnimationGroup(self)

        self.content_area = QtWidgets.QScrollArea(maximumHeight=0, minimumHeight=0)
        self.content_area.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        self.content_area.setFrameShape(QtWidgets.QFrame.NoFrame)

        lay = QtWidgets.QVBoxLayout(self)
        lay.setSpacing(0)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.content_area)

        self.toggle_animation.addAnimation(QtCore.QPropertyAnimation(self, b"minimumHeight"))
        self.toggle_animation.addAnimation(QtCore.QPropertyAnimation(self, b"maximumHeight"))
        self.toggle_animation.addAnimation(QtCore.QPropertyAnimation(self.content_area, b"maximumHeight"))

    @QtCore.pyqtSlot(bool)
    def on_pressed(self, checked):
        self.toggle_animation.setDirection(QtCore.QAbstractAnimation.Forward if checked else QtCore.QAbstractAnimation.Backward)
        self.toggle_animation.start()

    def setContentLayout(self, layout):
        lay = self.content_area.layout()
        del lay
        self.content_area.setLayout(layout)
        collapsed_height = self.sizeHint().height() - self.content_area.maximumHeight()
        content_height = layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(500)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(500)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)

if __name__ == '__main__':
    import sys
    import random

    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QMainWindow()
    scroll = QtWidgets.QScrollArea()
    content = QtWidgets.QWidget()
    scroll.setWidget(content)
    scroll.setWidgetResizable(True)
    vlay = QtWidgets.QVBoxLayout(content)
    counter = 0
    for i in range(10):
        box = CollapsibleBox("Collapsible Box Header-{}".format(i))
        vlay.addWidget(box)
        lay = QtWidgets.QVBoxLayout()
        for j in range(8):
            btn = QtWidgets.QPushButton("PushButton-{}".format(counter))       
            lay.addWidget(btn)
            counter += 1
        box.setContentLayout(lay)
    vlay.addStretch()
    w.setCentralWidget(scroll)
    w.resize(240, 480)
    w.show()

    sys.exit(app.exec_())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM