Мне было интересно реализовать динамическое меню для консольного приложения. Динамическое оно, потому что, перемещение по пунктам меню будет происходить при помощи клавиш вверх и вниз. В качестве языка программирования будем использовать Си.
И так приступим. Для начала нам необходимо подключить заголовочные файлы.
Функция frame отрисовывает рамку.
И так приступим. Для начала нам необходимо подключить заголовочные файлы.
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <conio.h>А так же для простоты введем макрос для вывода названия пункта меню.
#define PRINT( val ) printf("\n %s\n", val);
Далее, реализуем пункты меню. При выборе пункта меню, он будет выделен рамкой. Но так как любое консольное приложение это прежде всего текстовое приложение без какой либо графики, то в меню задействуем псевдографику. Например элемент псевдографики ╔ соответствует шестнадцатеричному коду 0xC9, а элемент ║ коду 0xBA и т. д.Функция frame отрисовывает рамку.
void frame(char *item)
{
int i, len;
len = strlen(item);
printf("%c", 0xC9);
for( i=0; i<len; i++ ) printf("%c", 0xCD);
printf("%c", 0xBC);
}
Для перемещения по пунктам меню необходимо использовать клавиши стрелок — вверх и вниз.
За клавишу вверх отвечает код 72, а за клавишу вниз 80.
Функция menu_items перебирает всевозможные варианты перемещения по меню и отображает
собственно само меню.
unsigned int menu_items( char *item[],
unsigned int cur_item,
unsigned int count_item,
unsigned int ch ) /* 80 DOWN key */
/* 72 UP key */
{
int i;
if ( (ch == 80 ) && ( cur_item != (count_item - 1) ) )
cur_item++;
else if ( (ch == 72) && ( cur_item != 0 ) )
cur_item--;
else if ( ( ch == 80 ) && ( cur_item == (count_item - 1) ) )
cur_item = 0;
else if ( ( ch == 72 ) && ( cur_item == 0 ) )
cur_item = count_item - 1;
for ( i = 0; i < count_item; i ++ )
{
if ( i == cur_item )
{
frame( item[ cur_item ] );
}
else
{
PRINT( item[i] );
}
}
return cur_item;
}
Для того, что бы создать иллюзию, что список пунктов меню остается на месте,
а рамка по ним перемещается, нужно в цикле очищать консольный вывод от
предыдущего отображения меню. Делаем это при помощи команды операционной
системы CLS.
Так же в этом цикле нам нужно считывать нажатие клавиш. Клавиши стрелок относятся
к системным, поэтому необходимо сначала считывать системный эскейп код 27,
который говорит нам, что нажата системная клавиша, а затем код самой клавиши.
а рамка по ним перемещается, нужно в цикле очищать консольный вывод от
предыдущего отображения меню. Делаем это при помощи команды операционной
системы CLS.
Так же в этом цикле нам нужно считывать нажатие клавиш. Клавиши стрелок относятся
к системным, поэтому необходимо сначала считывать системный эскейп код 27,
который говорит нам, что нажата системная клавиша, а затем код самой клавиши.
void menu( char *item[], unsigned int count_item )
{
unsigned int crtl, ch = 0,
cur_item = 0;
system("cls");
menu_items( item, cur_item, count_item, 0);
while ( 1 )
{
crtl = getch();
if ( crtl == 27 ) // ESC key
break;
ch = getch();
system( "cls" );
cur_item = menu_items( item, cur_item, count_item, ch );
}
}
Ну вот мы и добрались до финала, осталось только создать массив пунктов меню
и вызвать функцию menu.
и вызвать функцию menu.
int main()
{
char *item[] = { "item1", "item2", "item3", "item4",
"item5", "item6", "item7" };
unsigned int count = sizeof(item) / sizeof(item[0]);
menu( item, count );
return 0;
}
В результате получилось вот такое меню.

P.S.
В данном посте рассмотрен пример реализации под Windows, кому инетересен вариант под Linux, смотрим на гитхабе.

P.S.
В данном посте рассмотрен пример реализации под Windows, кому инетересен вариант под Linux, смотрим на гитхабе.
привет
ОтветитьУдалить