PyGTKでツリービューにリストのデータ(ListStore)を表示(モデルの内容を取り出す)
ここではPyGTKのListStore形式のデータから内容を取り出す手順についてを主に扱う。
取り出し方
基本的にはgtk.TreeModelオブジェクトのメンバ関数get_value()あるいはget()を用いて、取り出したい項目を指し示すgtk.TreeIterオブジェクトを渡すことになる。前者はコラム番号を渡してそのコラム項目だけを取り出す方法で、後者は複数のコラム番号を可変長引数で渡してタプルとしてそれぞれのコラム項目の内容を取り出す形となる。
データを取り出すのに必要となるgtk.TreeIterオブジェクトを得るには幾つかの方法があり、「PyGTKでツリービューにリストのデータ(ListStore)を表示(データを変更可能にする・コード例)」や「PyGTKでツリービューにリストのデータ(ListStore)を表示(項目をGUI上で追加/削除、データの並べ替えや入れ替えなど)」ですでにツリービュー上の選択範囲から得る方法をコード中に書いている。
本記事においては、他の方法として以下の2つの方法を試している。
ListStoreの全てのデータを順番に取り出す
gtk.TreeModelオブジェクトのメンバ関数get_iter_first()で先頭の項目を指し示すgtk.TreeIterオブジェクトを得た後、while文のループ内で各項目を取り出し、ループ内の最後にiter_next()を記述する(最後まで到達するとNoneが返るためループを抜ける)。
項目番号により任意のデータを取り出す
gtk.TreeModelオブジェクトのメンバ関数get_iter()に、ツリーパスと呼ばれる形式のデータを渡す。
ツリーパスはツリーモデルにおける任意の項目を指定するための表記で、タプルもしくは文字列の形をとる。
もしこのときにデータの範囲外の値が指定された場合は例外ValueErrorが発生する。
http://www.pygtk.org/pygtk2tutorial/sec-TreeModelInterface.html#sec-TreePaths
も参照。
その他メモ(ラジオボタン)
ラジオボタンはgtk.RadioButtonオブジェクトとなり、グループの指定については以下のようになる。
- 指定なし(あるいはgroup=None指定): 新しいグループの先頭のラジオボタンとなる
- group指定: 指定したgtk.RadioButtonオブジェクトのグループに含まれるラジオボタンとなる
値はgtk.ToggleButtonオブジェクトのメンバ関数get_active()で取得する。
コード例
「PyGTKでツリービューにリストのデータ(ListStore)を表示(データを変更可能にする・コード例)」のsexmark.pyが別途必要。
例によって、この中で使用した名前は架空のものであり、実在の個人名や団体名などと一致するものがあったとしても関係はない。
#! /usr/bin/python # -*- encoding: utf-8 -*- import sys try: import pygtk pygtk.require('2.0') except: pass try: import gtk except: print >> sys.stderr, 'Error: PyGTK is not installed' sys.exit(1) try: import sexmark except: print >> sys.stderr, 'Error: sexmark.py required' sys.exit(1) class TreeViewWithColumn(gtk.TreeView): """ コラムを含んだツリービュー """ ( COLUMN_NUM, COLUMN_SEX, COLUMN_FAMILY, COLUMN_GIVEN, ) = range(4) def __init__(self, *args, **kwargs): gtk.TreeView.__init__(self, *args, **kwargs) # コラムの設定 self.col_num = gtk.TreeViewColumn('No.', gtk.CellRendererText(), text=self.COLUMN_NUM) self.col_sex = gtk.TreeViewColumn('Sex', gtk.CellRendererPixbuf(), pixbuf=self.COLUMN_SEX) self.col_family = gtk.TreeViewColumn('Family name', gtk.CellRendererText(), text=self.COLUMN_FAMILY) self.col_given = gtk.TreeViewColumn('Given name', gtk.CellRendererText(), text=self.COLUMN_GIVEN) # コラムを追加 self.append_column(self.col_num) self.append_column(self.col_sex) self.append_column(self.col_family) self.append_column(self.col_given) class SexIcon: """ 性別のアイコンデータのPixbufを保持 各データは「[本クラス名].[メンバ変数]」で取り出す """ male = gtk.gdk.pixbuf_new_from_xpm_data(sexmark.male_icon_xpm) female = gtk.gdk.pixbuf_new_from_xpm_data(sexmark.female_icon_xpm) class MainWindow(gtk.Window): """ メインウィンドウ """ # 直接ウィンドウとは関係ないが、データは便宜上ここに用意しておくことにする data = \ [ (1, SexIcon.male, 'Tanaka', 'Ichiro'), (2, SexIcon.female, 'Yamana', 'Hanako'), (3, SexIcon.male, 'Urashima', 'Saburo'), (4, SexIcon.male, 'Kurusu', 'Santa'), (5, SexIcon.male, 'Handa', 'Fuuta'), (6, SexIcon.female, 'Umeno', 'Tsubomi'), (7, SexIcon.male, 'Yoshi', 'Yaruzo'), (8, SexIcon.female, 'Kawai', 'Nuko'), (9, SexIcon.male, 'Hoshi', 'Kintaro'), (10, SexIcon.female, 'Shirayuki', 'Himeko'), (11, SexIcon.female, 'Ashigaka', 'Yui'), (12, SexIcon.female, 'Ageyanagi', 'Masako'), (13, SexIcon.male, 'Torino', 'Kenta'), (14, SexIcon.male, 'Kubota', 'Mochio'), (15, SexIcon.female, 'Kuroi', 'Sora'), (16, SexIcon.male, 'Hirai', 'Shin'), (17, SexIcon.female, 'Akai', 'Midori'), (18, SexIcon.female, 'Nakano', 'Anko'), (19, SexIcon.male, 'Imai', 'Takeo'), (20, SexIcon.male, 'Kouno', 'Torio'), (21, SexIcon.male, 'Yoshino', 'Yasu'), (22, SexIcon.male, 'Komatsu', 'Taro'), (23, SexIcon.male, 'Kondo', 'Musashi'), (24, SexIcon.male, 'Ono', 'Ken'), (25, SexIcon.male, 'Mochida', 'Usuichi'), (26, SexIcon.female, 'Mochida', 'Kineko'), (27, SexIcon.female, 'Honma', 'Kayo'), (28, SexIcon.male, 'Matsuno', 'Sarunosuke'), (29, SexIcon.female, 'Nishi', 'Minami'), (30, SexIcon.female, 'Usui', 'Hikaru'), (31, SexIcon.male, 'Sato', 'Toshio'), (32, SexIcon.male, 'Doi', 'Tsubasa'), (33, SexIcon.female, 'Ishimaru', 'Denko'), (34, SexIcon.female, 'Usami', 'Mimi'), (35, SexIcon.male, 'Hattori', 'Shinobu'), (36, SexIcon.female, 'Kago', 'Yuri'), (37, SexIcon.male, 'Takeda', 'Ingen'), (38, SexIcon.male, 'Kai', 'Dankichi'), (39, SexIcon.male, 'Okusa', 'Ben'), (40, SexIcon.male, 'Hara', 'Tatsuo'), (41, SexIcon.female, 'Mizuno', 'Shizuku'), (42, SexIcon.female, 'Baba', 'Nana'), ] def __init__(self, *args, **kwargs): gtk.Window.__init__(self, *args, **kwargs) # ショートカットキー(アクセラレータ) self.accelgroup = gtk.AccelGroup() self.add_accel_group(self.accelgroup) # メニュー項目 self.item_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT, self.accelgroup) self.menu_file = gtk.Menu() self.menu_file.add(self.item_quit) self.item_file = gtk.MenuItem('_File') self.item_file.set_submenu(self.menu_file) self.menubar = gtk.MenuBar() self.menubar.append(self.item_file) # ツリービュー self.treeview = TreeViewWithColumn(model=gtk.ListStore(int, gtk.gdk.Pixbuf, str, str)) self.treeview.set_rules_hint(True) # ツリービュー向けスクロールウィンドウ self.sw = gtk.ScrolledWindow() self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.sw.add(self.treeview) # ラジオボタン項目 # groupを指定した場合、対象のラジオボタンのグループに入る # 値はgtk.ToggleButtonのget_active()で取得 self.radio_all = gtk.RadioButton(label='Get all items') self.radio_num = gtk.RadioButton(group=self.radio_all, label='Get a single item:') # データ取り出しを実行するボタン self.button = gtk.Button('Get data') # 取り出す項目を指定する番号を入力するスピンボタン self.spinbtn_path = gtk.SpinButton(gtk.Adjustment(0, 0, 999, 1, 0, 0)) # レイアウト用コンテナ self.hbox_num = gtk.HBox() self.hbox_num.pack_start(self.radio_num, expand=False, fill=False) self.hbox_num.pack_end(self.spinbtn_path, expand=False, fill=False) self.vbox = gtk.VBox() self.vbox.pack_start(self.menubar, expand=False, fill=False) self.vbox.pack_start(self.sw) self.vbox.pack_start(self.radio_all, expand=False, fill=False) self.vbox.pack_start(self.hbox_num, expand=False, fill=False) self.vbox.pack_start(self.button, expand=False, fill=False) # シグナル self.connect('delete_event', gtk.main_quit) self.item_quit.connect('activate', gtk.main_quit) self.button.connect('clicked', self.on_button_clicked) # データ追加 for rec in self.data: self.treeview.get_model().append(rec) # ウィンドウ self.add(self.vbox) self.set_size_request(350, 300) def on_button_clicked(self, widget): """ ボタンがクリックされたときの処理 """ model = self.treeview.get_model() if self.radio_all.get_active(): # 全てのデータを取り出して表示することにする iter = model.get_iter_first() while iter: # gtk.TreeModelのget()では複数のコラムのデータを一括でタプルとして取り出せる (num, sexicon, familyname, givenname) = model.get(iter, self.treeview.COLUMN_NUM, self.treeview.COLUMN_SEX, self.treeview.COLUMN_FAMILY, self.treeview.COLUMN_GIVEN) if sexicon == SexIcon.male: sex = 'Male' else: sex = 'Female' print 'Num: %d\nSex: %s\nFamily name: %s\nGiven name: %s' % \ (num, sex, familyname, givenname) iter = model.iter_next(iter) # 次が無ければNoneでループを抜ける else: # 指定された番号のデータを取り出して表示することにする # パスは何番目のデータかを整数で表したものを並べたタプルとなる # (ListStoreの場合は整数だけでもOK) # 他に文字列表記のパスもある # http://www.pygtk.org/pygtk2tutorial/sec-TreeModelInterface.html#sec-TreePaths も参照 path = (int(self.spinbtn_path.get_value()),) try: iter = model.get_iter(path) except ValueError: # 範囲外の値が指定されTreeIterが得られない場合 print '(invalid tree path)' return (num, sexicon, familyname, givenname) = model.get(iter, self.treeview.COLUMN_NUM, self.treeview.COLUMN_SEX, self.treeview.COLUMN_FAMILY, self.treeview.COLUMN_GIVEN) if sexicon == SexIcon.male: sex = 'Male' else: sex = 'Female' print 'Num: %d\nSex: %s\nFamily name: %s\nGiven name: %s' % \ (num, sex, familyname, givenname) class PyGTKTreeViewListStoreTest4: """ リストを用いたツリービューのテスト4 """ def main(self): """ アプリケーションのメイン処理 """ win = MainWindow() win.show_all() gtk.main() if __name__ == '__main__': app = PyGTKTreeViewListStoreTest4() app.main()
「Get all items」のラジオボタンが選択されている状態でボタンを押すと
Num: 1 Sex: Male Family name: Tanaka Given name: Ichiro Num: 2 Sex: Female Family name: Yamana Given name: Hanako (中略) Num: 42 Sex: Female Family name: Baba Given name: Nana
のようにリスト上の全ての項目が各コラム項目ごとに端末に表示され、「Get a single item」のラジオボタンが選択されている状態でボタンを押すと、内部的な項目番号(0から始まる)がその番号の項目が表示される。
例えば、「2」を入力してボタンを押すと
Num: 3 Sex: Male Family name: Urashima Given name: Saburo
のように表示される。
データ範囲外の値が指定されたときには
(invalid tree path)
と表示される。
関連記事:
- PyGTKでツリービューにリストのデータ(ListStore)を表示(概要とメモ)
- PyGTKでツリービューにリストのデータ(ListStore)を表示(簡単な例)
- PyGTKでツリービューにリストのデータ(ListStore)を表示(データを変更可能にする・メモ)
- PyGTKでツリービューにリストのデータ(ListStore)を表示(データを変更可能にする・コード例)
- PyGTKでツリービューに階層を持ったデータ(TreeStore)を表示
- PyGTKでツリービューにリストのデータ(ListStore)を表示(項目をGUI上で追加/削除、データの並べ替えや入れ替えなど)
- PyGTKでツリービューにリストのデータ(ListStore)を表示(ボタンからデータの順番を入れ替える・メモ)
- PyGTKでツリービューにリストのデータ(ListStore)を表示(ボタンからデータの順番を入れ替える・コード例)
参考URL: