2. Глава 14: Первый GTK-проект — Окно с кнопкой
В этой главе мы создадим простейшее полноценное приложение с использованием библиотеки GTK — окно с кнопкой «Закрыть», при нажатии на которую программа завершает работу.
Это первый практический шаг в создании интерактивных GUI-приложений с использованием GTK и языка C на Raspberry Pi Zero 2 W (или любой другой системе с установленной GTK3).
2.1. Основные цели этой главы:
Понять базовую структуру минимального GTK-приложения.
Создать основное окно приложения.
Добавить интерактивный элемент — кнопку — в окно.
Обработать событие нажатия на кнопку для завершения работы программы.
Скомпилировать и запустить ваше первое GUI-приложение.
—
### Пример кода: Окно с кнопкой «Закрыть»
Название исходного файла: minimal_window.c
В этом примере мы создадим окно, добавим в него кнопку и научим кнопку закрывать приложение при нажатии.
#include <gtk/gtk.h> // Подключаем основную библиотеку GTK. Этого достаточно для большинства базовых функций.
// Callback-функция, которая будет вызвана при нажатии кнопки.
// 'widget' - указатель на виджет, который испустил сигнал (в нашем случае, кнопка).
// 'data' - пользовательские данные, переданные при подключении сигнала.
// В этом случае 'data' будет указателем на наше окно, которое мы хотим закрыть.
static void on_button_clicked(GtkWidget *widget, gpointer data) {
// Закрываем окно, переданное в качестве 'data'.
// GTK_WINDOW(data) безопасно приводит gpointer к GtkWindow*, чтобы мы могли использовать gtk_window_close.
gtk_window_close(GTK_WINDOW(data));
}
int main(int argc, char *argv[]) {
// Инициализируем GTK. Это обязательный вызов для любой GTK-программы.
// Он обрабатывает аргументы командной строки, специфичные для GTK, и подготавливает библиотеку к работе.
gtk_init(&argc, &argv);
// Создаём новое окно верхнего уровня.
// GtkWidget* - это базовый тип для всех виджетов GTK.
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); // GTK_WINDOW_TOPLEVEL - это тип окна верхнего уровня
// Устанавливаем заголовок окна, который будет отображаться в строке заголовка.
// GTK_WINDOW(window) выполняет приведение типа, поскольку gtk_window_set_title ожидает GtkWindow*.
gtk_window_set_title(GTK_WINDOW(window), "GTK Minimal App");
// Устанавливаем размер окна по умолчанию (ширина, высота) в пикселях.
gtk_window_set_default_size(GTK_WINDOW(window), 300, 100);
// Устанавливаем положение окна на экране.
// GTK_WIN_POS_CENTER центрирует окно на экране.
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
// Подключаем сигнал "destroy" окна к функции gtk_main_quit.
// Этот сигнал испускается, когда пользователь закрывает окно (например, кликая на "X").
// gtk_main_quit() останавливает главный цикл GTK, что приводит к завершению программы.
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
// Создаём новую кнопку с текстовой меткой "Закрыть".
GtkWidget *button = gtk_button_new_with_label("Закрыть");
// Подключаем сигнал "clicked" от кнопки к нашей функции on_button_clicked.
// Когда кнопка будет нажата, вызовется on_button_clicked.
// Мы передаём указатель на 'window' как пользовательские данные (data),
// чтобы on_button_clicked знала, какое окно закрывать.
g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), window);
// Устанавливаем кнопку в качестве дочернего элемента окна.
// В GTK3 для окна можно установить только один прямой дочерний элемент.
// gtk_container_add() - это более старый, но часто используемый способ добавления виджетов.
// В более новых версиях GTK (и для GtkApplicationWindow) используется gtk_window_set_child().
gtk_container_add(GTK_CONTAINER(window), button);
// Показываем все виджеты, начиная с окна и включая все его дочерние элементы.
// Виджеты по умолчанию невидимы, их нужно явно показать.
gtk_widget_show_all(window); // Показывает и окно, и кнопку внутри него.
// Запускаем главный цикл событий GTK.
// Эта функция передает управление библиотеке GTK, которая начинает слушать события (клики, ввод и т.д.).
// Программа будет выполняться в этом цикле до тех пор, пока не будет вызвана gtk_main_quit().
gtk_main();
return 0; // Возвращаем 0, указывая на успешное завершение программы.
}
—
### Комментарии к коду и пояснения
Давайте разберём основные строки кода и функции, используемые в примере:
#include <gtk/gtk.h>
: Обязательная строка для всех GTK-приложений. Она включает все необходимые определения и функции для работы с библиотекой.gtk_init(&argc, &argv);
: Инициализация GTK. Это первый вызов, который должен быть сделан в любой GTK-программе. Он обрабатывает любые аргументы командной строки, предназначенные для GTK, и подготавливает внутренние структуры библиотеки.GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
: Создаёт новый объект окна верхнего уровня.GtkWidget
— это базовый тип для всех видимых элементов в GTK.gtk_window_set_title(GTK_WINDOW(window), "GTK Minimal App");
: Устанавливает текст заголовка окна.GTK_WINDOW(window)
— это макрос для безопасного приведения общего указателяGtkWidget*
к более специфичному типуGtkWindow*
, что необходимо для функций, работающих только с окнами.gtk_window_set_default_size(GTK_WINDOW(window), 300, 100);
: Задаёт желаемую ширину и высоту окна в пикселях.gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
: Устанавливает начальное положение окна на экране, в данном случае — по центру.g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
: Критически важный момент! Мы подключаем сигнал «destroy» (который испускается, когда окно закрывается пользователем через «крестик» или Alt+F4) к встроенной функции GTKgtk_main_quit()
. Эта функция завершает главный цикл событий GTK, позволяя программе корректно завершиться. Если этого не сделать, закрытие окна не остановит программу.GtkWidget *button = gtk_button_new_with_label("Закрыть");
: Создаёт новую кнопку с текстовой меткой «Закрыть» внутри неё.g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), window);
: Подключаем функциюon_button_clicked
к сигналу «clicked» от нашей кнопки. Когда пользователь нажимает на кнопку, GTK вызываетon_button_clicked
. В качестве user_data (четвёртый аргумент) мы передаём указатель на наше window, чтобы внутри on_button_clicked мы знали, какое окно закрывать.gtk_container_add(GTK_CONTAINER(window), button);
: Добавляет созданную кнопку в окно. В GTK3 большинство контейнеров (включая окна, если они используются как контейнеры для одного виджета) используютgtk_container_add()
.GTK_CONTAINER(window)
— это ещё одно приведение типа, позволяющее работать с окном как с контейнером.gtk_widget_show_all(window);
: Делает окно и все его дочерние элементы (в данном случае, кнопку) видимыми на экране. По умолчанию виджеты создаются невидимыми.gtk_main();
: Главный цикл событий GTK. Эта функция запускает бесконечный цикл, который ждёт событий (кликов, нажатий клавиш, системных сообщений и т.д.) и вызывает соответствующие обработчики. Программа остаётся активной в этом цикле до тех пор, пока не будет вызванаgtk_main_quit()
, обычно в ответ на сигнал «destroy» окна или клик по нашей кнопке.
—
### Компиляция и Запуск
Сохраните код в файл с именем minimal_window.c.
Компиляция:
Для сборки используйте следующую команду в терминале, находясь в директории с файлом:
gcc minimal_window.c -o minimal_window `pkg-config --cflags --libs gtk+-3.0`
Обратите внимание, что мы используем gtk+-3.0 в pkg-config, так как наш код написан для GTK3.
Запуск:
После успешной компиляции вы можете запустить ваше первое GTK-приложение:
./minimal_window
—
### Ожидаемый результат
На вашем рабочем столе откроется новое окно с заголовком «GTK Minimal App».
Внутри этого окна будет расположена кнопка с надписью «Закрыть».
При нажатии на кнопку «Закрыть» (или при закрытии окна стандартным способом, например, через «крестик» в заголовке), программа корректно завершит свою работу, и окно исчезнет.
—
### Дополнительные ресурсы
https://github.com/AIDevelopersMonster/C_GUI_Handbook - Репозиторий с примерами кода из этого руководства.
—