排序 QTableView 时如何保留选择

how to preserve selection when sorting QTableView

如何在对 table 进行排序时保留项目的 selection?在下面的示例中,selection 始终固定到行索引,即如果我 select 第一行,那么在排序后总是第一行是 selected,而不是我拥有的实际行selected.

import sys

from PySide2 import QtWidgets, QtGui, QtCore
from PySide2.QtCore import Qt


class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self._data = data

    def data(self, index, role):
        if role == Qt.DisplayRole:
            return self._data[index.row()][index.column()]

    def sort(self, column, order):
        if order == Qt.DescendingOrder:
            rev = True
        else:
            rev = False
        self.layoutAboutToBeChanged.emit()
        self._data.sort(key=lambda x: x[column], reverse=rev)
        self.layoutChanged.emit()

    def rowCount(self, parent=None):
        return len(self._data)

    def columnCount(self, parent=None):
        return len(self._data[0])


class Main(QtWidgets.QDialog):
    def __init__(self, data):
        super().__init__()
        self.layout = QtWidgets.QVBoxLayout()
        self.table = QtWidgets.QTableView()
        self.table.setSortingEnabled(True)
        self.table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
        self.model = TableModel(data)
        self.table.setModel(self.model)
        self.layout.addWidget(self.table)
        self.setLayout(self.layout)


def main():
    app = QtWidgets.QApplication(sys.argv)
    data = [
        [1,2,3,4],
        [5,6,7,8],
        [6,5,4,3],
        [2,1,0,9]
    ]
    m = Main(data)
    m.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

在实现排序方法时,您正在修改数据,并且视图无法知道项目的新位置,您必须使用 QSortFilterProxyModel 修改索引,而不是修改数据:

import sys

from PySide2 import QtCore, QtGui, QtWidgets


class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self._data = data

    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            return self._data[index.row()][index.column()]

    def rowCount(self, parent=None):
        return len(self._data)

    def columnCount(self, parent=None):
        return len(self._data[0])


class Main(QtWidgets.QDialog):
    def __init__(self, data):
        super().__init__()
        self.layout = QtWidgets.QVBoxLayout()
        self.table = QtWidgets.QTableView()
        self.table.setSortingEnabled(True)
        self.table.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows
        )
        self.model = TableModel(data)
        <b>self.proxy = QtCore.QSortFilterProxyModel()
        self.proxy.setSourceModel(self.model)
        self.table.setModel(self.proxy)</b>
        self.layout.addWidget(self.table)
        self.setLayout(self.layout)


def main():
    app = QtWidgets.QApplication(sys.argv)
    data = [[1, 2, 3, 4], [5, 6, 7, 8], [6, 5, 4, 3], [2, 1, 0, 9]]
    m = Main(data)
    m.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()