QTreeWidget:如何动态更改 sizeHint?
QTreeWidget: How to change sizeHint dynamically?
我有一个 QTreeWidget,其中 TopLevelIteps 被自定义小部件替换。所述小部件的最大和最小高度使用 QStateMachine 动画。
QTreeWidget (GIF):
自定义小部件动画 (GIF):
问题是行在扩展时不会调整其高度以适应自定义小部件:
行高固定大小 (GIF):
导致小部件项目之间重叠,而不是像这样相互推开:
我想要的结果 (GIF):
我尝试在顶级项目上使用 setSizeHint(),但它在 items/widgets:
之间创建了一个大空 space
使用 setSizeHint()(GIF):
我在想也许我必须实施 sizeHint() 但我不确定该放什么。或者有更好的方法来解决这个问题吗?
非常感谢一些提示。
示例代码:
# Custom Widget
class ExpandableFrame(QFrame):
def __init__(self):
QFrame.__init__(self)
# Default Properties
self.setFixedSize(200,50)
self.setStyleSheet('background-color: #2e4076; border: 2px solid black; border-radius: 10px;')
# Setup expand button
self.expandToggle = QToolButton()
self.expandToggle.setText('[]')
self.expandToggle.setMaximumSize(10,20)
self.expandToggle.setCursor(Qt.PointingHandCursor)
# Setup layout
layout = QHBoxLayout()
layout.setAlignment(Qt.AlignRight)
layout.addWidget(self.expandToggle)
self.setLayout(layout)
self.expandArea()
# Animates minimumHeight and maximumHeight
def expandArea(self):
heigth = self.height()
newHeigth = 100
machine = QStateMachine(self)
state1 = QState()
state1.assignProperty(self, b'minimumHeight', heigth)
state1.assignProperty(self, b'maximumHeight', heigth)
state2 = QState()
state2.assignProperty(self, b'minimumHeight', newHeigth)
state2.assignProperty(self, b'maximumHeight', newHeigth)
# Create animations
expandAnim = QPropertyAnimation(self, 'minimumHeight')
closeAnim = QPropertyAnimation(self, 'maximumHeight')
expandAnim.setDuration(125)
closeAnim.setDuration(125)
expandAnim.setEasingCurve(QEasingCurve.Linear)
# Create event transitions
eventTransition1 = QEventTransition(self.expandToggle, QEvent.MouseButtonPress)
eventTransition1.setTargetState(state2)
eventTransition1.addAnimation(expandAnim)
state1.addTransition(eventTransition1)
eventTransition2 = QEventTransition(self.expandToggle, QEvent.MouseButtonPress)
eventTransition2.setTargetState(state1)
eventTransition2.addAnimation(closeAnim)
state2.addTransition(eventTransition2)
# Add the states to the machine
machine.addState(state1)
machine.addState(state2)
machine.setInitialState(state1)
machine.start()
# Tree Widget
class CustomTree(QTreeWidget):
customWidget = []
def __init__(self, parent=None):
QTreeWidget.__init__(self, parent)
# Create top level items
itemCount = 3
for element in range(itemCount):
topLevelItem = QTreeWidgetItem()
self.addTopLevelItem(topLevelItem)
# Replace the top level items with the expandable custom widget:
# Get the Model Index to each item
modelIndex = self.indexFromItem(topLevelItem, 0)
# Create the ExpandableFrame widgets for all the top level items
self.customWidget.append(ExpandableFrame())
# Set the widget to each top level item based on its index
self.setIndexWidget(modelIndex, self.customWidget[element])
# Create more items and add them as children of the top level items
for x in range(itemCount):
child = QTreeWidgetItem()
child.setText(0,'Child')
topLevelItem.addChild(child)
示例如下所示:
最小代码示例运行:
一个解决方案是在每次更改任何小部件的大小时发出视图的项目委托的 sizeHintChanged
信号。这告诉视图应该更新项目的位置。为此,您可以覆盖 ExpandableFrame
的 resizeEvent
并发出自定义信号,例如
class ExpandableFrame(QFrame):
resized = pyqtSignal(QVariant)
def resizeEvent(self, event):
self.resized.emit(self.height())
super().resizeEvent(event)
在 CustomTree
中,您可以通过覆盖 setIndexWidget
将 ExpandableFrame.resized
连接到自定义树委托的 sizeHintChanged
信号,例如
class CustomTree(QTreeWidget):
...
def setIndexWidget(self, index, widget):
super().setIndexWidget(index, widget)
if isinstance(widget, ExpandableFrame):
widget.resized.connect(lambda: self.itemDelegate().sizeHintChanged.emit(index))
屏幕截图:
这种方法的缺点是,如果小部件被移动或替换,您将需要更新连接。
我有一个 QTreeWidget,其中 TopLevelIteps 被自定义小部件替换。所述小部件的最大和最小高度使用 QStateMachine 动画。
QTreeWidget (GIF):
自定义小部件动画 (GIF):
问题是行在扩展时不会调整其高度以适应自定义小部件:
行高固定大小 (GIF):
导致小部件项目之间重叠,而不是像这样相互推开:
我想要的结果 (GIF):
我尝试在顶级项目上使用 setSizeHint(),但它在 items/widgets:
之间创建了一个大空 space使用 setSizeHint()(GIF):
我在想也许我必须实施 sizeHint() 但我不确定该放什么。或者有更好的方法来解决这个问题吗?
非常感谢一些提示。
示例代码:
# Custom Widget
class ExpandableFrame(QFrame):
def __init__(self):
QFrame.__init__(self)
# Default Properties
self.setFixedSize(200,50)
self.setStyleSheet('background-color: #2e4076; border: 2px solid black; border-radius: 10px;')
# Setup expand button
self.expandToggle = QToolButton()
self.expandToggle.setText('[]')
self.expandToggle.setMaximumSize(10,20)
self.expandToggle.setCursor(Qt.PointingHandCursor)
# Setup layout
layout = QHBoxLayout()
layout.setAlignment(Qt.AlignRight)
layout.addWidget(self.expandToggle)
self.setLayout(layout)
self.expandArea()
# Animates minimumHeight and maximumHeight
def expandArea(self):
heigth = self.height()
newHeigth = 100
machine = QStateMachine(self)
state1 = QState()
state1.assignProperty(self, b'minimumHeight', heigth)
state1.assignProperty(self, b'maximumHeight', heigth)
state2 = QState()
state2.assignProperty(self, b'minimumHeight', newHeigth)
state2.assignProperty(self, b'maximumHeight', newHeigth)
# Create animations
expandAnim = QPropertyAnimation(self, 'minimumHeight')
closeAnim = QPropertyAnimation(self, 'maximumHeight')
expandAnim.setDuration(125)
closeAnim.setDuration(125)
expandAnim.setEasingCurve(QEasingCurve.Linear)
# Create event transitions
eventTransition1 = QEventTransition(self.expandToggle, QEvent.MouseButtonPress)
eventTransition1.setTargetState(state2)
eventTransition1.addAnimation(expandAnim)
state1.addTransition(eventTransition1)
eventTransition2 = QEventTransition(self.expandToggle, QEvent.MouseButtonPress)
eventTransition2.setTargetState(state1)
eventTransition2.addAnimation(closeAnim)
state2.addTransition(eventTransition2)
# Add the states to the machine
machine.addState(state1)
machine.addState(state2)
machine.setInitialState(state1)
machine.start()
# Tree Widget
class CustomTree(QTreeWidget):
customWidget = []
def __init__(self, parent=None):
QTreeWidget.__init__(self, parent)
# Create top level items
itemCount = 3
for element in range(itemCount):
topLevelItem = QTreeWidgetItem()
self.addTopLevelItem(topLevelItem)
# Replace the top level items with the expandable custom widget:
# Get the Model Index to each item
modelIndex = self.indexFromItem(topLevelItem, 0)
# Create the ExpandableFrame widgets for all the top level items
self.customWidget.append(ExpandableFrame())
# Set the widget to each top level item based on its index
self.setIndexWidget(modelIndex, self.customWidget[element])
# Create more items and add them as children of the top level items
for x in range(itemCount):
child = QTreeWidgetItem()
child.setText(0,'Child')
topLevelItem.addChild(child)
示例如下所示:
最小代码示例运行:
一个解决方案是在每次更改任何小部件的大小时发出视图的项目委托的 sizeHintChanged
信号。这告诉视图应该更新项目的位置。为此,您可以覆盖 ExpandableFrame
的 resizeEvent
并发出自定义信号,例如
class ExpandableFrame(QFrame):
resized = pyqtSignal(QVariant)
def resizeEvent(self, event):
self.resized.emit(self.height())
super().resizeEvent(event)
在 CustomTree
中,您可以通过覆盖 setIndexWidget
将 ExpandableFrame.resized
连接到自定义树委托的 sizeHintChanged
信号,例如
class CustomTree(QTreeWidget):
...
def setIndexWidget(self, index, widget):
super().setIndexWidget(index, widget)
if isinstance(widget, ExpandableFrame):
widget.resized.connect(lambda: self.itemDelegate().sizeHintChanged.emit(index))
屏幕截图:
这种方法的缺点是,如果小部件被移动或替换,您将需要更新连接。