Мне было интересно реализовать динамическое меню для консольного приложения. Динамическое оно, потому что, перемещение по пунктам меню будет происходить при помощи клавиш вверх и вниз. В качестве языка программирования будем использовать Си.
И так приступим. Для начала нам необходимо подключить заголовочные файлы.
Функция 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, смотрим на гитхабе.
привет
ОтветитьУдалить