Goswin von Brederlow Goswin von Brederlow - 5 months ago 49
Python Question

How to compute the height of a QTreeWidget content?

I want a

QTreeWidget
that has a preferred height that shows all its contents without scrollbar. Use case for this is twofold: 1) trees in a
QVBoxLayout
taking space proportional to their content and 2) trees in a
QScrollArea
where there should be only one scrollbar for all trees instead of individual scrollbars.

I tried querying the tree and its viewport but they always return the same values no matter how much content they have:

size = PySide.QtCore.QSize(100, 30)
sizeHint = PySide.QtCore.QSize(256, 192)
minimumSize = PySide.QtCore.QSize(0, 0)
minimumSizeHint = PySide.QtCore.QSize(76, 76)
maximumSize = PySide.QtCore.QSize(16777215, 16777215)
baseSize = PySide.QtCore.QSize(0, 0)
frameSize = PySide.QtCore.QSize(100, 30)
viewport.size = PySide.QtCore.QSize(94, 5)
viewport.sizeHint = PySide.QtCore.QSize(-1, -1)
viewport.minimumSize = PySide.QtCore.QSize(0, 0)
viewport.minimumSizeHint = PySide.QtCore.QSize(-1, -1)
viewport.maximumSize = PySide.QtCore.QSize(16777215, 16777215)
viewport.baseSize = PySide.QtCore.QSize(0, 0)
viewport.frameSize = PySide.QtCore.QSize(94, 5)


Next I tried computing the size by adding up all the size hints for every item:

size = super().sizeHint()
height = self.horizontalScrollBar().sizeHint().height()
rows = 0
it = QtGui.QTreeWidgetItemIterator(self)
while it.value() is not None:
rows += 1
size = it.value().sizeHint(0)
height += size.height()
it += 1
size = QtCore.QSize(size.width(), height)


But all items return a size of (-1, -1). Even after the tree is displayed, not just during construction.

So how do I compute the height of the tree?

Answer

The trick seems to be to query the header for the width, the tree for individual row heights and add the frameWidth on all sides like this:

class TreeWidget(QtGui.QTreeWidget):
    def sizeHint(self):
        print("TreeWidget.sizeHint()")
        print("  frameWidth = {0}".format(self.frameWidth()))
        height = 2 * self.frameWidth() # border around tree
        if not self.isHeaderHidden():
            header = self.header()
            headerSizeHint = header.sizeHint()
            print("  headerSizeHint = {0}".format(headerSizeHint))
            height += headerSizeHint.height()
        rows = 0
        it = QtGui.QTreeWidgetItemIterator(self)
        while it.value() is not None:
            rows += 1
            index = self.indexFromItem(it.value())
            print("  rowHeight = {0}".format(self.rowHeight(index)))
            height += self.rowHeight(index)
            it += 1
        print("  computed height for {0} rows = {1}".format(rows, height))
        return QtCore.QSize(header.length() + 2 * self.frameWidth(), height)
Comments