QTreeWidget - 排除排序中的顶级项目

时间:2016-09-04 15:59:21

标签: python sorting pyqt pyqt4 qtreewidget

我有一个2级QTreeWidget。顶级只有一列,仅用于分组第二级,它保存实际的多列数据。

当我通过单击标题(或任何其他方式,实际上)进行排序时,我只希望对第二级进行排序,因为顶级项目在应用程序的其他位置设置了固定顺序,不应该是影响。

我如何实现这一目标?

3 个答案:

答案 0 :(得分:2)

最简单的解决方案是创建QTreeWidgetItem的子类并重新实现其__lt__方法,以便它始终返回False。 Qt使用稳定的排序算法,因此这意味着项目将始终保持其原始顺序。此子类仅应用于顶级项目。

这是一个似乎符合您的规范的工作演示:

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

答案 1 :(得分:1)

您可以像这样使用QTreeWidgetItem的sortChildren方法:

sort_column = 1
# Iterate top-level elements
for index in range(tree.topLevelItemCount()):
    # Obtain the actual top-level item
    top_level_item = tree.topLevelItem(index)
    # Sort
    top_level_item.sortChildren(sort_column)

请注意,如果您向项目添加新子项,则需要再次对其进行排序(仅更改项目)

修改

  

谢谢,这是朝着正确方向迈出的一步,但现在的问题是如何覆盖默认的排序行为。我正在做self.treeWidget.header()。sortIndicatorChanged.connect(self.s ortChanged),但是因为那个' sa信号它只是在小部件进行常规排序后触发,所以最后它有没有效果 - 在调用函数之前对顶级项进行排序

除非您使用自定义模型/视图,否则您可以尝试两种方法(我没有测试过它们):

<强> 1。覆盖&#34;排序&#34; QTreeWidget

的方法

尝试用一些无操作替换sortItems()方法,但是小部件可能还有其他内部调用的私有方法。

<强> 2。覆盖根项sortChildren()

实现排序的可能是调用(隐藏)根项sortChildren(),它将对顶级项进行排序并调用那些的sortChildren() 。您可以使用rootIndex() / setRootIndex()了解如何获取/设置此项目,然后覆盖排序方法(例如root.sortChildren = lambda c, o: None)。

答案 2 :(得分:0)

我找到了一个基于this问题答案的解决方案。捕获sectionClicked信号并检查单击的列是否是第一个。如果是这样,强制静态排序方向,然后手动对子项进行排序。还需要一个变量来手动跟踪该列的排序方向。相关代码:

self.lastSortDir = 1
self.treeWidget.header().sectionClicked.connect(self.headerSectionClicked)

def headerSectionClicked(self, colId):
    flip = {0:1, 1:0}
    if colId == 0:
        self.treeWidget.header().setSortIndicator(0,1)
        sortDir = flip[self.lastSortDir]
        for gId in self.groupWidgets:
            self.groupWidgets[gId].sortChildren(0, sortDir)
        self.lastSortDir = sortDir

由于两个主要原因,这仍然不理想:

  1. 每次按第一列排序时,将执行两种排序,一种用于强制静态方向,另一种用于子项。可能是较大数据集的问题而且不够优雅。

  2. 第一列的排序指示器将停止显示静态排序方向,而不是子项排序的实际方向。大多只是化妆品问题,但它仍然触发我。

  3. 不理想,但考虑到我尝试的其他一切根本不起作用,我现在就把它拿走。我已经浪费了足够的时间,而且不完美,但工作比完美更好但不起作用。