Главная
Исходники
Вычисления
Работа со строками
Маленькие хитрости
Рекурсия
Работа с графикой
Работа с массивами
Работа с файлами
Работа с записями
Динамические структуры данных
Методы сортировок
Фракталы
Литература
Теория вероятностей
Видео уроки
Ссылки
ОднаКнопка

Web www.pascal.hop.ru

Организация простого меню, вертикального или горизонтального.

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

Программа будет состоять из функции MainMenu и основного кода, обрабатывающего результат выбора.

Чем должна делать функция MainMenu?

  1. Задавать пункты меню и выводить их на экран в нужном порядке в нужном месте;
  2. Показывать какой пункт меню выбрал пользователь;
  3. Скрывать пункты меню, выбранные ранее;
  4. Давать возможность выбрать нужный пункт меню с помощью клавиатуры.

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

Type TMenu = record
         X,Y : Byte;
           S : String[20];
     End;

где X и Y - координаты, в которых нужно выводить конкретный пункт меню, а S - его название.

Теперь можно определить переменную Menu, как массив типа TMenu, и задать его:

     Menu[0].S := 'item 0'; Menu[0].X := 20; Menu[0].Y :=  5;
     Menu[1].S := 'item 1'; Menu[1].X := 20; Menu[1].Y :=  6;
     Menu[2].S := 'item 2'; Menu[2].X := 20; Menu[2].Y :=  7;
     Menu[3].S := 'item 3'; Menu[3].X := 20; Menu[3].Y :=  8;
     Menu[4].S := ' exit '; Menu[4].X := 20; Menu[4].Y :=  9;

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

    Procedure DrawMenu;
    Var I : Byte;
    Begin
         For I := 0 To MaxMenuItem Do
         Begin
              GotoXY(Menu[I].X, Menu[I].Y);
              Write(Menu[I].S);
         End;
    End;

где MaxMenuItem - максимальное число пунктов в меню. Последний пункт, определяем как выход.

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

     TC := TextAttr mod 16;
     TB := TextAttr div 16;

Попробуем нарисовать выбранный пункт меню, используя отдельную процедуру:

    Procedure Select (I:Byte);
    Begin
         TextBackground(TC); TextColor(TB);
         GotoXY(Menu[I].X, Menu[I].Y);
         Write(Menu[I].S);
         TextBackground(TB); TextColor(TC);
    End;

Как видим, способ вывода ничем не отличается от процедуры DrawMenu. Единственное отличие - процедура рисует один пункт меню, номер которого является входным параметром. Для инверсии цвета, введены строчки: TextBackground(TC); TextColor(TB); Перед выходом из процедуры, цвета восстанавливаются: TextBackground(TB); TextColor(TC);

Процедура обратного выбора DeSelect, или сокрытия выбранного пункта меню полный аналог Select:

    Procedure DeSelect (I:Byte);
    Begin
         TextBackground(TB); TextColor(TC);
         GotoXY(Menu[I].X, Menu[I].Y);
         Write(Menu[I].S);
         TextBackground(TB); TextColor(TC);
    End;

Единственное отличие - первая строчка похожа на последнюю. Их можно вообще не писать, но я оставил так, для красоты кода.

Основной этап подготовки функции завершен. Нужно подготовиться к выводу на экран и обработки клавиатуры.

     DrawMenu;
     Sel := R_Select;
     Select(Sel);

Sel - выбранный пункт меню. R_Select - входной параметр функции MainMenu, он нужен для того, чтобы оставить выбранным тот пункт, который был выбран в момент обработки события. Так курсор не "прыгает" на первый пункт.

Напишем обработчик клавиатуры. Кроме тупого перебора пунктов меню, предоставим пользователю возможность выбрать пункт клавишей Enter и выйти из меню клавишей Esc.

     Run := False;
     While Not Run Do Begin
           Case ReadKey Of
                #13 : Run := True;
                #27 : Begin
                           Run := True;
                           Sel := MaxMenuItem;
                      End;

                #0 : Case ReadKey Of
                           #72 : Begin
                                      DeSelect(Sel);
                                      If Sel = 0
                                      Then Sel := MaxMenuItem
                                      Else Sel := Sel - 1;
                                      Select(Sel);
                                 End;
                           #80 : Begin
                                      DeSelect(Sel);
                                      If Sel = MaxMenuItem
                                      Then Sel := 0
                                      Else Sel := Sel + 1;
                                      Select(Sel);
                                 End;
                      End;
           End;
     End;
     MainMenu := Sel;

Run - пользователь закончил работу с меню и сделал свой выбор. Нажал Enter или Esc. #13 и #27 - коды этих клавиш.

Курсорные клавиши возвращают расширенный код. По этому при обнаружении #0 используем вложенный Case. #72 и #80 коды клавиш вверх и вниз.

Для того, чтобы сдвинуться в указанном направлении, надо спрятать выбранный ранее пункт меню, изменить переменную Sel так, чтобы она указывала на новый пункт и не выходила за пределы меню. Показать новый пункт.

Чтобы вертикальное меню превратить в горизонтальное, надо изменить координаты в массиве Menu и коды клавиш #72 и #80.

Теперь легко описать действия в зависимости от выбранного пункта в основной программе:

     ClrScr;
     TextBackground(Blue);
     TextColor(LightGreen);

     Ret := 0;
     Repeat
          Ret := MainMenu(Ret);
          Case Ret Of
               0: Begin
                       WriteLn('Выбран пункт: ', Ret);
                       WriteLn('... нажми клавишу ...');
                       ReadLn;
                  End;
               1: Begin
                       WriteLn('Выбран пункт: ', Ret);
                       WriteLn('... нажми клавишу ...');
                       ReadLn;
                  End;
               2: Begin
                       WriteLn('Выбран пункт: ', Ret);
                       WriteLn('... нажми клавишу ...');
                       ReadLn;
                  End;
               3: Begin
                       WriteLn('Выбран пункт: ', Ret);
                       WriteLn('... нажми клавишу ...');
                       ReadLn;
                  End;
               Else Begin
                       WriteLn('Выход из программы');
                       WriteLn('... нажми клавишу ...');
                       ReadLn;
                    End;
          End; {case Ret}
     Until Ret = MaxMenuItem;
     TextBackground(Black);
     TextColor(LightGray);
     ClrScr;

Пахтусов Сергей, 07.03.2006


Лень учить? Смотри pascal на видео