在 QAbstractItemModel 中不区分大小写排序
Posted
技术标签:
【中文标题】在 QAbstractItemModel 中不区分大小写排序【英文标题】:Sorting case insensitively in QAbstractItemModel 【发布时间】:2018-05-14 03:45:38 【问题描述】:我在尝试使用 QAbstractItemModel 创建自己的排序函数时遇到了麻烦。它有效,但不区分大小写。我曾尝试使用 QSortFilterProxyModel,但没有成功。我的排序功能:
def sort(self, col, order):
self.emit(SIGNAL("layoutAboutToBeChanged()"))
self.tableData = sorted(self.tableData, key=operator.itemgetter(col))
if order == Qt.AscendingOrder:
self.tableData.reverse()
self.emit(SIGNAL("layoutChanged()"))
我正在使用 QTableView。我怎样才能使它不区分大小写?
完整示例:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import operator
import sys
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
header = ["one", "two"]
tableDict = [["abcdef", "tuvwx"], ["aBcde", "TUvWx"], ["acdef","tUvWX"], ["Acdef", "TUVwx"], ["ACdef", "TUVwx"]]
self.myTable = newTableModel(header, tableDict)
mainLayout = QHBoxLayout()
mainLayout.addWidget(self.myTable.tableView)
self.setLayout(mainLayout)
self.setWindowTitle("Test table")
class newTableModel(QAbstractTableModel):
def __init__(self, header, data, parent=None, *args):
super(newTableModel, self).__init__(parent)
self.tableView = QTableView()
self.tableData = data
self.header = header
self.tableView.setShowGrid(True)
self.tableView.setFrameStyle( QFrame.NoFrame )
self.tableView.setFocusPolicy( Qt.NoFocus )
self.tableView.setSelectionMode( QAbstractItemView.NoSelection )
vHeader = self.tableView.verticalHeader()
vHeader.setVisible(False)
vHeader.setStretchLastSection(False)
hHeader = self.tableView.horizontalHeader()
hHeader.setVisible(True)
hHeader.setStretchLastSection(False)
self.tableView.setSortingEnabled(True)
self.tableView.setModel(self)
self.tableView.resizeRowsToContents()
self.tableView.resizeColumnsToContents()
vHeader.setResizeMode(QHeaderView.ResizeToContents)
self.tableView.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.tableView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
def rowCount(self, parent):
return len(self.tableData)
def columnCount(self, parent):
return len(self.tableData[0])
def data(self, index, role=Qt.DisplayRole):
row = index.row()
col = index.column()
if role == Qt.DisplayRole:
return "0".format(self.tableData[row][col])
return None
def setData(self, index, value, role):
if index.isValid():
return True
return False
def flags(self, index):
fl = QAbstractTableModel.flags(self, index)
if index.column() == 0:
fl |= Qt.ItemIsUserCheckable
return fl
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.header[col]
def sort(self, col, order):
self.emit(SIGNAL("layoutAboutToBeChanged()"))
self.tableData = sorted(self.tableData, key=operator.itemgetter(col))
if order == Qt.AscendingOrder:
self.tableData.reverse()
self.emit(SIGNAL("layoutChanged()"))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
示例中的此表数据显示排序 - 不区分大小写。
【问题讨论】:
提供minimal reproducible example 我已经更新了代码,现在有完整的例子 在函数末尾使用self.dataChanged.emit(self.index(0, 0), self.index(self.rowCount()-1, self.columnCount()-1))
,同时将def rowCount(self, parent)
改为def rowCount(self, parent=QModelIndex())
,def columnCount(self, parent)
改为def columnCount(self, parent=QModelIndex())
我必须做另一件事,因为仍然无法正常工作。例如。在我有字符串的第一列中,有很多名字,首先对大字母进行排序,然后再降低。我想要排序 Aa, Bb,... 而不是 ABC..abc
【参考方案1】:
您只需在传递给sorted
函数的排序键中将值转换为小写(或大写)。为了提高效率,您还可以使用 reverse 参数来避免在单独的步骤中这样做:
def sort(self, col, order):
self.layoutAboutToBeChanged.emit()
self.tableData = sorted(
self.tableData,
key=lambda row: row[col].lower(),
reverse=(order != Qt.AscendingOrder),
)
self.layoutChanged.emit()
请注意,sorted
进行稳定排序,因此相等的值(在应用键之后)将保留其原始位置。因此,示例中的第二列在排序时不会显示任何更改,因为值都是“相同的”(如果忽略大小写)。
更新:
这是一个适用于字符串和数字的解决方案。它假定列不是两种类型的混合:
def sort(self, col, order):
if self.tableData and self.tableData[0]:
self.layoutAboutToBeChanged.emit()
if isinstance(self.tableData[0][col], str):
sortkey = lambda row: row[col].lower()
else:
sortkey = operator.itemgetter(col)
self.tableData = sorted(
self.tableData, key=sortkey,
reverse=(order != Qt.AscendingOrder))
self.layoutChanged.emit()
【讨论】:
感谢您的解释和帮助!如何检查数据是否不是str类型?导致此解决方案不适用于我拥有的多类型表(数字和字符串,取决于列)。lower()
不能用于 int 或 float。但它对字符串很有效!
@Dave。你可以做str(row[col]).lower()
。
我之前尝试过,但是这样排序不好(例如 11、115、178、25、278,...)
@Dave。所以这些列实际上都是字符串或所有数字,而不是混合?
是的,在列中分开。有些只是str
,有些列是int
或float
。我正在寻找某种方法来检查类型 - 然后我可以针对每种情况使用特定的 sorted()
方法以上是关于在 QAbstractItemModel 中不区分大小写排序的主要内容,如果未能解决你的问题,请参考以下文章
QAbstractItemModel - QModelIndex 对象在创建时是不是应该被缓存?
字符串属性的 gql 查询中不区分大小写的 where 子句