如何对 QTreeWidget 列进行排序?
How to sort QTreeWidget Column?
我有一个小 UI,我在其中使用 QTreeWidget,它包含 4 列 ['Folder'、'FileName'、'Size'、'Owner']
现在,当我单击 'Size' 列进行排序时,它不会按 (B、Kib 和 Mib) 的正确顺序排序,因为 'Size' 的值在字符串中,它只对第一个数字进行排序并混淆所有字节、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_()
看起来像这样
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])
如果您不想使用 datasize,那么您将不得不实现自己的转换器,例如(有关其他示例,请参见 ):
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)
我有一个小 UI,我在其中使用 QTreeWidget,它包含 4 列 ['Folder'、'FileName'、'Size'、'Owner'] 现在,当我单击 'Size' 列进行排序时,它不会按 (B、Kib 和 Mib) 的正确顺序排序,因为 'Size' 的值在字符串中,它只对第一个数字进行排序并混淆所有字节、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_()
看起来像这样
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])
如果您不想使用 datasize,那么您将不得不实现自己的转换器,例如(有关其他示例,请参见
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)