Search code examples
pythonsortingpyqtpyqt4qtreewidget

QTreeWidget - excluding top level items from sort


I have a 2-level QTreeWidget. The top level only has one column and is just used for grouping the second level, which holds the actual multi-column data.

When I sort by clicking on a header (or any other way, really), I only want the second level to be sorted, as the top-level items have a fixed order set elsewhere in the app and shouldn't be affected.

How do I achieve this?


Solution

  • The simplest solution is to create a subclass of QTreeWidgetItem and reimplement its __lt__ method so that it always returns False. Qt uses a stable sort algorithm, so this means the items will always retain their original order. This subclass should be used for the top-level items only.

    Here is a working demo that seems to meet your spec:

    import sys
    from random import randint
    from PyQt4 import QtCore, QtGui
    
    class TreeWidgetItem(QtGui.QTreeWidgetItem):
        def __lt__(self, other):
            return False
    
    class Window(QtGui.QTreeWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.setHeaderLabels('Name X Y'.split())
            for text in 'One Two Three Four'.split():
                parent = TreeWidgetItem([text])
                for text in 'Red Blue Green Yellow'.split():
                    child = QtGui.QTreeWidgetItem([
                        text, str(randint(0, 9)), str(randint(0, 9))])
                    parent.addChild(child)
                self.addTopLevelItem(parent)
            self.expandAll()
            self.setSortingEnabled(True)
            self.sortByColumn(0, QtCore.Qt.AscendingOrder)
    
    if __name__ == "__main__":
    
        app = QtGui.QApplication(sys.argv)
        window = Window()
        window.setGeometry(800, 100, 320, 400)
        window.show()
        sys.exit(app.exec_())