PyQt5 removeRowsを使ってQTreeViewの行を削除する

Share on:

QTreeViewのremoveRowsメソッドを使って行の削除を試してみました。

removeRowsメソッド

removeRowsメソッドの処理はbeginRemoveRowsを発行してからアイテムを削除した後にendRemoveRowsを発行するだけです。

1def removeRows(self, row, count, parent=QtCore.QModelIndex()):
2    if not parent.isValid():
3        parent_item = self.root_item
4    else:
5        parent_item = parent.internalPointer()
6    self.beginRemoveRows(parent, row, row + count - 1)
7    parent_item.removeChildren(row, row + count)
8    self.endRemoveRows()

選択したインデックスの削除

QMainwindowなどから選択したアイテムを削除する場合は少し処理が面倒になります。まずは選択したアイテムから行番号の重複がないリストを作成します。

1def unique_row_indexes(self, indexes):
2    indexes2 = []
3    for index in indexes:
4        if not index.row() in set( i.row() for i in indexes2 if i.parent() == index.parent() ):
5            indexes2.append(index)
6    return indexes2
7
8selected = self.unique_row_indexes(self.ui.treeView.selectedIndexes())

次に、先ほど作成したリストから、階層が最も浅いインデックスだけを再帰的に抽出します。例えば、Aの子がBでAとBが選択されていた場合はAのみを抽出します。

1def is_selected_parent(index, selected):
2    if index == QtCore.QModelIndex():
3        return False
4    parent = index.parent()
5    if parent in selected:
6        return True
7    return is_selected_parent(parent, selected)
8
9indexes = [ index for index in selected if not is_selected_parent(index, selected) ]

その後、アイテムを親ごとのリストに分けます。

1parent_splited = {}
2for index in indexes:
3    if not index.parent() in parent_splited:
4        parent_splited[index.parent()] = []
5    parent_splited[index.parent()].append(index)

そして最後に、親ごとに分けられたリストの最後からアイテムを削除していきます。

1for key in parent_splited:
2    _sorted = sorted( parent_splited[key], key=lambda t:t.row() )[::-1]
3    for index in _sorted:
4        self.model.removeRows(index.row(), 1, index.parent())

以上をまとめて、下記のようなメソッドにしました。

 1def delete_item(self):
 2    def is_selected_parent(index, selected):
 3        if index == QtCore.QModelIndex():
 4            return False
 5        parent = index.parent()
 6        if parent in selected:
 7            return True
 8        return is_selected_parent(parent, selected)
 9
10    selected = self.unique_row_indexes(self.ui.treeView.selectedIndexes())
11    indexes = [ index for index in selected if not is_selected_parent(index, selected) ]
12
13    parent_splited = {}
14    for index in indexes:
15        if not index.parent() in parent_splited:
16            parent_splited[index.parent()] = []
17        parent_splited[index.parent()].append(index)
18    
19    for key in parent_splited:
20        _sorted = sorted( parent_splited[key], key=lambda t:t.row() )[::-1]
21        for index in _sorted:
22            self.model.removeRows(index.row(), 1, index.parent())

関連記事