翻訳して勉強するGtkチュートリアル第21章は Glade and Gtk.Builder です。はやく23章まで読み終わって、Gladeを使って自分のアプリを作りたいです。
Gtk.Builder クラスは、コードを一行も書かずにユーザ・インタフェースを設計する機会を提供します。これは XML ファイルでインターフェイスを記述し、実行時に XML の記述をロードしてオブジェクトを自動的に作成することで可能になります。手動で XML を書く必要がないため、Glade アプリケーションでは WYSIWYG (見たままを手に入れる) 方式でユーザーインターフェースを作成することができます。
この方法にはいくつかの利点があります:
- 書く必要のあるコードが少なくて済む
- UIの変更がより早くわかるので、UIの改善が可能になる
- プログラミングスキルのないデザイナーでもUIの作成や編集ができる
- ユーザーインターフェースの記述は、使用しているプログラミング言語に依存しない
ユーザー起因のインターフェース変更を処理するのに必要なコードは他にありますが、Gtk.Builder ではその機能の実装に集中することができます。
21.1. .gladeファイルの作成と読み込み
まずはGladeをダウンロードしてインストールする必要があります。Gladeについてはいくつかチュートリアルがあるので、ここでは詳しく説明しません。まず、ボタンのあるウィンドウを作成し、example.gladeという名前のファイルに保存します。結果のXMLファイルは以下のようになるはずです。
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">button</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
</child>
</object>
</interface>
Python でこのファイルを読み込むには Gtk.Builder オブジェクトが必要です。
builder = Gtk.Builder()
builder.add_from_file("example.glade")
2行目は、example.gladeで定義されたすべてのオブジェクトをBuilderオブジェクトにロードします。
また、一部のオブジェクトだけを読み込むことも可能です。次の行は、タプルで与えられたオブジェクト(とその子オブジェクト)だけを追加します。
# ここでは2つのボタンがあるわけではありません。これは単なる例です。
builder.add_objects_from_file("example.glade", ("button1", "button2"))
これら2つのメソッドは、ファイルではなく文字列から読み込むためにも存在します。対応する名前は Gtk.Builder.add_from_string() と Gtk.Builder.add_objects_from_string() で、単にファイル名の代わりに XML 文字列を受け取ります。
21.2. ウィジェットへのアクセス
ウィンドウとボタンが読み込まれたので、それらを表示したいと思います。そのため、Gtk.Window.show_all() メソッドをウィンドウ上で呼び出す必要があります。しかし、関連するオブジェクトにはどうやってアクセスするのでしょうか?
window = builder.get_object("window1")
window.show_all()
すべてのウィジェットは、Gtk.Builder.get_object() メソッドとウィジェットの id によってビルダーから取得することができます。これは本当に簡単なことです。
また、すべてのオブジェクトのリストを取得するためにこのメソッドが使えます:
builder.get_objects()
21.3. シグナルの接続
Glade はまた、ビルダーからすべてのオブジェクトを抽出して手動でシグナルに接続しなくても、コード内のハンドラに接続できるシグナルを定義することも可能にしています。最初にすべきことは、シグナル名を Glade で宣言することです。この例では、ウィンドウが閉じた時とボタンが押された時に動作させるとして、ウィンドウの “destroy” シグナルを処理するコールバックに “onDestroy”、ボタンの “pressed” シグナルを処理するコールバックに “onButtonPressed” という名前をつけています。これで、XMLファイルは以下のようになります。
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<signal name="destroy" handler="onDestroy" swapped="no"/>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">button</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="pressed" handler="onButtonPressed" swapped="no"/>
</object>
</child>
</object>
</interface>
ここで、コードの中でハンドラ関数を定義しなければなりません。onDestroy は単純に Gtk.main_quit() を呼び出す結果になります。
ボタンが押されたときに “Hello World!” という文字列を表示したいので、以下のようにハンドラを定義します:
def hello(button):
print("Hello World!")
次に、シグナルとハンドラ関数を接続しなければなりません。これを行う最も簡単な方法は、名前からハンドラへのマッピングを持つ dict を定義し、それを Gtk.Builder.connect_signals() メソッドに渡すことです。
handlers = {
"onDestroy": Gtk.main_quit,
"onButtonPressed": hello
}
builder.connect_signals(handlers)
別のアプローチとして、シグナルのように呼ばれるメソッドを持つクラスを作成することもできます。この例では、最後のコードスニペットを次のように書き換えることができます:
from gi.repository import Gtk
class Handler:
def onDestroy(self, *args):
Gtk.main_quit()
def onButtonPressed(self, button):
print("Hello World!")
builder.connect_signals(Handler())
21.4. 例
例題の最終的なコード:
# tut21.py
# Glade and Gtk.Builder
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class Handler:
def onDestroy(self, *args):
Gtk.main_quit()
def onButtonPressed(self, button):
print("Hello World!")
builder = Gtk.Builder()
builder.add_from_file("example.glade")
builder.connect_signals(Handler())
window = builder.get_object("window1")
window.show_all()
Gtk.main()