9. Глава 21: Меню Приложений (GtkMenuBar, GtkMenu, GtkMenuItem)
В этой главе мы научимся добавлять к нашему GTK-приложению меню, которое является фундаментальной частью классического графического интерфейса. Меню предоставляет пользователю интуитивно понятный доступ к часто используемым действиям, таким как «Открыть», «Сохранить», «Выход», а также к различным настройкам и функциям приложения.
Мы рассмотрим иерархию и взаимодействие следующих ключевых компонентов меню:
GtkMenuBar: Горизонтальная панель меню, которая обычно располагается в верхней части окна. Она содержит основные пункты меню (например, «Файл», «Правка», «Вид»).
GtkMenuItem: Отдельный элемент меню. Это может быть как корневой пункт в GtkMenuBar (например, «Файл»), так и пункт внутри выпадающего подменю (например, «Открыть», «Сохранить»). GtkMenuItem может также содержать подменю.
GtkMenu: Выпадающее подменю, которое появляется при активации GtkMenuItem. Оно содержит набор других GtkMenuItem, которые выполняют конкретные действия.
Обработка сигналов активации пунктов меню: Как подключить функции-обработчики к пунктам меню, чтобы они выполняли желаемые действия при клике пользователя.
—
### Пример 21.1: Простейшее Меню («Файл» -> «Выход»)
Файл: menu_basic_example.c
Этот пример демонстрирует создание минимального меню: окно с панелью меню, на которой расположен пункт «Файл». При нажатии на «Файл» появляется подменю с единственным пунктом «Выход». Выбор «Выход» завершает работу приложения.
#include <gtk/gtk.h> // Подключаем основную библиотеку GTK.
/**
* @brief Callback-функция, вызываемая при активации пункта меню "Выход".
*
* @param widget Указатель на виджет, который сгенерировал сигнал (в данном случае GtkMenuItem).
* @param data Дополнительные данные, переданные при подключении сигнала (NULL в этом примере).
*/
static void on_menu_item_activate(GtkWidget *widget, gpointer data) {
g_print("Выход из приложения\n"); // Печатаем сообщение в консоль.
gtk_main_quit(); // Завершаем главный цикл GTK, что закрывает приложение.
}
/**
* @brief Главная функция программы.
*
* Инициализирует GTK, создает окно и добавляет к нему простейшее меню.
*
* @param argc Количество аргументов командной строки.
* @param argv Массив строк аргументов командной строки.
* @return Код завершения программы.
*/
int main(int argc, char *argv[]) {
GtkWidget *window; // Основное окно приложения.
GtkWidget *vbox; // Контейнер GtkBox для вертикального размещения виджетов.
GtkWidget *menubar; // Горизонтальная панель меню (GtkMenuBar).
GtkWidget *file_menu; // Подменю "Файл" (GtkMenu).
GtkWidget *file_item; // Пункт меню "Файл" (GtkMenuItem), который открывает file_menu.
GtkWidget *exit_item; // Пункт меню "Выход" (GtkMenuItem).
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), 300, 200); // Устанавливаем размер по умолчанию.
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. Создание главного контейнера для окна.
// GtkBox с вертикальной ориентацией и без промежутков между виджетами.
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add(GTK_CONTAINER(window), vbox); // Добавляем vbox в окно.
// 3. Создание компонентов меню.
menubar = gtk_menu_bar_new(); // Создаем пустую панель меню.
file_menu = gtk_menu_new(); // Создаем пустое подменю для пункта "Файл".
// Создаем пункты меню с текстовыми метками.
file_item = gtk_menu_item_new_with_label("Файл");
exit_item = gtk_menu_item_new_with_label("Выход");
// 4. Сборка меню.
// Добавляем 'exit_item' в 'file_menu'. GtkMenu является GtkMenuShell.
gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), exit_item);
// Связываем 'file_menu' как подменю для 'file_item'.
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_item), file_menu);
// Добавляем 'file_item' (который теперь содержит подменю) в 'menubar'.
// GtkMenuBar также является GtkMenuShell.
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file_item);
// 5. Размещение панели меню в окне.
// Размещаем 'menubar' в верхней части 'vbox'.
// FALSE, FALSE: не расширять и не заполнять доступное пространство.
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
// 6. Подключение сигнала к пункту меню "Выход".
// При активации (клике) 'exit_item' будет вызвана функция 'on_menu_item_activate'.
g_signal_connect(exit_item, "activate", G_CALLBACK(on_menu_item_activate), NULL);
// 7. Отображение всех виджетов в окне.
gtk_widget_show_all(window);
// 8. Запуск главного цикла событий GTK.
gtk_main();
return 0; // Возвращаем 0, если программа завершилась успешно.
}
—
### Пример 21.2: Меню с Несколькими Пунктами и Разделителем
Файл: menu_multiple_example.c
Этот пример расширяет предыдущий, добавляя несколько пунктов в подменю «Файл» («Открыть», «Сохранить», «Выход») и используя разделитель между ними для лучшей организации. Каждый пункт меню связан со своим обработчиком.
#include <gtk/gtk.h> // Подключаем основную библиотеку GTK.
/**
* @brief Callback-функция для пункта меню "Открыть".
*/
static void on_open(GtkWidget *widget, gpointer data) {
g_print("Открытие файла...\n"); // Вывод сообщения в консоль.
}
/**
* @brief Callback-функция для пункта меню "Сохранить".
*/
static void on_save(GtkWidget *widget, gpointer data) {
g_print("Сохранение файла...\n"); // Вывод сообщения в консоль.
}
/**
* @brief Callback-функция для пункта меню "Выход".
* Завершает работу приложения.
*/
static void on_quit(GtkWidget *widget, gpointer data) {
gtk_main_quit(); // Завершаем главный цикл GTK.
}
/**
* @brief Главная функция программы.
*
* Инициализирует GTK, создает окно и добавляет к нему меню с несколькими пунктами.
*
* @param argc Количество аргументов командной строки.
* @param argv Массив строк аргументов командной строки.
* @return Код завершения программы.
*/
int main(int argc, char *argv[]) {
GtkWidget *window; // Основное окно.
GtkWidget *vbox; // Вертикальный контейнер.
GtkWidget *menubar; // Панель меню.
GtkWidget *file_menu; // Подменю "Файл".
GtkWidget *file_item; // Пункт меню "Файл".
GtkWidget *open_item; // Пункт меню "Открыть".
GtkWidget *save_item; // Пункт меню "Сохранить".
GtkWidget *separator; // Разделитель в меню.
GtkWidget *exit_item; // Пункт меню "Выход".
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), 400, 200);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
// 2. Создание вертикального контейнера и добавление его в окно.
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
// 3. Создание панели меню и подменю "Файл".
menubar = gtk_menu_bar_new();
file_menu = gtk_menu_new();
// 4. Создание пунктов меню.
file_item = gtk_menu_item_new_with_label("Файл");
open_item = gtk_menu_item_new_with_label("Открыть");
save_item = gtk_menu_item_new_with_label("Сохранить");
separator = gtk_separator_menu_item_new(); // Создаем горизонтальный разделитель.
exit_item = gtk_menu_item_new_with_label("Выход");
// 5. Добавление пунктов в подменю "Файл".
// Порядок добавления определяет порядок их отображения.
gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), open_item);
gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), save_item);
gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), separator); // Добавляем разделитель.
gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), exit_item);
// 6. Связывание подменю "Файл" с пунктом "Файл" и добавление его в панель меню.
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_item), file_menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file_item);
// 7. Размещение панели меню в вертикальном контейнере.
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
// 8. Подключение callback-функций к пунктам меню.
g_signal_connect(open_item, "activate", G_CALLBACK(on_open), NULL);
g_signal_connect(save_item, "activate", G_CALLBACK(on_save), NULL);
g_signal_connect(exit_item, "activate", G_CALLBACK(on_quit), NULL);
// 9. Отображение всех виджетов и запуск главного цикла.
gtk_widget_show_all(window);
gtk_main();
return 0;
}
—
9.1. Компиляция и Запуск Примеров
Сохраните каждый пример кода в соответствующий файл: menu_basic_example.c и menu_multiple_example.c.
### Компиляция:
Для сборки программ используйте следующие команды в терминале, находясь в директории с исходными файлами. Убедитесь, что у вас установлен GTK 3.
# Для Простейшего Меню:
gcc menu_basic_example.c -o menu_basic_example `pkg-config --cflags --libs gtk+-3.0`
# Для Меню с Несколькими Пунктами:
gcc menu_multiple_example.c -o menu_multiple_example `pkg-config --cflags --libs gtk+-3.0`
### Запуск:
После успешной компиляции вы можете запустить каждое приложение:
# Для Простейшего Меню:
./menu_basic_example
# Для Меню с Несколькими Пунктами:
./menu_multiple_example
—
9.2. Ожидаемый Результат
- `menu_basic_example`:
Откроется небольшое окно с заголовком «Пример Простейшего Меню».
В верхней части окна будет видна панель меню с одним пунктом «Файл».
При клике на «Файл» откроется выпадающее подменю, содержащее только пункт «Выход».
Выбор пункта «Выход» приведёт к закрытию окна и завершению работы программы. В консоли, из которой вы запустили программу, появится сообщение «Выход из приложения».
- `menu_multiple_example`:
Откроется окно с заголовком «Меню с Несколькими Пунктами».
В верхней части окна также будет панель меню с пунктом «Файл».
При клике на «Файл» откроется подменю, содержащее пункты «Открыть», «Сохранить», горизонтальный разделитель, и «Выход».
Выбор «Открыть» или «Сохранить» выведет соответствующее сообщение в консоль.
Выбор «Выход» закроет приложение, как и в предыдущем примере.
—
9.3. Дополнительные Ресурсы
—