Paepoi

Paepoi » PyGObject Tips » Gtk(PyGObject) Tips | ツリービュー、リストビュー

Gtk(PyGObject) Tips | ツリービュー、リストビュー

# 最終更新日 2019.09.01

2019 年現在の仕様に追記と書き換え、PyGtk 互換の削除。

GtkTreeView
ツリービューはタッチパネルに適さないということで全 OS にて廃止の方向です。
リストビューも GtkListBox というレンダラ不要の Widget が出て使われなくなりました。
一応まだ使えますのでここで少しだけ解説します。

GTK+ ではツリービューとリストビューは同一のものです。
データモデルに GtkTreeStore, GtkListStore のどちらを使うかで確定されます。

また Windows でよく利用されている LISTBOX 相当の Widget は GTK2 時に廃止されました。
ちょっとしたリストを利用したいという場合でも GtkTreeView 又は GtkListBox を使う必要があります。

GtkTreeView を利用するには以下のウイジェットを予め作成する必要があります。

GtkTreeViewColumn 表示領域
GtkCellRenderer etc. 表示部分
GtkTreeModel (GtkTreeStore, GtkListStore) データモデル

モデルにデータ(文字列、アイコン等)を挿入するとコラムのレンダラ部に描写される。
ツリービュー自体はコントローラの役目というわけです。
コラムのヘッダ文字列はコラムで、表示非表示はビューで指定みたいな感じです。

以下のサンプルコードにてモデルが違うだけでツリービューにもリストビューにもなるのが解る。
#!/usr/bin/env python3

import sys, gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class Win(Gtk.ApplicationWindow):
    '''
        左ペインがリストビュー、右ペインがツリービュー
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='Py')
        #
        # GtkListStore
        #
        # レンダラに文字列を描写したい場合は GtkCellRendererText
        cell1 = Gtk.CellRendererText()
        # コラムを作成しレンダラを挿入
        column1 = Gtk.TreeViewColumn()
        column1.pack_start(cell1, True)
        # コラムに何を表示するか指定
        column1.add_attribute(cell1, 'text', 0)
        # コラムのタイトル
        column1.set_title('ListStore')
        # モデルを作成しデータを入れていく
        store1 = Gtk.ListStore.new([str])
        store1.append(['リストビューは'])
        store1.append(['こう作ります'])
        # モデルを指定してツリービューを作成
        tree1 = Gtk.TreeView(model=store1)
        # モデルを表示するコラムを指定
        tree1.append_column(column1)
        #
        # GtkTreeStore
        #
        # レンダラに文字列を描写したい場合は GtkCellRendererText
        cell2 = Gtk.CellRendererText()
        # コラムを作成しレンダラを挿入
        column2 = Gtk.TreeViewColumn()
        column2.pack_start(cell2, True)
        # コラムに何を表示するか指定
        column2.add_attribute(cell2, 'text', 0)
        # コラムのタイトル
        column2.set_title('TreeStore')
        # モデルを作成しデータを入れていく
        store2 = Gtk.TreeStore.new([str])
        it_root = store2.append(None, ['ルート'])
        it_child = store2.append(it_root, ['子001'])
        store2.append(it_root, ['子002'])
        store2.append(it_root, ['子003'])
        store2.append(it_child, ['孫'])
        # モデルを指定してツリービューを作成
        tree2 = Gtk.TreeView(model=store2)
        # モデルを表示するコラムを指定
        tree2.append_column(column2)
        #
        paned = Gtk.Paned()
        paned.add1(tree1)
        paned.add2(tree2)
        self.add(paned)
        self.resize(300, 200)
        self.show_all()

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
etc/tree01.png
GtkTreeStore
GtkTreeStore をデータモデルに指定するとツリービューを作成できます。

データモデルは new の引数にリストで str 等の型を指定して作成します。
ツリーに表示する文字列は GtkTreeViewColumn で何番目データかを指定する。

データを append する時の第一引数は GtkTreeIter で第二引数は作成時に指定した型をリストで渡します。
第一引数を None にするとルートになり、GtkTreeIter にするとその子になる。
append の戻り値は GtkTreeIter でその戻り値を利用します。

クリック等で選択を行うと GtkSelection の changed シグナルが発行される。
このシグナルを利用してデータモデルの値を取得したり変更したりが可能です。

主に devhelp 等のようにツリーで何か選択すると別ペインにデータを表示したい場合に利用します。
以下はそのサンプル。
#!/usr/bin/env python3

import sys, gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class Win(Gtk.ApplicationWindow):
    '''
        TreeView
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='TreeStore')
        # Column
        cell = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn()
        column.pack_start(cell, True)
        column.add_attribute(cell, 'text', 0)
        # TreeStore
        store = Gtk.TreeStore.new([str, str])
        tree = Gtk.TreeView(model=store, headers_visible=False)
        tree.append_column(column)
        # Signal
        selection = tree.get_selection()
        selection.connect('changed', self.on_tree_selection_changeed)
        #
        # Data
        it0 = store.append(None, ['250cc', '何か選択しやがれ'])
        store.append(it0, ['CBR250RR', '前傾辛い...'])
        store.append(it0, ['YZF-R25', '無難っちゃ無難だが...'])
        store.append(it0, ['Ninja250', '400のがよくね?'])
        store.append(it0, ['GSX250R', 'カッコイイ!'])
        it1 = store.append(None, ['400cc', 'はよ選択しやがれ'])
        store.append(it1, ['CB400SF', '教習車だし...'])
        store.append(it1, ['Ninja400', '250にしか見えない...'])
        store.append(it1, ['Burgman400', 'カッコイイ!'])
        # pack
        self.label = Gtk.Label()
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.pack_start(tree, True, True, 0)
        vbox.pack_start(self.label, False, False, 0)
        # self
        self.add(vbox)
        self.resize(200, 300)
        self.show_all()

    def on_tree_selection_changeed(self, widget):
        '''
            Params @ widget: GtkTreeSelection
        '''
        model, it = widget.get_selected()
        if it:
            self.label.set_text(model.get_value(it, 1))

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
etc/tree02.png
GtkListStore
GtkListStore をデータモデルに指定するとリストビューを作成できます。

データモデル作成は GtkTreeStore と同じで new の引数に型リストにして指定します。
append は Tree のような親子関係が無いので作成時に指定した型をリストで渡すだけです。

コラムを表示したい数だけ作成し add_attribute の第三引数で何番目データを表示するかを指定。
主にファイルマネージャの詳細表示のように表示したい場合に利用します。
以下はそのサンプル。
#!/usr/bin/env python3

import sys, gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class Win(Gtk.ApplicationWindow):
    '''
        TreeView
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='ListStore')
        # Column 1
        cell_first = Gtk.CellRendererText()
        column_first = Gtk.TreeViewColumn()
        column_first.pack_start(cell_first, True)
        column_first.add_attribute(cell_first, 'text', 0)
        column_first.set_title('バイク')
        # Column 2
        cell_second = Gtk.CellRendererText()
        column_second = Gtk.TreeViewColumn()
        column_second.pack_start(cell_second, True)
        column_second.add_attribute(cell_second, 'text', 1)
        column_second.set_title('説明')
        # ListStore
        store = Gtk.ListStore.new([str, str])
        tree = Gtk.TreeView.new_with_model(store)
        tree.append_column(column_first)
        tree.append_column(column_second)
        #
        # Data
        store.append(['CB1300SF', '重過ぎるよ...'])
        store.append(['VMAX', 'もう売ってない...'])
        store.append(['Ninja H2', '高過ぎるよ...'])
        store.append(['刀', 'カッコイイ!'])
        # self
        self.add(tree)
        self.show_all()

    def on_tree_selection_changeed(self, widget):
        '''
            Params @ widget: GtkTreeSelection
        '''
        model, it = widget.get_selected()
        if it:
            self.label.set_text(model.get_value(it, 1))

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
etc/tree03.png
GtkTreeViewColumn
GtkTreeViewColumn は表示領域の提供、及び GtkTreeModel とレンダラの橋渡しを行います。

行毎に表示状態を変更させたい場合はコラムのシグナルを利用します。
gtk_tree_view_column_set_cell_data_func ()
関数で指定した GtkTreeCellDataFunc の引数に詳細が送られてきますので都度処理。

以下はチェックボックス状態で sensitive プロパティを切り替えする処理の例。
#!/usr/bin/env python3

import sys, gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class Win(Gtk.ApplicationWindow):
    '''
        Signal
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='ListStore')
        # Column Toggle
        cell_toggle = Gtk.CellRendererToggle()
        column_toggle = Gtk.TreeViewColumn(title='有効')
        column_toggle.pack_start(cell_toggle, True)
        column_toggle.add_attribute(cell_toggle, 'active', 0)
        # Column Text
        cell_text = Gtk.CellRendererText()
        column_text = Gtk.TreeViewColumn(title='会社')
        column_text.pack_start(cell_text, True)
        column_text.add_attribute(cell_text, 'text', 1)
        # Signal
        cell_toggle.connect('toggled', self.on_toggled)
        column_text.set_cell_data_func(cell_text, self.on_cell_func)
        # ListStore
        self.store = Gtk.ListStore.new([bool, str])
        tree = Gtk.TreeView(model=self.store)
        tree.append_column(column_toggle)
        tree.append_column(column_text)
        #
        # Data
        self.store.append([False, 'Honda'])
        self.store.append([False, 'Yamaha'])
        self.store.append([False, 'Kawasaki'])
        self.store.append([True, 'Suzuki'])
        # self
        self.add(tree)
        self.show_all()

    def on_toggled(self, widget, path):
        '''
            チェック毎に入れ替える
        '''
        self.store[path][0] = not self.store[path][0]

    def on_cell_func(self, column, cell, model, it, data):
        '''
            読み込み時にチェック無しなら薄くする
        '''
        cell.props.sensitive = model.get_value(it, 0)

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
etc/tree04.png
Copyright(C) sasakima-nao All rights reserved 2002 --- 2020.