QListView и QIdentityProxyModel
У меня есть тестовый код для & .
Когда я реализую, ошибка произошла в
setData
, функция
dataChanged
.Если я не реализую это, ошибка не возникнет.
Я пытался сделать то же самое с помощью
PyQt6
, но результат был тот же.
Пробовал делать через командную строку, сообщения об ошибках нет.
Наоборот, я могу успешно реализовать
QIdentityProxyModel
в случае
QTreeView
,
QTableView
без проблем. Я думал
QListView
является самым простым в этих просмотрах.
Где проблема в моем коде?
from PySide6 import QtWidgets, QtGui, QtCore
import sys
class ListView(QtWidgets.QListView):
def __init__(self, parent=None):
super(ListView, self).__init__(parent)
def insertItem(self):
self.model().insertRows(0, 1)
self.model().setData(self.model().index(0, 0), ListItem(text="Hallo!"))
class ListItem(object):
def __init__(self, text="", parent=None):
super(ListItem, self).__init__()
self.data = []
self.text = "Hi!" if not text else text
class ListModel(QtCore.QAbstractListModel):
def __init__(self, parent=None):
super(ListModel, self).__init__(parent)
self.items = []
def columnCount(self, parent=QtCore.QModelIndex()):
return 1
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def headerData(self, index):
return "LIST"
def index(self, row, column, _parent=QtCore.QModelIndex()):
if row >= len(self.items) - 1:
return QtCore.QModelIndex()
if self.items:
childIndex = self.createIndex(row, column, self.items[row])
return childIndex
return QtCore.QModelIndex()
def data(self, index, role=QtCore.Qt.ItemDataRole.DisplayRole):
if not index.isValid():
return None
row = index.row()
column = index.column()
if role == QtCore.Qt.DisplayRole:
if 0 <= row < self.rowCount() and 0 <= column < self.columnCount():
return self.items[row].text
def setData(self, index, value, role=QtCore.Qt.ItemDataRole.EditRole):
if role == QtCore.Qt.ItemDataRole.EditRole:
row = index.row()
if 0 <= row < self.rowCount():
self.items[row] = value
self.dataChanged["QModelIndex", "QModelIndex"].emit(index, index)
return True
return False
def flags(self, index):
return QtCore.Qt.ItemFlag.ItemIsEnabled|QtCore.Qt.ItemFlag.ItemIsSelectable
def index(self, row, column, parent=QtCore.QModelIndex()):
if row > len(self.items) - 1:
return QtCore.QModelIndex()
elif self.items:
childIndex = self.createIndex(row, column, self.items[row])
return childIndex
return QtCore.QModelIndex()
def insertRows(self, position, rows=1, parent=QtCore.QModelIndex()):
self.beginResetModel()
self.beginInsertRows(parent, position, position+rows-1)
for i in range(rows):
self.items.insert(position+i, ListItem())
self.endInsertRows()
self.dataChanged["QModelIndex", "QModelIndex"].emit(parent, parent)
self.layoutChanged.emit()
self.endResetModel()
return True
class ListIdentityModel(QtCore.QIdentityProxyModel):
def __init__(self, parent=None):
super(ListIdentityModel, self).__init__(parent)
def mapFromSource(self, sourceIndex):
if not sourceIndex.isValid():
return QtCore.QModelIndex()
return self.createIndex(sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer())
def mapSelectionFromSource(self, selection):
sourceIndexes = selection.indexes()
proxySelection = QtCore.QItemSelection(sourceIndexes[0], sourceIndexes[-1])
return proxySelection
def mapSelectionToSource(self, selection):
proxyIndexes = selection.indexes()
sourceSelection = QtCore.QItemSelection(proxyIndexes[0], proxyIndexes[-1])
return sourceSelection
def mapToSource(self, proxyIndex):
if not proxyIndex.isValid():
return QtCore.QModelIndex()
return self.sourceModel().createIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer())
def setSourceModel(self, sourceModel):
self.beginResetModel()
super(ListIdentityModel, self).setSourceModel(sourceModel)
self.endResetModel()
def main():
app = QtWidgets.QApplication([]) if QtWidgets.QApplication.instance() is None else QtWidgets.QApplication.instance()
widget = QtWidgets.QWidget()
pushbutton = QtWidgets.QPushButton("insert item")
main_view = ListView()
model = ListModel(main_view)
main_view.setModel(model)
#comment or uncomment
identity_view = ListView()
identityModel = ListIdentityModel()
identity_view.setModel(identityModel)
identityModel.setSourceModel(model)
#
hboxlayout = QtWidgets.QHBoxLayout()
hboxlayout.addWidget(pushbutton)
hboxlayout.addWidget(main_view)
#
hboxlayout.addWidget(identity_view)
#
widget.setLayout(hboxlayout)
pushbutton.clicked.connect(main_view.insertItem)
widget.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
1 ответ
The
insertRows()
функция не должна использовать
beginResetModel()
(который, как следует из названия, начинает сброс модели ), ни
layoutChanged()
: он не только всегда должен вызываться после
layoutAboutToBeChanged()
, но эту функцию следует использовать только при сортировке модели .
Излучающий
dataChanged()
также бессмысленно, так как подразумевается, что вставленная строка вызовет вызов представления
data()
по новым индексам.
def insertRows(self, position, rows=1, parent=QtCore.QModelIndex()):
self.beginInsertRows(parent, position, position+rows-1)
for i in range(rows):
self.items.insert(position+i, ListItem())
self.endInsertRows()
return True
Также обратите внимание, что вы определили дважды, но используется только второй и фактически правильный, из-за
if row > len(self.items) - 1:
проверить против
>=
предыдущего, что неверно. В любом случае, если вы используете QAbstractListItem, который является одномерной моделью, нет абсолютно никакой необходимости переопределять
index()
и вы можете использовать реализацию по умолчанию.