MENU

PySide Model/View【第2弾】QTreeViewで作るフォルダ構造・階層リストのGUI表示

\ 迷ったらまずTechAcademyの無料カウンセリング! /

前回の記事では QTableView と QStandardItemModel を使って、表形式のデータをきれいに表示する方法を学びました。
しかし実際のアプリでは「フォルダ構造」や「カテゴリ分けされたリスト」のように、階層構造を持つデータを扱いたい場面がよくあります。

そこで今回は、そのような場面で威力を発揮する QTreeView を取り上げます。
QTreeView を使えば、エクスプローラーのような ツリー形式のGUI を簡単に作ることができます。さらに、QStandardItemModel と組み合わせることで、前回の表形式の知識をそのまま応用できるのも大きな魅力です。

この記事では、初心者でも理解しやすいように QTreeView の基本操作から実践的な使い方まで、順を追って解説していきます。

目次

QTreeViewとは?

QTreeView は 階層構造を表示できるビュー です。
内部的には QStandardItemModel を組み合わせて使うことが多く、ツリー形式のデータを簡単に作成できます。

基本コード例(階層データの表示)

from PySide6.QtWidgets import QApplication, QTreeView, QMainWindow
from PySide6.QtGui import QStandardItemModel, QStandardItem
import sys

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QTreeView の基本")
        self.resize(400, 300)

        # モデル作成
        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(["項目名", "説明"])

        # 階層データを追加
        parent1 = QStandardItem("フルーツ")
        parent1.appendRow([QStandardItem("リンゴ"), QStandardItem("赤い果物")])
        parent1.appendRow([QStandardItem("バナナ"), QStandardItem("黄色い果物")])

        parent2 = QStandardItem("野菜")
        parent2.appendRow([QStandardItem("ニンジン"), QStandardItem("オレンジ色の野菜")])
        parent2.appendRow([QStandardItem("キャベツ"), QStandardItem("緑の野菜")])

        model.appendRow([parent1, QStandardItem("果物のカテゴリ")])
        model.appendRow([parent2, QStandardItem("野菜のカテゴリ")])

        # TreeView 設定
        tree = QTreeView()
        tree.setModel(model)
        tree.expandAll()  # すべて展開して表示

        self.setCentralWidget(tree)

app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())

主なプロパティとメソッド一覧(全解説)

Noメソッド / プロパティ説明
1tree.setModel(model) / tree.model()View と Model を関連付け/取得します。
2model.setHorizontalHeaderLabels(list)ヘッダー(列名)をまとめて設定します。
3model.invisibleRootItem()見えない最上位ルートを取得します(階層の起点)。
4item.appendRow(items) / item.insertRow(i, items) / item.removeRow(i)親アイテムの子行を追加/挿入/削除します。
5model.indexFromItem(item) / model.itemFromIndex(index)Item と QModelIndex を相互変換します。
6model.findItems(text, flags, column)テキスト検索(部分一致/正規表現/再帰)を行います。
7tree.setEditTriggers(flags)編集開始のトリガーを制御します。
8tree.setSelectionMode(mode) / tree.setSelectionBehavior(behav)選択の方法(単一・複数/行・項目)を制御します。
9tree.expandAll() / tree.collapseAll() / tree.setExpanded(idx, bool)展開・折りたたみを制御します。
10tree.setHeaderHidden(bool) / tree.header() → setSectionResizeMode(...) / resizeColumnToContents(col)ヘッダーの表示や列幅の自動調整など見た目を制御します。

各プロパティ・メソッド詳細解説

【1】モデルを設定する

概要:QTreeView は自分でデータを持たないため、QStandardItemModel などのモデルを関連付けて表示します。複数の View で同じ Model を共有できます。
メソッド:tree.setModel(model) / tree.model()
使い方(コード例):

model = QStandardItemModel(0, 2)   # 0行・2列
model.setHorizontalHeaderLabels(["項目名", "説明"])

# TreeView 設定
tree = QTreeView()
tree.setModel(model)
tree.expandAll()  # すべて展開して表示
self.setCentralWidget(tree)

【2】ヘッダー(列名)をまとめて設定する

概要:ツリーの列見出しを一括設定します。複数列構成のツリーでも可読性を保てます。
メソッド:model.setHorizontalHeaderLabels(list)
使い方(コード例):

model.setHorizontalHeaderLabels(["カテゴリ", "説明"])

個別列は model.setHeaderData(section, Qt.Horizontal, value, Qt.DisplayRole) でも設定可能。

【3】ルート(見えない最上位)を取得する

概要:invisibleRootItem() は、画面には表示されない最上位の親です。ここから appendRow で第一層(トップレベル)を作ります。
メソッド:model.invisibleRootItem()
使い方(コード例):

root = model.invisibleRootItem()
root.appendRow([QStandardItem("フォルダA"), QStandardItem("説明A")])

【4】子行の追加/挿入/削除

概要:任意の QStandardItem の下に子行を追加・挿入し、階層データを構築します。
メソッド:item.appendRow(items) / item.insertRow(i, items) / item.removeRow(i)
使い方(コード例):

parent = QStandardItem("親カテゴリ")
desc   = QStandardItem("このカテゴリの説明")
model.invisibleRootItem().appendRow([parent, desc])

child1 = QStandardItem("子1")
child1_desc = QStandardItem("子1の説明")
parent.appendRow([child1, child1_desc])          # 末尾に追加

parent.insertRow(0, [QStandardItem("先頭子"), QStandardItem("説明")])  # 先頭に挿入
parent.removeRow(1)  # 2番目の子を削除

items は 列数ぶんの QStandardItem を並べたリストです。

【5】Item ⇄ Index 相互変換

概要:選択やカーソルは QModelIndex で渡されます。表示や編集の実体(QStandardItem)と相互に行き来できると便利です。
メソッド:model.indexFromItem(item) / model.itemFromIndex(index)
使い方(コード例):

idx  = model.indexFromItem(parent)      # Item → Index
item = model.itemFromIndex(idx)         # Index → Item

index があれば model.data(index, role)、setData(index, value, role) も使えます。

【6】文字列検索(部分一致・再帰)

概要:findItems は列単位にテキスト検索します。Qt.MatchRecursive を付けると子孫ノードまで再帰的に検索します。
メソッド:model.findItems(text, flags=Qt.MatchContains, column=0)
使い方(コード例):

from PySide6.QtCore import Qt
hits = model.findItems("親カテゴリ", flags=Qt.MatchContains | Qt.MatchRecursive, column=0)
for it in hits:
    idx = model.indexFromItem(it)
    tree.setExpanded(idx, True)  # 見つけた項目を展開表示
    print(idx)

# <PySide6.QtCore.QModelIndex(1,0,0x223145fb0b0,QStandardItemModel(0x223146ab8f0)) at 0x000002233B215440>

正規表現は Qt.MatchRegExp を使います(必要に応じて Python 側でフィルタした方が柔軟な場合も)。

【7】編集開始トリガーを制御する

概要:どの操作でセル編集を始めるかをコントロールします(ダブルクリック/クリック/キー入力など)。
メソッド:tree.setEditTriggers(QAbstractItemView.EditTrigger)
使い方(コード例):

from PySide6.QtWidgets import QAbstractItemView as AIV
tree.setEditTriggers(AIV.NoEditTriggers)   # すべて禁止
# 例:ダブルクリックで編集
tree.setEditTriggers(AIV.DoubleClicked)

個別に編集不可にしたいときは item.setEditable(False) を併用します。

例説明
tree.setEditTriggers(QAbstractItemView.DoubleClicked)編集できるタイミングを設定
tree.setEditTriggers(QAbstractItemView.NoEditTriggers)編集不可
tree.setEditTriggers(QAbstractItemView.CurrentChanged)カレントセルが変わった時に編集可
tree.setEditTriggers(QAbstractItemView.DoubleClicked)ダブルクリックで編集可
tree.setEditTriggers(QAbstractItemView.SelectedClicked)選択中のセルをクリックで編集可
treew.setEditTriggers(QAbstractItemView.EditKeyPressed)EnterキーやF2キーで編集可
tree.setEditTriggers(QAbstractItemView.AnyKeyPressed)文字入力で即編集開始
tree.setEditTriggers(QAbstractItemView.AllEditTriggers)すべてのトリガーで編集可

【8】選択モード/選択単位を制御する

概要:単一選択/複数選択、行単位/項目単位など選択の挙動を決めます。
メソッド:tree.setSelectionMode(mode) / tree.setSelectionBehavior(behavior)
使い方(コード例):

from PySide6.QtWidgets import QAbstractItemView as AIV
tree.setSelectionMode(AIV.ExtendedSelection)   # Ctrl/Shift による複数選択
tree.setSelectionBehavior(AIV.SelectItems)     # 項目(セル)単位で選択

選択結果は tree.selectedIndexes() や tree.selectionModel() から取得します。

例説明
tree.setSelectionMode(QAbstractItemView.SingleSelection)選択方法を設定
tree.setSelectionMode(QAbstractItemView.NoSelection)選択不可
tree.setSelectionMode(QAbstractItemView.SingleSelection)1セルのみ選択可
tree.setSelectionMode(QAbstractItemView.MultiSelection)複数セル選択可(Ctrlクリック)
tree.setSelectionMode(QAbstractItemView.ExtendedSelection)複数セル選択可(ShiftやCtrl併用)
tree.setSelectionBehavior(QAbstractItemView.SelectRows)選択対象(セル・行・列)を設定
tree.setSelectionBehavior(QAbstractItemView.SelectItems)セル単位で選択
tree.setSelectionBehavior(QAbstractItemView.SelectRows)行単位で選択
tree.setSelectionBehavior(QAbstractItemView.SelectColumns)列単位で選択

【9】展開/折りたたみを制御する

概要:個別ノードやツリー全体の展開・折りたたみを制御します。初期状態の見せ方に有効です。
メソッド:tree.expandAll() / tree.collapseAll() / tree.setExpanded(index, bool)
使い方(コード例):

tree.expandAll()
# 特定ノードだけ展開
idx = model.indexFromItem(parent)
tree.setExpanded(idx, True)

大量ノードで expandAll() を多用すると描画コストが上がるので注意。

【10】ヘッダー表示と列幅調整

概要:ヘッダーの表示/非表示、列幅の伸縮モードや内容に応じた自動調整を行います。
メソッド:

  • tree.setHeaderHidden(bool)
  • tree.header().setSectionResizeMode(section, mode)
  • tree.resizeColumnToContents(col)

使い方(コード例):

from PySide6.QtWidgets import QHeaderView
tree.setHeaderHidden(True)
tree.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
tree.header().setSectionResizeMode(1, QHeaderView.Stretch)

1列テキスト主体なら「最後の列だけ Stretch」にするとバランスがよくなります。

よくある質問(FAQ)

QTreeViewとQTableViewの違いは?

QTableView は表形式(2次元)専用ですが、QTreeView は階層(ツリー)構造を持てる点が違います。

QTableWidgetのように簡単に使えますか?

QTreeWidget なら簡単に使えますが、拡張性を考えるなら QTreeView + QStandardItemModel が推奨です。

ノードの展開イベントを拾えますか?

はい、expanded や collapsed シグナルを使えます。

ユーザーが編集できるようにできますか?

item.setEditable(True) を設定すれば可能です。

ツリーをファイルシステム風に使えますか?

QFileSystemModel + QTreeView を組み合わせれば可能です。

まとめ

今回の記事では QTreeView + QStandardItemModel を使って、階層構造を持つデータを表示・操作する方法を解説しました。
前回の QTableView が「表形式の一覧表示」に適していたのに対して、QTreeView は フォルダツリーや設定階層のような「親子関係を持つデータ」 を表現できるのが大きな特徴です。

実際の開発では、ファイルブラウザ風のツリー、オプション設定の階層、カテゴリごとの一覧など、応用範囲は非常に広いです。
特に QStandardItemModel は「手軽に使える柔軟なモデル」なので、Model/View の入門から実践まで幅広く活用できます。

次のステップとしては、独自モデル(QAbstractItemModel を継承)で柔軟なデータ管理を行う方法 や、チェックボックス・アイコン付きのツリーUI に進むとさらに応用力が高まるでしょう。

シェアしてくださると嬉しいです!
  • URLをコピーしました!
目次