对模型排序后更新QListView选择



对模型进行排序并调用layoutChanged.emit((后,我的QListView项目显示顺序会更新,但选择保持在同一行(排序后,该行现在包含另一个项目(。

如何更新所选内容以遵循排序?

class Window(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.sequenceModel = SequenceModel()
def editSequence(self):
indexes = self.listView_sch_sequences.selectedIndexes()
if indexes:
# Indexes is a list of a single item in single-select mode.
index = indexes[0]
sequence = self.sequenceModel.sequences[index.row()]
sequence.name = self.lineEdit_sch_seq_name.text()
sequence.speed = self.spinBox_sch_speed.value()
sequence.order = self.spinBox_order.value()
self.sequenceModel.sequences.sort(key=lambda x: x.order, reverse=True)
self.sequenceModel.layoutChanged.emit()
class SequenceModel(QtCore.QAbstractListModel):
def __init__(self, *args, todos=None, **kwargs):
super(SequenceModel, self).__init__(*args, **kwargs)
self.NameRole = Qt.UserRole + 1
self.DataRole = Qt.UserRole + 2

self.sequences = []
def data(self, index, role):
row = index.row()
if role == Qt.DisplayRole:
text = self.sequences[row].name
return text
if role == self.DataRole:
sequence = self.sequences[row]
return sequence
def rowCount(self, index):
return len(self.sequences)
class Sequence:
def __init__(self, name: str, speed: int):
self.name = name
self.speed = speed
self.order = 0

仅仅改变内部数据结构是不够的:Qt模型索引(和选择(使用基于行、列和父级的引用来访问内部数据。

如果索引引用了行0,而您的数据结构没有保持索引引用,则该索引将始终引用数据的第一个索引。

选择索引遵循相同的模式,这意味着模型更新持久索引引用非常重要。无论何时更改内部布局,都必须保留对该布局的索引引用,因此,如果需要对当前模型进行排序,则必须调用changePersistentIndexList()

最好在模型类中完成所有这些,而不是从外部完成。

这是一种可能的实现方式:

class SequenceModel(QtCore.QAbstractListModel):
# ...
def sortByOrder(self):
oldIndexes = [self.index(i, 0) for i in range(len(self.sequences))]
newIndexes = sorted(
oldIndexes, 
key=lambda i: i.data(self.DataRole).order, 
reverse=True
)
self.changePersistentIndexList(oldIndexes, newIndexes)
self.layoutChanged.emit()

然后,只需在设置了新的序列实例属性后立即从editSequence调用self.sequenceModel.sortByOrder()

最新更新