PyQt5 InsertRowsを使ってQTreeViewに行を挿入する
2020/02/25 categories:PyQt5| tags:Python|PyQt5|QTreeView|
QTreeViewのInsertRowsメソッドを使って行の挿入を試してみました。
ツリーのデータを編集しようと思ったときに、行を挿入したり、アイテムに子を追加する機能が必要になります。その機能はQAbstractItemModelのInsertRowsをオーバーライドしてメソッドを作成することで実装できます。
insertRowsメソッド
insertRowsでは下記の通りに処理をするだけです。
- 親のインデックスを取得
- beginInsertRowsを発行
- 親アイテムにアイテムを追加
- endInsertRowsを発行
def insertRows(self, row, count, parent=QtCore.QModelIndex()):
if parent == QtCore.QModelIndex():
parent_item = self.root_item
else:
parent_item = parent.internalPointer()
items = [ Item(parent_item, {}) for i in range(count) ]
self.beginInsertRows(parent, row, row + count - 1)
parent_item.insertChildren(items, row)
self.endInsertRows()
選択したインデックスの次の行にアイテムを挿入
選択したインデックスが無い場合は、ルートの最後にアイテムを追加して、選択したインデックスが有る場合は、そのインデックスの次の行にアイテムを挿入するようにしました。選択可能なアイテムが1つだけなら単純に次の行に挿入するだけですが、アイテムを複数選択可能にしている場合は少し面倒でした。
まずは下記のように、選択したインデックスのリストを親ごとのリストに分けて、そのリストを親のインデックスをキーとした辞書に入れます。
parent_splited = {}
for index in indexes:
if not index.parent() in parent_splited:
parent_splited[index.parent()] = []
parent_splited[index.parent()].append(index)
次に親ごとに分けたリストを行番号でソートして、そのリストの最後から行を挿入していきます。リストの最初から追加していった場合、追加するたびに行が増えていくため、挿入位置がずれていってしまいます。
for key in parent_splited:
_sorted = sorted( parent_splited[key], key=lambda t:t.row() )[::-1]
for index in _sorted:
self.model.insertRows(index.row() + 1, 1, index.parent())
上記のコードをまとめて、行の挿入メソッドは下記の通りにしました。
def insert_item(self):
indexes = self.unique_row_indexes(self.ui.treeView.selectedIndexes())
if len(indexes) == 0:
self.model.insertRows(self.model.root_item.childCount(), 1, QtCore.QModelIndex())
return
parent_splited = {}
for index in indexes:
if not index.parent() in parent_splited:
parent_splited[index.parent()] = []
parent_splited[index.parent()].append(index)
for key in parent_splited:
_sorted = sorted( parent_splited[key], key=lambda t:t.row() )[::-1]
for index in _sorted:
self.model.insertRows(index.row() + 1, 1, index.parent())
選択したアイテムに子を追加する
子の追加は、行の挿入よりも単純です。選択したアイテムの最後に子を追加するだけです。また、こちらも選択したインデックスが無い場合は、ルートの最後に子を追加する処理にしています。子の追加は順番にinsertRowsで追加していくだけで問題ありませんでした。
def add_childitem(self):
indexes = self.unique_row_indexes(self.ui.treeView.selectedIndexes())
if len(indexes) == 0:
self.model.insertRows(self.model.root_item.childCount(), 1, QtCore.QModelIndex())
return
for index in indexes:
item = index.internalPointer()
self.model.insertRows(item.childCount() + 1, 1, index)
これで行の挿入や子の追加が出来るようになりました。次は削除を実装してみます。