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()и вы можете использовать реализацию по умолчанию.

Другие вопросы по тегам