Глава 21: Меню Приложений (GtkMenuBar, GtkMenu, GtkMenuItem) ============================================================ В этой главе мы научимся добавлять к нашему GTK-приложению **меню**, которое является фундаментальной частью классического графического интерфейса. Меню предоставляет пользователю интуитивно понятный доступ к часто используемым действиям, таким как "Открыть", "Сохранить", "Выход", а также к различным настройкам и функциям приложения. Мы рассмотрим иерархию и взаимодействие следующих ключевых компонентов меню: * `GtkMenuBar`_: Горизонтальная панель меню, которая обычно располагается в верхней части окна. Она содержит основные пункты меню (например, "Файл", "Правка", "Вид"). * `GtkMenuItem`_: Отдельный элемент меню. Это может быть как корневой пункт в `GtkMenuBar` (например, "Файл"), так и пункт внутри выпадающего подменю (например, "Открыть", "Сохранить"). `GtkMenuItem` может также содержать подменю. * `GtkMenu`_: Выпадающее подменю, которое появляется при активации `GtkMenuItem`. Оно содержит набор других `GtkMenuItem`, которые выполняют конкретные действия. * **Обработка сигналов активации пунктов меню**: Как подключить функции-обработчики к пунктам меню, чтобы они выполняли желаемые действия при клике пользователя. --- ### Пример 21.1: Простейшее Меню ("Файл" -> "Выход") **Файл:** `menu_basic_example.c` Этот пример демонстрирует создание минимального меню: окно с панелью меню, на которой расположен пункт "Файл". При нажатии на "Файл" появляется подменю с единственным пунктом "Выход". Выбор "Выход" завершает работу приложения. .. code-block:: c #include // Подключаем основную библиотеку 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` Этот пример расширяет предыдущий, добавляя несколько пунктов в подменю "Файл" ("Открыть", "Сохранить", "Выход") и используя разделитель между ними для лучшей организации. Каждый пункт меню связан со своим обработчиком. .. code-block:: c #include // Подключаем основную библиотеку 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; } --- Компиляция и Запуск Примеров ----------------------------- Сохраните каждый пример кода в соответствующий файл: `menu_basic_example.c` и `menu_multiple_example.c`. ### Компиляция: Для сборки программ используйте следующие команды в терминале, находясь в директории с исходными файлами. Убедитесь, что у вас установлен GTK 3. .. code-block:: bash # Для Простейшего Меню: 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` ### Запуск: После успешной компиляции вы можете запустить каждое приложение: .. code-block:: bash # Для Простейшего Меню: ./menu_basic_example # Для Меню с Несколькими Пунктами: ./menu_multiple_example --- Ожидаемый Результат ------------------- * **`menu_basic_example`**: * Откроется небольшое окно с заголовком **"Пример Простейшего Меню"**. * В верхней части окна будет видна **панель меню** с одним пунктом **"Файл"**. * При клике на **"Файл"** откроется выпадающее подменю, содержащее только пункт **"Выход"**. * Выбор пункта **"Выход"** приведёт к закрытию окна и завершению работы программы. В консоли, из которой вы запустили программу, появится сообщение "Выход из приложения". * **`menu_multiple_example`**: * Откроется окно с заголовком **"Меню с Несколькими Пунктами"**. * В верхней части окна также будет **панель меню** с пунктом **"Файл"**. * При клике на **"Файл"** откроется подменю, содержащее пункты **"Открыть"**, **"Сохранить"**, горизонтальный **разделитель**, и **"Выход"**. * Выбор **"Открыть"** или **"Сохранить"** выведет соответствующее сообщение в консоль. * Выбор **"Выход"** закроет приложение, как и в предыдущем примере. --- Дополнительные Ресурсы ----------------------- * `GtkMenuBar`_ * `GtkMenuItem`_ * `GtkMenu`_ * `GtkMenuShell`_ * `GtkSeparatorMenuItem`_ * `C_GUI_Handbook GitHub`_ .. _GtkMenuBar: https://docs.gtk.org/gtk3/class.MenuBar.html .. _GtkMenuItem: https://docs.gtk.org/gtk3/class.MenuItem.html .. _GtkMenu: https://docs.gtk.org/gtk3/class.Menu.html .. _GtkMenuShell: https://docs.gtk.org/gtk3/class.MenuShell.html .. _GtkSeparatorMenuItem: https://docs.gtk.org/gtk3/class.SeparatorMenuItem.html .. _C_GUI_Handbook GitHub: https://github.com/AIDevelopersMonster/C_GUI_Handbook ---