Мир программирования

 


Найти: на:


Меню
Партнеры
Счетчики
Реклама

Техника программирования на Turbo C
Глава 10


Автор: Ал. Стивенс

Оконные меню

Итак, сейчас вы уже можете адресовать область пользовательского интерфейса интерактивной системы, ссответствующую определенным операциям. Для ввода различных полей данных - это средства поддержки формо-ориентированного ввода; для ввода текста - это оконный текстовый редактор; для обеспечения пользователей help-информацией по этим операциям - это контекстно -зависимая help-система; для поддержки каждой из этих операций - библиотека функций окна. Ранее мы с вами рассмотрели примеры адресации области пользовательского интерфейса для случая, когда прикладная программа использует только одну из операций. Однако диалоговые системы обычно обеспечивают поддержку целого ряда операций, которые может инициализировать пользователь. Выбор конкретной операции, которую необходимо выполнить в данный момент, чаще осуществляется пользователем интерактивной системы, чем самой системой. Это связано с тем, что зачастую требуется выбор из группы сложных независимых операций, а пользователь всегда лучше знает, какая именно операция должна быть выполнена в данный момент.

Меню

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

Вы уже встречались с одним из видов меню в Главе 6 при рассмотрении программы poetry.exe. Это меню содержало список опций окна. Пользователь мог осуществлять выбор из этого меню путем нажатия клавиш, соответствующих одной из опций меню, или путем перемещения курсора по элементам меню и нажатия клавиши <ВВОД> в позиции соответствующего элемента. Такой тип меню является наиболее часто используемым в интерактивных системах, но в то же время относится к разряду наиболее эффективных и понимаемых пользователем приемов.

Другим популярным типом меню, который часто используется в компьютерах, снабженных графическим пользовательским интерфейсом и манипулятором типа "мышь", является меню в виде скользящей строки (sliding bar menu). Этот тип меню представляет собой горизонтальное меню, расположенное в верхней части, с "всплывающими" вертикальными меню, раскрывающими и конкретизирующими содержание выбранных из горизонтального меню элементов. Вертикальные меню "всплывают" под соответствующими элементами горизонтального меню, и после этого пользователь получает возможность осуществлять выборку из вертикального меню, перемещаясь по нему вверх и вниз. Примером такого меню может служить система меню, принятая во Framework-II - широко распространенном продукте фирмы Ashton Tate .

К преимуществам такого типа меню относится то, что оно занимает минимальную область экрана (обычно - одна строка) и наиболее полно отражает взгляд пользователя на конкретное приложение программы. Вертикальные меню реализованы в виде "всплывающих" окон. Вследствие того, что они лишь временно перекрывают изображение на экране, не уничтожая его, применение такого меню раскрывает новые перспективы в разработке диалоговых систем. Пользователи системы Borland's Superkey могут видоизменить это
меню.

Процесс, образующий оконное меню

В этой главе содержится вводная информация о функциях-драйверах меню, которые используются для создания и поддержки скользящего меню-строки, которое описано выше. Такое меню создается как окно и управляется с помощью последовательности управляющих таблиц, образующихся после обращения к программе. Эти таблицы описывают последовательность выборки в скользящем меню-строке и каждом из "всплывающих" вертикальных меню. Функции-драйверы меню осуществляют обслуживание основного (целевого) процесса выполнения вашей программы. Они управляют пользовательским интерфейсом путем контроля процесса отображения меню и ввода пользователем выбранного элемента меню. Процесс ввода управляется набором таблиц меню, которые кодируются в вашей программе.

Основной таблицей меню является массив MENU-структур.

Структура MENU определена в twindow.h (см. Главу 6). Этот массив является входным для каждого процесса выборки из скользящей меню- строки. Каждый ввод выбранного элемента меню содержит отображаемое пользователю имя элемента меню и ряд указателей, описывающих содержание "всплывающего" вертикального меню, соответствующего указанному пользователю элементу горизонтального меню. Эти указатели включают в себя указатель на массив имен элементов "всплывающего" меню и указатель на массив указателей функций на языке Си. Имена отображаются во "всплывающем" меню, а функции входят в состав системы, использующей это меню, и выполняются, когда пользователь отмечает в качестве выбранных соответствующие имена элементов меню.

Иерархическая система меню состоит из двух уровней. Первый уровень включает в себя выборку из горизонтального меню и ограничен лишь шестью элементами вследствие того, что элементы этого уровня располагаются на одной строке. Любая выборка элемента на этом уровне приводит к появлению соответствующего "всплывающего" меню на втором уровне. Размер "всплывающего" меню ограничен 21 элементами, что соответствует максимальному числу строк, которое может быть включено в "всплывающее" меню. Каждая выборка на этом уровне приводит к вызову определенной Си-функции из закрепленных за элементами меню.

Если вы хотите получить дополнительные уровни в вашем иерархическом меню, то должны описать дополнительные управляющие таблицы меню, присвоить им значения и определить рекурсивные вызовы функций поддержки системы меню. Вследствие того, что функции поддержки меню реентерабельны, выборка на втором уровне "всплывающего" меню может привести к появлению нового горизонтального меню.

Описание иерархии системы меню фактически осуществляет ваша прикладная программа (или программная система), которая непосредственно генерирует массивы меню. Пример, представленный на листинге 10.3 (листинг см. ниже в этой главе), поясняет процесс формирования массивов. Обсуждение этого примера включает обсуждение полученного изображения как результата предварительной генерации массивов меню, а также детальное описание самого процесса их генерации.

Функции поддержки меню

Для использования оконных меню в этой главе вы должны вначале сгенерировать массив MENU, затем массив, на который ссылается массив MENU, а также написать и оттранслировать прикладные функции, которые будут выполняться, когда пользователь выберет конкретный элемент "всплывающего" меню. Затем вы так или иначе обращаетесь к функции menu_select, которая описана ниже.

void menu_select(char *name, Menu *mn)

Эта функция активизирует меню-процесс, отображая на экране дисплея горизонтальное скользящее меню-строку и переходя в состояние ожидания использования пользователем клавиатуры для выборки из меню. Указатель name является именем заголовка скользящей меню-строки. Указатель mn содержит адрес массива структур MENU в вызывающей программе. Этот массив и указатель на массив MENU определяют иерархию меню для меню-процесса.После того, как функция menu_select отобразила горизонтальное меню, пользователь, используя клавиши управления курсором вправо и влево, может перемещаться по меню. Если пользователь нажал клавишу <КЛЮЧ> (<ESC>), то меню-процесс прерывается, и управление передается в точку вызова функции menu_ select. Если же пользователь нажал клавишу <ВВОД> (<ENTER>), то осуществляется привязка конкретного "всплывающего" вертикального меню к текущему элементу горизонтального меню (определяется текущим положением маркера меню или курсора) и отображение нужного вертикального меню.

Во время отображения вертикального "всплывающего" меню пользователь может использовать клавиши передвижения курсора вправо и влево для выбора других элементов горизонтального меню-строки. В этом режиме в соответствии с движением курсора в меню-строке осуществляется последовательное отображение вертикальных меню, причем перед отображением очередного вертикального меню предыдущее вертикальное меню уничтожается. Если пользователь нажмет клавишу <КЛЮЧ> (<ESC>), то текущее "всплывающее" меню уничтожается, и процесс возвращается к обработке скользящего меню-строки аналогично описанному выше. Пользователь может использовать клавиши перемещения курсора вверх и вниз для навигации по вертикальному меню и выбора нужного элемента меню. После того, как нужный элемент выбран, нужно нажать клавишу <ВВОД> (<ENTER>). Нажатие этой клавиши приведет к исчезновению как вертикального, так и горизонтального меню и вызову функции, соответствующей указателю, хранимому в массиве указателей функций "всплывающего"меню и, в свою очередь, соответствующего выбранному элементу меню. Выполнение функций осуществляется путем обычного обращения к ним.

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

Исходный листинг: tmenu.c

Листинг 10.1 содержит текст библиотечной функции tmenu.c, предназначенной для поддержки предварительного описания меню-процесса.

Листинг 10.1: tmenu.c

/* ------------ tmenu.c ------------ */

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include "keys.h"
#include "twindow.h"

extern int VSG;

WINDOW *open_menu(char *mnm, MENU *mn, int hsel);
int gethmenu(MENU *mn, WINDOW *hmenu, int hsel);
int getvmn(MENU *mn, WINDOW *hmenu, int *hsel, int vsel);
int haccent(MENU *mn, WINDOW *hmenu, int hsel, int vsel);
void dimension(char *sl[], int *ht, int *wd);
void light(MENU *mn, WINDOW *hmenu, int hsel, int d);

/* ------------ Отображение и обработка меню--------- */
void menu_select(char *name, MENU *mn)
{
WINDOW *open_menu();
WINDOW *hmenu;
int sx, sy;
int hsel = 1, vsel;
curr_cursor(&sx, &sy);
cursor(0, 26);
hmenu = open_menu(name, mn, hsel);
while (hsel = gethmenu(mn, hmenu, hsel)) {
vsel = 1;
while (vsel = getvmn(mn, hmenu, &hsel, vsel)) {
delete_window(hmenu);
set_help("", 0, 0);
(*(mn+hsel-1)->func [vsel-1])(hsel, vsel);
hmenu = open_menu(name, mn, hsel);
}
}

delete_window(hmenu);
cursor(sx, sy);
}
/* ----Инициализация горизонтального меню-------*/
static WINDOW *open_menu(char *mnm, MENU *mn, int hsel)
{
int i = 0;
WINDOW *hmenu;
set_help("menu ", 30, 10);
hmenu = establish_window(0, 0, 3, 80);
set_title(hmenu, mnm);
set_colors(hmenu, ALL, BLUE, AQUA, BRIGHT);
set_colors(hmenu, ACCENT, WHITE, BLACK, DIM);
display_window(hmenu);
while ((mn+i)->mname)
wprintf(hmenu, " %-10.10s ", (mn+i++)->mname);
light(mn, hmenu, hsel, 1);
cursor(0, 26);
return hmenu;
}
/* ----Выборка из горизонтальногоь меню------*/
static int gethmenu(MENU *mn, WINDOW *hmenu, int hsel)
{
int sel;
light(mn, hmenu, hsel, 1);
while (TRUE) {
switch (sel = get_char()) {
case FWD:
case BS: hsel = haccent(mn, hmenu, hsel, sel);
break;
case ESC: return 0;
case '\r': return hsel;
default: putchar(BELL);
break;
}
}
}
/* -----Всплывающее вертикальное меню--------*/
static int getvmn(MENU *mn,WINDOW *hmenu,int *hsel,int vsel)
{
WINDOW *vmenu;
int ht = 10, wd = 20;
char **mp;
while (1) {
dimension((mn+*hsel-1)->mselcs, &ht, &wd);
vmenu = establish_window(2+(*hsel-1)*12, 2, ht, wd);
set_colors(vmenu, ALL, BLUE, AQUA, BRIGHT);
set_colors(vmenu, ACCENT, WHITE, BLACK, DIM);
set_border(vmenu, 4);
display_window(vmenu);
mp = (mn+*hsel-1)->mselcs;
while (*mp)
wprintf(vmenu, "\n%s", *mp++);
vsel = get_selection(vmenu, vsel, "");
delete_window(vmenu);
if (vsel == FWD || vsel == BS) {
*hsel = haccent(mn, hmenu, *hsel, vsel);
vsel = 1;
}
else
return vsel;
}
}

/* -----Управление отображением выбранных элементов

горизонтального меню -----*/
static int haccent(MENU *mn,WINDOW *hmenu,int hsel,int sel)
{
switch (sel) {
case FWD:
light(mn, hmenu, hsel ,0);
if ((mn+hsel)->mname)
hsel++;
else
hsel = 1;
light(mn, hmenu, hsel ,1);
break;
case BS:
light(mn, hmenu, hsel ,0);
if (hsel == 1)
while ((mn+hsel)->mname)
hsel++;
else
--hsel;
light(mn, hmenu, hsel ,1);
break;
default:
break;
}
return hsel;
}
/* -----Вычисление высоты и ширины меню-------*/
static void dimension(char *sl[], int *ht, int *wd)
{
unsigned strlen(char *);
*ht = *wd = 0;
while (sl [*ht]) {
*wd = max(*wd, strlen(sl [*ht]));
(*ht)++;
}
*ht += 2;
*wd += 2;
}
/* --------Отображение в соответствии с параметром
accent элемента горизонтального меню ---*/
static void light(MENU *mn, WINDOW *hmenu, int hsel, int d)
{
if (d)
revers_video(hmenu);
wcursor(hmenu, (hsel-1)*12+2, 0);
wprintf(hmenu, (mn+hsel-1)->mname);
normal_video(hmenu);
cursor(0, 26);
}

Описание программы: tmenu.c

Функция menu_select вызывается для обработки меню, описанного в массиве структур MENU. Эта функция запоминает текущее положение системы меню и позицию курсора относительно координат экрана. Затем вызывается функция open_menu, которая осуществляет инициализацию и отображение на экране (в его верхней части) горизонтального меню-строки. Цикл while осуществляет обработку горизонтального меню-строки до тех пор, пока пользователь не нажмет клавишу <КЛЮЧ> (<ESC>). На каждой итерации цикла вызывается функция getmenu. Если функция getmenu возвращает значение 0, значит, пользователь нажал клавишу <КЛЮЧ> (<ESC>). Если функция getmenu возвращает ненулевое значение, значит, пользователь произвел выборку одного из элементов горизонтального меню. Возвращаемое функцией значение специфицирует выбранный пользователем элемент меню. Следующий цикл while обрабатывает "всплывающее" вертикальное меню, соответствующее выбранному ранее элементу горизонтального меню-строки. На каждой операции этого цикла происходит обращение к функции getvmn, которая осуществляет обработку "всплывающего" меню. При нажатии пользователем клавиши <КЛЮЧ> (<ESC>) функция getvmn возвращает значение 0, в противном случае getvmn возвращает значение, специфицирующее выбранный пользователем элемент вертикального меню. После этого окно, выделенное для горизонтального и вертикальных меню, уничтожается, вызывается функция, реализующая действия, соответствующие выбранному пользователем элементу вертикального меню. По завершении работы этой функции open_menu вызывает восстановление изображения на экране горизонтального меню-строки.

Функция open_menu открывает окно в верхней части экрана на всю его ширину. Это окно предназначено для горизонтального меню-строки. Меню выбора функций вашей программы отображается в этом окне в соответствии с таблицей MENU. Первый из выбранных пользователем элементов этого меню отображается в акцентированном цвете функцией light.

Функция getmenu анализирует прерывания от клавиатуры при выборе элементов меню или при передвижении курсора по меню. Если пользователь нажал клавишу перемещения курсора вправо или влево, то вызывается функция haccent для перемещения курсора по меню-строке. Если пользователь нажал клавишу <КЛЮЧ> (<ESC>), то функция getmenu возвращает 0. При нажатии клавиши <ВВОД> (<ESC>) функция возвращает значение, соответствующее выбранному элементу меню, и передает управление в точку ее вызова.

Функция getvmn предназначена для обработки вертикального меню, "всплывшего" под соответствующим элементом горизонтального меню. Вертикальное меню представляет собой окно, а его состав определяется в соответствии с таблицей MENU. Функция get_selection (см. Главу 6) вызывается для считывания пользовательского выбора. После того, как в вызывающую программу передано значение выбранного пользователем элемента меню, окно, выделяемое для "всплывающего" меню, уничтожается. При нажатии пользователем клавиш перемещения курсора вправо или влево вызывается функция haccent для перемещения вперед или назад курсора по элементам горизонтального меню-строки, а обработка вновь появляющихся (в процессе перемещения курсора по горизонтальному меню) вертикальных меню осуществляется опять функцией getvmn; в противном случае значение, возвращаемое функцией get_selection приводит к возврату управления в точку вызова функции getvmn.

Пример оконного меню

Листинги 10.2, 10.3 и 10.4 содержат пример программы, иллюстрирующей использование и обработку меню. Этот пример строит меню, позволяющее выполнять в рамках одной интегрированной системы все оконные функции, рассмотренные в качестве примеров, иллюстрирующих содержание глав с шестой по девятую.

Листинг 10.2, программа menu.c, является простейшей управляющей программой, которая вызывает программу, реализующую пример (exec.c) и представленную листингом 10.3. Листинг 10.4 программы menu.prj является make-файлом Турбо Си, по которому строится выполняемая программа, реализующая пример.

Листинг 10.2:menu.c

/* ------------------menu.c-------------------*/
#include "twindow.h"
void exec(void);

char notefile [] = "note.pad";

main()
{
load_help("tcprogs.hlp");
exec();
}

Листинг 10.3:exec.c

/* ----------------exec.c------------------- */
#include <stdio.h>
#include "twindow.h"
/* ----------Локальные прототипы----------- */
void testmove(void);
void promote(void);
void ccolor(void);
void fasttest(void);
void notepad(void);
void ordent(void);
void poems(void);
void maxims(void);
/* -----------Таблицы меню------------------ */
char *dselcs[] = {
" move ",
" promote ",
" colors ",
" fast ",
NULL
};
char *pselcs[] = {
" notepad ",
" orders ",
" poetry ",
" sayings ",
NULL
};
static void (*dfuncs[])()={testmove,promote,ccolor,fasttest};
static void (*pfuncs[])()={notepad,ordent,poems,maxims};
static MENU tmn [] = {
{" demos ", dselcs, dfuncs},
{" programs ", pselcs, pfuncs},
{NULL,NULL,NULL}
};
void exec()
{
menu_select(" TC Executive ", tmn);
}

Листинг 10.4:menu.prj

menu.c
exec.c (twindow.h, keys.h)
testmove (twindow.h, keys.h)
promote (twindow.h, keys.h)
ccolor (twindow.h, keys.h)
fasttest (twindow.h)
notepad (twindow.h)
ordent (twindow.h)
maxims (twindow.h, keys.h)
poems (twindow.h, keys.h)
editor (twindow.h, keys.h)
entry (twindow.h, keys.h)
thelp (twindow.h, keys.h)
tmenu (twindow.h)
twindow (twindow.h, keys.h)
ibmpc.obj

Для запуска программы-примера введите следующую команду

C>MENU

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

Обратимся теперь к массиву структур MENU, поименованному как tmn (см. листинг 10.3 программы exec.c). Массив содержит лишь два элемента, соответствующих элементам горизонтального меню, отображаемых пользователю. Структура MENUI определена в twindow.h (см. Главу 6) и включает три элемента: указатель на имя выбранного элемента меню, указатель на массив имен элементов "всплывающего" меню, соответствующего элементу горизонтального меню, и указатель на массив указателей функции, реализующей ту или иную операцию.

Для перемещения по меню с целью выборки нужного элемента из горизонтального меню используются клавиши перемещения курсора вправо и влево. Если текущим является элемент меню demos, нажмите клавишу <Ввод>. Теперь вернемся к листингу 10.3 и обратим внимание на содержимое первого элемента массива tmn, который соответствует элементу горизонтального меню demos. Здесь dselcs - адрес, указывающий размещение массива указателей типа char на имена элементов demosвертикального "всплывающего" меню, dfuncs - адрес размещения массива указателей функций. Каждый из указателей этого массива адресует одну из функций, которые рассматривались в качестве примеров в предыдущих главах. Для перемещения по вертикальному меню применяются клавиши перемещения курсора вверх и вниз. Если вы остановились на каком-то выборе, нажмите клавишу <Ввод>. После этого будет выполнена одна из функций в зависимости от того, какой элемент меню вы выбрали. После передачи управления из этой функции в точку ее вызова (как было показано в этой главе, для функций, требующих какого-либо выбора от пользователя, это клавиша <ESC>, на экране восстанавливается изображение горизонтального и вертикального меню в том состоянии, которое предшествовало вызову функции, и разрешена дальнейшая работа с ними. Для уничтожения текущего вертикального меню нажмите клавишу <ESC>. Для выхода из программы и уничтожения горизонтального меню требуется повторное нажатие клавиши <ESC>.

Резюме

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

В следующей главе будут рассмотрены резидентные утилиты. Функции поддержки окон, описанные в этой книге, могут быть включены в обычные однозадачные программы, выполняемые в среде DOS, или могут быть преобразованы в программы, которые постоянно находятся в памяти, и инициализация их выполнения закрепляется за определенными клавишами. Технические приемы написания таких программ (они еще носят название резидентных программ или резидентных утилит), а также примеры их использования при разработке систем рассматриваются в следующих главах.


Опрос

Конкурсы
Реклама

 

Web дизайн: Бурлаков Михаил    

Web программирование: Бурлаков Михаил

Используются технологии uCoz