Форум программистов, компьютерный форум CyberForum.ru

Меню на консоли - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 11, средняя оценка - 4.64
Darthriddikc
10 / 10 / 0
Регистрация: 23.12.2012
Сообщений: 45
19.12.2013, 02:07     Меню на консоли #1
Здравствуйте! Изучаю C++, для практики ради делаю консольное меню через класс.
Может быть мне, пока что, ещё далеко до претендента на гуру по адекватной реализации алгоритмов
Вот, как я это реализовал...

classias.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <iostream>
#include <conio.h>
#include <windows.h>
using namespace std;
 
#ifndef CPP_MENU
#define CPP_MENU
 
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
 
class Menu{
 
///////////////////////// * СТЕК * ///////////////////////////
    // Структура стека и функции работы с ним, хранит предыдущие директории(меню)
    static struct STACK_DIR{
        static int num;
        Menu *elem;
        STACK_DIR *last;
    }*stackDir;
 
    void push(STACK_DIR* &stack, Menu* i){
        STACK_DIR *last_stack=stack;
        stack=new STACK_DIR;
        STACK_DIR::num++;
        stack->elem=i;
        stack->last=last_stack;
    }
 
    Menu* pop(STACK_DIR* &stack){
        Menu *pop_elem=stack->elem;
        STACK_DIR *temp=stack;
        stack=stack->last;
        delete temp;
        STACK_DIR::num--;
        return pop_elem;
    }
//////////////////////////////////////////////////////////////
 
    // LINES_Data - структура данных одной строки в объекте
    struct LINES_Data{
        char name[32]; // Название строки
        Menu *nextDir; // Куда эта строка ведёт
    }*lineData;
 
    static Menu *delLines; // для "подтирания" оставшихся символов предыдущего меню
    unsigned short lines; // число строк в одной директиве
    short position; // позиция, где на данный момент находится выбор
 
    // GoToXY - метод который будет устанавливать "каретку" на поле консоли (x-столбец y-строка)
    // по сути с помощью него будет очищаться экран от старого меню, но в отличии от CLS будет замещать старое меню новым
    void GoToXY(unsigned x, unsigned y){
        COORD coord = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
    }
 
public:
 
    static unsigned Y_Console_pos; //положение "каретки" по X
    static unsigned X_Console_pos; //положение "каретки" по Y
 
    //В конструктор задаётся число строк менюшки и 2 необязательных параметра - положение X Y (по умолчанию 0,0)
    Menu(unsigned lines, unsigned X_Console_pos=Menu::X_Console_pos, unsigned Y_Console_pos=Menu::Y_Console_pos){
        Menu::Y_Console_pos=Y_Console_pos;
        Menu::X_Console_pos=X_Console_pos;
        position=0;
        char ch_i[4];
        Menu::lines=lines;
        lineData=new LINES_Data[lines];
        for(int i=0; i<lines; i++){
            strcpy(lineData[i].name,"ITEM_");
            sprintf(ch_i,"%d",i+1);
            strcat(lineData[i].name,ch_i);
            lineData[i].nextDir=this;
        }
    }
    ~Menu(){
        delete []lineData;
    }
 
    // startMenu - запуск меню
    void startMenu(){
        int key; // код клавиши
        if(delLines){
            for (int i=0; i<delLines->lines; i++){
                GoToXY(X_Console_pos,Y_Console_pos+i);
                for(int j=0; j<strlen(delLines->lineData[i].name); j++)
                    cout<<' ';
                cout<<endl;
            }
        }
        while(1){
            if(position<0)
                position=lines-1;
            if(position>=lines)
                position=0;
            for (int i=0; i<lines; i++){
                GoToXY(X_Console_pos,Y_Console_pos+i);
                if(i==position)
                    SetConsoleTextAttribute(hConsole, 0+(7<<4));
                cout<<lineData[i].name<<endl;
                SetConsoleTextAttribute(hConsole, 7+(0<<4));
            }
            key=_getch();
            if(key==27){ // Esc
                if(STACK_DIR::num){
                    delLines=this;
                    pop(stackDir)->startMenu();
                }
                break;
            }
            if(key==224){
                key=_getch();
                switch (key){
                case 72: // стрелка вверх
                    position--;
                    break;
                case 80: // стрелка вниз
                    position++;
                    break;
                }
            }
            if(key==13){ // Enter
                if(!lineData[position].nextDir)
                    break;
                if(lineData[position].nextDir!=this){
                    delLines=this;
                    if(STACK_DIR::num && stackDir->elem==lineData[position].nextDir){
                        pop(stackDir)->startMenu();
                        break;
                    }
                    push(stackDir,this);
                    lineData[position].nextDir->startMenu();
                    break;
                }
            }
        }
    }
 
    // lineInit - метод инициализации строки (номер строки, куда она пошлёт, имя строки)
    void lineInit(int i, Menu* nextDir, char *name=0){
        if(i>lines-1){
            cerr<<"Line "<<i<<" Error! Overflowing lines! Max="<<lines-1<<endl;
        }
        else{
            if(name)
                strcpy(lineData[i].name,name);
            lineData[i].nextDir=nextDir;
        }
    }
};
 
unsigned Menu::X_Console_pos=0;
unsigned Menu::Y_Console_pos=0;
int Menu::STACK_DIR::num=0;
Menu::STACK_DIR *Menu::stackDir=0;
Menu *Menu::delLines=0;
 
#endif
Ну и как это работает на примере
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "classias.h"
 
int main(){
    Menu Main(5,35,5), NewGame(4), Options(3), Keyboard(5), About(1), Score(2);
 
    Main.lineInit(0,&NewGame,      "NEW GAME");
    Main.lineInit(1,&Options,      "OPTIONS");
    Main.lineInit(2,&About,        "ABOUT");
    Main.lineInit(3,&Score,        "SCORE");
    Main.lineInit(4,0,             "EXIT");
 
    NewGame.lineInit(0,&NewGame,   "EASY");
    NewGame.lineInit(1,&NewGame,   "MEDIUM");
    NewGame.lineInit(2,&NewGame,   "HARD");
    NewGame.lineInit(3,&Main,      "BACK");
 
    Options.lineInit(1,&Keyboard,  "KEYBOARD");
    Keyboard.lineInit(4,&Options,  "BACK");
    Options.lineInit(2,&Main,      "BACK");
 
    About.lineInit(0,&Main,        "BACK");
 
    Score.lineInit(1,&Main,        "BACK");
 
    Main.startMenu();
    return 0;
}
В этом меню, пока что, можно только "гулять" из директории в директорию (то есть передавать в nextDir указатель на объект Menu)... И вот я запоролся на вроде бы тривиальной задачке, как реализовать переход к какой-нибудь функции и чтоб это было "красиво", в смысле к примеру чтоб можно было сделать так:
C++
1
2
3
4
5
6
7
void func1( ... ){
    /* . . . */
};
 
/* . . . */
 
NewGame.lineInit(0,func1( ... ),   "EASY");
Ну и естественно желательно чтоб это всё также оставалось храниться в структуре LINES_Data.
У меня есть предположения, что это можно реализовать как-то через шаблоны (template), но для этого потребуется "шаблонить" LINES_Data, а значит, при создании объекта этой структуры, нужно заранее указывать типы, но в моём случае получается, что, до инициализации строки меню, ещё неизвестно какой тип будет у объекта структуры. Правда я совсем недавно изучил шаблоны, и может быть многое про них не знаю, к примеру можно ли как-то обойти объявление типов при объявлении объекта... Но главный мой вопрос этой темы я уже оговорил выше

Добавлено через 8 часов 59 минут
Попробовал всячески через шаблоны, только запутался
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
19.12.2013, 02:07     Меню на консоли
Посмотрите здесь:

Меню в консоли, управление стрелками C++
C++ Меню в консоли
C++ оригинальное меню в консоли
Работа с меню в консоли C++
C++ Помогите создать меню в консоли
организация меню в консоли C++
Меню в консоли - Ввод данных C++
C++ Меню в консоли

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ПерС
366 / 282 / 84
Регистрация: 05.11.2013
Сообщений: 806
Записей в блоге: 5
Завершенные тесты: 1
19.12.2013, 12:22     Меню на консоли #2
а просто указатель на функцию не пробовал?
пример из сети:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <conio.h>
#include <stdlib.h>
typedef unsigned char byte;
typedef void (*FUN)(void);
 //Указатель на функцию обработки
 //пункта меню - указатель на объекты вида void Функция(void)
 
struct MENU { //например, опишем простейшее меню
 int x,y; // Позиция на экране пункта меню
 byte *str; // Строка текста меню
 FUN sf; // Указатель на функцию
         // обработки пункта
};
 
/* код функций обработки пункта меню */
 
void Exit () { exit (0); }
 
void Start () {  }
 
/* Код функций вывода и поддержки меню */
 
void DrawMenu (MENU *m) {
 gotoxy(m->x,m->y);
 cprintf ("%s",m->str);
}
#define ITEMS 2
void main () {
 MENU Menu[ITEMS]={
  { 1, 1, "Начать", Start },
  {10, 1, "Выход", Exit }
 };
 clrscr ();
 for (int i=0; i<ITEMS; i++)
  DrawMenu (&Menu[i]);
 Menu[0].sf(); /*Вызвали Start() косвенно, через указатель на функцию*/
}
Darthriddikc
10 / 10 / 0
Регистрация: 23.12.2012
Сообщений: 45
19.12.2013, 15:39  [ТС]     Меню на консоли #3
Цитата Сообщение от ПерС Посмотреть сообщение
а просто указатель на функцию не пробовал?
Ну я так и хочу, через указатель, попасть на стороннюю функцию в конечном итоге, но в вашем примере нормально перейти можно, только к сторонней функции, так как он очень упрощённый, а если, как в моём случае, это может быть ещё и сам объект класса меню (например, реализовать переход к следующему меню), тогда каждому методу вывода меню, у каждого объекта, нужно делать обёртку, которая помимо того, что должна возвращать метод, должна ещё менять некоторые значения элементов класса и подчас частные, а значит ещё плюс эту обёртку нужно объявить другом класса.
Yandex
Объявления
19.12.2013, 15:39     Меню на консоли
Ответ Создать тему
Опции темы

Текущее время: 02:40. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru