前言
我不喜欢冗长的答案,甚至不喜欢长篇难以阅读的代码,但这些仍然是我在寻找答案时想出的解决方案这个问题我自己前一阵子。
简单
这第一段代码基本上是我最后使用的非常简化的解决方案。它更高效,更重要的是,更易于阅读和理解。
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem
class SimpleMultisortTreeWidget(QTreeWidget):
def __init__(self, *a, **k):
super().__init__(*a, **k)
self._csort_order = []
self.header().sortIndicatorChanged.connect(self._sortIndicatorChanged)
def _sortIndicatorChanged(self, n, order):
try:
self._csort_order.remove(n)
except ValueError:
pass
self._csort_order.insert(0, n)
self.sortByColumn(n, order)
class SimpleMultisortTreeWidgetItem(QTreeWidgetItem):
def __lt__(self, other):
corder = self.treeWidget()._csort_order
return list(map(self .text, corder)) < \
list(map(other.text, corder))
扩展
我也有需要...
- 将某些列排序为整数和/或
decimal.Decimal 类型的对象。
- 混合升序和降序(即注意为每一列设置
Qt.SortOrder)
因此,我最终使用了以下示例。
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem
class MultisortTreeWidget(QTreeWidget):
u"""QTreeWidget inheriting object, to be populated by
``MultisortTreeWidgetItems``, that allows sorting of multiple columns with
different ``Qt.SortOrder`` values.
"""
def __init__(self, *arg, **kw):
r"Pass on all positional and key word arguments to super().__init__"
super().__init__(*arg, **kw)
self._csort_corder = []
self._csort_sorder = []
self.header().sortIndicatorChanged.connect(
self._sortIndicatorChanged
)
def _sortIndicatorChanged(self, col_n, order):
r"""
Update private attributes to reflect the current sort indicator.
(Connected to self.header().sortIndicatorChanged)
:param col_n: Sort indicator indicates column with this index to be
the currently sorted column.
:type col_n: int
:param order: New sort order indication. Qt enum, 1 or 0.
:type order: Qt.SortOrder
"""
# The new and current column number may, or may not, already be in the
# list of columns that is used as a reference for their individual
# priority.
try:
i = self._csort_corder.index(col_n)
except ValueError:
pass
else:
del self._csort_corder[i]
del self._csort_sorder[i]
# Force current column to have highest priority when sorting.
self._csort_corder.insert(0, col_n)
self._csort_sorder.insert(0, order)
self._csort = list(zip(self._csort_corder,self._csort_sorder))
# Resort items using the modified attributes.
self.sortByColumn(col_n, order)
class MultisortTreeWidgetItem(QTreeWidgetItem):
r"""QTreeWidgetÍtem inheriting objects that, when added to a
MultisortTreeWidget, keeps the order of multiple columns at once. Also
allows for column specific type sensitive sorting when class attributes
SORT_COL_KEYS is set.
"""
@staticmethod
def SORT_COL_KEY(ins, c):
return ins.text(c)
SORT_COL_KEYS = []
def __lt__(self, other):
r"""Compare order between this and another MultisortTreeWidgetItem like
instance.
:param other: Object to compare against.
:type other: MultisortTreeWidgetItem.
:returns: bool
"""
# Fall back on the default functionality if the parenting QTreeWidget
# is not a subclass of MultiSortTreeWidget or the SortIndicator has not
# been changed.
try:
csort = self.treeWidget()._csort
except AttributeError:
return super(MultisortTreeWidgetItem, self).__lt__(other)
# Instead of comparing values directly, place them in two lists and
# extend those lists with values from columns with known sort order.
order = csort[0][1]
left = []
right = []
for c, o in csort:
try:
key = self.SORT_COL_KEYS[c]
except (KeyError, IndexError):
key = self.SORT_COL_KEY
# Reverse sort order for columns not sorted according to the
# current sort order indicator.
if o == order:
left .append(key(self , c))
right.append(key(other, c))
else:
left .append(key(other, c))
right.append(key(self , c))
return left < right
用法
上述MultisortTreeWidgetItem 类的静态方法SORT_COL_KEY 和SORT_COL_KEYS 类属性还允许使用除self.text(N) 返回的值之外的其他值,例如self.data() 返回的列表。
以下示例将第一列的行中的文本排序为整数,并根据self.data() 返回的列表中的相应对象对第三列的行进行排序。所有其他列按item.text() 值排序,按字符串排序。
class UsageExampleItem(MultisortTreeWidgetItem):
SORT_COL_KEYS = {
0: lambda item, col: int(item.text(col)),
2: lambda item, col: item.data()[col],
5: lambda item, col: int(item.text(col) or 0) # Empty str defaults to 0
}
创建一个MultisortTreeWidget 对象并将其添加到布局中,然后创建UsageExampleItems 并将它们添加到MultisortTreeWidget。
此解决方案“记住”之前使用的列和排序顺序。因此,如果您想按第一列中的值对 UsageExampleItems 小部件中的项目进行排序,并且让共享一个值的行彼此之间按第二列排序,那么您将首先单击第二列,然后继续点击第一列的标题项。