Глава 22: Диалоговые Окна и Окна Сообщений ========================================== В этой главе мы освоим создание **диалоговых окон** в GTK. Диалоги — это временные окна, которые появляются поверх основного приложения для запроса информации, подтверждения действия или отображения важного сообщения. Они критически важны для взаимодействия с пользователем, позволяя запрашивать ввод, выбор файлов, отображать предупреждения, ошибки или просто информационные уведомления. GTK предлагает два основных подхода для создания диалоговых окон: * `GtkMessageDialog`_: Это специализированный и простой в использовании диалог, предназначенный для отображения стандартных сообщений (информация, предупреждение, ошибка, вопрос). Он быстро создается и настраивается для типовых сценариев. * `GtkDialog`_: Это более универсальный и настраиваемый базовый класс для всех диалоговых окон в GTK. Он позволяет создавать собственные диалоги с любым содержимым, заголовком, набором кнопок и поведением. --- ### Основные понятия и функции * **`gtk_message_dialog_new()`**: Создаёт новый `GtkMessageDialog` с заданными параметрами. * **`gtk_dialog_run()`**: Отображает диалог и запускает локальный цикл событий, ожидая действия пользователя. Возвращает ответ пользователя (например, OK, Cancel). * **`gtk_widget_destroy()`**: Удаляет виджет из памяти. **Важно** вызывать для диалогов после `gtk_dialog_run()`. * **`gtk_dialog_new_with_buttons()`**: Создаёт новый `GtkDialog` с заданным заголовком и предустановленными кнопками. * **`gtk_dialog_get_content_area()`**: Получает указатель на область содержимого `GtkDialog`, куда можно добавлять свои виджеты. * **`GTK_DIALOG_DESTROY_WITH_PARENT`**: Флаг для `GtkMessageDialog`, означающий, что диалог будет уничтожен вместе с родительским окном. * **`GTK_DIALOG_MODAL`**: Флаг для `GtkDialog`, делающий его модальным, то есть блокирующим взаимодействие с родительским окном до своего закрытия. * **`GTK_MESSAGE_INFO`, `GTK_MESSAGE_WARNING`, `GTK_MESSAGE_ERROR`, `GTK_MESSAGE_QUESTION`**: Типы сообщений для `GtkMessageDialog`, влияющие на его иконку. * **`GTK_BUTTONS_OK`, `GTK_BUTTONS_OK_CANCEL`, `GTK_BUTTONS_YES_NO`, `GTK_BUTTONS_NONE`**: Предустановленные наборы кнопок для `GtkMessageDialog`. * **`GTK_RESPONSE_OK`, `GTK_RESPONSE_CANCEL`, `GTK_RESPONSE_YES`, `GTK_RESPONSE_NO`**: Возвращаемые значения от `gtk_dialog_run()`, указывающие, какая кнопка была нажата. * **`gtk_label_new()`**: Создаёт новый виджет метки (`GtkLabel`) с заданным текстом. * **`gtk_button_new_with_label()`**: Создаёт новую кнопку (`GtkButton`) с текстовой меткой. --- --- ### Пример 22.1: Использование GtkMessageDialog **Файл:** `message_dialog_example.c` Этот пример демонстрирует, как создать и отобразить стандартное информационное сообщение с помощью `GtkMessageDialog`. Приложение состоит из основного окна с кнопкой. Нажатие этой кнопки вызывает диалоговое окно. .. code-block:: c #include // Подключаем основную библиотеку GTK. /** * @brief Callback-функция, вызываемая при нажатии кнопки в главном окне. * Отвечает за создание и отображение GtkMessageDialog. * * @param widget Указатель на кнопку, которая была нажата. * @param window Указатель на главное окно (родительское окно для диалога), * переданный через параметр `data` при подключении сигнала. */ static void on_button_clicked(GtkWidget *widget, gpointer window) { GtkWidget *dialog; // Декларация указателя на диалоговое окно. // Создаем новый GtkMessageDialog. // Параметры: // 1. GTK_WINDOW(window): Родительское окно для диалога. // Это обеспечивает правильное позиционирование диалога и его уничтожение при закрытии родителя. // 2. GTK_DIALOG_DESTROY_WITH_PARENT: Флаг поведения диалога. // Означает, что диалог будет автоматически уничтожен, если его родительское окно будет закрыто. // 3. GTK_MESSAGE_INFO: Тип сообщения. Определяет иконку, которая будет отображаться в диалоге (информационная). // Другие варианты: GTK_MESSAGE_WARNING, GTK_MESSAGE_ERROR, GTK_MESSAGE_QUESTION. // 4. GTK_BUTTONS_OK: Набор кнопок, которые будут присутствовать в диалоге. // Здесь будет только кнопка "OK". Другие: GTK_BUTTONS_OK_CANCEL, GTK_BUTTONS_YES_NO. // 5. "Это информационное сообщение.": Формат строки сообщения. Работает как printf. dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Это информационное сообщение."); // Запускаем диалог. Эта функция отображает диалог и блокирует // основное окно до тех пор, пока пользователь не закроет диалог (нажав кнопку). // Она возвращает значение GTK_RESPONSE_..., соответствующее нажатой кнопке. // В данном случае, поскольку есть только кнопка "OK", она вернет GTK_RESPONSE_OK. gtk_dialog_run(GTK_DIALOG(dialog)); // Уничтожаем диалог после того, как он был закрыт. // Это освобождает выделенные для него ресурсы. gtk_widget_destroy(dialog); } /** * @brief Главная функция программы. * * Инициализирует GTK, создает основное окно с кнопкой, * которая при нажатии отображает GtkMessageDialog. * * @param argc Количество аргументов командной строки. * @param argv Массив строк аргументов командной строки. * @return Код завершения программы. */ int main(int argc, char *argv[]) { GtkWidget *window; // Указатель на главное окно. GtkWidget *button; // Указатель на кнопку. gtk_init(&argc, &argv); // Инициализация библиотеки GTK. // 1. Создание главного окна. window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "Пример MessageDialog"); gtk_window_set_default_size(GTK_WINDOW(window), 300, 150); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); // Подключаем сигнал "destroy" окна к функции gtk_main_quit. g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); // 2. Создание кнопки. button = gtk_button_new_with_label("Показать сообщение"); // Подключаем сигнал "clicked" кнопки к нашей функции on_button_clicked. // В качестве пользовательских данных (data) передаем указатель на главное окно, // чтобы функция on_button_clicked могла использовать его как родителя для диалога. g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), window); // 3. Добавление кнопки в окно. gtk_container_add(GTK_CONTAINER(window), button); // 4. Отображение всех виджетов и запуск главного цикла GTK. gtk_widget_show_all(window); gtk_main(); return 0; } --- ### Пример 22.2: Создание Кастомного GtkDialog **Файл:** `custom_dialog_example.c` В этом примере мы создаем более гибкий, **пользовательский диалог** с помощью `GtkDialog`. Мы добавляем в него метку с вопросом и две кнопки ("OK" и "Отмена"). Программа отслеживает, какая из кнопок была нажата пользователем, и выводит соответствующее сообщение в консоль. .. code-block:: c #include // Подключаем основную библиотеку GTK. /** * @brief Callback-функция, вызываемая при нажатии кнопки в главном окне. * Отвечает за создание, настройку и отображение кастомного GtkDialog. * * @param widget Указатель на кнопку, которая была нажата. * @param window Указатель на главное окно (родительское окно для диалога). */ static void on_button_clicked(GtkWidget *widget, gpointer window) { GtkWidget *dialog; // Указатель на диалоговое окно. gint result; // Переменная для хранения результата (какая кнопка была нажата). GtkWidget *content_area; // Область содержимого диалога, куда мы добавим нашу метку. GtkWidget *label; // Метка для отображения текста в диалоге. // Создаем новый GtkDialog с предопределенными кнопками. // Параметры: // 1. "Кастомный диалог": Заголовок диалогового окна. // 2. GTK_WINDOW(window): Родительское окно. // 3. GTK_DIALOG_MODAL: Флаг, делающий диалог модальным. Это означает, что // пользователь не сможет взаимодействовать с родительским окном, // пока этот диалог открыт. // 4. "_OK": Текст первой кнопки. Подчеркивание `_` используется для создания мнемонического доступа // (например, Alt+O, если это поддерживается системой). // 5. GTK_RESPONSE_OK: Значение, которое `gtk_dialog_run()` вернет, если будет нажата эта кнопка. // 6. "_Отмена": Текст второй кнопки. // 7. GTK_RESPONSE_CANCEL: Значение, возвращаемое при нажатии этой кнопки. // 8. NULL: Обозначает конец списка кнопок. dialog = gtk_dialog_new_with_buttons("Кастомный диалог", GTK_WINDOW(window), GTK_DIALOG_MODAL, "_OK", GTK_RESPONSE_OK, "_Отмена", GTK_RESPONSE_CANCEL, NULL); // Получаем область содержимого диалога. // Это GtkBox, куда можно добавлять любые виджеты, формируя пользовательский интерфейс диалога. content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); // Создаем метку с вопросом. label = gtk_label_new("Вы хотите продолжить?"); // Добавляем метку в область содержимого диалога. gtk_container_add(GTK_CONTAINER(content_area), label); // Отображаем все виджеты в диалоге (метку и кнопки). gtk_widget_show_all(dialog); // Запускаем диалог и получаем ответ пользователя. // Эта функция блокирует выполнение программы до закрытия диалога. result = gtk_dialog_run(GTK_DIALOG(dialog)); // Анализируем результат, чтобы определить, какая кнопка была нажата. if (result == GTK_RESPONSE_OK) { g_print("Пользователь нажал OK\n"); } else if (result == GTK_RESPONSE_CANCEL) { g_print("Пользователь нажал Отмена\n"); } else { // Может быть GTK_RESPONSE_NONE, если диалог был закрыт другим способом (например, кнопкой закрытия окна). g_print("Диалог был закрыт без явного выбора OK/Отмена\n"); } // Уничтожаем диалог после его использования. // Это освобождает ресурсы, которые он занимал. gtk_widget_destroy(dialog); } /** * @brief Главная функция программы. * * Инициализирует GTK, создает основное окно с кнопкой, * которая при нажатии отображает кастомный GtkDialog. * * @param argc Количество аргументов командной строки. * @param argv Массив строк аргументов командной строки. * @return Код завершения программы. */ int main(int argc, char *argv[]) { GtkWidget *window; // Указатель на главное окно. GtkWidget *button; // Указатель на кнопку. gtk_init(&argc, &argv); // Инициализация библиотеки GTK. // 1. Создание главного окна. window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "Пример Кастомного Диалога"); gtk_window_set_default_size(GTK_WINDOW(window), 350, 150); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); // Подключаем сигнал "destroy" окна. g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); // 2. Создание кнопки. button = gtk_button_new_with_label("Открыть диалог"); // Подключаем сигнал "clicked" кнопки к нашей функции on_button_clicked, // передавая главное окно в качестве пользовательских данных. g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), window); // 3. Добавление кнопки в окно. gtk_container_add(GTK_CONTAINER(window), button); // 4. Отображение всех виджетов и запуск главного цикла GTK. gtk_widget_show_all(window); gtk_main(); return 0; } --- Компиляция и Запуск Примеров ----------------------------- Сохраните каждый пример кода в соответствующий файл: `message_dialog_example.c` и `custom_dialog_example.c`. ### Компиляция: Для сборки программ используйте следующие команды в терминале, находясь в директории с исходными файлами. Убедитесь, что у вас установлен GTK 3. .. code-block:: bash # Для примера с GtkMessageDialog: gcc message_dialog_example.c -o message_dialog_example `pkg-config --cflags --libs gtk+-3.0` # Для примера с Кастомным GtkDialog: gcc custom_dialog_example.c -o custom_dialog_example `pkg-config --cflags --libs gtk+-3.0` ### Запуск: После успешной компиляции вы можете запустить каждое приложение: .. code-block:: bash # Для примера с GtkMessageDialog: ./message_dialog_example # Для примера с Кастомным GtkDialog: ./custom_dialog_example --- Ожидаемый Результат ------------------- * **`message_dialog_example`**: * Откроется основное окно с заголовком **"Пример MessageDialog"** и одной кнопкой **"Показать сообщение"**. * При нажатии на эту кнопку появится **всплывающее диалоговое окно** с заголовком, иконкой информации, текстом "Это информационное сообщение." и одной кнопкой **"OK"**. * После нажатия "OK" диалог закроется, и управление вернется к основному окну. * **`custom_dialog_example`**: * Откроется основное окно с заголовком **"Пример Кастомного Диалога"** и кнопкой **"Открыть диалог"**. * При нажатии на эту кнопку появится **модальное диалоговое окно** с заголовком **"Кастомный диалог"**. * Внутри диалога будет отображаться текст **"Вы хотите продолжить?"** и две кнопки: **"OK"** и **"Отмена"**. * Если вы нажмете **"OK"**, диалог закроется, и в консоли появится сообщение **"Пользователь нажал OK"**. * Если вы нажмете **"Отмена"**, диалог закроется, и в консоли появится сообщение **"Пользователь нажал Отмена"**. --- Дополнительные Ресурсы ----------------------- * `GtkDialog`_ * `GtkMessageDialog`_ * `GtkButtonsType`_ * `GtkResponseType`_ * `C_GUI_Handbook GitHub`_ .. _GtkDialog: https://docs.gtk.org/gtk3/class.Dialog.html .. _GtkMessageDialog: https://docs.gtk.org/gtk3/class.MessageDialog.html .. _GtkButtonsType: https://docs.gtk.org/gtk3/enum.ButtonsType.html .. _GtkResponseType: https://docs.gtk.org/gtk3/enum.ResponseType.html .. _C_GUI_Handbook GitHub: https://github.com/AIDevelopersMonster/C_GUI_Handbook ---