Python GTK+3 チュートリアル

12. ツリーとリストウィジェット① Model

翻訳して勉強するGtkチュートリアル第12章 Tree and List Widgets は、モデル・ビュー・セレクション・ソート・フィルタリングの5つの説明があります。長くなるので3回に分けて学びます。

1回目はデータモデルの話。で始まる行とそれに続く画像は原文にはない箇所です。説明がよくわからなかったので補完のために付け加えました。


Gtk.TreeView とそれに付随するウィジェットは、データを表示するための非常に強力な方法です。これらは Gtk.ListStore Gtk.TreeStore と一緒に使われ、以下のような様々な方法でデータを表示したり操作したりする方法を提供します。

  • データの追加、削除、編集時の自動更新
  • ドラッグ&ドロップ対応
  • データのソート
  • チェックボックスやプログレスバーなどのウィジェットの埋め込み
  • 並び替え可能でリサイズ可能なカラム
  • データのフィルタリング

Gtk.TreeView のパワーと柔軟性には複雑さが伴います。開発の初心者にとっては、必要とされるメソッドの数が多いため、正しく利用することが難しいことがよくあります。


12.1. モデル

個々の Gtk.TreeView は関連する Gtk.TreeModel を持ち、TreeView によって表示されるデータが含まれています。Gtk.TreeModel は複数の Gtk.TreeView で使用できます。これにより例えば、表示や編集がされようとしている同じ元データを、同時に2つの異なる方法で表示できます。また、2つのSQLクエリ(または “ビュー”)が同じデータベーステーブルの異なるフィールドを表示するのと同じ方法で、2つのビューが同じモデルデータの異なる列を表示することもできます。

理論的には独自のモデルを実装することもできますが、通常は Gtk.ListStore Gtk.TreeStore モデルクラスを使用します。Gtk.ListStore は単純なデータの行を含み、各行には子がありません。Gtk.TreeStore は各行に子が持てるようなデータ行を含みます。

モデルを構築する際には、モデルが保持する各列のデータ型を指定する必要があります。

store = Gtk.ListStore(str, str, float)

これは、最初の2つは文字列、3つ目はフロート型の3本の列で構成されるリストストアを作成します。

モデルへのデータの追加は、作成されたモデルの種類に応じて Gtk.ListStore.append() Gtk.TreeStore.append() を使って行います。

treeiter = store.append(["The Art of Computer Programming", "Donald E. Knuth", 25.46])

どちらのメソッドも、新しく挿入された行の位置を指す Gtk.TreeIter のインスタンスを返します。Gtk.TreeModel.get_iter() を呼び出すことで Gtk.TreeIterter を取得することができます。

データが挿入されると、ツリー反復や列のインデックスを使ってデータを取得したり、変更したりすることができます。

print(store[treeiter][2])    # 3つ目の列の値を表示

※コンソールで確かめました。

ListStoreモデル

Pythonの組み込み リスト オブジェクトと同様に、len() を使って行数を取得したり、スライスを使って値を取得したり設定したりすることができます。

※コンソールの続き:

ListStoreモデル

ツリーモデルの全行を反復処理するのも非常に簡単です。

for row in store:
    # Print values of all colums
    print(row[:])

※ListStoreに2件データを追加して確認

ListStoreモデル

Gtk.TreeStore を使用している場合、上記のコードはトップレベルの行のみを繰り返し処理しますが、ノードの子は処理されないことに注意してください。すべての行とその子を反復処理するには、print_tree_store 関数を使用します。

※確認用にTreeStoreに何件かデータを入れます

確認用にTreeStoreに何件かデータを入れます

子ノードの中身をプリントするための関数を定義します。

def print_tree_store(store):
    rootiter = store.get_iter_first()
    print_rows(store, rootiter, "")

def print_rows(store, treeiter, indent):
    while treeiter is not None:
        print(indent + str(store[treeiter][:]))
        if store.iter_has_child(treeiter):
            childiter = store.iter_children(treeiter)
            print_rows(store, childiter, indent + "\t")
        treeiter = store.iter_next(treeiter)

※コンソールで確認

TreeStoreのプリント

Gtk.TreeModel に保存されている値に前述のlistライクなメソッドでアクセスする以外にも、Gtk.TreeIter Gtk.TreePath のインスタンスを使用することも可能です。どちらもツリーモデルの特定の行を参照します。Gtk.TreeModel.get_iter() を呼び出すことで、パスをイテレータに変換することができます。Gtk.ListStore は一つのレベルしか含まないので、つまりノードは子ノードを持たないので、パスは基本的にはアクセスしたい行のインデックスになります。

# Get path pointing to 6th row in list store
path = Gtk.TreePath(5)
treeiter = liststore.get_iter(path)
# Get value at 2nd column
value = liststore.get_value(treeiter, 1)

※ get_iterの確認

get_iterの確認

Gtk.TreeStore の場合、パスはインデックスのリストか文字列です。文字列の形式はコロンで区切られた数字のリストです。各数値はそのレベルでのオフセットを参照します。したがって、パス “0” はルートノードを指し、パス “2:4” は 3 番目のノードの 5 番目の子を指します。

# Get path pointing to 5th child of 3rd row in tree store
path = Gtk.TreePath([2, 4])
treeiter = treestore.get_iter(path)
# Get value at 2nd column
value = treestore.get_value(treeiter, 1)

※ 1つ目のノード内の(「好きなバンド・一番好きな曲」)、2つ目のデータの(「Eagles・The Long Run」)、2つ目の項目の値(「The Long Run」)

treestore.get_valueの確認

Gtk.TreePath のインスタンスはリストのようにアクセスすることができます。つまり len(treepath) treepath が指し示しているアイテムの深さを返し、 treepath[i] i 番目のレベルの子のインデックスを返します。


関連記事