PyQt5 QTableWidget无法通过UserRole数据排序的问题求助
QTableWidget按UserRole值排序的解决方法
问题场景
已开启QTableWidget的排序功能(setSortingEnabled(True)),为每个QTableWidgetItem设置了:
Qt.DisplayRole:显示字符串f'M - {r}'Qt.UserRole:存储整数r
但点击表头排序时,列仍按DisplayRole的字符串排序,而非UserRole的整数值。尝试改用Qt.EditRole存储整数,不仅表格显示内容变为EditRole的值,排序逻辑也未按整数值执行。
最小可复现代码
from random import randint from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QWidget, QGridLayout, \ QTableWidgetItem, QPushButton class Table(QTableWidget): def __init__(self): super().__init__() self.setSortingEnabled(True) def populate(self): self.clear() self.setColumnCount(3) self.setRowCount(200) for row in range(500): for column in range(3): r = randint(0, 1000) item = QTableWidgetItem() item.setData(Qt.DisplayRole, f'M - {r}') item.setData(Qt.UserRole, r) self.setItem(row, column, item) class MainApp(QMainWindow): def __init__(self): super().__init__() self.table = Table() self.button = QPushButton('Roll') self.button.clicked.connect(self.table.populate) layout = QWidget() self.setCentralWidget(layout) grid = QGridLayout() layout.setLayout(grid) grid.addWidget(self.button) grid.addWidget(self.table) if __name__ == '__main__': app = QApplication([]) main_app = MainApp() main_app.showMaximized() app.exec()
解决思路
QTableWidget的默认排序逻辑依赖于QTableWidgetItem的__lt__方法,该方法默认比较的是Qt.DisplayRole的数据。要让排序使用Qt.UserRole的值,需要自定义Item类并重写__lt__方法,指定排序时使用UserRole的数据进行比较。
修改后的代码
- 自定义可排序的TableWidgetItem类
class SortableTableWidgetItem(QTableWidgetItem): def __lt__(self, other): # 获取UserRole对应的值 self_value = self.data(Qt.UserRole) other_value = other.data(Qt.UserRole) # 确保为整数类型后执行比较 if isinstance(self_value, int) and isinstance(other_value, int): return self_value < other_value # 若类型不匹配, fallback到默认排序逻辑 return super().__lt__(other)
- 在
populate方法中使用自定义Item替换原QTableWidgetItem
修改Table类的populate方法中创建Item的部分:
# 替换原item = QTableWidgetItem() item = SortableTableWidgetItem() item.setData(Qt.DisplayRole, f'M - {r}') item.setData(Qt.UserRole, r) self.setItem(row, column, item)
完整修改后的代码
from random import randint from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QWidget, QGridLayout, \ QTableWidgetItem, QPushButton class SortableTableWidgetItem(QTableWidgetItem): def __lt__(self, other): self_value = self.data(Qt.UserRole) other_value = other.data(Qt.UserRole) if isinstance(self_value, int) and isinstance(other_value, int): return self_value < other_value return super().__lt__(other) class Table(QTableWidget): def __init__(self): super().__init__() self.setSortingEnabled(True) def populate(self): self.clear() self.setColumnCount(3) self.setRowCount(200) for row in range(500): for column in range(3): r = randint(0, 1000) item = SortableTableWidgetItem() item.setData(Qt.DisplayRole, f'M - {r}') item.setData(Qt.UserRole, r) self.setItem(row, column, item) class MainApp(QMainWindow): def __init__(self): super().__init__() self.table = Table() self.button = QPushButton('Roll') self.button.clicked.connect(self.table.populate) layout = QWidget() self.setCentralWidget(layout) grid = QGridLayout() layout.setLayout(grid) grid.addWidget(self.button) grid.addWidget(self.table) if __name__ == '__main__': app = QApplication([]) main_app = MainApp() main_app.showMaximized() app.exec()
现在点击表头排序,列就会按照UserRole存储的整数值进行排序,同时保持DisplayRole的字符串显示内容不变。
内容的提问来源于stack exchange,提问作者Collaxd
相关产品推荐
相关产品推荐

