6. Глава 18: Элементы Пользовательского Ввода

В этой главе мы сосредоточимся на ключевых элементах пользовательского ввода в GTK, которые позволяют вашему приложению получать информацию от пользователя. Мы рассмотрим три основных виджета:

  • doc:

    GtkEntry <https://docs.gtk.org/gtk3/class.Entry.html>однострочное текстовое поле для ввода текста.

  • doc:

    GtkSpinButton <https://docs.gtk.org/gtk3/class.SpinButton.html>числовой спиннер для ввода чисел в заданном диапазоне.

  • doc:

    GtkCheckButton <https://docs.gtk.org/gtk3/class.CheckButton.html>чекбокс (флажок) для переключения логических состояний (включено/выключено).

Эти виджеты являются основой для создания интерактивных форм, настроек и других элементов управления, где требуется получить данные от пользователя.

6.1. GtkEntry: Однострочное Текстовое Поле

GtkEntry — это универсальный виджет для ввода и отображения однострочного текста. Он широко используется для полей ввода имени пользователя, пароля, пути к файлу, поисковых запросов и других текстовых данных.

### Основные функции и свойства GtkEntry:

  • gtk_entry_new(): Создаёт новый пустой GtkEntry.

  • gtk_entry_new_with_buffer(GtkEntryBuffer *buffer): Создаёт GtkEntry с привязанным буфером, что даёт больше контроля над текстом.

  • gtk_entry_set_text(GtkEntry *entry, const gchar *text): Устанавливает текст в поле ввода.

  • gtk_entry_get_text(GtkEntry *entry): Получает текущий текст из поля ввода. Возвращаемая строка принадлежит виджету, её не нужно освобождать, но она станет недействительной после изменения текста.

  • gtk_entry_set_visibility(GtkEntry *entry, gboolean visible): Управляет видимостью текста (например, для полей пароля). FALSE скрывает текст, отображая символы-заполнители.

  • gtk_entry_set_placeholder_text(GtkEntry *entry, const gchar *text): Устанавливает текст-подсказку, который отображается, когда поле пустое и не в фокусе.

### Сигналы GtkEntry:

  • "changed": Испускается при любом изменении текста в поле ввода.

  • "activate": Испускается, когда пользователь нажимает Enter в поле ввода (часто используется для подтверждения ввода).

6.2. GtkSpinButton: Числовой Спиннер

GtkSpinButton — это удобный виджет для ввода числовых значений в определённом диапазоне. Он состоит из текстового поля и двух кнопок (стрелок) для увеличения или уменьшения значения. Идеально подходит для ввода количества, уровня громкости, выбора номера страницы и т.д.

GtkSpinButton тесно связан с объектом GtkAdjustment, который определяет диапазон значений, шаг изменения и текущее значение.

### Основные функции GtkSpinButton:

  • gtk_adjustment_new(gdouble value, gdouble lower, gdouble upper, gdouble step_increment, gdouble page_increment, gdouble page_size): Создаёт новый объект GtkAdjustment.
    • value: Начальное значение.

    • lower: Минимально допустимое значение.

    • upper: Максимально допустимое значение.

    • step_increment: Шаг изменения при нажатии на стрелки (один щелчок).

    • page_increment: Шаг изменения при нажатии PageUp/PageDown (или Shift+стрелки).

    • page_size: Обычно 0 для GtkSpinButton.

  • gtk_spin_button_new(GtkAdjustment *adjustment, gdouble climb_rate, guint digits): Создаёт новый GtkSpinButton.
    • adjustment: Объект GtkAdjustment, управляющий значениями.

    • climb_rate: Коэффициент ускорения изменения значения при удержании кнопки (обычно 1.0).

    • digits: Количество знаков после запятой для отображения. 0 для целых чисел.

  • gtk_spin_button_get_value_as_int(GtkSpinButton *spin_button): Получает текущее значение спиннера как целое число.

  • gtk_spin_button_get_value(GtkSpinButton *spin_button): Получает текущее значение спиннера как gdouble.

  • gtk_spin_button_set_value(GtkSpinButton *spin_button, gdouble value): Устанавливает значение спиннера.

### Сигналы GtkSpinButton:

  • "value-changed": Испускается при любом изменении значения в спиннере (как от стрелок, так и от ручного ввода).

6.3. GtkCheckButton: Флажок (Чекбокс)

GtkCheckButton — это простой виджет-переключатель, который имеет два состояния: отмечен (включен) или не отмечен (выключен). Он используется для представления логических опций, которые пользователь может включить или выключить.

### Основные функции GtkCheckButton:

  • gtk_check_button_new(): Создаёт новый пустой GtkCheckButton.

  • gtk_check_button_new_with_label(const gchar *label): Создаёт GtkCheckButton с текстовой меткой рядом.

  • gtk_check_button_new_with_mnemonic(const gchar *label): Создаёт GtkCheckButton с меткой, где подчёркнутый символ может быть использован для активации с клавиатуры (акселератор).

  • gtk_toggle_button_get_active(GtkToggleButton *button): Получает текущее состояние чекбокса (TRUE если отмечен, FALSE если нет). GtkCheckButton является наследником GtkToggleButton.

  • gtk_toggle_button_set_active(GtkToggleButton *button, gboolean is_active): Устанавливает состояние чекбокса программно.

### Сигналы GtkCheckButton:

  • "toggled": Испускается каждый раз, когда состояние чекбокса меняется (пользователь отмечает или снимает отметку).

6.4. Обработка Событий: Общие Принципы

Для всех этих виджетов, как и для GtkButton, основным механизмом взаимодействия является система сигналов и слотов (callbacks). Вы подключаете (g_signal_connect) свои функции-обработчики (callbacks) к определённым сигналам, которые испускают виджеты при определённых действиях пользователя.

Пример подключения сигналов:

g_signal_connect(entry, "changed", G_CALLBACK(on_entry_changed), NULL);
g_signal_connect(spin, "value-changed", G_CALLBACK(on_spin_changed), NULL);
g_signal_connect(check, "toggled", G_CALLBACK(on_check_toggled), NULL);

### Пример 18.1: Окно с текстовым полем, спиннером и чекбоксом

Название исходного файла: input_widgets_example.c

Эта программа демонстрирует создание окна с тремя описанными выше элементами ввода. Все они размещены вертикально с помощью GtkBox, а их изменения отслеживаются через соответствующие callback-функции, выводящие информацию в консоль.

#include <gtk/gtk.h> // Подключаем основную библиотеку GTK.

/**
 * @brief Обработчик сигнала "changed" для GtkEntry.
 * Вызывается каждый раз при изменении текста в GtkEntry.
 * @param entry Указатель на GtkEntry, который испустил сигнал.
 * @param user_data Пользовательские данные (в данном случае NULL).
 */
void on_entry_changed(GtkEntry *entry, gpointer user_data) {
    // Получаем текущий текст из поля ввода.
    const gchar *text = gtk_entry_get_text(entry);
    g_print("Entry changed: %s\n", text);
}

/**
 * @brief Обработчик сигнала "value-changed" для GtkSpinButton.
 * Вызывается каждый раз при изменении числового значения в GtkSpinButton.
 * @param spin Указатель на GtkSpinButton, который испустил сигнал.
 * @param user_data Пользовательские данные (в данном случае NULL).
 */
void on_spin_changed(GtkSpinButton *spin, gpointer user_data) {
    // Получаем текущее значение спиннера как целое число.
    gint value = gtk_spin_button_get_value_as_int(spin);
    g_print("Spin value: %d\n", value);
}

/**
 * @brief Обработчик сигнала "toggled" для GtkCheckButton.
 * Вызывается каждый раз при изменении состояния чекбокса (отмечен/не отмечен).
 * @param check Указатель на GtkToggleButton (базовый класс для GtkCheckButton),
 * который испустил сигнал.
 * @param user_data Пользовательские данные (в данном случае NULL).
 */
void on_check_toggled(GtkToggleButton *check, gpointer user_data) {
    // Проверяем, активно ли (отмечено) состояние чекбокса.
    gboolean active = gtk_toggle_button_get_active(check);
    g_print("Check toggled: %s\n", active ? "ON" : "OFF"); // Выводим "ON" или "OFF"
}

/**
 * @brief Главная функция программы, точка входа.
 * Инициализирует GTK, создает окно, добавляет в него элементы ввода
 * и запускает главный цикл событий GTK.
 * @param argc Количество аргументов командной строки.
 * @param argv Массив строк аргументов командной строки.
 * @return Код завершения программы.
 */
int main(int argc, char *argv[]) {
    // Инициализация GTK. Всегда вызывается первой.
    gtk_init(&argc, &argv);

    // 1. Создание главного окна приложения.
    GtkWidget *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" для корректного завершения приложения.
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    // 2. Создание вертикального контейнера GtkBox.
    // Используем GtkBox для размещения всех виджетов вертикально,
    // с отступом в 10 пикселей между ними.
    GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
    // Добавляем GtkBox в главное окно.
    gtk_container_add(GTK_CONTAINER(window), vbox);

    // 3. Создание GtkEntry (текстового поля).
    GtkWidget *entry = gtk_entry_new();
    // Устанавливаем текст-заполнитель, который виден, когда поле пустое.
    gtk_entry_set_placeholder_text(GTK_ENTRY(entry), "Введите ваше имя...");
    // Добавляем GtkEntry в вертикальный GtkBox.
    gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0);
    // Подключаем обработчик на изменение текста.
    g_signal_connect(entry, "changed", G_CALLBACK(on_entry_changed), NULL);

    // 4. Создание GtkSpinButton (числового спиннера).
    // Сначала создаем объект GtkAdjustment, который определяет диапазон и шаг.
    // (начальное значение, нижний предел, верхний предел, шаг при клике, шаг при PageUp/Down, размер страницы)
    GtkAdjustment *adj = gtk_adjustment_new(0, 0, 100, 1, 10, 0);
    // Создаем спиннер, привязывая его к созданному GtkAdjustment.
    // 1.0 - скорость "взбирания" при удержании кнопки, 0 - количество знаков после запятой (целые числа).
    GtkWidget *spin = gtk_spin_button_new(adj, 1.0, 0);
    // Добавляем спиннер в вертикальный GtkBox.
    gtk_box_pack_start(GTK_BOX(vbox), spin, FALSE, FALSE, 0);
    // Подключаем обработчик на изменение значения.
    g_signal_connect(spin, "value-changed", G_CALLBACK(on_spin_changed), NULL);

    // 5. Создание GtkCheckButton (флажка/чекбокса).
    GtkWidget *check = gtk_check_button_new_with_label("Я согласен с условиями");
    // Устанавливаем начальное состояние чекбокса (например, изначально не отмечен).
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
    // Добавляем чекбокс в вертикальный GtkBox.
    gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0);
    // Подключаем обработчик на изменение состояния.
    g_signal_connect(check, "toggled", G_CALLBACK(on_check_toggled), NULL);

    // 6. Отображение всех виджетов в окне.
    gtk_widget_show_all(window);

    // 7. Запуск главного цикла событий GTK.
    // Приложение будет ждать действий пользователя, пока не будет закрыто.
    gtk_main();

    return 0; // Возвращаем код успешного завершения.
}

6.5. Компиляция и Запуск

Сохраните код выше в файл с именем input_widgets_example.c.

### Компиляция:

Для сборки программы используйте следующую команду в терминале, находясь в директории с исходным файлом:

gcc input_widgets_example.c -o input_widgets_example `pkg-config --cflags --libs gtk+-3.0`

### Запуск:

После успешной компиляции вы можете запустить ваше приложение:

./input_widgets_example

6.6. Ожидаемый результат

При запуске программы вы увидите окно с заголовком «Пример Полей Ввода». Внутри окна будут расположены вертикально следующие элементы:

  • Текстовое поле (`GtkEntry`): Будет отображаться текст-подсказка «Введите ваше имя…». При вводе текста, каждое изменение символа будет выводиться в консоль.

  • Числовой спиннер (`GtkSpinButton`): Будет показывать числовое значение (изначально 0), которое можно изменять с помощью стрелок вверх/вниз или вводя число вручную. Каждое изменение значения будет выводиться в консоль.

  • Чекбокс (`GtkCheckButton`): Рядом с ним будет метка «Я согласен с условиями». Изначально чекбокс будет не отмечен. При клике на него, его состояние будет меняться между «ON» и «OFF», и это изменение будет выводиться в консоль.

6.7. Дополнительные материалы

  • GtkEntry: Официальная документация GtkEntry.

  • GtkSpinButton: Официальная документация GtkSpinButton.

  • GtkCheckButton: Официальная документация GtkCheckButton.

  • GtkAdjustment: Официальная документация GtkAdjustment.

  • C_GUI_Handbook GitHub - Репозиторий с примерами кода из этого руководства.

6.8. Навигация

  • doc:

    Глава 17: Гибкая Компоновка с GtkGrid <chapter17>

  • doc:

    Глава 19: Выпадающие списки и радиокнопки <chapter19>