Техника
программирования на Turbo C
Глава 7
Автор: Ал. Стивенс
Контекстно-управляемые окна
подсказки
Первой проблемой, обычно возникающей
при запуске новой программы, является незнакомство программы с языком
своего пользователя. Какая клавиша должна быть нажата? Какое действие
будет следующим? Что выполняет данный элемент меню? Независимо от того,
сколько усилий вложено в разработку самообъясняемого пользовательского
языка, у пользователей всегда возникают вопросы, поскольку язык новой
системы для него всегда иностранный. Дело не только в знакомстве пользователей
с языком, часто они даже не знают, что система может, а чего не может
делать. По традиции эта проблема решается обращением к печатным руководствам
пользователя и, возможно, автоматизированным справочникам. Недостатком
этих решений является необходимость переключения внимания пользователя
от работы с системой к чтению руководства или запуску справочника.
Если бы экраны были достаточно большими,
система могла бы поддерживать постоянный показ руководства пользователя.
Как только пользователю потребовалась бы информация, руководство было
бы доступно. Это решение не продержалось бы долго; когда пользователь
уже знает систему, информация подсказки не нужна и нежелательна. Значимая
для новичка информация - это мусор для ветерана.
Большинство интерактивных систем имеют
общее свойство: когда пользователю необходима информация, он смотрит
на экран и гадает, какую клавишу нажать. Представляется вполне естественным,
что в число нажатий клавиш, которые система будет распознавать в любое
время, нужно включить функциональную клавишу <Help> (Подсказка).
Нажмите требуемую прикладную клавишу, и программа выполнит ваш запрос;
нажмите функциональную клавишу подсказки, и программа сообщит вам кое-что
о том, какие клавиши она ожидает и что случится при их нажатии.
Поскольку интерактивные системы используют
экран для общения с пользователем и показа данных, сообщение подсказки
- это материал для выталкиваемого вверх окна. Такое построение окна
позволяет получить подсказку без нарушения прикладного использования
экрана. Такое окно называется контекстно- управляемым окном подсказки,
окном, которое выскакивает для подсказки пользователю при нажатии назначенной
функциональной клавиши подсказки. (Программная промышленность признала
<F1> стандартом для функциональной клавиши подсказки, однако многие
программные пакеты используют другие клавиши). Окно подсказки содержит
текст, который объясняет некоторую часть программы. Когда пользователи
работают с программой и переходят от возможности к возможности, содержимое
и расположение окон подсказки изменяются для отражения текущего контекста.
Эти изменения не видны, поскольку они происходят внутри программ.
Когда пользователь нажимает функциональную клавишу подсказки, соответствующее
сообщение-подсказка выдается в выскакивающем окне.
Поскольку сообщение-подсказка зависит
от текущего положения в программе, окно подсказки называется контекстно-управляемым.
Опытные пользователи могут игнорировать возможности подсказки программы;
новички могут нажимать функциональную клавишу подсказки при каждом изменении
состояния программы и получать советы, напоминания или детальные инструкции.
Разработчик системы решает, как много
и какого вида подсказки система будет предусматривать для пользователя.
Некоторые системы обладают несколькими уровнями подсказки в зависимости
от опыта пользователя. Программа обработки слов Word Star применяла
эту технологию на протяжении многих лет. Уровни подсказки изменяются
от простых сообщений типа "нажмите <Ключ> для возврата к..."
до полных пользовательских руководств. Многие разработчики программ
предпочитают передавать руководство пользователя таким способом, а не
в виде больших громоздких документов. Эта процедура имеет два последствия:
пользователи связывают экстравагантные руководства с качеством программ,
а большие книги способствуют борьбе с "программными пиратами".
Как бы там ни было, пользователи также
пришли к ожиданию систем, требующих минимального использования пользовательских
руководств. Пользователи хотят интерактивную подсказку.
Программирование окон подсказки
Функции подсказки в этой книге поддерживают
концепции контекстно-управляемой подсказки с помощью использования оконных
функций, текстового файла и функциональных вызовов из прикладной программы.
Каждая прикладная программа сообщает функциям подсказки, какой файл
подсказки использовать и какое окно подсказки является текущим. Файл
подсказки содержит текст для каждого окна подсказки. Функции подсказки
отслеживают сигналы от клавиатуры и выдают текущее окно подсказки при
нажатии функциональной клавиши <Help>.
Программа, использующая программное обеспечение
подсказки, должна предусматривать следующие интерфейсы с функциями подсказки:
- функциональный вызов для задания имени текстового файла подсказки;
- значение функциональной клавиши подсказки;
- функциональные вызовы для идентификации текущего окна подсказки;
- использование функции клавиатурного ввода get_char для любого ввода
с клавиатуры (get_char описана в Главе 4).
Последнее из этих четырех требований
может потребовать некоторых разъяснений. Во время работы программы программное
обеспечение подсказки перехватывает каждое прерывание от клавиатуры
для того, чтобы убедиться, не нажата ли функциональная клавиша подсказки.
Если это так, то управление передается оконному процессу подсказки.
Если нет, значение клавиши пересылается в ожидающую его программную
функцию. Программное обеспечение подсказки может управлять этим перехватом
только в том случае, если вы используете функцию get_char для ввода
с клавиатуры. Как разъяснено выше, get-char следит за нажатием на клавиатуре
функциональной клавиши подсказки. Если вы используете другие способы
чтения символов с клавиатуры, то переключение функциональной клавишей
подсказки не будет сделано.
Имеются и другие методы наблюдения за
клавиатурой с ожиданием нажатия функциональной клавиши подсказки. Некоторые
из этих методов привлекают присоединяющее перехватывающее программное
обеспечение к вектору клавиатурного прерывания или вектору клавиатурной
BIOS. По различным причинам было решено, что эти методы не будут использоваться.
Во-первых, программное обеспечение, описываемое в данной книге, предполагает
пользовательскую среду, включающую окна для меню, ввода данных и текста.
Весь клавиатурный ввод, необходимый программе, может управляться одной
из этих возможностей, причем все они используют функцию get_char. Вам
никогда не понадобится снова программировать клавиатурный ввод. Во-вторых,
если программа присоединяет себя к вектору прерывания, то при ненормальном
завершении программы происходят странные вещи; обычно ПЭВМ приходится
перезапускать. В-третьих, разрабатываемые вами программы могут быть
резидентными в памяти. Резидентные в памяти программы часто присоединяются
к клавиатуре для других целей. Вы узнаете больше о резидентных в памяти
программах, векторах прерываний и о том, как присоединять одно окно
к другому, в Главе 11. Допустим, что ваше программное
обеспечение читает клавиатуру с помощью функции get_char. Тогда вектора
клавиатуры остаются одни, и система хорошо себя ведет независимо от
резидентных программ, аварийных завершений программ при тестировании
или неожиданных завершений программы в производственной системе.
Требуемое использование get_char лишает
вас трех стандартных возможностей Си:
- вы не сможете использовать стандартные
библиотечные функции scanf или getchar, поскольку ни одна из этих функций
не использует функцию get_char;
- вы не сможете воспользоваться стандартной
функцией ввода с консоли (getch), предусмотренной в Турбо Си;
- вы не сможете использовать логическое
устройство stdin для клавиатурного ввода, что означает для вашей программы
невозможность назначать файлы или программные каналы вместо клавиатуры.
Потеря функций scanf и getchar - это
небольшая потеря для программирования диалога. Эти функции бесполезны
в интерактивной среде. Они являются функциями буферизованного ввода,
требующими нажатия клавиши <Ввод> для завершения ввода символа
или строки; кроме того, они нечувствительны к расположению курсора и
длине поля. Эти функции дублируют свой ввод в стандартный вывод, соблюдая
соглашения командной строки ДОС, и они будут дублировать изображения
двойных символов при вводе управляющего символа. Если введена клавишная
комбинация Упр/С, функции могут аварийно завершить программу. Функции
плохо работают с функциональными или курсорными клавишами. Турбо Си
включает их для поддержки совместимости с UNIX. Эти функции происходят
из компьютерных систем с телетайпными терминалами.
Может показаться, что вы теряете ряд
возможностей, когда лишаетесь устройства stdin, однако это устройство
предназначено для программ, которые могут принимать входные данные из
файлов и выходов других программ так же, как и с клавиатуры. Эти программы
(или, по крайней мере, stdin используется для ввода данных в них) обычно
не предназначены для использования в интерактивной среде.
Текстовый файл окна подсказки
Окна подсказки появляются, когда пользователь
нажимает функциональную клавишу подсказки, описанную в текстовом файле.
Текстовый файл подсказки - это ASCII-файл, который вы строите текстовым
редактором Турбо Си или любым другим редактором, который может создавать
ASCII-файлы.
Окна подсказки описываются мнемоническим
идентификатором, который используется программным обеспечением подсказки
для идентификации и расположения текста. Строки, следующие за идентификатором,
содержат текст, количество строк и длина строки которого определяют
высоту и ширину окна подсказки.
Идентификатор окна подсказки состоит
ровно из восьми символов и окружается угловыми скобками. Каждый идентификатор
появляется в своей собственной строке, последней строкой файла должен
быть лексический вход.
Все примеры программ, которые приводятся
в этой и последующих главах, используют программное обеспечение подсказки.
Далее рассматривается простой пример для иллюстрации самой подсказки,
а затем - использование подсказки по прямому назначению - для предоставления
пользователю интерактивной контекстно-управляемой подсказки. С этой
целью один и тот же файл подсказки предусматривается для всех программ.
Он называется tcprogs.hlp и показан на листинге 7.1.
Листинг 7.1: tcprogs.hlp
<maxims >
Press 1, 2, or 3
for a pithy maxim.
<menu >
Use arrow keys to move the cursor bars.
Use Enter to make the selection.
<poemmenu>
Arrows move the cursor bar.
Enter will select the poem
under the cursor bar.
Press a digit (1-5) to
select any other poem.
<poems >
Move poem with arrow keys
Select poem with 1 - 5
Use + to bring poem forward
Use - to push poem back
<name >
Enter the name of the person
who is placing the order.
<address >
Enter the address of the
person who is placing the
order.
<state >
The State may be one of these:
VA, NC, SC, GA, FL
<phome >
Enter the phone number
of the person who is
placing the order
<amount >
Enter the amount
of the order
<notepad >
--------Cursor Movement----- --------Page Movement--------
arrows = move text cursor Ctrl-Home = Beginning of File
Ctrl-T = Top of Window Ctrl-End = End of File
Ctrl-B = Bottom of Window PgUp = Previous Page
Ctrl -> = Next Word PgDn = Next Page
Ctrl <- = Previous Word
Home = Beginning of Line --------Editor Control-------
End = End of Line Scroll Lock = No Auto Reform
--------Block Controls----- ---------Edit
Commands--------
F4 = Form Paragraph F2 or Esc = Done
F5 = Mark Block Beginning F3 = Erase File
F6 = Mark Block End Ins = Toggle Insert Mode
F7 = Move Block Del = Delete Char
F8 = Copy Block <-- = Rubout
F9 = Delete Block Ctrl-D = Delete Word
F10 = Unmark Block Alt-D = Delete Line
<end>
Функции подсказки
Для введения контекстно-управляемых окон
подсказки в ваши программы необходимо к ним добавить два вызова функций,
которые находятся в исходном файле thelp.c, представленном ниже в листинге
7.2.
void load_help(char *filename)
Вызовите эту функцию для загрузки файла
подсказки или перехода к другому файлу подсказки. Функция открывает
файл подсказки и анализирует в нем сообщения подсказки, строя таблицу
идентификаторов окон подсказки, их размеров и расположений в файле подсказки.
void set_help(char *helpname, int x, int
y)
Эта функция задает текущее окно подсказки
с восьмисимвольным массивом, соответствующим наименованию окна в файле
подсказки. Наименование окружается в файле подсказки угловыми скобками,
причем не включает в себя эти скобки. Целые числа х и y задают координаты
верхнего левого угла (в символьных позициях) окна подсказки, что позволяет
пользователям использовать одно и то же окно в различных контекстах,
но в различных листах экрана.
Изменение функциональной
клавиши подсказки
Если вам нужно задать значение функциональной
клавиши, отличной от <F1> (по умолчанию), вы должны изменить значение
глобальной целочисленной переменной helpkey. Эта переменная объявлена
в ibmpc.c в Главе 4. Вы можете включить исходный файл keys.h (см. Главу
4) в вашу программу и использовать одно из определенных в этом файле
значений клавиш. Следующий фрагмент изменяет функциональную клавишу
подсказки на <F2>.
#include "keys.h"
extern int helpkey;
helpkey = F2;
Изменение функции подсказки
Файл с именем ibmpc.c в Главе 4 включает
указатель на функцию с именем helpfunc. Обычно этот указатель содержит
значение NULL. Когда используются функции подсказки, указатель инициализируется
адресом функции с именем help. Если вам нужно использовать другую функцию,
скажем, вместо стандартной функции help, вы можете изменить значение
указателя helpfunc. Для применения функциональной клавиши подсказки
для вызова вашей функции используйте следующие операторы:
extern void (*helpfunc)();
void yourfunc();
helpfunc = yourfunc;
Вы можете вернуться к указанию helpfunc
на стандартную функцию подсказки с помощью следующих операторов:
extern void (*helpfunc)();
extern void help();
helpfunc = help;
Выключение подсказки
Имеются три пути для выключения подсказки:
вы можете установить значение функциональной клавиши подсказки равным
0; можно установить указатель функции подсказки равным NULL; можно вызвать
set_help, передавая указатель на строку нулевой длины. Для включения
подсказки необходимо отменить выбранное действие.
Исходный листинг: thelp.c
Теперь перейдем к листингу 7.2 thelp.c.
Этот файл является исходным текстом функций, поддерживающих контекстно-управляемые
окна подсказки.
Листинг 7.2: thelp.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "twindow.h"
#include "keys.h"
#define MAXHELPS 25
#define HBG WHITE
#define HFG BLACK
#define HINT DIM
#define TRUE 1
#define FALSE 0
static struct helps {
char hname [9];
int h, w;
long hptr;
} hps [MAXHELPS+1];
static int hp = 0;
static int ch = 0;
static int hx, hy;
FILE *helpfp = NULL;
long ftell();
char *fgets();
void help();
char helpname[64];
void getline(char *lineh);
void load_help(char *hn)
{
extern void (*helpfunc)();
extern int helpkey;
char lineh [80];
if (strcmp(helpname, hn) == 0)
return;
helpfunc = help;
helpkey = F1;
hp = 0;
strcpy(helpname, hn);
if ((helpfp = fopen(helpname, "r")) == NULL)
return;
getline(lineh);
while (1) {
if (hp == MAXHELPS)
break;
if (strncmp(lineh, "<end>", 5) == 0)
break;
if (*lineh != '<')
continue;
hps[hp].h = 3;
hps[hp].w =18;
strncpy(hps[hp].hname, lineh+1, 8);
hps[hp].hptr = ftell(helpfp);
getline(lineh);
while (*lineh != '<') {
hps[hp].h++;
hps[hp].w = max(hps[hp].w, strlen(lineh)+2);
getline(lineh);
}
hp++;
}
}
static void getline(char *lineh)
{
if (fgets(lineh, 80, helpfp) == NULL)
strcpy(lineh, "<end>");
}
void set_help(char *s, int x, int y)
{
for (ch = 0; ch < hp; ch++)
if (strncmp(s, hps[ch].hname, 8) == 0)
break;
hx = x;
hy = y;
}
void help()
{
char ln [80];
int i, xx, yy;
WINDOW *wnd;
extern int helpkey;
if (hp && ch != hp) {
curr_cursor(&xx, &yy);
cursor(0, 25);
wnd = establish_window(hx, hy, hps[ch].h, hps[ch].w);
set_colors(wnd, ALL, HBG, HFG, HINT);
display_window(wnd);
fseek(helpfp, hps[ch].hptr, 0);
for (i = 0; i < hps[ch].h-3; i++) {
getline(ln);
wprintf(wnd, ln);
}
wprintf(wnd, "[Help] to return");
while (get_char() != helpkey)
putchar(BELL);
delete_window(wnd);
cursor(xx, yy);
}
}
Описание программы: thelp.c
Программа thelp.c содержит четыре имени
#define, устанавливающих глобальные параметры системы подсказки. MAXHELPS
получает значение максимального количества окон подсказки, которое программа
может поддерживать одновременно. HBG, HFG и HINT являются цветами фона,
переднего плана и яркостью окон подсказки.
Структура helps описывает окно подсказки.
Она содержит мнемоническое имя окна, его высоту и ширину, а также символьное
смещение описания окна в текстовом файле, включающем окна подсказки.
Массив hps структур helps содержит один элемент для каждого окна в текстовом
файле и строится функцией load_help. Функция load_help читает текстовый
файл подсказки, заданный при вызове, и строит массив hps. Она распознает
угловую скобку, идентифицирующую каждое имя окна, копируя имя и символьное
смещение в файле в структуру. Затем она читает текст окна для определения
длины и ширины окна. Длина яляется функцией количества строк текста,
а ширина является функцией размера самой длинной строки текста окна.
Функция set_help просматривает массив
для поиска окна с именем, заданным при вызове. Целочисленная переменная
ch, которая используется для индексации в массиве при поиске, будет
содержать индекс текущего окна при нажатии функциональной клавиши подсказки.
Переменные hx и hy получают значения при вызове. Эта процедура устанавливает
позицию окна.
Функция help вызывается функцией get_char
из ibmpc.c при нажатии заданной функциональной клавиши подсказки. Функция
help сохраняет текущую позицию курсора и убирает курсор с экрана. Создается
окно подсказки с координатами и размерами, записанными в элементе массива
с индексом ch. Текущая символьная позиция в текстовом файле перемещается
к месту, указанному в элементе массива. Каждая строка текста читается
из файла и записывается в окно. Дописывается последняя строка, сообщающая
пользователю о необходимости повторного нажатия клавиши подсказки для
очистки окна подсказки и возврата. Программа ожидает нажатия клавиши
подсказки, уничтожает окно и восстанавливает курсор на экране в прежнем
положении.
Пример контекстно-управляемой
подсказки
Программы на листингах 7.3, 7.4 и 7.5
представляют пример использования программного обеспечения подсказки.
Листинг 7.3, sayings.c, содержит главную функцию, вызывающую функцию
примера, maxims.c, показанную в листинге 7.4. Листинг 7.5 является проектным
make-файлом, используемым Турбо Си для построения этого примера.
Для запуска программы вводите следующую
команду:
c>sayings
Программа sayings.c загружает файл teprogs.hlp
с помощью вызова load_help и вызывает функцию с именем maxims. Такая
последовательность была выбрана для того, чтобы maxims.c могла быть
встроена в последующие программы, предусматривающие примеры обработки
меню и резидентных в памяти утилит. Maxims.c показывает, как использовать
set_help и get_char в ваших программах. Используется только одно окно
подсказки. Maxims.c открывает окно и ожидает нажатия клавиши. Если вы
нажимаете 1, 2 или 3, в окне показывается одна из трех старых пословиц.
Если вы нажмете <Ключ>, программа завершится. Если будет нажата
<F1>, выдается окно подсказки.
Листинг 7.3: sayings.c
#include "twindow.h"
void maxims(void);
main()
{
load_help("tcprogs.hlp");
maxims();
}
Листинг 7.4:
maxims.c
#include "twindow.h"
#include "keys.h"
void maxims()
{
int c;
WINDOW *wnd;
set_help("maxims ", 50, 10);
wnd = establish_window(5, 10, 3, 50);
set_title(wnd, "Press F1 for help");
set_colors(wnd, ALL, RED, WHITE, DIM);
display_window(wnd);
while ((c = get_char()) != ESC) {
switch (c) {
case '1':
wprintf(wnd, "\nA stitch in time \
saves nine ");
break;
case '2':
wprintf(wnd, "\nA rolling stone \
gathers no moss");
break;
case '3':
wprintf(wnd, "\nA penny saved \
is a penny earned");
break;
default:
break;
}
}
delete_window(wnd);
}
Листинг 7.5: sayings.prj
saying
maxims (twindow.h, keys.h)
thelp (twindow.h, keys.h)
twindow (twindow.h, keys.h)
ibmpc.obj
Резюме
Ваши оконные средства теперь включают
возможность контекстно -управляемой подсказки. Следующие главы содержат
дополнительные возможности обработки окон и примеры их использования.
Каждый пример использует окна контекстно-управляемой подсказки, поэтому
ваше понимание средств подсказки возрастает с каждой добавленной возможностью.
Это обучение имеет существенное значение, поскольку, как правило, диалоговые
программы должны предусматривать оперативную подсказку пользователю.
Следующее дополнение к использованию окон в диалоговой программе представлено
в Главе 8, которая описывает использование окон в качестве форм для
ввода данных. Глава 8 включает функции, позволяющие
вам описывать содержимое и формат шаблона ввода данных, и описывает
программное обеспечение для сбора элементов данных, вводимых пользователем
в форму.
|