Содержание
Построение меню в программах
Вступление
Часто приходится сталкиваться с программами, в которых студенты пытались построить нечто похожее на меню, и это было нечто… (слов не подобрать ). Построение меню занимало большую часть программы и алгоритм терялся в недрах гигантских программ.
Программа состоит из набора алгоритмов, данных и интерфейса. Но ошибаются те, которые считают, что интерфейс главнее. Это большое заблужение! Потому, что основную задачу выполняют именно алгоритмы, а не украшательства. Интерфейс же совсем необязательная часть.
Более того, неприемлемо смешивание кода алгоритмов и интерфейса: в этом случае очень затрудняется поиск ошибок и нарушается строение программы.
Построение меню
Поэтому советую взять за основу эту программу, которая строит меню (горизонтальное или вертикальное) с управлением клавиш стрелок.
Выбор пункта меню ведёт к отдельной подзадаче, каждая из которых оформлена в виде процедуры. В них вы будете выполнять действия, предусмотренные вашей программой. Я привёл пример для операций над числами.
uses crt; Type MenuType = (Vertical, Horizontal); const width = 9; { Максимальная длина элементов (букв) меню } Items1 = 5; { Количество элементов меню 1 } optText1: array [0..Items1-1] of string = ('Сложение', 'Вычитание', 'Деление', 'Умножение', 'Выход'); Items2 = 3; { Количество элементов меню 2 } optText2: array [0..Items2-1] of string = ( 'item 1', 'item 2', 'item 3' ); optNormal = LightGray; { цвет невыделенных элементов меню } optSelected = Yellow; { цвет выделенных элементов меню } var X, Y, selected, { Индекс элемента, который будет подсвечиваться в начале программы } row: integer; _style: menuType; { Указывает на тип меню: вертикальный (Vertical) или горизонтальный (Horizontal) } { Эта процедура используется процедурой MenuOption для построения меню } procedure MakeMenu (optText: array of string; MaxItems: integer); var i, _X: byte; begin Y := row; _X := X; for i := 0 to MaxItems-1 do begin GoToXY (_X, Y); if i = selected then TextColor (optSelected) else TextColor (optNormal); write (optText[i]); If _style = Horizontal Then inc (_X, width + 1) Else inc (Y, 2); end; end; { выбираем нужный элемент меню этой функцией } function MenuOption (optText: array of string; MaxItems: integer): byte; var ch: char; begin selected := 0; If _style = Vertical then begin X := (80 - width) div 2; row := (25 - MaxItems) div 2; End Else Begin X := (80 - MaxItems * width) div 2; row := 2; { строчка, в которой будет находиться горизонтальное меню } GotoXY(1, row); ClrEol; { ... а для горизонтального - только строку где будет меню. } End; repeat MakeMenu (optText, MaxItems); ch := readkey; if ch = #0 then ch := readkey; case ch of #80, #77: {Down/Right} begin inc (Selected); if Selected = MaxItems then Selected := 0; MakeMenu (optText, MaxItems); end; #72, #75: {Up/Left} begin dec (Selected); if Selected < 0 then Selected := MaxItems-1; MakeMenu (optText, MaxItems); end; end; until ch = #13; {Enter} MenuOption := Selected + 1; TextColor (optNormal); If _style = Vertical Then clrscr; end; procedure Add; begin end; procedure Subtract; begin end; procedure Divide; begin end; procedure Multiply; begin end; var Option: byte; { номер выбранного пункта } begin clrscr; _style := Vertical; { вертикальное меню } Option := MenuOption (optText1, Items1); case option of 1: Add; { сложить числа } 2: Subtract; { вычесть числа } 3: Divide; { поделить числа } 4: Multiply; { умножить числа } 5: exit; { Выйти из программы } end; { вывести (если нужно) номер выбранного пункта } writeln ('Номер пункта: ', option); readln; _style := Horizontal; { горизонтальное меню } Option := MenuOption (optText2, Items2); end.
Бывает, что есть необходимость добавить пояснительный текст рядом с меню. В подавляющем количестве студенты пишут тогда следующий код:
begin GotoXY (1,2); writeln ('Для управления пользуйтесь клавишами стрелок:'); GotoXY (1,4); writeln ('1 - сделать то-то...'); writeln ('2 - сделать то-то...'); writeln ('3 - сделать то-то...'); writeln ('4- сделать то-то...'); writeln ('5 - сделать то-то...'); end;
Особенно неудобно в программах с большим текстом кода. В нём можно просто утонуть.
Это дико неудобно возиться со множеством writeln, которые только отвлекают от сути, в то время как можно загрузить текст из текстового файла, заранее отредактированного в любом текстовом редакторе такой текст:
Для управления пользуйтесь клавишами стрелок:
1 - сделать то-то... 2 - сделать то-то... 3 - сделать то-то... 4 - сделать то-то... 5 - сделать то-то...
Не правда ли, удобнее?
Теперь рассмотрим процедуру, которая загрузит текст из отдельного текстового файла.
{ Эта процедура используется процедурой TextWindow для загрузки текста из отдельного текстового файла. }
procedure LoadText (fname: string); var F: text; str: string; begin Assign (F, fname); {$I-} Reset (F); {$I+} if IOresult = 0 then while Not EOF (F) do begin readln (F, str); writeln (str); end; Close (F); end;
Эта процедура выведет текст в заданном регионе (окне) из текстового файла fn.
{ Выводит текст в заданном регионе из текстового файла fn } procedure TextWindow (x1, y1, x2, y2: integer; fn: string); const TextColor = Cyan; { цвет фона региона } begin Window (x1, y1, x2, y2); TextBackground (TextColor); ClrScr; LoadText (fn); Window (1, 1, 80, 25); TextBackground (Black); end;
Таким образом, задав нужные вам параметры, вы увидите текст рядом с меню.
Например,
TextWindow (2, 2, 78, 7, 'strelki.txt'); _style := Vertical; { вертикальное меню } Option := MenuOption (optText1, Items1);
Здесь текст выводится в окне с границами 2, 2, 78, 7 из файла ‘strelki.txt’.
Вариант с использованием модуля
uses crt, menu_u; const width1 = 9; { Максимальная длина элементов (букв) меню } Items1 = 5; { Максимальное количество элементов меню 1 } optText1: array [0..Items1-1] of string = ('Сложение', 'Вычитание', 'Деление', 'Умножение', 'Выход'); width2 = 6; { Максимальная длина элементов (букв) меню } Items2 = 3; { Максимальное количество элементов меню 2 } optText2: array [0..Items2-1] of string = ( 'item 1', 'item 2', 'item 3' ); procedure Add; begin end; procedure Subtract; begin end; procedure Divide; begin end; procedure Multiply; begin end; var Option: byte; { номер выбранного пункта } begin clrscr; TextWindow (2, 2, 78, 7, 'menu.txt'); _style := Vertical; { вертикальное меню } Option := MenuOption (optText1, Items1, width1); case option of 1: Add; { сложить числа } 2: Subtract; { вычесть числа } 3: Divide; { поделить числа } 4: Multiply; { умножить числа } 5: exit; { Выйти из программы } end; { вывести (если нужно) номер выбранного пункта } writeln ('Номер пункта: ', option); readln; _style := Horizontal; { горизонтальное меню } Option := MenuOption (optText2, Items2, width2); end.
Описание программы
За построение меню отвечает процедура MakeMenu — её вызывает функция MenuOption, которая возвращает результат в виде индекса выбранного пункта.
Стиль меню определяется значением _style (Vertical/Horizontal) — то, как меню будет располагаться на экране.
_style := Vertical; { вертикальное меню }
Цвет нормальных элементов определяется константой optNormal, а цвет выделенных — optSelected.
Остаётся всего-лишь определить названия элементов меню в optText, константу Items (количество элементов меню), константу width (максимальная длина букв самой длинной строки меню) и меню готово!
Для вывода пояснительного текста рядом с меню можно воспользоваться процедурой TextWindow. Пять параметров означают координаты окна и название файла, из которого загрузится описание для меню.
Примечание:
Процедура TextWindow должна находиться перед построением меню. Иначе текста не будет видно!
Снимок экрана
Скачать
menudemo.zip
-
Menudemo.pas — программа построения меню без использования модуля.
-
Menu_t.pas — программа построения меню с модулем Menu_u.
Menu_u.pas — модуль с основными функциями и процедурами для построения меню.
Вариант 2 более предпочтителен, т.к. за счёт использования модуля гораздо легче ориентироваться в программе и отслеживать ошибки.
Пишем свое меню на Паскале
uses crt; { Глобальные данные: }
const maxmenu=2; {количество меню}
maxpoints=3; {макс. количество пунктов}
var x1,x2,y: array [1..maxmenu] of integer;
{x1,x2- начало и конец каждого меню, y- строка начала каждого меню}
kolpoints, points: array [1..maxmenu] of integer;{Кол-во пунктов и текущие пункты }
text: array [1..maxmenu,1..maxpoints] of string[12]; { Названия пунктов }
txtcolor, textback, cursorback:integer; { Цвета текста, фона, курсора}
mainhelp:string[80]; { Строка помощи }
procedure DrawMain (s:string); {Очищает экран, рисует строку главного меню s }
begin Window (1,1,80,25);
textcolor (txtcolor);
textbackground (textback);
clrscr; gotoxy (1,1); write (s);
end;
procedure DrawHelp (s:string); { Выводит подсказку s }
var i:integer; begin
textcolor (txtcolor);
textbackground (textback); gotoxy (1,25);
for i:=1 to 79 do write (‘ ‘);
gotoxy (1,25); write (s);
end;
procedure doubleFrame (x1,y1,x2,y2:integer; Header: string);
{ Процедура рисует двойной рамкой окно }
var i,j: integer;
begin gotoxy (x1,y1);
write (‘╔’);
for i:=x1+1 to x2-1 do write(‘═’);
write (‘╗’);
for i:=y1+1 to y2-1 do begin
gotoxy (x1,i); write(‘║’);
for j:=x1+1 to x2-1 do write (‘ ‘);
write(‘║’);
end;
gotoxy (x1,y2); write(‘╚’);
for i:=x1+1 to x2-1 do write(‘═’);
write(‘╝’);
gotoxy (x1+(x2-x1+1-Length(Header))
div 2,y1);
write (Header); {Выводим заголовок}
gotoxy (x1+1,y1+1);
end;
procedure clearFrame (x1,y1,x2,y2:integer);
var i,j:integer;
begin textbackground (textback);
for i:=y1 to y2 do begin
gotoxy (x1,i);
for j:=x1 to x2 do write (‘ ‘);
end;
end;
procedure cursor (Menu,Point: integer; Action: boolean);
{ Подсвечивает (если Action=true) или гасит п. Point меню Menu}
begin textcolor (Txtcolor);
if Action=true then
textbackground (cursorBack)
else textbackground (textBack);
gotoxy (x1[Menu]+1,y[Menu]+Point);
write (text[Menu][Point]);
end;
procedure DrawMenu (Menu:integer; Action: boolean);
{Рисует меню с номером Menu, если Action=true, иначе стирает }
var i:integer;
begin
if Action=true then textcolor (Txtcolor)
else textcolor (textBack);
textbackground (textBack);
doubleFrame (x1[Menu], y[Menu], x2[Menu], y[Menu]+1+KolPoints[Menu],»);
for i:=1 to KolPoints[Menu] do begin
gotoxy (x1[Menu]+1, y[Menu]+i);
writeln (text[Menu][i]);
end;
end;
{Часть, определяемая пользователем}
procedure Init; { Установка глобальных данных и начальная отрисовка }
begin
txtcolor:=yELLOW; textback:=BLUE;
cursorback:=LIGHTcyAN;
kolpoints[1]:=2; kolpoints[2]:=1;
{пунктов в каждом меню}
points[1]:=1; points[2]:=1; {выбираем по умолчанию в каждом меню}
x1[1]:=1; x2[1]:=9; y[1]:=2;
text[1,1]:=’Запуск’; text[1,2]:=’Выход ‘;
x1[2]:=9; x2[2]:=22; y[2]:=2;
text[2,1]:=’О программе’;
DrawMain (‘Файл Справка’);
MainHelp:=’ESC — Выход из программы ‘+’ENTER — выбор пункта меню ‘+ ‘Стрелки — перемещение’;
DrawHelp(MainHelp);
end;
procedure Work; { Рабочая процедура }
var i,kol:integer; ch:char;
begin
DrawHelp(‘Идет расчет…’); { Строка статуса }
textcolor (LIGHTGRAY);
textbackground (BLACK); { Выбираем цвета для работы в окне }
doubleFrame (2,2,78,24,’ Расчет ‘);
Window (3,3,77,23);
{Секция действий, выполняемых программой}
writeln;
write (‘Введите число шагов: ‘);
{$I-}read (kol);{$I+}
if IoResult<>0 then writeln (‘Ошибка! Вы ввели не число’)
else if kol>0 then begin
for i:=1 to kol do
writeln (‘Выполняется шаг ‘,i);
writeln (‘Все сделано!’);
end
else writeln (‘Ошибка! Число больше 0’);
{Восстановление окна и выход}
Window (1,1,80,25);
DrawHelp(‘Нажмите любую клавишу…’);
ch:=readkey;
clearFrame (2,2,78,24); { Стираем окно }
end;
procedure Out; { Очистка экрана и выход}
begin
textcolor (LIGHTGRAY);
textbackground (BLACK); clrscr; halt(0);
end;
procedure Help; {Окно с информацией}
var ch:char;
begin
textcolor (Txtcolor);
textbackground (textback);
doubleFrame (24,10,56,13,’ О программе ‘);
DrawHelp (‘Нажмите клавишу…’);
gotoxy (25,11);
writeln(‘ Демонстрация простейшего меню’);
gotoxy (25,12);
write ( ‘ Киев, КГУ’);
ch:=readkey;
clearFrame (24,10,58,13);
end;
procedure command (Menu,Point:integer);
{Вызывает процедуры после выбора в меню }
begin
if Menu=1 then begin
if Point=1 then Work
else if Point=2 then Out;
end
else begin
if Point=1 then Help;
end;
end;
{Конец части пользователя }
procedure MainMenu (Point,
HorMenu:integer); { Поддерживает систему одноуровневых меню }
var ch: char; funckey:boolean;
begin
Points[HorMenu]:=Point;
DrawMenu (HorMenu,true);
repeat
cursor (HorMenu,Points[HorMenu],true);
ch:=readkey;
cursor (HorMenu,Points[HorMenu],false);
if ch=#0 then begin
funckey:=true; ch:=readkey;
end
else funckey:=false;
if funckey=true then begin
ch:=Upcase (ch);
if ch=#75 then begin { Стрелка влево }
DrawMenu (HorMenu,false);
HorMenu:=HorMenu-1;
if (HorMenu<1) then HorMenu:=maxMenu;
DrawMenu (HorMenu,true);
end
else if ch=#77 then begin
{ Стрелка вправо }
DrawMenu (HorMenu,false);
HorMenu:=HorMenu+1;
if (HorMenu>maxMenu) then HorMenu:=1;
DrawMenu (HorMenu,true);
end
else if ch=#72 then begin
{ Стрелка вверх }
Points[HorMenu]:=Points[HorMenu]-1;
if Points[HorMenu]<1 then
Points[HorMenu]:=Kolpoints[HorMenu];
end
else if ch=#80 then begin
{ Стрелка вниз }
Points[HorMenu]:=Points[HorMenu]+1;
if (Points[HorMenu]>KolPoints[HorMenu])
then Points[HorMenu]:=1;
end;
end
else if ch=#13 then begin
{ Клавиша ENTER }
DrawMenu (HorMenu,false);
command (HorMenu,Points[HorMenu]);
DrawMenu (HorMenu,true);
DrawHelp (MainHelp);
end;
until (ch=#27) and (funckey=false);
{ Пока не нажата клавиша ESC }
end;
{ Основная программа }
begin
Init;
MainMenu (1,1);
Out;
end.
2010-07-17 • Просмотров [ 10420 ]
1.Вывести на экран монитора систему меню, расположенную горизонтально или
вертикально. Перед выводом системы меню необходимо вывести заставку.
2. В любой момент времени должен быть выбран только один элемент меню,
который должен выделяться с помощью другого цвета, повышенной или пониженной
интенсивности свечения, выделения первой буквы в названии или иным способом.
3. Необходимо иметь возможность перемещаться по пунктам горизонтальной
системы меню с помощью клавиш <Стрелка влево> и <Стрелка вправо>, а по пунктам
вертикальной системы меню с помощью клавиш <Стрелка вверх> и <Стрелка вниз>.
4. Необходимо иметь возможность выбора элемента меню нажатием на клавишу
<Enter> или какую-либо другую аналогичную клавишу.
5. Необходимо иметь возможность выхода из системы меню нажатием на клавишу
<Esc> или какую-либо другую аналогичную клавишу.
Заставка:Выбор учебного предмета;
Элементы меню:1)Физика;2)Математика;3)Химия;4)Биология;
Тип меню:Вертикальное
Информационное сообщение:»Выбран учебный предмет<…>»
uses crt; {массив названий пунктов меню} const vybor:array[1..5] of string=('1-Физика', '2-Математика', '3-Химия', '4-Биология', '5-Выход'); procedure Menyu(var k:byte;kol:byte); var kod: char; i:byte; begin clrscr; k:=1; gotoxy(1,1); repeat for i:=1 to kol do begin if i=k then begin textbackground(2); textcolor(1); end else begin textbackground(7); textcolor(0) end; gotoxy(1,i); write(vybor[i]); end; writeln; textbackground(0); textcolor(15); write('Для выхода можно нажать Esc..'); repeat kod:=readkey; until kod in [#32, #72, #80,#27]; case kod of #72: begin {стрелка вверх} k:=k-1; if k=0 then k:=kol;{если верхний край, вниз} end; #80: begin {стрелка вниз} k:=k+1; if k>kol then k:=1;{если нижний край, вверх} end; #27:begin{возможность выхода по Esc} k:=5; exit; end; end; until kod in [#32,#27]; end; var k:byte; begin textbackground(3); textcolor(14); clrscr; gotoXY(30,11); write('ВЫБОР УЧЕБНОГО ПРЕДМЕТА'); gotoXY(25,12); write('перемещение по меню стрелки вверх и вниз'); gotoXY(29,13); write('выбор пункта меню клавиша ПРОБЕЛ'); textcolor(15); gotoXY(35,15); write('нажмите Enter'); readln; repeat Menyu(k,5);{выводим меню} case k of{выбираем стрелками действие} 1:begin clrscr; writeln('Выбран учебный предмет Физика'); write('нажмите Enter'); readln; end; 2:begin clrscr; writeln('Выбран учебный предмет Математика'); write('нажмите Enter'); readln; end; 3:begin clrscr; writeln('Выбран учебный предмет Химия'); write('нажмите Enter'); readln; end; 4:begin clrscr; writeln('Выбран учебный предмет Биология'); write('нажмите Enter'); readln; end; end; until k=5; end.
Реализация меню
предполагает выполнение следующих
операций:
1)
вывод пунктов меню основной парой цветов
(фона и текста);
2)
вывод выбранного пункта меню другой
парой цветов (более яркой);
3) передвижение по
меню с помощью традиционных управляющих
клавиш;
4)
выбор пункта меню для выполнения
соответствующей операции;
5) выход из меню.
Три последние
операции выполняются с использованием
управляющих клавиш, которые имеют
следующие коды:
#13
–
Enter;
#27
– Esc;
#77
– перемещение курсора влево;
#75
– перемещение курсора вправо;
#72
– перемещение курсора вверх;
#80
– перемещение курсора вниз.
Первым
двум кодам соответствует один байт
(символ), а остальным – два, причем первый
байт у них имеет нулевой код.
Рассмотрим
алгоритм и программу на примере
горизонтального меню, содержащего не
более 5 пунктов. Выбор пункта осуществляется
нажатием клавиши Enter,
а выход из него и из программы – нажатием
клавиши Esc.
После выбора пункта для простоты выдается
сообщение о том, что он выполняется.
Названия пунктов соответствуют названиям
операций.
Алгоритм
1.1. Задать пункты
меню.
1.2. Очистить экран.
1.3. Начальное
положение курсора (пункт меню) pm = 1.
2. Повторять
{движение по меню}
2.1. Повторять
2.1.1.
Вывести все пункты меню основной парой
цветов.
2.1.2.
Вывести текущий пункт меню pm другой
парой цветов.
2.1.3.
Считать символ с клавиатуры
{действия пользователя}
2.1.4.
Если символ = #0, то {нажата
управляющая клавиша}
а)
Считать символ {читаем второй
код нажатой клавиши}
б) Выбрать символ
из значений
#77 : Движение вправо
#75 : Движение влево
Пока
Символ не будет равен Esc
или Enter.
2.2.
Если Символ равен Enter
то
Выбрать pm из
значений
1
: Вывести: ’Выполняется
пункт 1’
2
: Вывести: ’Выполняется
пункт 2’
3
: Вывести: ’Выполняется
пункт 3’
4
: Вывести: ’Выполняется
пункт 4’
5
: Закончить (Символ = Esc)
Пока
Символ не будет равен Esc.
3. Закончить
Движение
вправо и влево должно быть круговым,
т.е. при движении вправо номер пункта
увеличивается на 1, пока он не станет
равен последнему номеру. После этого
номер должен принять значение 1. При
движении влево после первого пункта
номер должен стать последним.
В
программе необходимо задать координаты
первого пункта. Если принять названия
всех пунктов меню одинаковыми, то начало
пункта с номером pm
на экране будет иметь координаты:
(xn + (pm — 1)*dl, yn),
где
xn и yn – координаты начала первого
пункта меню;
dl
— длина названия пункта меню (одинаковая
для всех пунктов).
Программа
для описанного выше алгоритма имеет
вид.
Program
Gor_Menu;
Uses
Crt;
Const
Dl
= 12; {длина названия пункта меню — шаг
перемещения}
M
= 5; { количество пунктов }
Enter
= #13;
Esc
= #27;
Var
Punkt
: Array[1..m] of String[dl]; { Массив
названий
}
{
пунктов
меню}
pm,i,xn,yn
: Integer;
Sim
: Char;
Begin
{п.
1.1 }
Punkt[1]
:= ’ Операция
1 ’;
Punkt[2]
:= ’ Операция 2 ’;
Punkt[3]
:= ’ Операция 3 ’;
Punkt[4]
:= ’ Операция 4 ’;
Punkt[5]
:= ’ Выход ’;
{
Очистка
экрана
}
TextBackGround(Blue);
ClrScr;
{
Начальное положение курсора и меню }
pm
:= 1;
xn
:= 10;
yn
:= 3;
Repeat
{ п.
2 }
Repeat
{ Цикл движения по меню }
GotoXY(xn,yn);
{
Основные цвета меню }
TextBackGround(Blue);
TextColor(White);
For
i := 1 to m do
Write(Punkt[i]);
{
Текущий пункт перекрашиваем }
TextBackGround(Green);
TextColor(Red);
GotoXY(xn+dl*(pm-1),yn);
Write(Punkt[pm]);
{
Ожидаем действий пользователя на
клавиатуре}
Sim
:= Readkey;
If
Sim = #0 then
Begin
{ Управляющая
клавиша
}
Sim
:= Readkey;
Case
Sim of
#77
: { Движение
вправо
}
If
pm=m then
pm:=1
Else
pm:=pm+1;
#75
: { Движение влево }
If
pm=1 then
pm:=m
Else
pm:=pm-1;
End;
{ Case }
End;
{ If }
Until
(Sim = Enter) Or ( Sim = Esc); { Цикл
движения
}
If
Sim = Enter then
{
Пункт
меню
выбран
}
If
pm
= m
then
Sim
:= Esc
{Выбран последний пункт меню — выход}
Else
Begin
GotoXY(30,10);
Write(’Выполняется
’,Punkt[pm]);
End;
Until
Sim = Esc;
{ Внешний цикл, окончание работы }
GotoXY(30,10);
Writeln(’Конец
работы, нажмите любую клавишу ’);
Repeat
Until KeyPressed;
End.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #