[英]PyQT 5 Add widgets dynamically to a spoiler
我正在編寫一個小程序,理想情況下我希望有一個固定大小的組,這些組可以展開,其中我有更多的劇透,代表我可以打開和關閉的項目,以便向我的系統添加一些實體。
我一直在這里尋找類似的問題,並得到了以下內容以半正確地工作:
我添加了-
按鈕以從組中刪除這些孩子,並添加了+
將孩子添加到組中。
只要我不刪除或添加小部件,這似乎就可以正常工作。
我的代碼如下所示:
spoilers.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Spoiler(QWidget):
def __init__(self, parent=None, title='', animationDuration=300, addRemoveOption='None'):
super(Spoiler, self).__init__(parent=parent)
self.animationDuration = animationDuration
self.toggleAnimation = QParallelAnimationGroup()
self.contentArea = QScrollArea()
self.headerLine = QFrame()
self.toggleButton = QToolButton()
self.mainLayout = QGridLayout()
self.childWidgets = []
self.toggleButton.setStyleSheet("QToolButton { border: none; }")
self.toggleButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.toggleButton.setArrowType(Qt.RightArrow)
self.toggleButton.setText(str(title))
self.toggleButton.setCheckable(True)
self.toggleButton.setChecked(False)
self.addRemoveOperation = addRemoveOption
if addRemoveOption is not 'None':
if addRemoveOption is 'Add':
self.addRemoveButton = QPushButton('+')
else:
self.addRemoveButton = QPushButton('-')
self.addRemoveButton.clicked.connect(self.onAddRemoveButton)
self.contentArea.setStyleSheet("QScrollArea { background-color: white; border: none; }")
self.contentArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
# start out collapsed
self.contentArea.setMaximumHeight(0)
self.contentArea.setMinimumHeight(0)
# let the entire widget grow and shrink with its content
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)
self.mainLayout.addWidget(self.toggleButton, 0, 0, 1, 1, Qt.AlignLeft)
if addRemoveOption is not 'None':
self.mainLayout.addWidget(self.addRemoveButton, 0, 2, 1, 1, Qt.AlignRight)
self.mainLayout.addWidget(self.contentArea, 1, 0, 1, 3)
self.setLayout(self.mainLayout)
def start_animation(checked):
arrow_type = Qt.DownArrow if checked else Qt.RightArrow
direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward
self.toggleButton.setArrowType(arrow_type)
self.toggleAnimation.setDirection(direction)
self.toggleAnimation.start()
self.toggleButton.clicked.connect(start_animation)
self.contentLayout = QVBoxLayout()
self.setContentLayout(self.contentLayout)
def setContentLayout(self, contentLayout):
self.contentArea.destroy()
self.contentArea.setLayout(contentLayout)
collapsedHeight = self.sizeHint().height() - self.contentArea.maximumHeight()
contentHeight = contentLayout.sizeHint().height()
for i in range(self.toggleAnimation.animationCount()-1):
spoilerAnimation = self.toggleAnimation.animationAt(i)
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)
def addChild(self, child):
self.childWidgets += [child]
self.contentLayout.addWidget(child)
self.setContentLayout(self.contentLayout)
def removeChild(self, child):
self.childWidgets.remove(child)
#self.contentLayout.removeWidget(child)
child.destroy()
#self.setContentLayout(self.contentLayout)
def onAddRemoveButton(self):
self.addChild(LeafSpoiler(root=self))
class LeafSpoiler(Spoiler):
def __init__(self, parent=None, root=None, title=''):
if(root == None):
addRemoveOption = 'None'
else:
addRemoveOption = 'Sub'
super(LeafSpoiler, self).__init__(parent=parent, title=title, addRemoveOption=addRemoveOption)
self.root = root
def onAddRemoveButton(self):
self.root.removeChild(self)
gui.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from spoilers import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setGeometry(300, 300, 300, 220)
# self.setWindowIcon(QIcon('web.png'))
self.centralWidget = QFrame()
self.centralLayout = QVBoxLayout()
self.centralWidget.setLayout(self.centralLayout)
self.spoiler1 = Spoiler(addRemoveOption='Add', title='Group 1')
self.spoiler2 = Spoiler(addRemoveOption='Add', title='Group 2')
for i in range(3):
leaf = LeafSpoiler(root=self.spoiler1)
self.spoiler1.addChild(leaf)
leaf = LeafSpoiler(root=self.spoiler2)
self.spoiler2.addChild(leaf)
self.centralLayout.addWidget(self.spoiler1)
self.centralLayout.addWidget(self.spoiler2)
self.setCentralWidget(self.centralWidget)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
我不確定為什么這不起作用。 我認為Spoiler.setContentLayout()
不應該被多次調用。
如果有人能幫助我解決這個問題,我會很高興!
你好,芬蘭人
我不太確定我是否正確理解了您的問題。 我假設您在嘗試刪除 Spoilerleaf 時正在談論 pyqt 崩潰? 至少這是我機器上發生的事情。
您的“removeChild”方法似乎是這里的罪魁禍首。 在不太了解崩潰源的情況下,將其替換為對deleteLater()的調用可以在我的機器上啟用子刪除:
class LeafSpoiler(Spoiler):
# [...] same init as your's
def onAddRemoveButton(self):
self.deleteLater()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.