【问题标题】:QTreeWidget - excluding top level items from sortQTreeWidget - 从排序中排除顶级项目
【发布时间】:2017-01-12 03:07:06
【问题描述】:

我有一个 2 级 QTreeWidget。顶层只有一列,仅用于对第二层进行分组,其中包含实际的多列数据。

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

我如何做到这一点?

【问题讨论】:

    标签: python sorting pyqt pyqt4 qtreewidget


    【解决方案1】:

    最简单的解决方案是创建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_())
    

    【讨论】:

      【解决方案2】:

      您可以像这样使用 QTreeWidgetItem(s) 的 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),但由于这是一个信号,它只是在小部件进行常规排序后触发,所以最后它没有效果 - 顶部在调用函数之前对级别项目进行排序

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

      1.覆盖QTreeWidget的“排序”方法

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

      2。覆盖根项目sortChildren()

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

      【讨论】:

      • 谢谢,这是朝着正确方向迈出的一步,但现在的问题是如何覆盖默认的排序行为。我正在做self.treeWidget.header().sortIndicatorChanged.connect(self.sortChanged),但由于这是一个信号,它只是在 小部件进行常规排序之后触发,所以最后它没有效果 - 顶级项目在函数之前被排序调用。
      • 也许这可以实现,但这将是一个非常丑陋的黑客,您是否考虑过使用模型/视图方法?如果您可以将 QTreeView 与模型一起使用,那么管理排序应该会容易得多。
      • 我从未使用过模型/视图方法,因为我并不真正需要它,而且它似乎给一切增加了一定程度的复杂性。在一个理想的世界中,QTreeWidget 会有一个我可以拦截的sortEvent,但由于情况并非如此,我正在考虑子类化QHeaderView。麻烦的是我不知道它的哪个成员负责排序,我找不到实际的源代码来参考。如果一切都失败了,我会采用模型/视图解决方案。
      • 这些小部件的问题(QTreeWidget 和可能)是模型/视图 suff 的某种复杂实现。无论如何,您可以尝试两种解决方案,我将编辑答案以包含它们。
      • 不幸的是,这两种方法我都没有运气,但我确实设法找到了一个可接受的解决方案,并将很快发布我自己的答案。不过,感谢您的时间和精力。
      【解决方案3】:

      我根据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. 第一列的排序指示器将卡住,显示静态排序方向,而不是子级排序的实际方向。主要只是一个外观问题,但它仍然会触发我。

      不理想,但考虑到我尝试过的所有其他方法根本不起作用,我现在就接受它。我已经在这上面浪费了足够多的时间,不完美但工作总比完美但不工作要好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-11
        • 1970-01-01
        • 2013-06-10
        • 1970-01-01
        • 2019-05-10
        • 2014-01-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多