傳統 GTK+ 程式將 UI 佈局硬編碼在 C 代碼中,修改介面需重新編譯。**GtkBuilder** 讓開發者將 UI 定義為 XML(通常由 Glade 設計器產生),運行時動態載入,實現「介面與邏輯分離」。
GtkBuilder *builder = gtk_builder_new();gtk_builder_add_from_file(builder, "main.ui", &error);GtkWidget *win = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));// main.c
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
GtkBuilder *builder = gtk_builder_new();
GError *err = NULL;
if (!gtk_builder_add_from_file(builder, "main.ui", &err)) {
g_printerr("載入 UI 失敗: %s\n", err->message);
g_error_free(err);
return 1;
}
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
GtkWidget *button = GTK_WIDGET(gtk_builder_get_object(builder, "btn_hello"));
// 連接信號(需在 .ui 中定義 handler 名稱)
gtk_builder_connect_signals(builder, NULL);
g_object_unref(builder); // 釋放 builder,widget 由 container 管理
gtk_widget_show_all(window);
gtk_main();
return 0;
}
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="main_window">
<property name="title">Hello GtkBuilder</property>
<property name="default-width">300</property>
<signal name="destroy" handler="gtk_main_quit"/>
<child>
<object class="GtkButton" id="btn_hello">
<property name="label">Click Me</property>
<signal name="clicked" handler="on_btn_hello_clicked"/>
</object>
</child>
</object>
</interface>
// 簽名必須符合 GCallback: void func(GtkWidget*, gpointer)
void on_btn_hello_clicked(GtkButton *btn, gpointer user_data) {
g_print("Button clicked!\n");
}
編譯:gcc main.c -o main `pkg-config --cflags --libs gtk+-3.0`
glib-compile-resources 將 .ui 編譯進二進制,避免外部檔案遺失。GtkWidgetClass + gtk_widget_class_set_template_from_resource,更物件導向。gtk_builder_connect_signals → 按鈕無反應。gtk_builder_get_object 回傳 NULL → ID 拼錯或層級錯誤。g_object_unref(builder) → 記憶體洩漏(widget 已被 container 參考,builder 可釋放)。