如何在调整大小时隐藏 QTreeWidget 中的 QWidgets?

How to keep QWidgets in QTreeWidget hidden during resize?

我在 QTreeWidget 中有一个简单的 UI 和 QWidgets。 其中一些需要隐藏。 每次调整应用程序大小时,所有 QWidget 都会变得可见。 下面是演示该问题的最小示例。 在显式调用 setVisible(True) 之前,如何确保 QWidgets 保持隐藏状态? pyqt版本是5.12.3

from PyQt5.QtWidgets import QApplication, QWidget, QTreeWidgetItem, QTreeWidget, QCheckBox, QPushButton, QVBoxLayout
import sys

class Foo(QWidget):

    def __init__(self):   
        super().__init__() 
        lay = QVBoxLayout(self)        
        tree = QTreeWidget()
        
        item = QTreeWidgetItem()
        tree.addTopLevelItem(item)
        self.checkBox = QCheckBox()
        tree.setItemWidget(item,0,self.checkBox)        
        
        button = QPushButton('Hide Checkbox')
        button.clicked.connect(self.hideCheckbox)
        
        lay.addWidget(tree)
        lay.addWidget(button)
        lay.addWidget(button)
    
    def hideCheckbox(self):
        self.checkBox.setVisible(False)  # is reset on resize
    
if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = Foo()
    w.show()
    sys.exit(app.exec_())

考虑到这是由调用项视图的 private updateEditorGeometries() 函数引起的,只要视图更新其内容的几何形状,它就会自动显示索引小部件,对此没有直接控制。

不过,有两种可能的解决方法。

将项目小部件添加到容器

在这种情况下,项目小部件是一个基本的 QWidget,充当 actual 小部件的容器。由于 show() 只会在项目小部件上调用,显式隐藏子小部件将避免问题:

    self.checkBox = QCheckBox()
    container = QWidget()
    containerLayout = QHBoxLayout(container)
    containerLayout.setContentsMargins(0, 0, 0, 0)
    containerLayout.addWidget(self.checkBox)
    tree.setItemWidget(item, 0, container)

请注意,将内容边距设置为 0 很重要(否则将添加默认的 Qt 布局边距)。

在 QTreeWidget 子类中覆盖 updateGeometries()

updateGeometries() 在项目视图调整大小时或视口内容需要内部更改(columns/rows 调整大小、模型已更改等)时由项目视图调用。

您可以创建 QTreeWidget 的子类,保留为项目设置的内部小部件列表,然后在调用基本实现之前跟踪隐藏的小部件:

class TreeWidget(QTreeWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.itemWidgets = set()

    def setItemWidget(self, item, column, widget):
        self.itemWidgets.add(widget)
        widget.destroyed.connect(lambda: self.itemWidgets.discard(widget))
        super().setItemWidget(item, column, widget)

    def updateGeometries(self):
        hidden = [w for w in self.itemWidgets if w.isHidden()]
        super().updateGeometries()
        for widget in hidden:
            widget.setVisible(False)