Issue
After sorting the model and calling layoutChanged.emit(), my QListView item display order gets updated but selection stays at same row (which now contains another item as a result of the sort).
How can I update the selection to follow the sort?
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
Solution
Changing the internal data structure is not enough: Qt model indexes (and selections) use references based on row, column and parent to access the internal data.
If an index refers to row 0 and your data structure doesn't keep up the index reference, that index will always refer to the first index of your data.
Selection indexes follow the same pattern, which means that it's important that the model updates the persistent index references. Whenever you change the internal layout, it's mandatory to keep up the index reference to that layout, so if you need to sort the current model, you must call changePersistentIndexList()
.
It is also better to do all of this from the model class, not from outside.
This is a possible implementation:
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()
Then, just call self.sequenceModel.sortByOrder()
from editSequence
right after you've set the new sequence instance attributes.
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.