10. Глава 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) с текстовой меткой.
10.1. —
### Пример 22.1: Использование GtkMessageDialog
Файл: message_dialog_example.c
Этот пример демонстрирует, как создать и отобразить стандартное информационное сообщение с помощью GtkMessageDialog. Приложение состоит из основного окна с кнопкой. Нажатие этой кнопки вызывает диалоговое окно.
#include <gtk/gtk.h> // Подключаем основную библиотеку 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» и «Отмена»). Программа отслеживает, какая из кнопок была нажата пользователем, и выводит соответствующее сообщение в консоль.
#include <gtk/gtk.h> // Подключаем основную библиотеку 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;
}
—
10.2. Компиляция и Запуск Примеров
Сохраните каждый пример кода в соответствующий файл: message_dialog_example.c и custom_dialog_example.c.
### Компиляция:
Для сборки программ используйте следующие команды в терминале, находясь в директории с исходными файлами. Убедитесь, что у вас установлен GTK 3.
# Для примера с 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`
### Запуск:
После успешной компиляции вы можете запустить каждое приложение:
# Для примера с GtkMessageDialog:
./message_dialog_example
# Для примера с Кастомным GtkDialog:
./custom_dialog_example
—
10.3. Ожидаемый Результат
- `message_dialog_example`:
Откроется основное окно с заголовком «Пример MessageDialog» и одной кнопкой «Показать сообщение».
При нажатии на эту кнопку появится всплывающее диалоговое окно с заголовком, иконкой информации, текстом «Это информационное сообщение.» и одной кнопкой «OK».
После нажатия «OK» диалог закроется, и управление вернется к основному окну.
- `custom_dialog_example`:
Откроется основное окно с заголовком «Пример Кастомного Диалога» и кнопкой «Открыть диалог».
При нажатии на эту кнопку появится модальное диалоговое окно с заголовком «Кастомный диалог».
Внутри диалога будет отображаться текст «Вы хотите продолжить?» и две кнопки: «OK» и «Отмена».
Если вы нажмете «OK», диалог закроется, и в консоли появится сообщение «Пользователь нажал OK».
Если вы нажмете «Отмена», диалог закроется, и в консоли появится сообщение «Пользователь нажал Отмена».
—
10.4. Дополнительные Ресурсы
—