13. Глава 25: Glade – Визуальный Редактор Интерфейсов
Glade — это мощный визуальный редактор интерфейсов для GTK. Он позволяет создавать сложные пользовательские интерфейсы методом «drag-and-drop», без необходимости писать каждую строку кода для размещения и настройки виджетов. Созданный в Glade интерфейс сохраняется в XML-файле (обычно с расширением .glade), который затем может быть загружен и использован в вашем C-коде через объект GtkBuilder.
Использование Glade значительно ускоряет разработку GUI, делает код более чистым, отделяя логику приложения от описания интерфейса, и позволяет дизайнерам работать над внешним видом независимо от программистов.
Основные темы этой главы:
Установка Glade на Raspberry Pi и других системах Linux.
Создание ``.glade``-файла: Как создать простой интерфейс в Glade, назначить ID виджетам и связать сигналы.
Лучшие практики создания интерфейсов в Glade (логичные ID, адаптивные контейнеры).
Загрузка интерфейса в C через GtkBuilder: Как прочитать
.glade-файл и получить ссылки на виджеты.Автоматическое связывание сигналов с обработчиками в C-коде.
Передача пользовательских данных в функции обратного вызова сигналов.
Отладка GTK-интерфейсов с помощью GtkInspector.
Компиляция и запуск GTK-приложения, использующего Glade.
—
### Основные понятия и функции
``Glade``: Визуальный редактор интерфейсов для GTK, позволяющий создавать GUI методом «drag-and-drop».
``.glade``-файл: XML-файл, сгенерированный Glade, который описывает структуру пользовательского интерфейса.
``GtkBuilder``: Объект GTK, который парсит
.glade-файл и создает соответствующие виджеты в памяти.``gtk_builder_new_from_file()``: Создает новый объект
GtkBuilderи загружает в него интерфейс из указанного.glade-файла.``gtk_builder_get_object()``: Получает указатель на виджет из загруженного интерфейса по его ID (строковому идентификатору), который был задан в Glade.
``gtk_builder_connect_signals()``: Автоматически подключает все сигналы, определенные в
.glade-файле, к функциям обратного вызова в вашем C-коде (если имена функций совпадают).ID виджета: Уникальный строковый идентификатор, который вы присваиваете каждому виджету в Glade, чтобы можно было получить к нему доступ из кода. Используйте логичные и описательные ID (например,
btn_submit,entry_username,label_status).Имя обработчика сигнала (Handler Name): Имя функции в вашем C-коде, которая будет вызываться при срабатывании определенного сигнала виджета (например,
on_button_clickedдля сигналаclickedкнопки).
—
### Исходные файлы в этой главе
В этой главе мы рассмотрим один комплексный пример:
glade_example.c — Демонстрирует полный процесс создания простого интерфейса в Glade, сохранения его в .glade-файл, а затем загрузки и использования в GTK-приложении на C, включая передачу пользовательских данных.
interface.glade — Файл интерфейса, который вы создадите с помощью Glade.
—
### Установка Glade
Для установки Glade на большинстве дистрибутивов Linux (включая Raspberry Pi OS, Ubuntu, Debian) используйте следующие команды в терминале:
sudo apt update # Обновляем список пакетов
sudo apt install glade # Устанавливаем Glade
После успешной установки вы сможете запустить Glade из терминала командой:
glade
Или найдите его в меню приложений вашей операционной системы.
—
### Создание .glade-интерфейса
Мы создадим простой интерфейс с главным окном, полем ввода текста (GtkEntry), меткой (GtkLabel) и кнопкой (GtkButton). При нажатии на кнопку текст из поля ввода будет копироваться в метку.
Запустите Glade. Вы увидите пустое окно Glade.
В палитре виджетов (обычно слева) найдите ``GtkWindow`` (в категории «Top Level») и перетащите его в центральную область. Это будет ваше основное окно.
На правой панели, во вкладке «General», в поле «ID» (идентификатор), задайте уникальное имя для окна:
main_window. В поле «Title» (заголовок) введите"Glade Пример".Добавьте ``GtkBox`` (Gtk-контейнер, обычно «Containers» -> «GtkBox») внутрь
main_window. Выберите вертикальную ориентацию (GtkOrientation Vertical) и установите небольшой отступ (например, 10px) между элементами в свойстве «Spacing». Это поможет расположить виджеты аккуратно. Вкладка «Packing» (Паковка) дляGtkBoxпозволяет настроить отступы между его содержимым и отступы от краев контейнера.Добавьте ``GtkEntry`` (поле ввода текста) внутрь
GtkBox. ВыберитеGtkEntryи на правой панели, во вкладке «General», задайте его ID какentry_input. В поле «Placeholder Text» (текст-заполнитель) введите"Введите текст здесь...".Добавьте ``GtkButton`` внутрь того же
GtkBox. ВыберитеGtkButtonи на правой панели, во вкладке «General», задайте его ID какbtn_copy. В поле «Label» (метка) напишите"Скопировать текст".Все еще выбрав
GtkButton, перейдите на вкладку «Signals» (Сигналы) на правой панели.В разделе «GtkButton» найдите сигнал ``clicked``. Дважды щелкните по нему или нажмите кнопку «+» рядом с ним.
В появившемся окне в поле «Handler» (Обработчик) введите имя функции, которая будет вызвана при нажатии кнопки. Назовите её
on_btn_copy_clicked. Нажмите Enter или «OK».Добавьте ``GtkLabel`` (метку для вывода текста) внутрь того же
GtkBox, после кнопки. Задайте ее ID какlabel_output. В поле «Label» пока ничего не пишите или напишите"Здесь будет ваш текст".Сохраните проект. Перейдите в меню «File» → «Save» (или «Save As…»). Сохраните файл как
interface.gladeв той же директории, где вы планируете хранить свой C-код.
Теперь у вас есть interface.glade файл, описывающий ваш GUI.
—
### Лучшие практики создания интерфейсов в Glade
Используйте логичные ID: Присваивайте каждому виджету уникальные и осмысленные ID (например,
btn_submit,entry_username,label_error). Это значительно упрощает поиск и доступ к виджетам из вашего C-кода.- Организуйте интерфейс с контейнерами: Избегайте использования
GtkFixedдля сложных интерфейсов, так как он не является адаптивным. Вместо этого используйте: ``GtkBox``: Для последовательного расположения виджетов по горизонтали или вертикали.
``GtkGrid``: Для табличного расположения виджетов, где вы можете точно указать строки и столбцы.
``GtkStack``: Для создания интерфейсов с несколькими «страницами» или видами, где только одна страница видна одновременно.
- Организуйте интерфейс с контейнерами: Избегайте использования
Используйте вложенные контейнеры для адаптивного дизайна: Комбинируйте различные типы контейнеров. Например,
GtkBoxвнутри ячейкиGtkGridпозволит вам создать сложный, но при этом легко масштабируемый и адаптивный макет.
—
### Пример 25.1: Загрузка Glade-интерфейса и Связывание Сигналов с Пользовательскими Данными
Файл: glade_example.c
Этот пример демонстрирует, как загрузить интерфейс, созданный в Glade (interface.glade), получить доступ к виджетам по их ID и автоматически подключить обработчики сигналов. Самое главное, он показывает, как передать структуру пользовательских данных в функцию обратного вызова, чтобы обработчик мог взаимодействовать с несколькими виджетами.
#include <gtk/gtk.h> // Подключаем библиотеку GTK.
/**
* @brief Структура для хранения указателей на виджеты и других данных,
* которые должны быть доступны в функциях обратного вызова.
*/
typedef struct {
GtkWidget *entry_input; // Указатель на поле ввода GtkEntry.
GtkWidget *label_output; // Указатель на метку GtkLabel для вывода.
} AppData;
/**
* @brief Обработчик сигнала 'clicked' для кнопки 'btn_copy'.
* Копирует текст из поля ввода в метку.
*
* @param button Указатель на объект GtkButton, который сгенерировал сигнал.
* @param user_data Пользовательские данные, приведенные к типу AppData*.
*/
void on_btn_copy_clicked(GtkButton *button, gpointer user_data) {
// Приводим gpointer к нашему типу AppData*.
AppData *app = (AppData *)user_data;
// Получаем текст из поля ввода.
const gchar *text = gtk_entry_get_text(GTK_ENTRY(app->entry_input));
// Устанавливаем полученный текст в метку.
gtk_label_set_text(GTK_LABEL(app->label_output), text);
g_print("Текст скопирован: %s\n", text); // Выводим в консоль для отладки.
}
/**
* @brief Главная функция программы.
* Инициализирует GTK, загружает интерфейс из Glade-файла,
* подключает сигналы и запускает главный цикл GTK.
*
* @param argc Количество аргументов командной строки.
* @param argv Массив строк аргументов командной строки.
* @return Код завершения программы.
*/
int main(int argc, char *argv[]) {
GtkBuilder *builder; // Объявляем указатель на GtkBuilder.
GtkWidget *window; // Объявляем указатель на главное окно.
AppData app; // Объявляем структуру для хранения данных приложения.
gtk_init(&argc, &argv); // Инициализируем библиотеку GTK.
// Создаем новый объект GtkBuilder и загружаем в него интерфейс из файла "interface.glade".
if (!g_file_test("interface.glade", G_FILE_TEST_EXISTS)) {
g_critical("Ошибка: файл interface.glade не найден в текущей директории.");
g_critical("Убедитесь, что вы создали его с помощью Glade и сохранили.");
return 1;
}
builder = gtk_builder_new_from_file("interface.glade");
// Если builder не смог загрузить файл, выходим.
if (!builder) {
g_critical("Не удалось загрузить Glade-файл: interface.glade. Проверьте его синтаксис.");
return 1;
}
// Получаем указатель на главное окно по его ID "main_window".
window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
if (!window) {
g_critical("Ошибка: не удалось получить виджет 'main_window' из Glade-файла.");
return 1;
}
// Получаем указатели на поле ввода и метку по их ID.
app.entry_input = GTK_WIDGET(gtk_builder_get_object(builder, "entry_input"));
app.label_output = GTK_WIDGET(gtk_builder_get_object(builder, "label_output"));
// Проверяем, что все нужные виджеты были найдены.
if (!app.entry_input || !app.label_output) {
g_critical("Ошибка: не удалось получить один или несколько виджетов (entry_input, label_output).");
g_critical("Убедитесь, что их ID правильно заданы в Glade-файле.");
return 1;
}
// Подключаем все сигналы, определенные в Glade-файле, к соответствующим функциям в коде.
// Передаем адрес нашей структуры 'app' в качестве пользовательских данных.
gtk_builder_connect_signals(builder, &app);
// Соединяем сигнал "destroy" главного окна с функцией завершения GTK.
// Это гарантирует, что приложение закроется при закрытии окна.
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
// Отображаем все виджеты в окне.
gtk_widget_show_all(window);
// Запускаем главный цикл GTK. Программа будет ожидать событий (нажатий кнопок и т.д.).
gtk_main();
// Освобождаем ресурсы GtkBuilder.
// Важно освободить builder после того, как все виджеты и сигналы подключены,
// так как builder больше не нужен, но виджеты остаются в памяти.
g_object_unref(builder);
return 0; // Возвращаем 0, показывая успешное завершение.
}
—
### Компиляция и Запуск
Перед компиляцией убедитесь, что вы выполнили шаги по «Созданию ``.glade``-интерфейса» и сохранили файл как ``interface.glade`` в той же директории, что и ``glade_example.c``.
Сохраните код из [примера 25.1](glade_example.c) в файл с названием
glade_example.c.Убедитесь, что файл
interface.gladeнаходится в той же директории.Откройте терминал и перейдите в директорию, где вы сохранили файлы.
Скомпилируйте программу, используя
pkg-configдля автоматического подключения необходимых флагов GTK: .. code-block:: bashgcc glade_example.c -o glade_example pkg-config –cflags –libs gtk+-3.0
Примечание: Если вы используете Glade с GTK4, флаг будет ``gtk4``.
Важно: Исполняемый файл (glade_example) должен иметь доступ к interface.glade во время выполнения. Обычно это означает, что они должны быть в одной директории, или interface.glade должен быть установлен в известное системе место (например, через make install или CMake). Для CMake-проектов, чтобы убедиться, что .glade файл копируется рядом с исполняемым файлом или в нужное место, можно использовать: .. code-block:: cmake
# В вашем CMakeLists.txt install(FILES interface.glade DESTINATION bin) # Копирует interface.glade в директорию bin
Запустите скомпилированную программу: .. code-block:: bash
./glade_example
—
### Ожидаемый Результат
После запуска программы появится окно с заголовком «Glade Пример».
В окне будет поле ввода текста (GtkEntry) с текстом-заполнителем «Введите текст здесь…».
Под полем ввода будет кнопка «Скопировать текст».
Под кнопкой будет метка (GtkLabel), изначально отображающая «Здесь будет ваш текст» или похожий текст.
Введите любой текст в поле ввода.
Нажмите кнопку «Скопировать текст».
Текст, который вы ввели в поле ввода, мгновенно появится в метке.
В терминале, из которого вы запустили программу, будет выведено сообщение: «Текст скопирован: [ваш_текст]».
Закрытие окна приведет к завершению программы.
—
### Отладка GTK-интерфейсов с GtkInspector
GtkInspector — это мощный инструмент для отладки и проверки GTK-приложений. Он позволяет на лету изменять свойства виджетов, просматривать их иерархию, стили CSS и многое другое. Это незаменимый помощник при работе с Glade и GTK.
Чтобы запустить ваше GTK-приложение с активированным GtkInspector:
GTK_DEBUG=interactive ./glade_example
После запуска приложения: * Нажмите комбинацию клавиш Ctrl + Shift + I (латинская «i»). Откроется отдельное окно GtkInspector. * Используйте вкладки Inspector для просмотра:
Objects: Иерархия виджетов в вашем приложении.
CSS: Применяемые CSS-стили к выбранному виджету.
Properties: Все свойства выбранного виджета и их текущие значения. Вы можете изменять их на лету!
Measuring: Инструменты для измерения отступов и размеров виджетов.
—
## Дополнительные Ресурсы
Для более глубокого изучения Glade и GtkBuilder обратитесь к официальной документации:
C_GUI_Handbook GitHub (Полный репозиторий с исходным кодом и руководством по всем главам)
—