[PyQt] QListWidgetでQStandardItemModelを使う


PyQtの話ですが、基本はQtでも変わらないと思います。
あんまりC++のQtはわからないけれども。

# model/view programimg

こまかいことは[こっち](http://doc.qt.io/qt-5/model-view-programming.html "Qt5 document")で読んでください。

おおざっぱな話すると、
QTreeView, QListView, QTableViewという３つのView classは
QFileSystemModel, QStandardItemModel, QTableWidgetModel, etcといったModel classによって
大まかな挙動や表示が来まる。
使い方はこんな感じ。

```python:QTreeView
class MyTreeView(QTreeViw):
    def __init__(self,parent=None):
        super(MyTreeView,self).__init__(parent)
        model = QFileSystemModel()
        model.setRootPath('')
        self.setModel(model)
        self.setRootIndex(model.index(os.path.expanduser('~')))

def main():
    app = QApplication(sys.argv)

    view = MyTreeView()
    view.show()

    app.exec_()

if __name__ == '__main__':
    main()
```

# デフォルトのQListWidget

QTreeView, QListView, QTableViewにはそれぞれQTreeWidget, QListWidget, QTableWidgetがある。
今回使ったのはQListWidget。
QListWidgetでアイテムを追加するにはデフォルトだとこうする。

```python:QListWidget
class MyListWidget(QListWidget):
    def __init__(self,parent=None):
        super(MyListWidget,self).__init__(parent)
        self.addItem('first row')
        self.addItem('second row')


def main():
    app = QApplication(sys.argv)

    view = MyListWidget()
    view.show()

    app.exec_()

if __name__ == '__main__':
    main()
```

打って変わってModelとかViewとか関係なく動く。

# QListWidgetでQStandardItemModelを使う

ちょっとListアイテムをドラッグアウトしたときに埋め込む情報を弄りたくて
QStandardItem & QStandardItemModelを使うことにした。
その場合、アイテムの追加方法が変わる。

```python:QListWidget
class MyListWidget(QListWidget):
    def __init__(self,parent=None):
        super(MyListWidget,self).__init__(parent)
        self.model = QStandardItemModel(self)
        self.view = QListView(self)
        self.view.setModel(self.model)
        self.model.appendRow(QStandardItem('first row'))
        self.model.appendRow(QStandardItem('second row'))

def main():
    app = QApplication(sys.argv)

    view = MyListWidget()
    view.show()

    app.exec_()

if __name__ == '__main__':
    main()
```

今度はアイテムの管理はQListWidget上では行わない。
QListWidgetはQListViewの親として表示する場所を与えるだけ。
QListViewもアイテムの管理を行わず、modelを表示するだけ。
肝心のアイテムはmodelで管理される。
modelをいじればViewが変わってWidgetに適応される、自動で。

# QListwidgetでQStandardItemModelを使い、Drag&Dropする

で、更に面倒なのがこれ。
もともと、デフォルトのQListWidgetを使う場合は次のようにしてD&Dを設定する。

```python:QListWidget
class MyListWidget(QListWidget):
    def __init__(self,parent=None):
        super(MyListWidget,self).__init__(parent)
        self.setAcceptDrops(True)
        self.setDragEnabled(True)
        self.setDragDropMode(QAbstractItemView.InternalMove)

    def dragEnterEvent(self,event):
        hogehoge

    def dragMoveEvent(self,event):
        hogehoge

    def dropEvent(self,event):
        hogehoge


def main():
    app = QApplication(sys.argv)

    view = MyListWidget()
    view.show()

    app.exec_()

if __name__ == '__main__':
    main()
```

ところが、QStandardItemModelをセットするとD&Dの設定はWidgetじゃなくてViewで行う。

```python:QListWidget
class MyListWidget(QListWidget):
    def __init__(self,parent=None):
        super(MyListWidget,self).__init__(parent)
        self.view = MyListView(self)

class MyListView(QListView):
    def __init__(self,parent=None):
        super(MyListView,self).__init__(parent)
        self.model = QStandardItemModel()
        self.setModel(self.model)
        self.setAcceptDrops(True)
        self.setDragEnabled(True)
        self.setDragDropMode(QAbstractItemView.InternalMove)

    def dragEnterEvent(self,event):
        hogehoge

    def dragMoveEvent(self,event):
        hogehoge

    def dropEvent(self,event):
        hogehoge


def main():
    app = QApplication(sys.argv)

    view = MyListWidget()
    view.show()

    app.exec_()

if __name__ == '__main__':
    main()
```

これがわからず結構ハマった。