52488
pyqt5でQListViewを使ったときに表示されるリストを後から変更したいです。次は試しに書いてみたコードです。

```

    import sys
    from PyQt5 import QtGui,QtCore, QtWidgets
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    
    class TreeModel(QtCore.QAbstractItemModel):
        def __init__(self):
            QtCore.QAbstractItemModel.__init__(self)
            self.nodes = ['node0', 'node1', 'node2', "node4", "node5"]
    
        def index(self, row, column, parent):
            return self.createIndex(row, column, self.nodes[row])
    
        def parent(self, index):
            return QtCore.QModelIndex()
    
        def rowCount(self, index):
            if index.internalPointer() in self.nodes:
                return 0
            return len(self.nodes)
    
        def columnCount(self, index):
            return 1
    
        def data(self, index, role):
            if role == 0: 
                return index.internalPointer()
            else:
                return None
    
        def supportedDropActions(self): 
            return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction         
    
        def flags(self, index):
            if not index.isValid():
                return QtCore.Qt.ItemIsEnabled
            return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | \
                   QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled        
    
        def mimeTypes(self):
            return ['text/xml']
    
        def mimeData(self, indexes):
            mimedata = QtCore.QMimeData()
            mimedata.setData('text/xml', 'mimeData')
            return mimedata
    
        def dropMimeData(self, data, action, row, column, parent):
            print ('dropMimeData %s %s %s %s' % (data.data('text/xml'), action, row, parent))
            return True
    
    
    class MainForm(QWidget):
        def __init__(self, parent=None):
            super(MainForm, self).__init__(parent)
    
            self.treeModel = TreeModel()
    
            self.view2 = QListView()
            self.view2.setModel(self.treeModel)
            self.view2.activated.connect(self.viewClicked2)#ダブルクリックでの動作
            self.view2.clicked.connect(self.viewClicked)
    
            self.btn=QPushButton("data")
            self.btn.clicked.connect(self.change_data)
    
            layout = QHBoxLayout(self)
            layout.addWidget(self.view2)
            layout.addWidget(self.btn)
    
            self.setLayout(layout)
    
            self.show()
    
        def viewClicked(self, indexClicked):
            print('index of proxy row', indexClicked.row())
    
        def viewClicked2(self, index):
            print(index.row())
    
        def change_data(self):
            self.treeModel.nodes=["data1","data2","data3"]
    
    def main():
        app = QApplication(sys.argv)
        form = MainForm()
        form.show()
        app.exec_()
    
    if __name__ == '__main__':
        main()
    
```

これを実行することで、次のようなGUIが作成されます。  
[![画像](https://i.stack.imgur.com/hd5is.png)](https://i.stack.imgur.com/hd5is.png)  
ここで、右のdataボタンを押したときに左のリストに表示されるデータが[data1,data2,data3]に変更されるように書いてみたつもりなのですが、ボタンを押すと、次のようなエラーが延々と表示されます。

```

        Traceback (most recent call last):
    
      File "C:/Users/toma/Desktop/pyqt/アイテムモデル/practice2.py", line 20, in index
        return self.createIndex(row, column, self.nodes[row])
    
    IndexError: list index out of range
    
```

しかし、どのように修正すればよいのか全く分かりません。どなたかご教授お願いします。
CC BY-SA 4.0
2019-02-01T09:33:11.047
52481
2019-02-01T13:42:07.367
26529
question
python3 pyqt5
pyqt5でQListViewで表示させる項目を変化させたい
修正前

```

    class MainForm(QWidget):
        def change_data(self):
            self.treeModel.nodes=["data1","data2","data3"]
    
```

修正後

```

    class TreeModel(QtCore.QAbstractItemModel):
        def changeNodes(self, nodes):
            self.beginResetModel()
            self.nodes = nodes
            self.endResetModel()
    
    class MainForm(QWidget):
        def change_data(self):
            self.treeModel.changeNodes(["data1","data2","data3"])
    
```

QAbstractItemModelとQListViewのような、モデル・ビューアの関連性を持つものは、単にモデルの方で内容を更新してもダメで、「モデルの内容が変わった」という事をビューアに知らせなければなりません。  
QAbstractItemModelの場合、[begin/endで始まるメソッド](http://doc.qt.io/qt-5/qabstractitemmodel.html#protected-
functions)がそれだと思っています。  
(「思っています」というのは、明確なソースを見つけられなかったから。ただ自分の経験上、このような仕組みのものは大抵そのようになっています)  
ですので、内容の更新をする場合には、更新の内容に従って然るべきメソッドを呼んでください。  
(今回は内容の全とっかえのようですので、「beginResetModel/endResetModel」でよろしいかと。)

ちなみに、わざわざTreeModelのメソッドchangeNodesを作ったのは、Qt5のQAbstractItemModelクラスのbeginResetModel/endResetModelメソッドがprotectedメンバだから。  
まぁpythonにpublic/protectedなんて制約はないのでこんなことをしなくてもいいかもしれませんが、なんとなくです。
CC BY-SA 4.0
2019-02-01T13:42:07.367
52488
2019-02-01T13:42:07.367
15473
52481
answer