pygtkで遊ぼう(17) GObjectのサブクラスを作ってみる(その1)

今日は、GObjectのサブクラスを作ってみることにしました。

参考にしたサイト:
http://www.sicem.biz/personal/lgs/docs/docs/gobject-python/gobject-tutorial.html
http://trac.atzm.org/index.cgi/wiki/PyGTK

また、第1弾として作成したサブクラスに、プロパティを持たせるようにしてみました。
ポイントとしては、

(1) クラスのトップレベルに__gproperties__という辞書を持たせる。

(2) __gproperties__の辞書は、
    ・key  : プロパティ名(文字列)
    ・value : タプル。(タイプ、ニックネーム、説明文、いろいろ、フラグ)
    
    「いろいろ」の部分は最初の要素であるタイプに応じて、設定すべき要素の意味、数が変わる。
    詳しくは上記の参考サイトで確認できる。

(3) do_get_property(), do_set_property()というメソッドを作成する。これらの関数は
   set_property(), get_property()メソッドが呼ばれた際に間接的に呼び出される。


実際に書いたスクリプトはこんな感じです。

# -*- coding utf-8 -*-

import sys
import pygtk
if sys.platform != 'win32':
    pygtk.require('2.0')

import gobject


#
#
class SubGObject(gobject.GObject):
    '''
    GObjectのサブクラス実験クラス
    '''
    # properties
    __gproperties__ = {
        'floatValue': (gobject.TYPE_FLOAT,
                       'nick name of the float value',
                       'description of the float value',
                       0.0,
                       100.0,
                       50.0,
                       gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),

        'doubleValue': (gobject.TYPE_DOUBLE,
                        'nick name of the double value',
                        'description of the double value',
                        0.0,
                        1000.0,
                        500.0,
                        gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
        
        'boolValue': (gobject.TYPE_BOOLEAN,
                      'nick name of the bool value',
                      'description of the bool value',
                      True,
                      gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
        
        'charValue': (gobject.TYPE_CHAR,
                      'nick name of the char value',
                      'description of the char value',
                      'a',
                      'z',
                      'c',
                      gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
        
        'intValue': (gobject.TYPE_INT,
                     'nick name of the int value',
                     'description of the char value',
                     0,
                     100000,
                     50000,
                     gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
        
        'strValue': (gobject.TYPE_STRING,
                     'nick name of the string',
                     'description of the string',
                     'default string',
                     gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
        }

    def __init__(self):
        '''
        初期化
        '''
        gobject.GObject.__init__(self)

    def do_get_property(self, prop):
        '''
        プロパティ取得時に呼び出されるメソッド
        '''
        try:
            return getattr(self, prop.name)
        except AttributeError:
            raise AttributeError, 'unknown property %s' % prop.name

    def do_set_property(self, prop, value):
        '''
        プロパティ設定時に呼び出されるメソッド
        '''
        try:
            return setattr(self, prop.name, value)
        except AttributeError:
            raise AttributeError, 'unknown property %s' % prop.name

gobject.type_register(SubGObject)

冒頭に書いてある参考サイト(特に最初のほうのサイト)では、
「サブクラス中の__init__メソッド中で、インスタンス変数の初期値を設定しましょう」
といった内容のソースコードになっていましたが、

「__gproperties__には初期値の項目も持っているのに、なぜわざわざ同じような初期化コードが必要??」と
疑問に思っていました。

解決策としては、上記のスクリプトにあるように

gobject.PARAM_CONSTRUCT

を指定します。
そうすることで、コンストラクタが呼び出された際に、インスタンス変数の生成と初期化を行うようになります。


● 疑問点(宿題。。)

・__gproperties__という辞書、__init__メソッドの中で参照しようとすると、AttributeErrorになってしまう見たいですが。。
 Pythonってそういうものでしたっけ。。。


●悩みどころ

・結構便利なんですが、使用はGTKを使ってGUIを構築する場合にとどめ、なるべくPythonの新スタイルクラスの
 propertyを使用したほうがいい気がします。(GUIだけ別のツールキットに置き換えるのも楽だし)