Изучивши предложенные варианты и впоследствии систематизировав их, я понял что это не то. А вот те критерии, которые считаю главенствующими в моём представлении о меню: 1)Небольшое(20-40 строк)-иначе говоря для чайников; 2)Расположенное только в процедуре(НЕ в модуле и основной программе)-чтобы, как говорится с места в карьер; 3)Управление меню только КЛАВИШАМИ (точнее стрелками "вверх" и "вниз"). Причём указанная в данный момент (как бы её назвать) титра должна делать вид, что именно её на даный момент выбрали; 4)Прежде чем спросить про язык, на которым я ПРОШУ написать меню, просто вспомните название сайта; 5)Всего 3 титры. За сим удаляюсь с большой надеждою, всегда ваш 1234.
TarasBer
2.02.2007 23:24
Подразумевается, что подключены CRT и Graph.
function Menu(Params: string): integer; var Count: integer; Strings: array [0 .. 15] of string [127]; i: integer; Ch: char; X, Y, H: integer; begin Count := 1; Strings[0] := ''; for i := 1 to Length(Params) do begin if Params[i] = #13 then begin Inc(Count); Strings[Count - 1] := ''; end else begin Strings[Count - 1] := Strings[Count - 1] + Params[i]; end; end; SetTextJustify(CenterText, CenterText); H := TextHeight('A') + 10; ClearDevice; SetColor(WHITE); for i := 0 to Count - 1 do OutTextXY(GetMaxX div 2, GetMaxY div 2 - (Count - 1) * H div 2 - H div 4 + i * H, Strings[i]); i := 0; repeat SetColor(GREEN); X := TextWidth(Strings[i]) + 10; Y := TextHeight(Strings[i]) + 10; Rectangle(GetMaxX div 2 - X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H - Y div 2, GetMaxX div 2 + X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H + Y div 2); ch := readkey; SetColor(BLACK); X := TextWidth(Strings[i]) + 10; Y := TextHeight(Strings[i]) + 10; Rectangle(GetMaxX div 2 - X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H - Y div 2, GetMaxX div 2 + X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H + Y div 2); case ch of #0: case ReadKey of #72: begin Dec(i); if i < 0 then i := Count - 1; end; #80: begin Inc(i); if i >= Count then i := 0; end; end; end; until ch = #13; Menu := i; end;
Примитивнее не могу.
Пример вызова такой процедуры: Choise := Menu('New'#13'Open'#13'Save'#13'Exit'); Возвращает номер выбранного пункта, причём нумерация от нуля (New - это 0, а Exit - это 3)
То есть параметр - одна строчка, которая содержит все пункты меню, разделённые #13. Количество пунктов - не более 15, каждый пункт не длинее 100 символов. Если перед вызовом написать SetTextStyle(4, 0, 7); то выглядит интересно...
volvo
2.02.2007 23:43
Цитата
просто вспомните название сайта
Больше так не говори, хорошо?
TMT Pascal / VP (Virtual Pascal) / Turbo Pascal / FPC (Free Pascal) / GPC (GNU Pascal Compiler) ... А теперь посмотри на название сайта... И что? Я же могу и продолжить список...
М
В следующий раз давай точное название компилятора - твои предыдущие темы не обязаны быть прочитанными перед чтением этой... volvo
1234
3.02.2007 21:49
Да, Pascal безграничен. Как сделать, чтобы войдя в титру, получить итогом ещё одну титру(напрмер, войдя в "Уровень сложности" получить "Hard", "Meadle", "Easy"). А также, как обращаться к функции(нажав ЕXIT получить выход).
mamont001
3.02.2007 22:54
Просто делаеш :
if нажато уровень сложности then begin clearscreen; newmenu('hard'#13'medium'#13'easy') end;
TarasBer
3.02.2007 23:04
Цитата(1234 @ 3.02.2007 17:49)
Да, Pascal безграничен. Как сделать, чтобы войдя в титру, получить итогом ещё одну титру(напрмер, войдя в "Уровень сложности" получить "Hard", "Meadle", "Easy"). А также, как обращаться к функции(нажав ЕXIT получить выход).
Ну, например (условно):
Код
begin i := 9; j := 2; {VGA 640X480 16 colors} InitGraph(i, j, ''); CanExit := False; BotLevel := 1; repeat case Menu('New'#13'Level'#'Exit') of 0: Game; 1: BotLevel := Menu('Easy'#13'Medium'#13'Hard'); 2: CanExit := True; end; until CanExit; CloseGraph; end.
Типа тело программы... Должно работать. Советую найти (или сделать, как я когда-то...) русский файл со шрифтом и все пункты меню написать по-русски. Процедура Game - типа запуск игры (сами напишете). Для выхода из программы надо выбрать Exit (тогда происходит выброс из цикла); А после выбора уровня сложности снова вызывается первоначальное меню... (Переменная BotLevel хранит уровень сложности).
А лучше почитайте Фаронова на досуге... Полезная книга.
1234
4.02.2007 22:46
А как сделать так, чтобы (желательно в самой подпрограммке) при нажатии определённой клавиши производился переход на предыдущее меню(скажем, выхожу из меню выбора сложности и попадаю в начальное меню). Честно говоря, менюшка замудрённая (точнее способ её осуществления)-сам факт того, что осуществляется она в функции...Хотя, конечно, огромное спасибо создателю. И ещё, пожалуй, вопросик: при описании после case и 0: или 1: почему нельзя поставить подпрограмму(например, по выводу какой-то информации).
Bokul
4.02.2007 22:57
Ты сначала разберись с тем, что тебе дали. Подобные вопросы сразу отпадут.
Цитата
Честно говоря, менюшка замудрённая (точнее способ её осуществления)-сам факт того, что осуществляется она в функции...
Наоборот. Тебе что нужно знать от меню? Выбранный пункт, что и предоставляет тебе функция. А способ реализации тебя вообще не волнует. Вот ты, написав прогу на тысячу строк, решил что графика меню тебя не удовлетворяет. Но вместо переписывания пол программы, ты меняешь одну функцию, и то только способ вывода на экран.
1234
4.02.2007 23:27
Ты знаешь, только хотел сказать. Чтобы осуществлять Васк у меня ума хватило. Второй вопрос остаётся открытым(хотя я сейчас занимаюсь тем, чтоб он отпал).
volvo
4.02.2007 23:35
Цитата
И ещё, пожалуй, вопросик: при описании после case и 0: или 1: почему нельзя поставить подпрограмму(например, по выводу какой-то информации).
Тогда и у меня к тебе вопросик - что есть по-твоему Game? Не подпрограмма? Она что, НЕ стоит после Case 0: ?
Задавай вопросы яснее, что ты имеешь в виду?
1234
4.02.2007 23:57
Не мешало бы мсье TarasBerу написать комментарии к данной функции. А тем временем у меня уже немного другое обращение к функции. И где должна стоять GAME ничего не стоит, т.к. запускается она в основной программе позже. Кстати, налицо небольшой глюк-меню появляется, когда Press any key.
While c<>#98 do Begin C:=Readkey; Case Menu('New'#13'option'#13'Exit') of 0: C:=#98; 1: OutTextXY(140,90,'Hello'); 2: Exit; End; Case Menu('Easy'#13'Medium'#13'Hard'#13'Back') of 0: Begin Sl:=50; C:=#98; End; 1: Begin Sl:=100; C:=#98; End; 2: Begin Sl:=1; C:=#98; End; 3: C:=#4; end;
А, кстати, что это у меня репутация -1. Где меня успела настигнуть дурная слава.
TarasBer
5.02.2007 1:08
Цитата(1234 @ 4.02.2007 19:57)
Не мешало бы мсье TarasBerу написать комментарии к данной функции.
А что именно неясно? Всё элементарно... Сразу предупрежу: после добавления коментариев текст уже не влезает в 80 символов по ширине...
function Menu(Params: string): integer; {так объявляются функции} var {это открывается раздел локальных переменных} Count: integer; {это объявляется переменная целого типа - она будет обозначать число пунктов меню} Strings: array [0 .. 15] of string [127]; {а это сами пункты меню - для них я завёл массив} i: integer; {вспомогательная переменная - счётчик. впоследствии является номером выбранного пункта меню} Ch: char; {переменная - символ - обозначает нажатую клавишу} X, Y, H: integer; {X и Y - размеры пункта меню. H - высота символа} begin Count := 1; {сначала дробим строку на подстроки. Считаем, что одна подстрока уже есть} Strings[0] := ''; {и что она изначально пустая} for i := 1 to Length(Params) do begin {перебираем все символы строки - параметра. ленгтх - это длина строки} if Params[i] = #13 then begin {если очередной символ - #13} Inc(Count); {то добавляем новый пункт меню} Strings[Count - 1] := ''; {который считаем изначально пустым} end else begin {иначе} Strings[Count - 1] := Strings[Count - 1] + Params[i]; {к последнему пункту меню приписываем текущий символ строки} end; {а в бегин-енд я это загнал просто так, потому что писАл экспромтом} end; SetTextJustify(CenterText, CenterText); {чтобы всё посерединке выводилось} H := TextHeight('A') + 10; {высота символа, к которой для запаса прибавили 10} ClearDevice; {очищаем экран, то есть всё стираем} SetColor(WHITE); {устанавливаем белый цвет текста} for i := 0 to Count - 1 do {ну и выводим все строки} OutTextXY( { чтоб середина строки совпала с серединой экрана } GetMaxX div 2,
{ и здесь аналогично с учётом номера пункта меню, только - H div 4 я приписал для того, чтобы хвостики букв p, q, y итд не вылазили (извините, люди, я специально пошёл против себя и написал div 4 вместо shr 2, чтобы 1234 точно понял) } GetMaxY div 2 - (Count - 1) * H div 2 - H div 4 + i * H,
Strings[i] ); i := 0; {с этого момента i - номер выбраного пункта меню} repeat {начало цикла с постусловием (вроде в термине не ошибся?)} SetColor(GREEN); {устанавливаем зелёный цвет прямоугольников} X := TextWidth(Strings[i]) + 10; {запоминаем ширину строки з запасом} Y := TextHeight(Strings[i]) + 10; {ну и высоту} Rectangle(GetMaxX div 2 - X div 2, {и обводим её в прямоугольничек} GetMaxY div 2 - (Count - 1) * H div 2 + i * H - Y div 2, GetMaxX div 2 + X div 2, {надеюся, назначеник процедуры ректангл пояснять не надо...} GetMaxY div 2 - (Count - 1) * H div 2 + i * H + Y div 2); ch := readkey; {ждём нажатия клавиши...} SetColor(BLACK); {устанавливаем чёрный цвет} X := TextWidth(Strings[i]) + 10; {это убрать} Y := TextHeight(Strings[i]) + 10; {это стереть} Rectangle(GetMaxX div 2 - X div 2, {удаляем зелёный прямокгольник, нарисовав поверх него чёрный} GetMaxY div 2 - (Count - 1) * H div 2 + i * H - Y div 2, GetMaxX div 2 + X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H + Y div 2); case ch of {смотрим, какая же клавиша нажата...} { если встретился нулевой символ - значит надо опять вызвать ридкей, потому что так надо } #0: case ReadKey of #72: begin {сканкод стрелочки вверх} Dec(i); {ну уменьшаем на 1 номер выбранного пункта меню} if i < 0 then {а если залезли вверх за край} i := Count - 1; {то вылазим снизу} end; #80: begin {сканкод стрелочки вниз} Inc(i); {увеличиваем на 1 номер выбранного пункта меню} if i >= Count then {но если ниже некуда} i := 0; {то переносимся наверх} end; end; end; until ch = #13; {и весь цикл крутим, пока 1234 не нажмёт enter} Menu := i; {и говорим, чтобы функция выдала номер выбранного пункта меню} end;
Мсье 1234, самый главный коментарий - почитайте хорошее руководство по Паскалю. Особенно я рекомендую 1ю часть Фаронова. Прочитав её и разобравшись в ней, вы уже не будете задавать такие вопросы, а то, извиняюсь, возникает ассоциация со Светланой Семененко (<http://forum.kaspersky.com/index.php?showtopic=19230>)...
М
Подкорректировал пост, чтобы все-таки не было такого "расползания" в ширину... volvo
TarasBer
5.02.2007 1:57
Пока писал коментарии, под конец нервы стали сдавать...
1234, в вашем куске программы мало что понятно... Во-первых, переменная цэ у вас не инициализирована. И может так оказаться, что цэ изначально был равен #98, и тогда цикл вообще ни разу не выполнится. Поэтому советую вайл заменить на репит-антил. Во-вторых, непонятно назначение первого ридкея. Причём вы не учли, что некоторые клавиши оставляют в клавиатурном буфере не 1, а 2 символа. То есть, надо как минимум его заменить на
if ReadKey = #0 then ReadKey;
Во-третьих, второе меню вызывается в любом случае... Кроме пункта Exit. Я надеюсь, что это у вас кусок из процедуры, а не из тела программы, а то при выборе Exit программа завершает работу, даже не закрыв графический режим - для тех, кто работает в фаре или вообще под досом, это важно. В-четвёртых, фраза хелло будет видна на экране долю секунды, так как при вызове второго меню она тут же сотрётся. Чтоб не стиралось, можно убрать строчку клиардевайс из поцедуры меню, но тогда вы сами должны не забывать стирать лишнее перед его вызовом.
Так что я даже идею текста не понял...
1234
5.02.2007 18:03
Заменой преведённой выше воспользовался. Эффект тот же. Как пахало, так и пашет. А вот про пункт Exit ты меня заинтересовал. И "приведённый ниже кусок" (как вы изволили выразиться) у меня в основной части. Чтобы лучше понять, связываю меню с програмкою-так сказать, для наглядности.
Uses Graph,Crt; const Left =#75; Right = #77; Up = #72; Esc = #27; var ErrCode : Integer; P1: pointer; S, x, y, sized,i,j :integer; Ch: char; x1: integer; C:Char;Sl:Integer; Function Menu(new: string): Integer; Var Count: integer; Strings: array [0 .. 15] of string [127]; I: integer; Ch: char; X, Y, H: integer; Begin Count := 1; Strings[0] := ''; For i := 1 to Length(new) do begin If new[i] = #13 then begin Inc(Count); Strings[Count - 1] := ''; end else Strings[Count - 1] := Strings[Count - 1] + new[i]; end; SetTextJustify(CenterText, CenterText); H := TextHeight('A') + 10; ClearDevice; SetColor(WHITE); For i := 0 to Count - 1 do OutTextXY(GetMaxX div 2, GetMaxY div 2 - (Count - 1) * H div 2 - H div 4 + i * H, Strings[i]); I := 0; Repeat SetColor(GREEN); X := TextWidth(Strings[i]) + 10; Y := TextHeight(Strings[i]) + 10; Rectangle(GetMaxX div 2 - X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H - Y div 2, GetMaxX div 2 + X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H + Y div 2); Ch := readkey; SetColor(BLACK); X := TextWidth(Strings[i]) + 10; Y := TextHeight(Strings[i]) + 10; Rectangle(GetMaxX div 2 - X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H - Y div 2, GetMaxX div 2 + X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H + Y div 2); Case ch of #0: Case ReadKey of #72: Begin Dec(i); If i < 0 then I := Count - 1; End; #80: Begin Inc(i); If i >= Count then I := 0; End; End; End; Until ch = #13; Menu := i; If ch=#13 then ClearDevice; End; Procedure Init; Var Gd,Gm:Integer; Begin Gd:=Detect; InitGraph(Gd,Gm,'') End; Begin Init; {Число клавиши 98 взял от фонаря(главное чтоб выполнялось)} While c<>#98 do {Вот здесь где-то зарыта собака-чтобы меню высветилось необходимочто-нибудь нажать} Begin If ReadKey=#0 Then ReadKey; Case Menu('New'#13'option'#13'Exit') of 0: C:=#98; {Данное присваивание- это как какой-то доступ к последующему этапу} 1:Begin SetTextStyle(DefaultFont,HorizDir,5); SetColor(LightBlue); {Здесь я просто хочу, чтобы на экране высветились сведения об игре} OutTextXY(140,90,'Hello'); End; 2: Exit;{А здесь то в чём ошибка} End; Case Menu('Easy'#13'Medium'#13'Hard'#13'Back') of 0: Begin Sl:=50; {Это у меня уровень сожности} C:=#98; {Эта операция-для доступа к игре} End; 1: Begin Sl:=100; C:=#98; End; 2: Begin Sl:=1; C:=#98; End; 3: C:=#4; end; {4-число от фонаря: главное-что не 98} end; setfillstyle(1,4); {Эту часть програмы оставьте без анализа-она просто демонстрирует работу меню} setcolor(4); line(110,50,110,60); line(110,70,110,73); setfillstyle(1,1); setcolor(1); fillellipse(110,65,20,5); floodfill(110,65,1); line(130,73,90,73); sized:=imagesize(30,50,180,50); getmem(p1,sized); getimage(30,56,180,90,p1^); cleardevice; x:=225; y:=450; x1:=x; putimage(x,y,p1^, xorput); repeat ch:=readkey; if ch=#0 then ch:=readkey; case ch of left : x1:=x-10; right: x1:=x+10; end; if ch=up then begin for i:=1 to 450 do begin if i<440 then putpixel(x1+80,440-i+5,white); delay (1); putpixel(x1+80,440-i+10,black); end; end; if (x1 < 0) or (x1 > GetmaxX-150) then x1:=x; putimage(x,y,p1^,xorput); putimage(x1,y, p1^,xorput); x:=x1; until ch=Esc; CloseGraph; end. End.
TarasBer
5.02.2007 18:57
Эээ... Я не понял. Вам надо, чтом меню сразу высветилось? Или чтоб именно после нажатия клавиши? В первом случае ридкей убрать надо, конечно. А во втором случае надо перед ридкеем на всякий случай очистить клавиатурный буфер. То есть перед ридкеем надо написать
while KeyPressed do ReadKey;
Я так и не увидел, как вы боритесь со случаем, когда c изначально, при запуске программы, равно #98. В Паскале непроинициализированные переменные не обнуляются. Что было в оперативной памяти до запуска программы, то в переменной и окажется. Далее, замените же наконец Exit на
begin CloseGraph; Exit; end;
Вы работаете в проводнике что-ли? Или всё таки в тотал командере? Так вот, некоторые люди, вроде меня, в качестве файлового менеджера используют ФАР, который использует ТЕКСТОВЫЙ режим. И если какая-то программа забыла за собой закрыть графику, то ФАР вместо связной картинки выведет на экран бред. А тем, кто работает под ДОСом после вашей программы остаётся либо запустить что-нибудь, восстнавливающее текстовыцй режим, либо всё - РЕСЕТ. Для вывода сведений о программе вместо options пишут about... Определитесь с отступами - 2 или 3 пробела. А то увидел, как вы мою процедуру переписали - чуть не упал. Лучше бы вы её просто ctrl-insert - shift-insert в любую виндоуз-программу, в которой открыт ваш ***.pas. Меня сейчас все обматерят, но рекомендую для повышения читабельности писать бегин на одной строчке с предыдущим словом (енд - елсе тоже пишите в одну строчку, а не так, что елсе на следующей строке после десяти пробелов) и писать все зарезервированные слова маленькими буквами. Конечно, выбор стиля программирования - дело творческое, но вы, похоже, этот выбор ещё не сделали. Далее, не рекомендую defaultfont. Например потому, что у некоторых (у меня, например) этот шрифт вместо цифр и пробелов рисует иероглифы. Или потому, что его нельзя переделать под русские буквы. После writeln('Hello'); неплохо б написать
WriteLn('press enter...'); while KeyPressed do ReadKey; repeat ch := ReadKey; if ch = #0 then ReadKey; until ch = #13;
И при выводе сведений о программе рекомендую во всех outtextxy первым параметром писать GetMaxX div 2 (или shr 1, чтобы мне глаз меньше резало), чтобы весь текст выводился повередине. Либо вы вообще не указывайте явные координаты, либо явно задайте графический режим (Gd := 9; Gm := 2), а то вдруг у кого-то на древнем 8086 - CGA... Надо, чтоб программа либо в любом случае рисовала правильную картинку, либо просто не запускалась на компах с не тем видеоадаптером. И у вас всё равно после вывода сведений о программе вызывается второе меню. Чтобы этого не было, поместите тогда уж первое меню в цикл репит-антил с условием выхода i=0 (где в переменную i сразу записывается значение функции, то есть вместь case menu of сделайте i := menu; case i of). И не забывайте, что #72 - это всё таки 'H', а #0#72 - это уже стрелочка. Либо заводите две переменные для считывания (я так делаю) - Key и ScanKey и пишите везде
Key := ReadKey; if Key = #0 then ScanKey := ReadKey else ScanKey := #0;
либо, случай Key = #0 разбирайте внутри:
ch := ReadKey; case ch of #0: begin ch := ReadKey; case ch of Up: ... Left: ... Right: ... end; {здесь писать if ch = up then ... нельзя, птому что сработает и при нажатии 'H'}
И всё, что я вам объясняю сейчас, есть в первой части Фаронова. В который раз я из-за вас нарушаю правило №8, рекламируя одну и ту же книгу...
Чёто я после case of стал двоеточия ставить... А ведь вечер ещё не наступил...
1234
5.02.2007 20:25
Первый случай, второй... Это хоть в основной части. Поясните. А так же, после надписи приветствия я давлю ентер и попадаю в меню выбора сложности. А как хотелось бы в начальном. Как хоть ваш Фаронов выглядит: была у мнея одна такая. Так в ней писалось о традиционных прцедурах. Вместо подробностей были какие-то защиты от нелегального копирования. Зачем бороться с 98? Ума не приложу. Ведь всё арекрасно вкатывает. Что касается стиля программирования, то от текущего я не отступлю. НИКОГДА.
TarasBer
5.02.2007 21:07
Цитата(1234 @ 5.02.2007 16:25)
Первый случай, второй... Это хоть в основной части. Поясните. А так же, после надписи приветствия я давлю ентер и попадаю в меню выбора сложности. А как хотелось бы в начальном. Как хоть ваш Фаронов выглядит: была у мнея одна такая. Так в ней писалось о традиционных прцедурах. Вместо подробностей были какие-то защиты от нелегального копирования. Зачем бороться с 98? Ума не приложу. Ведь всё арекрасно вкатывает. Что касается стиля программирования, то от текущего я не отступлю. НИКОГДА.
В таком случае ничем не могу помочь. Я всё объяснил.
volvo
5.02.2007 21:12
Цитата
В Паскале непроинициализированные переменные не обнуляются. Что было в оперативной памяти до запуска программы, то в переменной и окажется.
Глобальные - ОБЯЗАНЫ обнуляться, локальные - нет, с локальными действительно проблема...
1234
5.02.2007 21:45
Объяснить-то ты всё объяснил. А мне необходимо пояснить. Укажи, какие именно случаи ReadKey?
TarasBer
6.02.2007 18:56
Да, глобальные обнуляются... Даже массивы, как ни странно. Ошибся я. Но злоупотреблять этим не стОит, лучше для очистки совести самому всё обнулить. 1234: держите. Сделал всё что мог. Я ушёл писать редактор chr файлов...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.