コンテンツにスキップ

GTK.Builder

出典: フリー教科書『ウィキブックス(Wikibooks)』

GTK.Builderの基本

[編集]

GTK.Builderは、UIをコードから分離してXMLで定義するためのGTKの機能です。UIの構造をXMLで記述し、プログラムから動的に構築できます。

基本的な使用方法

[編集]
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

builder = Gtk.Builder()
builder.add_from_string("""
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <object class="GtkWindow" id="window">
    <property name="title">Builder Example</property>
    <child>
      <object class="GtkBox">
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkButton" id="button1">
            <property name="label">Click Me</property>
          </object>
        </child>
      </object>
    </child>
  </object>
</interface>
""")

window = builder.get_object("window")
window.connect("destroy", Gtk.main_quit)
window.show_all()
Gtk.main()

UIの定義

[編集]

複雑なレイアウト例

[編集]
ui_string = """
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <object class="GtkWindow" id="main_window">
    <property name="default-width">400</property>
    <property name="default-height">300</property>
    <child>
      <object class="GtkGrid" id="grid">
        <property name="row-spacing">6</property>
        <property name="column-spacing">6</property>
        <child>
          <object class="GtkLabel">
            <property name="label">Name:</property>
            <layout>
              <property name="left-attach">0</property>
              <property name="top-attach">0</property>
            </layout>
          </object>
        </child>
        <child>
          <object class="GtkEntry" id="name_entry">
            <layout>
              <property name="left-attach">1</property>
              <property name="top-attach">0</property>
            </layout>
          </object>
        </child>
        <child>
          <object class="GtkButton" id="submit_button">
            <property name="label">Submit</property>
            <layout>
              <property name="left-attach">1</property>
              <property name="top-attach">1</property>
            </layout>
          </object>
        </child>
      </object>
    </child>
  </object>
</interface>
"""

シグナルの接続

[編集]

シグナルハンドラーの実装

[編集]
class Handler:
    def __init__(self, builder):
        self.builder = builder
        
    def on_submit_button_clicked(self, button):
        entry = self.builder.get_object("name_entry")
        text = entry.get_text()
        print(f"Submitted: {text}")
    
    def on_window_destroy(self, *args):
        Gtk.main_quit()

builder = Gtk.Builder()
builder.add_from_string(ui_string)
handler = Handler(builder)

# シグナルの接続
window = builder.get_object("main_window")
button = builder.get_object("submit_button")
window.connect("destroy", handler.on_window_destroy)
button.connect("clicked", handler.on_submit_button_clicked)

カスタムウィジェット

[編集]

カスタムウィジェットの定義と使用

[編集]
class CustomWidget(Gtk.Box):
    def __init__(self):
        super().__init__()
        
        builder = Gtk.Builder()
        builder.add_from_string("""
        <interface>
          <object class="GtkBox" id="custom_box">
            <property name="orientation">horizontal</property>
            <child>
              <object class="GtkLabel" id="label">
                <property name="label">Custom Widget</property>
              </object>
            </child>
            <child>
              <object class="GtkButton" id="button">
                <property name="label">Click</property>
              </object>
            </child>
          </object>
        </interface>
        """)
        
        box = builder.get_object("custom_box")
        button = builder.get_object("button")
        button.connect("clicked", self.on_button_clicked)
        
        self.pack_start(box, True, True, 0)
    
    def on_button_clicked(self, button):
        print("Custom widget button clicked!")

動的UIの構築

[編集]

実行時のUI変更

[編集]
class DynamicUI:
    def __init__(self):
        self.builder = Gtk.Builder()
        self.builder.add_from_string("""
        <interface>
          <object class="GtkWindow" id="window">
            <child>
              <object class="GtkBox" id="main_box">
                <property name="orientation">vertical</property>
              </object>
            </child>
          </object>
        </interface>
        """)
        
        self.main_box = self.builder.get_object("main_box")
        
    def add_new_button(self):
        new_button = Gtk.Button(label="Dynamic Button")
        new_button.connect("clicked", self.on_dynamic_clicked)
        self.main_box.pack_start(new_button, True, True, 0)
        new_button.show()
    
    def on_dynamic_clicked(self, button):
        print("Dynamic button clicked!")

リソース管理

[編集]

リソースファイルの使用

[編集]
resources.xml
<!-- resources.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
  <gresource prefix="/org/example/app">
    <file>ui/interface.ui</file>
    <file>css/style.css</file>
  </gresource>
</gresources>
from gi.repository import Gio

resource = Gio.Resource.load('resources.gresource')
Gio.Resource._register(resource)

builder = Gtk.Builder()
builder.add_from_resource('/org/example/app/ui/interface.ui')

エラー処理とデバッグ

[編集]
try:
    builder = Gtk.Builder()
    builder.add_from_string(ui_string)
except GLib.Error as e:
    print(f"Builder error: {e.message}")
    sys.exit(1)

# オブジェクトの存在確認
button = builder.get_object("submit_button")
if button is None:
    print("Error: Button not found in UI definition")
    sys.exit(1)

Glade との比較

[編集]

GTK.Builder

[編集]
メリット
  • プログラムによる完全な制御が可能
  • 動的なUI生成が容易
  • コードでのデバッグが可能
  • バージョン管理が容易
デメリット
  • UIの視覚的な設計が困難
  • XMLの手動編集が必要
  • レイアウトの試行錯誤が時間がかかる

Glade

[編集]
メリット
  • 視覚的なUI設計が可能
  • WYSIWYG編集
  • レイアウトの即時プレビュー
  • プロパティの視覚的な編集
デメリット
  • 外部ツールへの依存
  • 動的なUI生成が比較的複雑
  • カスタムウィジェットの扱いが面倒

使い分けの指針

[編集]
  1. GTK.Builderを選ぶ場合:
    • プログラムによるUI生成が必要
    • 動的なUIが多い
    • 外部依存を減らしたい
    • コードベースでの完全な制御が必要
  2. Gladeを選ぶ場合:
    • 静的なUIが中心
    • デザイナーとの協業
    • 迅速なプロトタイピング
    • 視覚的なUI設計を重視

多くの場合、両方を組み合わせて使用することで最適な開発フローを実現できます。