#include <curses.h>
WINDOW *subwin(WINDOW *parent, int num_of_lines, int num_of_cols,
int start_y, int start_x);
int delwin(WINDOW *window_to_delete);
У функции subwin почти такой же список параметров, как у функции newwin, и удаляются вложенные окна так же, как другие окна с помощью вызова delwin. Для записи во вложенные окна, как и в новые окна, вы можете применять ряд функций mvw. На самом деле большую часть времени вложенные окна ведут себя почти так же, как новые окна, но есть одно важное отличие: подокна самостоятельно не хранят отдельный набор экранных символов; они используют ту же область хранения символов, что и родительское окно, заданное при создании вложенного окна. Это означает, что любые изменения, сделанные во вложенном окне, вносятся и в лежащее в основании родительское окно, поэтому, когда подокно удаляется, экран не меняется.
На первый взгляд вложенные окна кажутся бесполезным экспериментом. Почему не изменять просто родительское окно? Основная сфера их применения — предоставление простого способа прокрутки другого окна. Потребность в прокрутке небольшой области экрана удивительно часто возникает при написании программ с использованием curses. Создав вложенное окно и прокручивая его, вы добьетесь желаемого результата.
Одно ограничение, накладываемое на применение вложенных окон, заключается в необходимости перед обновлением экрана вызвать в приложении функцию touchwin для родительского окна.
Выполните упражнение 6.5.
Теперь, когда вы познакомились с новыми функциями, этот короткий пример покажет, как они действуют и чем отличаются от функций окна, применявшихся ранее.
1. Начальная секция кода программы subscl.c инициализирует отображение базового окна с некоторым текстом:
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
int main() {
WINDOW *sub_window_ptr;
int x_loop;
int y_loop;
int counter;
char a_letter = '1';
initscr();
for (y_loop = 0; y_loop < LINES - 1; y_loop++) {
for (x_loop = 0; x_loop < COLS - 1; x_loop++) {
mvwaddch(stdscr, y_loop, x_loop, a_letter);
a_letter++;
if (a_letter > '9') a_letter = '1';
}
}
2. Теперь создайте новое подокно с прокруткой. Как рекомендовалось, вам следует перед обновлением экрана "коснуться" родительского окна:
ub_window_ptr = subwin(stdscr, 10, 20, 10, 10);
scrollok(sub_window_ptr, 1);
touchwin(stdscr);
refresh();
sleep(1);
3. Сотрите содержимое вложенного окна, выведите в нем текст и обновите его. Прокрутка текста обеспечивается циклом:
werase(sub_window_ptr);
mvwprintw(sub_window_ptr, 2, 0, "%s", "This window will now scroll");
wrefresh(sub_window_ptr);
sleep(1);
for (counter = 1; counter < 10; counter++) {
wprintw(sub_window_ptr, "%s", "This text is both wrapping and \
scrolling.");
wrefresh(sub_window_ptr);
sleep(1);
}
4. Завершив цикл, удалите вложенное окно и обновите основной экран:
delwin(sub_window_ptr);
touchwin(stdscr);
refresh();
sleep(1);
endwin();
exit(EXIT_SUCCESS);
}
К концу программы вы увидите вывод, показанный на рис. 6.6.
Рис. 6.6
Как это работает
После присвоения указателю sub_window_ptr результата вызова subwin вы включаете прокрутку вложенного окна. Даже после удаления вложенного окна и обновления базового окна (strdcr) текст на экране не меняется, поскольку вложенное окно на самом деле откорректировало символьные данные экрана strdcr.
Дополнительная клавиатура
Вы уже познакомились с некоторыми средствами библиотеки curses для обработки клавиатурного ввода. У многих клавиатур, как минимум, есть клавиши управления курсором и функциональные клавиши. Кроме того, у многих клавиатур есть дополнительная клавиатура и другие клавиши, например, <Insert> и <Home>.
Для большинства терминалов расшифровка этих клавиш — серьезная проблема, потому что они посылают строку символов, начинающуюся с escape-символа. Дело не только в том, что приложению трудно отличить одиночное нажатие клавиши <Esc> от строки символов, появившейся в результате нажатия функциональной клавиши, оно еще должно справляться с терминалами разных типов, применяющими разные управляющие последовательности для одних и тех же логических клавиш.
К счастью, библиотека curses предоставляет элегантное решение для управления функциональными клавишами. Обычно в структуре terminfo для каждого терминала хранится последовательность, отправляемая каждой функциональной клавишей, и во включенном в программу файле curses.h для логических клавиш есть набор определений, начинающихся с префикса KEY_.
Когда curses стартует, преобразование последовательностей в логические клавиши отключено, и его следует включить вызовом функции keypad. Если вызов успешен, функция вернет OK, в противном случае ERR.
#include <curses.h>
int keypad(WINDOW *window_ptr, bool keypad_on);