(Py)Qt: QSortFilterProxyModel вызывает index() с родителем из неправильной модели
У меня странная проблема с QSortFilterProxyModel
, Я делаю это в моем QTreeView:
class CompletionView(QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
self.setModel(QSortFilterProxyModel())
m1 = CompletionModel()
print("Model 1: {}".format(m1))
m1.init_data({'test1': [('one', 'two'), ('three', 'four')]})
self.model().setSourceModel(m1)
self.expandAll()
m2 = CompletionModel()
print("Model 2: {}".format(m2))
m2.init_data({'test': [('five', 'six'), ('seven', 'eight')]})
self.model().setSourceModel(m2)
self.expandAll()
Это моя CompletionModel, которую я не мог упростить больше:
class CompletionModel(QAbstractItemModel):
def __init__(self, parent=None):
super().__init__(parent)
self._id_map = {}
self._root = CompletionItem([""] * 2)
self._id_map[id(self._root)] = self._root
def _node(self, index):
if index.isValid():
return self._id_map[index.internalId()]
else:
return self._root
def init_data(self, data):
for (cat, items) in data.items():
newcat = CompletionItem([cat], self._root)
self._id_map[id(newcat)] = newcat
self._root.children.append(newcat)
for item in items:
newitem = CompletionItem(item, newcat)
self._id_map[id(newitem)] = newitem
newcat.children.append(newitem)
def columnCount(self, parent=QModelIndex()):
return self._root.column_count()
def rowCount(self, parent=QModelIndex()):
if parent.column() > 0:
return 0
if not parent.isValid():
pitem = self._root
else:
pitem = self._id_map[parent.internalId()]
return len(pitem.children)
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return QVariant()
try:
item = self._id_map[index.internalId()]
except KeyError:
return QVariant()
try:
return QVariant(item.data(index.column(), role))
except (IndexError, ValueError):
return QVariant()
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return QVariant(self._root.data(section))
return QVariant()
def index(self, row, column, parent=QModelIndex()):
if parent.model() is not None and parent.model() is not self:
raise ValueError("Model mismatch: parentmodel {}, self {}".format(parent.model(), self))
if (0 <= row < self.rowCount(parent) and
0 <= column < self.columnCount(parent)):
pass
else:
return QModelIndex()
if not parent.isValid():
parent_item = self._root
else:
parent_item = self._id_map[parent.internalId()]
child_item = parent_item.children[row]
if child_item:
index = self.createIndex(row, column, id(child_item))
self._id_map.setdefault(index.internalId(), child_item)
return index
else:
return QModelIndex()
def parent(self, index):
if not index.isValid():
return QModelIndex()
item = self._id_map[index.internalId()].parent
if item == self._root or item is None:
return QModelIndex()
return self.createIndex(item.row(), 0, id(item))
class CompletionItem():
def __init__(self, data, parent=None):
self.parent = parent
self.children = []
self._data = data
def data(self, column, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
return self._data[column]
else:
raise ValueError("Invalid role {}".format(role))
def column_count(self):
return len(self._data)
def row(self):
if self.parent:
return self.parent.children.index(self)
return 0
Обратите внимание, я поднимаю ValueError
в index()
если я получу неправильный родитель.
Теперь, когда я выполняю мой пример сценария (вставленный в мой каталог), это происходит:
Model 1: <__main__.CompletionModel object at 0x7fefe1ccd770>
Model 2: <__main__.CompletionModel object at 0x7fefe1ccd808>
Traceback (most recent call last):
File "model.py", line 59, in index
raise ValueError("Model mismatch: parentmodel {}, self {}".format(parent.model(), self))
ValueError: Model mismatch: parentmodel <__main__.CompletionModel object at 0x7fefe1ccd770>, self <__main__.CompletionModel object at 0x7fefe1ccd808>
Traceback (most recent call last):
File "model.py", line 59, in index
raise ValueError("Model mismatch: parentmodel {}, self {}".format(parent.model(), self))
ValueError: Model mismatch: parentmodel <__main__.CompletionModel object at 0x7fefe1ccd770>, self <__main__.CompletionModel object at 0x7fefe1ccd808>
Почему это происходит? Я делаю что-то не так в своей модели, или это ошибка Qt?
Я также пытался использовать None
в качестве дозорного значения, где я использую QModelIndex()
как значение по умолчанию для параметра функции (хотя он не должен изменяться, поэтому это не должно быть проблемой), это не помогло.
2 ответа
Вероятно, при сбросе настроек где-то хранятся ссылки на предыдущую модель, поэтому вы получаете ошибки "Несоответствие модели".
Когда я попробовал ваш пример, я обнаружил, что установка исходной модели на None
между перезагрузками устраняются ошибки:
self.model().setSourceModel(m1)
...
self.model().setSourceModel(None) # clear the current model
...
self.model().setSourceModel(m2)
Просто вспомнил, почему у вас такая проблема.
На самом деле это особенность Python аргументов метода со значением по умолчанию. Особенность Python в том, что такой аргумент является static_variable. Итак, когда в первый раз это был звонок:
m1.index (1,2, parent_from_model_m1);
а позже просто позвоните:
m2.index (3,4)
тогда для второго вызова "parent" получит значение по умолчанию - не QModelIndex(), а parent_from_model_m1 (аргумент "parent" в качестве статической переменной запоминается parent_from_model_m1 из первого вызова)
Решение должно быть простым - удалить значения по умолчанию.