Глава 14: Первый GTK-проект — Окно с кнопкой ============================================= В этой главе мы создадим простейшее полноценное приложение с использованием библиотеки **GTK** — окно с кнопкой **«Закрыть»**, при нажатии на которую программа завершает работу. Это первый практический шаг в создании интерактивных GUI-приложений с использованием **GTK** и языка **C** на **Raspberry Pi Zero 2 W** (или любой другой системе с установленной GTK3). Основные цели этой главы: -------------------------- * **Понять базовую структуру** минимального GTK-приложения. * **Создать основное окно** приложения. * **Добавить интерактивный элемент** — кнопку — в окно. * **Обработать событие** нажатия на кнопку для завершения работы программы. * **Скомпилировать и запустить** ваше первое GUI-приложение. --- ### Пример кода: Окно с кнопкой "Закрыть" Название исходного файла: `minimal_window.c` В этом примере мы создадим окно, добавим в него кнопку и научим кнопку закрывать приложение при нажатии. .. code-block:: c #include // Подключаем основную библиотеку 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_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) к встроенной функции GTK ``gtk_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`. **Компиляция:** Для сборки используйте следующую команду в терминале, находясь в директории с файлом: .. code-block:: bash gcc minimal_window.c -o minimal_window `pkg-config --cflags --libs gtk+-3.0` Обратите внимание, что мы используем `gtk+-3.0` в `pkg-config`, так как наш код написан для GTK3. **Запуск:** После успешной компиляции вы можете запустить ваше первое GTK-приложение: .. code-block:: bash ./minimal_window --- ### Ожидаемый результат * На вашем рабочем столе откроется новое окно с заголовком "GTK Minimal App". * Внутри этого окна будет расположена кнопка с надписью **«Закрыть»**. * При нажатии на кнопку **«Закрыть»** (или при закрытии окна стандартным способом, например, через "крестик" в заголовке), программа корректно завершит свою работу, и окно исчезнет. --- ### Дополнительные ресурсы * `https://github.com/AIDevelopersMonster/C_GUI_Handbook` - Репозиторий с примерами кода из этого руководства. ---