Search code examples
qtpyqtpysidepyqt5qtreeview

PyQt: How Can I set row heights of QTreeView


In PyQt, I am looking for a way to set the height of rows in a QTreeView (similarly to QTableView.setRowHeight(row, row_height), but QTreeView does not have this function). QAbstractItemModel is used to set the tree model. I read some suggestions here using and sub-classing QAbstractItemDelegate.sizeHint(option, index) but I don't know exactly how to call them correctly within my tree model.

Any minimal code or suggestion would be greatly appreciated. Thanks.


Solution

  • The QTreeView works out a height for each row based on the data and size hints returned for each item. I think you probably just need to return size hints, either for all your items, or at least the first row (if you have setUniformRowHeights(True)). Incidentally this can significantly improve performance and so you should set it if you can.

    So you just need to implement your AbstractItemModel.data() method to return a size hint in the SizeHintRole. Something like this:

    def data(self, index, role = QtCore.Qt.DisplayRole):
        #  Check the index, possibly return None
        if role == QtCore.Qt.DisplayRole:
            # Return the data
        elif role == QtCore.Qt.SizeHintRole:
            return QtCore.QSize(item_width,item_height)
        # Other roles - maybe return None if you don't use them.
    

    EDIT: Big example

    You say you are still having trouble so here is a complete working example, based on the standard QT itemviews example. Try varying the QSize returned in the data method to see how the view changes:

    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(40,40)
    
            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_())