如何对 QTreeWidget 列进行排序?

Posted

技术标签:

【中文标题】如何对 QTreeWidget 列进行排序?【英文标题】:How to sort QTreeWidget Column? 【发布时间】:2021-06-20 07:31:27 【问题描述】:

我使用 QTreeWidget 的 UI 很小,它包含 4 列 ['Folder'、'FileName'、'Size'、'Owner'] 现在,当我单击“大小”列进行排序时,它没有按(B、Kib 和 Mib)的正确顺序排序,因为“大小”的值在字符串中它只对第一个数字进行排序并混合所有字节、Kib & Mib.

如果列同时包含 int 和 string 类型,谁能指导以正确顺序进行排序的正确方法是什么?

from PyQt5.QtWidgets import *


class TestUI(QWidget):
    def __init__(self):
        super(TestUI, self).__init__(parent=None)

        self.setGeometry(10, 10, 700, 350)
        self.setWindowTitle('Runner up !')
        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        self.tree_widget = QtGui.QTreeWidget()
        self.tree_widget.setSelectionMode(QtGui.QTreeWidget.ExtendedSelection)
        headers = ['Folder', 'Filepath', 'Size', 'Owner']
        self.tree_widget.setHeaderLabels(headers)
        self.tree_widget.setSortingEnabled(True)

        metadata = 'Desktop': [('/u/donald/Desktop/file_test.txt', '2 MiB', 'Donald'),
                                ('/u/donald/Desktop/file_test_01.txt', '20 KiB', 'Donald')]

        for folder, folderdata in metadata:
            top_item = QtGui.QTreeWidgetItem(self.tree_widget,
                                     [folder, '', '', ''])
            for data in folderdata:
                filepath, size, owner = data[0], data[1], data[2]

                child_item = QtGui.QTreeWidgetItem(top_item, ['', filepath, size, owner])


if __name__ == '__main__':
    app = QApplication(sys.argv)
    WIN = TestUI()
    WIN.show()
    app.exec_()

看起来像这样

【问题讨论】:

【参考方案1】:

Qt 不知道它们是文件大小而是字符串,因此它会将它们与这些规则进行比较。因此,如果您想要自定义排序,则必须覆盖 QTreeWidgetItem 的 __lt__ 方法。为了进行比较,您可以进行映射以将单位转换为可以比较的数字,但为了避免这项工作,我更喜欢使用可以做到这一点的库:datasize (python -m pip install datasize)

from datasize import DataSize

SIZE_COLUMN = 2


class TreeWidgetItem(QtGui.QTreeWidgetItem):
    def __lt__(self, other):
        column = self.treeWidget().sortColumn()
        if column == SIZE_COLUMN:
            # DataSize does not accept space between the quantity and the unit,
            # so we eliminate the spaces:
            text_with_spaces = self.text(column).replace(" ", "")
            other_text_with_spaces = other.text(column).replace(" ", "")
            return DataSize(text_with_spaces) < DataSize(other_text_with_spaces)
        return super(TreeWidgetItem, self).__lt__(other)
for filepath, size, owner in folderdata:
    child_item = TreeWidgetItem(top_item, ["", filepath, size, owner])

如果您不想使用数据大小,那么您将不得不实现自己的转换器,例如(其他示例请参见 Python - Parse human-readable filesizes into bytes):

SIZE_COLUMN = 2
SIZE_MAPPING = "MiB": 2 ** 20, "KiB": 2 ** 10


def converter(text):
    string_value, unit = text.split()
    return float(string_value) * SIZE_MAPPING[unit]


class TreeWidgetItem(QtGui.QTreeWidgetItem):
    def __lt__(self, other):
        column = self.treeWidget().sortColumn()
        if column == SIZE_COLUMN:
            return converter(self.text(column)) < converter(other.text(column))
        return super().__lt__(other)

【讨论】:

很遗憾,我的工作环境已关闭,无法在其中安装 datasize。你能建议其他方法吗? 对不起,如果我问的是一个菜鸟问题,但它将如何联系起来。假设如果单击 UI 列“大小”,那么 TreeWidgetItem 类将如何触发? 如果我在发布的问题中没有被清除,我已经重新编辑了代码。我有点困惑,因为这将是我第一个覆盖现有方法的案例,这让我感到困惑,您能否根据编辑的代码重新发布您的建议。 @mehulJ 只需添加类TreeWidgetItemconverter 函数,同时将child_item = QtGui.QTreeWidgetItem(top_item, ['', filepath, size, owner]) 更改为child_item = TreeWidgetItem(top_item, ['', filepath, size, owner])

以上是关于如何对 QTreeWidget 列进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何对二维数组的列进行排序?

如何在角度 4 材料排序中对日期/时间列进行排序?

如何对加密的列数据进行排序?

如何使用 Spark SQL 对均值列进行排序?

如何在熊猫中按值计数对列进行排序

如何使用 vb.net 以编程方式对 Excel 中的列进行排序?