Python with GTK3 @ GtkTreeView

gjots2 が ORBit2 を必要とするので GNOME3 に入れたくない。
というわけで代わりになるものを自作することにした。
まてよ、私は GtkTreeView を ListView としてしか使ったことがない。
GtkListStore を GtkTreeStore にすればいい、だと思うけど実験だ。

ところで PyGI のウイジェットには new というメソッドがあるわけだが。

store = Gtk.TreeStore.new([str, str])
# or Compatibility PyGtk
store = Gtk.TreeStore(str, str)

GtkTreeStore を作るには new でシーケンスを渡すか PyGtk と同様に作成。
というか TreeStore(str, str) のほうは多分 PyGtk 互換用だろう。
C では数と内容をズラズラだから PyGI 的にはシーケンスで書くほうが正しいかと思う。

けど new_with_model とかのパラメータ指定差を吸収する互換も便利だから捨てがたい。
パラメータが void しか無いウイジェットは互換のままでいいと思うけど。

そういえば、最近気がついたのだが Property も props メソッドから辿れる。
どちらでも結果は同じなのでお好みで、しかしなんというか Gtk# 臭くなったものだ。
ハイフンをアンダースコアに変換するのを忘れないでね。

# Convert '-' to '_'
tree.props.headers_visible = False
# or Compatibility PyGtk
tree.set_property("headers-visible", False)

それはともかく、GtkTreeView の利用方法。
CellRenderer, TreeViewColumn, TreeStore(ListStore) が必要。

ツリーに表示するレンダラを決める、今回は文字列なので GtkCellRendererText を。
そのレンダラを表示するカラムが必要、複数作れば ListView になると解るね。
シーケンスの何番目データをツリー表示するか、今回は最初のデータなので 0 を指定。

型を指定してシーケンスにして TreeStore を作成。
ソレを TreeModel として TreeView 作成のパラメータにする。
先ほど作成したカラムをアペンド、コレでツリー部分作成は終わり。

ツリー選択を変更したシグナルを捕まえるコードを忘れずに。
ハンドラの widget は GtkTreeSelection になるようだ。

後は GtkTreeIter を介してデータを入れていく。
GtkTreeIter に None を指定すればツリーの先頭に入る。

人により微妙に言い回しが違う専門用語だらけになったけどなんとなく解って。
GTK+ には簡単な ListBox が無いので嫌でも使うハメになる時があるから。

ということでサンプルコード。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from gi.repository import Gtk, Gio, GtkSource

class TreeWin(Gtk.Window):
    """
        GtkTreeView Sample
    """
    def __init__(self):
        Gtk.Window.__init__(self)
        # CellRenderer
        cell = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("Tree Title", cell)
        column.add_attribute(cell, "text", 0)
        # TreeView and TreeStore
        store = Gtk.TreeStore.new([str, str])
        tree = Gtk.TreeView.new_with_model(store)
        tree.append_column(column)
        # Hide Header
        tree.props.headers_visible = False
        # Signal
        selection = tree.get_selection()
        selection.connect("changed", self.selection_changeed)
        #
        # Data
        it0 = store.append(None, ["1.0", "Kaname Madoka"])
        store.append(it0, ["1.1", "Akemi Homura"])
        store.append(it0, ["1.2", "Tomoe Mami"])
        store.append(None, ["2.0", "Miki Sayaka"])
        it1 = store.append(None, ["3.0", "Sakura Kyoko"])
        store.append(it1, ["3.1", "QB"])
        #
        # GtkSourceView
        self.view = GtkSource.View()
        self.view.set_show_line_numbers(True)
        # Paned and ScrolledWindow
        swa = Gtk.ScrolledWindow()
        swa.add(tree)
        swb = Gtk.ScrolledWindow()
        swb.add(self.view)
        hp = Gtk.HPaned()
        hp.add1(swa)
        hp.add2(swb)
        # self
        self.set_title("TreeView Test")
        self.add(hp)
        self.show_all()

    def selection_changeed(self, widget, data=None):
        """
            Params @ widget: GtkTreeSelection
        """
        model, it = widget.get_selected()
        if it:
            buf = self.view.get_buffer()
            buf.set_text(model.get_value(it, 1))

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(
                self,
                application_id="apps.test.treeview",
                flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.connect("activate", self.on_activate)
        
    def on_activate(self, data=None):
        w = TreeWin()
        w.set_application(self)
    
if __name__ == "__main__":
    app = App()
    app.run(None)

ツリー構築だけならそんなに難しくはないね。
後はファイルを読み込んでどうメモリ展開するかだ。

せっかくなので不満だった部分
・GtkSourceView を利用した色分け表示
・タイトルは一行目ではなく独自データに
なんかも実装しつつ Gjots2 完全互換も可能にできればいいな。

# おまけ

窓の杜 – 【NEWS】「AzPainter」「AzDrawing」の作者がWindows向けの全ソフトの開発終了を宣言

書いていることが Linux を初めたばかり丸解りなんだが…
AU○RA とかみたく寒いことにならなきゃいいけど。

Linux では Windows なんて比較にならないほど有名どころ以外は見向きもされないのだから外国人向けに英語でサンプルコードでも書いて自分が使う範囲だけ作ってたほうがマシだって。