Exemple #1
0
class CollapsibleBox(QWidget):
    def __init__(self, title="", parent=None):
        super(CollapsibleBox, self).__init__(parent)

        self.toggle_button = QToolButton(text=title,
                                         checkable=True,
                                         checked=False)
        self.toggle_button.setStyleSheet("QToolButton { border: none; }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)

        self.toggle_animation = QParallelAnimationGroup(self)

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

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

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

    @pyqtSlot()
    def on_pressed(self):
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else 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)
Exemple #2
0
class Spoiler(QWidget):
    def __init__(self, title="", animationDuration=300, parent=None):
        QWidget.__init__(self, parent)

        self.mainLayout = QGridLayout()
        self.toggleButton = QToolButton()
        self.toggleAnimation = QParallelAnimationGroup()
        self.contentArea = QScrollArea()
        self.headerLine = QFrame()
        self.animationDuration = animationDuration

        self.toggleButton.setStyleSheet("QToolButton { border: none; }")
        self.toggleButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggleButton.setArrowType(Qt.ArrowType.RightArrow)
        self.toggleButton.setText(title)
        self.toggleButton.setCheckable(True)
        self.toggleButton.setChecked(False)

        self.headerLine.setFrameShape(QFrame.HLine)
        self.headerLine.setFrameShadow(QFrame.Sunken)
        self.headerLine.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Maximum)

        self.contentArea.setStyleSheet(
            "QScrollArea { background-color: white; border: none; }")
        self.contentArea.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Fixed)

        self.contentArea.setMaximumHeight(0)
        self.contentArea.setMinimumHeight(0)
        # let the entire widget grow and shrink with its content
        self.toggleAnimation.addAnimation(QPropertyAnimation())
        self.toggleAnimation.addAnimation(QPropertyAnimation(self))
        self.toggleAnimation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggleAnimation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggleAnimation.addAnimation(
            QPropertyAnimation(self.contentArea, b"maximumHeight"))

        # don't waste space
        self.mainLayout.setVerticalSpacing(0)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        row = 0
        self.mainLayout.addWidget(self.toggleButton, 0, 0, 1, 1, Qt.AlignLeft)
        self.mainLayout.addWidget(self.headerLine, 0, 2, 1, 1)
        self.mainLayout.addWidget(self.contentArea, 1, 0, 1, 3)
        self.setLayout(self.mainLayout)

        self.toggleButton.clicked[bool].connect(self.expandShrinkContent)

    def expandShrinkContent(self, checked):
        if checked:
            self.toggleButton.setArrowType(Qt.ArrowType.DownArrow)
            self.toggleAnimation.setDirection(QAbstractAnimation.Forward)

        else:
            self.toggleButton.setArrowType(Qt.ArrowType.RightArrow)
            self.toggleAnimation.setDirection(QAbstractAnimation.Backward)

        self.toggleAnimation.start()

    def setContentLayout(self, contentLayout):

        self.contentArea.setLayout(contentLayout)
        collapsedHeight = self.sizeHint().height(
        ) - self.contentArea.maximumHeight()
        contentHeight = contentLayout.sizeHint().height()
        i = 0
        while i < self.toggleAnimation.animationCount():
            i += 1
            spoilerAnimation = self.toggleAnimation.animationAt(i)
            if spoilerAnimation is not None:
                spoilerAnimation.setDuration(self.animationDuration)
                spoilerAnimation.setStartValue(collapsedHeight)
                spoilerAnimation.setEndValue(collapsedHeight + contentHeight)

        contentAnimation = self.toggleAnimation.animationAt(
            self.toggleAnimation.animationCount() - 1)
        contentAnimation.setDuration(self.animationDuration)
        contentAnimation.setStartValue(0)
        contentAnimation.setEndValue(contentHeight)
Exemple #3
0
class SlidingStackedWidget(QStackedWidget):
    animationEasingCurve = QtDynamicProperty('animationEasingCurve', int)
    animationDuration = QtDynamicProperty('animationDuration', int)
    verticalMode = QtDynamicProperty('verticalMode', bool)
    wrap = QtDynamicProperty('wrap', bool)

    animationFinished = pyqtSignal()

    LeftToRight, RightToLeft, TopToBottom, BottomToTop, Automatic = list(range(5))

    def __init__(self, parent=None):
        super(SlidingStackedWidget, self).__init__(parent)
        self.animationEasingCurve = QEasingCurve.Linear
        self.animationDuration = 250
        self.verticalMode = False
        self.wrap = False
        self._active = False
        self._animation_group = QParallelAnimationGroup()
        self._animation_group.finished.connect(self._SH_AnimationGroupFinished)

    def slideInNext(self):
        next_index = self.currentIndex() + 1
        if self.wrap or next_index < self.count():
            self.slideInIndex(next_index % self.count(), direction=self.BottomToTop if self.verticalMode else self.RightToLeft)

    def slideInPrev(self):
        previous_index = self.currentIndex() - 1
        if self.wrap or previous_index >= 0:
            self.slideInIndex(previous_index % self.count(), direction=self.TopToBottom if self.verticalMode else self.LeftToRight)

    def slideInIndex(self, index, direction=Automatic):
        self.slideInWidget(self.widget(index), direction)

    def slideInWidget(self, widget, direction=Automatic):
        if self.indexOf(widget) == -1 or widget is self.currentWidget():
            return

        if self._active:
            return

        self._active = True

        prev_widget = self.currentWidget()
        next_widget = widget

        if direction == self.Automatic:
            if self.indexOf(prev_widget) < self.indexOf(next_widget):
                direction = self.BottomToTop if self.verticalMode else self.RightToLeft
            else:
                direction = self.TopToBottom if self.verticalMode else self.LeftToRight

        width = self.frameRect().width()
        height = self.frameRect().height()

        # the following is important, to ensure that the new widget has correct geometry information when sliding in the first time
        next_widget.setGeometry(0, 0, width, height)

        if direction in (self.TopToBottom, self.BottomToTop):
            offset = QPoint(0, height if direction == self.TopToBottom else -height)
        elif direction in (self.LeftToRight, self.RightToLeft):
            offset = QPoint(width if direction == self.LeftToRight else -width, 0)

        # re-position the next widget outside of the display area
        prev_widget_position = prev_widget.pos()
        next_widget_position = next_widget.pos()

        next_widget.move(next_widget_position - offset)
        next_widget.show()
        next_widget.raise_()

        prev_widget_animation = QPropertyAnimation(prev_widget, b"pos")
        prev_widget_animation.setDuration(self.animationDuration)
        prev_widget_animation.setEasingCurve(QEasingCurve(self.animationEasingCurve))
        prev_widget_animation.setStartValue(prev_widget_position)
        prev_widget_animation.setEndValue(prev_widget_position + offset)

        next_widget_animation = QPropertyAnimation(next_widget, b"pos")
        next_widget_animation.setDuration(self.animationDuration)
        next_widget_animation.setEasingCurve(QEasingCurve(self.animationEasingCurve))
        next_widget_animation.setStartValue(next_widget_position - offset)
        next_widget_animation.setEndValue(next_widget_position)

        self._animation_group.clear()
        self._animation_group.addAnimation(prev_widget_animation)
        self._animation_group.addAnimation(next_widget_animation)
        self._animation_group.start()

    def _SH_AnimationGroupFinished(self):
        prev_widget_animation = self._animation_group.animationAt(0)
        next_widget_animation = self._animation_group.animationAt(1)
        prev_widget = prev_widget_animation.targetObject()
        next_widget = next_widget_animation.targetObject()
        self.setCurrentWidget(next_widget)
        prev_widget.hide()  # this may have been done already by QStackedWidget when changing the current widget above -Dan
        prev_widget.move(prev_widget_animation.startValue())  # move the out-shifted widget back to its original position
        self._animation_group.clear()
        self._active = False
        self.animationFinished.emit()
Exemple #4
0
class Spoiler(QWidget):
    class Orientation(Enum):
        HORIZONTAL = 1
        VERTICAL = 2

    def __init__(self,
                 orientation=Orientation.HORIZONTAL,
                 animationDuration=120,
                 parent=None):
        QWidget.__init__(self, parent)

        self.opened = False
        self.orientation = orientation
        self.animationDuration = animationDuration
        self.mainLayout = None
        self.animator = QParallelAnimationGroup()

        if orientation is self.Orientation.HORIZONTAL:
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

            self.setMaximumWidth(0)
            self.setMinimumWidth(0)
            # let the entire widget grow and shrink with its content
            self.animator.addAnimation(QPropertyAnimation(self))
            self.animator.addAnimation(
                QPropertyAnimation(self, b"minimumWidth"))
            self.animator.addAnimation(
                QPropertyAnimation(self, b"maximumWidth"))

        elif orientation is self.Orientation.VERTICAL:
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

            self.setMaximumHeight(0)
            self.setMinimumHeight(0)
            # let the entire widget grow and shrink with its content
            self.animator.addAnimation(QPropertyAnimation(self))
            self.animator.addAnimation(
                QPropertyAnimation(self, b"minimumHeight"))
            self.animator.addAnimation(
                QPropertyAnimation(self, b"maximumHeight"))

    def open(self):
        self.animator.setDirection(QAbstractAnimation.Forward)
        self.animator.start()
        self.opened = True

    def close(self):
        self.animator.setDirection(QAbstractAnimation.Backward)
        self.animator.start()
        self.opened = False

    def isOpened(self):
        return self.opened

    def setContentLayout(self, contentLayout):
        self.setLayout(contentLayout)

        if self.orientation is self.Orientation.HORIZONTAL:
            collapsedSize = self.maximumWidth()
            contentSize = contentLayout.sizeHint().width()
        elif self.orientation is self.Orientation.VERTICAL:
            collapsedSize = self.maximumHeight()
            contentSize = contentLayout.sizeHint().height()

        i = 0
        while i < self.animator.animationCount():
            animation = self.animator.animationAt(i)
            animation.setDuration(self.animationDuration)
            animation.setStartValue(collapsedSize)
            animation.setEndValue(collapsedSize + contentSize)
            i += 1
Exemple #5
0
class CollapsibleWidget(QWidget):
    def __init__(self, title="", parent=None, animation_duration=300):
        """
        References:
            # Adapted from c++ version
            http://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt
        """
        super(CollapsibleWidget, self).__init__(parent)
        self.title = title
        self.toggle_button = QToolButton()
        self.toggle_animation = QParallelAnimationGroup(self)
        self.content_area = QScrollArea()
        self.animation_duration = animation_duration
        self._init_base_ui()

    def _init_base_ui(self):
        self.toggle_button.setStyleSheet("QToolButton { border: none; }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)
        self.toggle_button.setText(str(self.title))
        self.toggle_button.setCheckable(True)
        self.toggle_button.setChecked(False)

        self.content_area.setMaximumHeight(0)
        self.content_area.setMinimumHeight(0)
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        self.content_area.setFrameShape(QFrame.NoFrame)

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

        layout = QVBoxLayout(self)
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.toggle_button)
        layout.addWidget(self.content_area)

    def on_pressed(self):
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def set_content_layout(self, layout):
        initial_layout = self.content_area.layout()
        del initial_layout
        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(self.animation_duration)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

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

    def set_content_widget(self, widget):
        initial_layout = self.content_area.layout()
        del initial_layout
        self.content_area.setWidget(widget)
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = widget.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(self.animation_duration)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(self.animation_duration)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
Exemple #6
0
class GroupWidget(QWidget):
    def __init__(self, parent=None, title='', animation_duration=300):
        """
        References:
            # Adapted from c++ version
            http://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt
        """
        super(GroupWidget, self).__init__(parent=parent)

        self.animation_duration = animation_duration
        self.toggle_animation = QParallelAnimationGroup()
        self.content_area = QScrollArea()
        self.header_line = QFrame()
        self.toggle_button = QToolButton()
        self.main_layout = QGridLayout()

        toggle_button = self.toggle_button
        toggle_button.setStyleSheet("QToolButton { border: none; }")
        toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        toggle_button.setArrowType(Qt.RightArrow)
        toggle_button.setText(str(title))
        toggle_button.setCheckable(True)
        toggle_button.setChecked(False)

        header_line = self.header_line
        header_line.setFrameShape(QFrame.HLine)
        header_line.setFrameShadow(QFrame.Sunken)
        header_line.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)

        self.content_area.setStyleSheet(
            "QScrollArea { background-color: white; border: none; }")
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        # start out collapsed
        self.content_area.setMaximumHeight(0)
        self.content_area.setMinimumHeight(0)
        # let the entire widget grow and shrink with its content
        toggle_animation = self.toggle_animation
        toggle_animation.addAnimation(
            QPropertyAnimation(self, bytes("minimumHeight", "utf-8")))
        toggle_animation.addAnimation(
            QPropertyAnimation(self, bytes("maximumHeight", "utf-8")))
        toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area,
                               bytes("maximumHeight", "utf-8")))
        # don't waste space
        main_layout = self.main_layout
        main_layout.setVerticalSpacing(0)
        main_layout.setContentsMargins(0, 0, 0, 0)
        row = 0
        main_layout.addWidget(self.toggle_button, row, 0, 1, 1, Qt.AlignLeft)
        main_layout.addWidget(self.header_line, row, 2, 1, 1)
        row += 1
        main_layout.addWidget(self.content_area, row, 0, 1, 3)
        self.setLayout(self.main_layout)

        def start_animation(checked):
            arrow_type = Qt.DownArrow if checked else Qt.RightArrow
            direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward
            toggle_button.setArrowType(arrow_type)
            self.toggle_animation.setDirection(direction)
            self.toggle_animation.start()

        self.toggle_button.clicked.connect(start_animation)

    def set_content_layout(self, content_layout):
        # Not sure if this is equivalent to self.contentArea.destroy()
        self.content_area.destroy()
        self.content_area.setLayout(content_layout)
        collapsed_height = self.sizeHint().height(
        ) - self.content_area.maximumHeight()
        content_height = content_layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount() - 1):
            spoiler_animation = self.toggle_animation.animationAt(i)
            spoiler_animation.setDuration(self.animation_duration)
            spoiler_animation.setStartValue(collapsed_height)
            spoiler_animation.setEndValue(collapsed_height + content_height)
        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(self.animation_duration)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
class CollapsibleBox(QWidget):
    def __init__(self, title="", parent=None):
        super(CollapsibleBox, self).__init__(parent)
        self.toggle_button = QToolButton(text=title,
                                         checkable=True,
                                         checked=False)
        self.toggle_button.setStyleSheet("QToolButton {border: none;\
                border: 1px solid #FF17365D;\
                border-top-left-radius: 15px;\
                border-top-right-radius: 15px;\
                background-color: #FF17365D;\
                padding: 5px 0px;\
                color: rgb(255, 255, 255);\
                max-height: 30px;\
                font-size: 14px;\
            }\
            QToolButton:hover {\
                background-color: lightgreen;\
                color: black;\
            }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)

        self.toggle_animation = QParallelAnimationGroup(self)

        self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0)
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)

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

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

    @QtCore.pyqtSlot()
    def on_pressed(self):
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def clear_layout(self, layout):
        try:
            for i in reversed(range(layout.count())):
                widgetToRemove = layout.itemAt(i).widget()
                layout.removeWidget(widgetToRemove)
                widgetToRemove.setPArent(None)
        except AttributeError:
            pass

    def setContentLayout(self, layout):
        lay = self.content_area.layout()
        self.clear_layout(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)
Exemple #8
0
class CollapsibleMessageBox(QWidget):
    ''' docstring: 消息显示类,按钮触发折叠 '''
    def __init__(self,
                 Title="",
                 parent=None,
                 defaultLayout=False,
                 Message=None):
        super().__init__(parent)

        self.toggle_button = QToolButton(text=Title,
                                         checkable=True,
                                         checked=False)
        self.toggle_button.setStyleSheet("QToolButton { border: none; }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)

        self.toggle_animation = QParallelAnimationGroup(self)

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

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

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

        if defaultLayout:
            lay = QVBoxLayout()
            self.text = QLabel()
            pa = QPalette()
            pa.setColor(pa.Background, Qt.white)
            pa.setColor(pa.Foreground, Qt.black)
            self.text.setAutoFillBackground(True)
            self.text.setPalette(pa)
            self.text.setTextInteractionFlags(Qt.TextSelectableByMouse)
            self.text.setTextFormat(Qt.MarkdownText)
            self.text.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
            self.text.setWordWrap(True)
            if not Message:
                Message = '空'
            self.text.setText(Message.replace('\n', '\n\n') + '\n')
            lay.addWidget(self.text)
            self.setContentLayout(lay)

    @pyqtSlot()
    def on_pressed(self):
        ''' docstring: 按钮函数,设置动画参数并触发 '''
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def setContentLayout(self, layout):
        ''' docstring: 重新设置布局,并计算按钮动画参数 '''
        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)