PyGObject/PyGTKにおけるGObjectプロパティの操作について
ここではgobject.GObjectクラスから派生した定義済みクラスにおけるGObjectプロパティの操作のみを扱い、自分でgobject.GObjectクラスを継承してプロパティを作り設定する手順については別記事にて扱う。
PyGObjectのプロパティ
[モジュール名].[クラス名] Properties
という一覧がある場合がある(例:gtk.Windowクラスの場合・一覧が存在しないクラスもある)。これがGObjectの世界におけるプロパティとなっており、扱いはPythonのプロパティとは異なる。
値の読み書きを行うメンバ関数
PyGObjectのgobject.GObjectクラスに
- get_property(単数読み込み・値で受け取る)
- get_properties(複数読み込み・タプルで受け取る)
- set_property(単数書き込み)
- set_properties(複数書き込み)
といったメンバ関数があり、PyGTKのほとんどのクラスを含め、ここから派生しているクラスではこれらのメンバ関数を用いて値の出し入れができる。ただし、リファレンスのプロパティ一覧においてプロパティ名の右に
- 「Read-Write」もしくは「Read」と書かれているものにしかget_property()系メンバ関数は使えない
- 「Read-Write」もしくは「Write」と書かれているものにしかset_property()系メンバ関数は使えない
という制限があり、各プロパティごとのアクセス許可の設定となっている。不正な操作をするとTypeError例外が発生し「TypeError: property [プロパティ名] is not [readable もしくは writable]」となる。
propsメンバ
PyGObjectのgobject.GObjectクラスとその派生クラス(PyGTKの各種クラス含む)にある「props」というメンバを用いると、更にその下のメンバとしてそのオブジェクトのGObjectプロパティにアクセスできる。読み書きのアクセスの制限は上のメンバ関数と同様に存在し、リファレンス内のアクセス許可が「Read」を含めば値の取り出しが可能となり、「Write」を含めば代入ができる。「props」を挟まずに直接プロパティ名のメンバにアクセスしてもダメなので注意。
例えば、PyGTKにおけるウィンドウのgtk.Windowクラスには「title」というプロパティがあり、ウィンドウのタイトルとして読み書きができるようになっていて
[gtk.Windowオブジェクト].props.title = 'window title'
とするとそのウィンドウのタイトルが「window title」になり
print [gtk.Windowオブジェクト].props.title
とするとウィンドウタイトルが取り出されて端末に表示される。
この形を用いることで、別に用意されている「set_[文字列]」といった名前のメンバ関数を呼ぶ代わりに値の代入で処理ができる場合がある。ただ、「set_[文字列]」といった名前のメンバ関数全てがGObjectプロパティで置き換えられるわけではない。値の取り出しについても同様。*1
プロパティ名にハイフンを含むと文法エラー?
プロパティにハイフン(「-」)文字が含まれている場合、get_properties(),set_properties()やpropsメンバを用いると「SyntaxError: can't assign to operator」となってうまくいかない。これについてはget_property()やset_property()を用いてもよいが、ハイフンをアンダースコア(「_」)文字に置き換えるとうまくいくようだ。
例
下は「PythonでUNIXシグナルのハンドラを扱う(後半)」のコードをもとに、一部メンバ関数の呼び出しをpropsメンバを用いたGObjectプロパティの代入に置き換えたものとなる。
#! /usr/bin/python # -*- encoding: utf-8 -*- import signal import sys import os try: import pygtk pygtk.require('2.0') except: pass try: import gtk except: sys.exit(1) class MainWindow(gtk.Window): """ メインウィンドウ """ def __init__(self, *args, **kwargs): gtk.Window.__init__(self, *args, **kwargs) self.props.title = 'test' self.set_size_request(320, 200) 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.props.submenu = self.__menu_file self.__menubar = gtk.MenuBar() self.__menubar.append(self.__item_file) self.__button = gtk.Button() self.__button.props.label = 'Test' self.__statusbar = gtk.Statusbar() self.__vbox = gtk.VBox(False, 0) self.__vbox.pack_start(self.__menubar, expand=False, fill=False) self.__vbox.pack_start(self.__button) self.__vbox.pack_start(self.__statusbar, expand=False, fill=False) self.add(self.__vbox) self.__button.connect('clicked', self.__on_button_clicked) self.__item_quit.connect('activate', gtk.main_quit) self.connect('delete_event', gtk.main_quit) def __on_button_clicked(self, widget): """ ボタンが押されたときの処理 """ print '__on_button_clicked()' class PyGTKUnixSigHandlerTest2Prop: """ UNIXシグナルハンドラのテスト2 PyGObjectプロパティ使用版 """ def main(self): """ ウィンドウを作成してGTK+のメインループを呼ぶ """ # シグナルSIGINTを受け取った場合に # 例外KeyboardInterruptを出さずに終了する signal.signal(signal.SIGINT, signal.SIG_DFL) win = MainWindow() win.show_all() gtk.main() if __name__ == '__main__': app = PyGTKUnixSigHandlerTest2Prop() app.main()
関連記事:
- PythonでUNIXシグナルのハンドラを扱う(後半)
- Pythonでオブジェクトのプロパティを使用する
- PyGObjectで gobject.GObjectクラスを継承してGObjectプロパティを用いる(前半)
- PyGObjectで gobject.GObjectクラスを継承してGObjectプロパティを用いる(後半)
使用したバージョン:
- Python 2.6.4
- PyGTK 2.16.0