Search code examples
resizerowpysideqtreeview

How to resize rows in a QTreeView and a QStandardItemModel?


I'd like to set my rows to a fixed height. I've found an example using QAbstractItemModel, but I'm using QStandardItemModel. When I run the app, the QTreeView is blank. Any thoughts on how I could get this working for a QStandardItemModel?

import sys
from PySide import QtCore, QtGui


class TreeItem(object):
    def __init__(self, data, parent=None):
        self.parentItem = parent
        self.data = data
        self.childItems = []

    def appendChild(self, item):
        self.childItems.append(item)

    def row(self):
        if self.parentItem:
            return self.parentItem.childItems.index(self)
        return 0


class TreeModel(QtCore.QAbstractItemModel):
    def __init__(self, parent=None):
        super(TreeModel, self).__init__(parent)
        self.rootItem = TreeItem(None)
        for i, c in enumerate("abcdefg"):
            child = TreeItem([i, c], self.rootItem)
            self.rootItem.appendChild(child)
        parent = self.rootItem.childItems[1]
        child = TreeItem(["down", "down"], parent)
        parent.appendChild(child)

    def columnCount(self, parent):
        return 2

    def data(self, index, role):
        if not index.isValid():
            return None
        if role == QtCore.Qt.DisplayRole:
            item = index.internalPointer()
            return item.data[index.column()]
        elif role == QtCore.Qt.SizeHintRole:
            print "giving size hint"
            return QtCore.QSize(10, 10)

        return None

    def flags(self, index):
        if not index.isValid():
            return QtCore.Qt.NoItemFlags
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

    def headerData(self, section, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return ["A", "B"][section]
        return None

    def index(self, row, column, parent):
        if not self.hasIndex(row, column, parent):
            return QtCore.QModelIndex()

        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()

        childItem = parentItem.childItems[row]
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QtCore.QModelIndex()

    def parent(self, index):
        if not index.isValid():
            return QtCore.QModelIndex()
        parentItem = index.internalPointer().parentItem
        if parentItem == self.rootItem:
            return QtCore.QModelIndex()
        return self.createIndex(parentItem.row(), 0, parentItem)

    def rowCount(self, parent):
        if parent.column() > 0:
            return 0
        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()
        return len(parentItem.childItems)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    model = TreeModel()

    view = QtGui.QTreeView()
    view.setModel(model)
    view.setWindowTitle("Simple Tree Model")
    view.show()
    sys.exit(app.exec_())

Also, I've been looking around for the meaning of the term delegate in Qt, but the concept still isn't clicking in my head yet. Any insight into that would be appreciated as well!


Solution

  • You generally do this using QItemDelegates (or QStyledItemDelegate if you want stylesheet styling to work) by overriding the sizeHint method and always returning a size of a fixed height.

    class MyDelegate(QtGui.QStyledItemDelegate):
    
        def sizeHint(self, option, index):
            my_fixed_height = 30
            size = super(MyDelegate, self).sizeHint(option, index)
            size.setHeight(my_fixed_height)
            return size
    
    
    view = QtGui.QTreeView()
    delegate = MyDelegate()
    view.setItemDelegate(delegate)