|
| 1 | +#!/usr/bin/env python |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | +''' |
| 4 | +@resource:http://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt |
| 5 | +@description: 摘录自上方 |
| 6 | +@Created on none |
| 7 | +@email: none |
| 8 | +''' |
| 9 | + |
| 10 | +from PyQt5 import QtGui, QtWidgets, QtCore |
| 11 | +from PyQt5.QtCore import * |
| 12 | +from PyQt5.QtGui import * |
| 13 | +from PyQt5.QtWidgets import * |
| 14 | + |
| 15 | + |
| 16 | +class Spoiler(QWidget): |
| 17 | + def __init__(self, parent=None, title='', animationDuration=300): |
| 18 | + """ |
| 19 | + References: |
| 20 | + # Adapted from c++ version |
| 21 | + http://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt |
| 22 | + """ |
| 23 | + super(Spoiler, self).__init__(parent=parent) |
| 24 | +#if 此处可以跳过不看 |
| 25 | + self.groupBox = QtWidgets.QGroupBox(self) |
| 26 | + self.groupBox.setGeometry(QtCore.QRect(210, 30, 95, 134)) |
| 27 | + self.groupBox.setObjectName("groupBox") |
| 28 | + self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox) |
| 29 | + self.verticalLayout.setObjectName("verticalLayout") |
| 30 | + self.pushButton3 = QtWidgets.QPushButton(self.groupBox) |
| 31 | + icon = QtGui.QIcon() |
| 32 | + |
| 33 | + self.pushButton3.setIcon(icon) |
| 34 | + self.pushButton3.setObjectName("pushButton3") |
| 35 | + self.verticalLayout.addWidget(self.pushButton3) |
| 36 | + self.pushButton2 = QtWidgets.QPushButton(self.groupBox) |
| 37 | + self.pushButton2.setObjectName("pushButton2") |
| 38 | + self.verticalLayout.addWidget(self.pushButton2) |
| 39 | + self.label_2 = QtWidgets.QLabel(self.groupBox) |
| 40 | + |
| 41 | + self.label_2.setObjectName("label_2") |
| 42 | + self.verticalLayout.addWidget(self.label_2) |
| 43 | + self.pushButton = QtWidgets.QPushButton(self.groupBox) |
| 44 | + self.pushButton.setIcon(icon) |
| 45 | + self.pushButton.setObjectName("pushButton") |
| 46 | + self.verticalLayout.addWidget(self.pushButton) |
| 47 | + |
| 48 | + self.animationDuration = 300 |
| 49 | + self.toggleAnimation = QParallelAnimationGroup() |
| 50 | + self.contentArea = QScrollArea() |
| 51 | + self.headerLine = QFrame() |
| 52 | + self.toggleButton = QToolButton() |
| 53 | + self.mainLayout = QGridLayout() |
| 54 | + |
| 55 | + toggleButton = self.toggleButton |
| 56 | + toggleButton.setStyleSheet("QToolButton { border: none; }") |
| 57 | + toggleButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) |
| 58 | + toggleButton.setArrowType(Qt.RightArrow) |
| 59 | + toggleButton.setText(str(title)) |
| 60 | + toggleButton.setCheckable(True) |
| 61 | + toggleButton.setChecked(False) |
| 62 | + |
| 63 | + headerLine = self.headerLine |
| 64 | + headerLine.setFrameShape(QFrame.HLine) |
| 65 | + headerLine.setFrameShadow(QFrame.Sunken) |
| 66 | + headerLine.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) |
| 67 | +#endif 以下开始为源代码 |
| 68 | + |
| 69 | + self.contentArea.setStyleSheet( |
| 70 | + "QScrollArea { background-color: white; border: none; }") |
| 71 | + self.contentArea.setSizePolicy( |
| 72 | + QSizePolicy.Expanding, QSizePolicy.Fixed) |
| 73 | + # start out collapsed |
| 74 | + self.contentArea.setMaximumHeight(0) |
| 75 | + self.contentArea.setMinimumHeight(0) |
| 76 | + # let the entire widget grow and shrink with its content |
| 77 | + toggleAnimation = self.toggleAnimation |
| 78 | + toggleAnimation.addAnimation( |
| 79 | + QPropertyAnimation(self, b"minimumHeight")) |
| 80 | + toggleAnimation.addAnimation( |
| 81 | + QPropertyAnimation(self, b"maximumHeight")) |
| 82 | + toggleAnimation.addAnimation( |
| 83 | + QPropertyAnimation(self.contentArea, b"maximumHeight")) |
| 84 | + # don't waste space |
| 85 | + mainLayout = self.mainLayout |
| 86 | + mainLayout.setVerticalSpacing(0) |
| 87 | + mainLayout.setContentsMargins(0, 0, 0, 0) |
| 88 | + row = 0 |
| 89 | + mainLayout.addWidget(self.toggleButton, row, 0, |
| 90 | + 1, 1, Qt.AlignLeft) |
| 91 | + mainLayout.addWidget(self.headerLine, row, 2, 1, 1) |
| 92 | + row += 1 |
| 93 | + mainLayout.addWidget(self.contentArea, row, 0, 1, 3) |
| 94 | + self.setLayout(self.mainLayout) |
| 95 | + |
| 96 | + def start_animation(checked): |
| 97 | + arrow_type = Qt.DownArrow if checked else Qt.RightArrow |
| 98 | + direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward |
| 99 | + toggleButton.setArrowType(arrow_type) |
| 100 | + self.toggleAnimation.setDirection(direction) |
| 101 | + self.toggleAnimation.start() |
| 102 | + |
| 103 | + self.toggleButton.clicked.connect(start_animation) |
| 104 | + |
| 105 | + def setContentLayout(self, contentLayout): |
| 106 | + # Not sure if this is equivalent to self.contentArea.destroy() |
| 107 | + self.contentArea.destroy() |
| 108 | + self.contentArea.setLayout(contentLayout) |
| 109 | + collapsedHeight = self.sizeHint().height() - self.contentArea.maximumHeight() |
| 110 | + contentHeight = contentLayout.sizeHint().height() |
| 111 | + for i in range(self.toggleAnimation.animationCount()-1): |
| 112 | + spoilerAnimation = self.toggleAnimation.animationAt(i) |
| 113 | + spoilerAnimation.setDuration(self.animationDuration) |
| 114 | + spoilerAnimation.setStartValue(collapsedHeight) |
| 115 | + spoilerAnimation.setEndValue(collapsedHeight + contentHeight) |
| 116 | + contentAnimation = self.toggleAnimation.animationAt( |
| 117 | + self.toggleAnimation.animationCount() - 1) |
| 118 | + contentAnimation.setDuration(self.animationDuration) |
| 119 | + contentAnimation.setStartValue(0) |
| 120 | + contentAnimation.setEndValue(contentHeight) |
| 121 | + |
| 122 | + |
| 123 | +if __name__ == "__main__": |
| 124 | + import sys |
| 125 | + |
| 126 | + app = QtWidgets.QApplication(sys.argv) |
| 127 | + |
| 128 | + ui = Spoiler() |
| 129 | + ui.setContentLayout(ui.verticalLayout) |
| 130 | + ui.show() |
| 131 | + |
| 132 | + sys.exit(app.exec_()) |
| 133 | + |
| 134 | + |
0 commit comments