Issue
How do i retrieve the correctly selected item from my custom QAbstractListModel which contains a custom sorting algorithm?
You can test the tool by simply making selections in the UI and looking at the console. You can see it's printing the wrong information for the selected item.
I'm assuming the issue relates to how i use the selection indexes to get the item in the Model.
complete code:
import os, sys
from PySide import QtGui, QtCore
class ExplorerItem(object):
def __init__(self, name, tags):
self.name = name
self.tags = tags
class ElementModel(QtCore.QAbstractListModel):
TagsRole = QtCore.Qt.UserRole + 1
NameRole = QtCore.Qt.UserRole + 2
def __init__(self, *args, **kwargs):
QtCore.QAbstractListModel.__init__(self, *args, **kwargs)
self._items = []
self._icons = {}
def rowCount(self, index=QtCore.QModelIndex()):
return len(self._items)
def addItem(self, item):
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self._items.append(item)
self.endInsertRows()
def getItem(self, index):
row = index.row()
if index.isValid() and 0 <= row < self.rowCount():
return self._items[row]
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return None
if 0 <= index.row() < self.rowCount():
item = self._items[index.row()]
if role == ElementModel.TagsRole:
return item.tags
elif role == ElementModel.NameRole:
return item.colors
elif role == QtCore.Qt.DisplayRole:
return item.name
elif role == QtCore.Qt.TextAlignmentRole:
return QtCore.Qt.AlignCenter
class ExplorerSortModel(QtGui.QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(ExplorerSortModel, self).__init__(*args, **kwargs)
self._patterns = {}
self.setDynamicSortFilter(True)
self.setSourceModel(ElementModel())
self.sort(0, QtCore.Qt.AscendingOrder)
def set_pattern(self, role, value):
self._patterns[role] = value
def lessThan(self, left, right):
leftData = self.sourceModel()._items[left.row()]
rightData = self.sourceModel()._items[right.row()]
if leftData and rightData:
l = getattr(leftData, 'name', '')
r = getattr(rightData, 'name', '')
return l > r
return True
def filterAcceptsRow(self, sourceRow, sourceParent):
sm = self.sourceModel()
ix = sm.index(sourceRow)
if ix.isValid():
val = True
for role, fvalue in self._patterns.items():
value = ix.data(role)
val = val and self.filter(value, fvalue, role)
return val
return False
@staticmethod
def filter(value, fvalue, role):
'''
fvalue: search value
value: properties value being tested
'''
if role == ElementModel.TagsRole:
if fvalue == []:
return True
else:
return all(any(x in y for y in value) for x in fvalue)
elif role == ElementModel.NameRole:
return True
else:
return False
class QExplorerWidget(QtGui.QWidget):
def __init__(self, *args, **kwargs):
super(QExplorerWidget, self).__init__(*args, **kwargs)
self.resize(400,400)
# control
self.ui_explorer = QtGui.QListView()
self.ui_explorer.setResizeMode(QtGui.QListView.Adjust)
self.ui_explorer.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.ui_explorer.setMovement(QtGui.QListView.Static)
self.ui_explorer.setSpacing(10)
self.explorer_model = ExplorerSortModel()
self.ui_explorer.setModel(self.explorer_model)
self.ui_explorer_selection = self.ui_explorer.selectionModel()
lay = QtGui.QVBoxLayout()
lay.addWidget(self.ui_explorer)
self.setLayout(lay)
# connections
self.ui_explorer_selection.selectionChanged.connect(self.changed_selection)
# test data
self.explorer_model.sourceModel().addItem(ExplorerItem('John',['john','sports']))
self.explorer_model.sourceModel().addItem(ExplorerItem('Apple',['apple','fruit']))
self.explorer_model.sourceModel().addItem(ExplorerItem('Kevin',['kevin','money']))
self.explorer_model.sourceModel().addItem(ExplorerItem('Zoo',['zoo','animals']))
def changed_selection(self):
indexes = self.ui_explorer_selection.selectedIndexes()
for index in indexes:
item = self.explorer_model.sourceModel().getItem(index)
print item.name, item.tags, index
if __name__ == '__main__':
''
app = QtGui.QApplication(sys.argv)
ex = QExplorerWidget()
ex.show()
sys.exit(app.exec_())
Solution
The QModelIndex
of the selectedIndexes
belong to the model that was established in the view, and in this case it is the ExplorerSortModel
, so these indexes can not be passed directly to the getItem()
method of ElementModel since that method expects that the QModelIndex
belongs to ElementModel
.
In your case you must convert that QModelIndex
belonging to ExplorerSortModel
to the corresponding QModelIndex
that belongs to ElementModel
using the mapSource()
method.
def changed_selection(self):
indexes = self.ui_explorer_selection.selectedIndexes()
for index in indexes:
ix_source = self.explorer_model.mapToSource(index)
item = self.explorer_model.sourceModel().getItem(ix_source)
print(item.name, item.tags)
Answered By - eyllanesc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.