Jump to content

[C++] Cum sa faci un meniu in consola


Cdorsu
 Share

Recommended Posts

Sa trecem direct in cod. Avem nevoie de o clasa "menu" (la mine o sa fie singletone, la voi poate sa nu fie)

 

menu.h

#pragma once
#include <vector> //std::vector
#include <string> //std::string
#include <string.h> // strlen
#include <functional> // std::move
#include <windows.h> //ReadConsoleInput, HANDLE, SetConsoleCursorPosition, SetConsoleTextAttribute
#include <iostream> // std::cout
 

class menu
{
    //Voi face aceasta clasa un Singletone
    //Adica o clasa cu UN SINGUR OBIECT
private: // Atribute private
   std::vector<std::string> m_vecstrOptiuni;
   HANDLE hInPut;
private: // Constructori / Destructor
   menu(std::vector<std::string> elemente);
   menu(const menu&) = delete;
   menu(const menu&&) = delete;
   const menu& operator = (const menu&) = delete;
   ~menu();
private: // Atribute statice private
    static menu* m_pmenuInstance;
public: // Singletone
    static void Create(std::vector<std::string>);//Cu aceasta functie vom crea obiectul
    static menu* GetInstance();//Aceasta functie returneaza obiectul
    static void Destroy();//Cu aceasta functie vom distruge obiectul
public:
    std::string PrintMenu();//Functia principala
};

menu.cpp

#include "menu.h"

menu* menu::m_pmenuInstance = nullptr; // Initial m_pmenuInstance va avea valoarea nullptr

void menu::Create(std::vector<std::string> elemente)
{
    m_pmenuInstance = new menu(elemente); // Initializam obiectul m_pmenuInstance
}

menu* menu::GetInstance()
{
    return m_pmenuInstance; // Returnam instanta
}

void menu::Destroy()
{
    delete m_pmenuInstance; // Stergem instanta
}

menu::menu(std::vector<std::string> elemente)
	:hInPut(GetStdHandle(STD_INPUT_HANDLE)) // Initializam
{
    m_vecstrOptiuni = elemente; // Initializam
}

menu::~menu()
{
}
//O "consola normala" are 24 de linii si 80 de "coloane"
std::string menu::PrintMenu()
{
	UINT i;
	int iInitOy = (24 / 2 - (m_vecstrOptiuni.size() / 2 + 0.5f));
		//Asta inseamna jumatatea ecranului  (Oy)
	int iOptiune = 0;//Initial, va fi aleasa optiunea 0
	DWORD EventsToRead = 0; //Pentru ReadConsoleInput. Cate evenimente a inregistrat, pana acum
	INPUT_RECORD irBuffer; //Aceasta ne va arata evenimentele inregistrate
	while (true)
	{
	    //Scriem optiunile
		for (i = 0; i < m_vecstrOptiuni.size(); ++i)
		{
		    //Sunteti pregatiti pentru putina matematica?
			if (iOptiune == i)
			{
			    // 80 / 2 - (short(strlen(m_vecstrOptiuni[i].data()))) / 2 inseamna mijlocul ecranului (Axa Ox) si in partea Stanga a optiunii
			    //iInitOy este linia de unde vom incepe sa scriem ( i va incepe de la 0)
			    //Si vom adauga cate 1 pentru fiecare optiune pe care o vom afisa
                SafePrint({ 80 / 2 - (short(strlen(m_vecstrOptiuni[i].data()) / 2)),short(iInitOy + i) },
                    m_vecstrOptiuni[i],10);
			}
			else
			{
                SafePrint({ 80 / 2 - (short(strlen(m_vecstrOptiuni[i].data()) / 2)),short(iInitOy + i) },
                    m_vecstrOptiuni[i]);
			}
		}
		while (true)
		{
		    //hInPut - Bufferul pentru input al consolei
		    //&irBuffer - vom trece pe referinta variabila de tip INPUT_BUFFER
		    //1 - Lungimea variabilei de mai sus
		    //  - Ar trebui sa fie un vector, dar nu avem nevoie de asa ceva
		    //&EventsToRead - Cate evenimente s-au inregistrat ( Daca veti face debug veti observa ca va creste de fiecare data cand consola primeste un input)
			ReadConsoleInput(hInPut, &irBuffer, 1, &EventsToRead);
			if (irBuffer.EventType == KEY_EVENT)//Verificam daca s-a apasat vreo tasta
			{
			    //Windows-ul inregistreaza momentul in care s-a apasat o tasta si cel in care s-a ridicat ( am luat degetul de pe ea )
				if (irBuffer.Event.KeyEvent.wVirtualKeyCode == VK_DOWN && //Daca a apasat pe 'VK_DOWN' (Sageata-jos)
					irBuffer.Event.KeyEvent.bKeyDown)//Daca tasta e jos
				{
					++iOptiune;
					if (iOptiune == m_vecstrOptiuni.size())//Daca a iesti din meniu, il introducem inapoi in meniu
						iOptiune = 0;
					break;//O luam de la inceput, de la scrierea optiunilor
				}
				if (irBuffer.Event.KeyEvent.wVirtualKeyCode == VK_UP &&//Daca a apasat pe 'VK_UP' (Sageata-sus)
					irBuffer.Event.KeyEvent.bKeyDown)//Daca tasta e jos
				{
					--iOptiune;
					if (iOptiune == -1)//Daca a iesti din meniu, il introducem inapoi in meniu
						iOptiune = m_vecstrOptiuni.size() - 1;
					break;//O luam de la inceput, de la scrierea optiunilor
				}
				if (irBuffer.Event.KeyEvent.wVirtualKeyCode == VK_RETURN &&//Daca a apasat pe 'VK_RETURN'(Enter)
					irBuffer.Event.KeyEvent.bKeyDown)//Daca tasta e jos
				{
					return m_vecstrOptiuni[iOptiune];//Returnam optiunea
				}
				if (irBuffer.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE &&//Daca a apasat pe 'VK_ESCAPE'(Esc)
					irBuffer.Event.KeyEvent.bKeyDown)//Daca tasta e jos
					return "Exit";//Userul doresta sa iasa
			}
			else if (irBuffer.EventType == MOUSE_EVENT)//Daca utilizatorul a "intrat" cu mouse-ul in consola
			{
				for (i = 0; i < m_vecstrOptiuni.size(); ++i)
				{
				    /**
                    80 / 2 - strlen("Optiune") / 2 ->|Optiune|<- 80 / 2 + strlen("Optiune") / 2
                    */
                    if (irBuffer.Event.MouseEvent.dwMousePosition.X >= 80 / 2 - (short(strlen(m_vecstrOptiuni[i].data()) / 2)) &&//Verificam daca utilizatorul a pus mouse-ul intre partea stanga
                        irBuffer.Event.MouseEvent.dwMousePosition.X <= 80 / 2 + (short(strlen(m_vecstrOptiuni[i].data()) / 2)) &&//si partea dreapta a optiunii
                        irBuffer.Event.MouseEvent.dwMousePosition.Y == iInitOy + i)//Verificam daca utilizatorul a dus mouse-ul pe linia pe care se afla optiunea
                    {
                        iOptiune = i;//Daca mouse-ul e deasupra scrisului iOptiune va deveni Pe ce a pus utilizatorul mouse-ul
                        if (irBuffer.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)//Daca a apasat pe 'FROM_LEFT_1ST_BUTTON_PRESSED' Click-Stanga
                        {
                            return m_vecstrOptiuni[i];//Returnam
                        }
                        break;//Oprim for-ul
                    }
				}
				break;//O luam de la inceput, de la scrierea optiunilor
			}
		}
	}
}

main.cpp

#include "menu.h"

int main()
{
    menu::Create({"Salut!", "Exit"});
    Initial:
    auto strOptiune = menu::GetInstance()->PrintMenu();
    if(strOptiune == "Salut!")
    {
        SafePrint({0,0},"Salut selected");
        goto Initial;
    }
    else if(strOptiune == "Exit")
    {
        SafePrint({0,0},"Exit selected");
        return 0;
    }
    menu::Destroy();
}

Compilat in C++11.

 

 

Sper ca ati inteles, cat de cat, ce am incercat eu sa explic aici.

Este o versiune mai complexa a meniului de aici.

Link to comment
Share on other sites

@@Cdorsu, te'ai complicat.. Si celalalt e destul de complex. Un menu se poate face foarte usor, in putine linii de cod.

 

Stiu ca e destul de complex.

Dar alta varianta pentru un meniu care poate procesa input de la mouse nu cunosc si m-am gandit ca ar fi frumos sa fac publica metoda mea.

 

 

Mda.. Este un program complez am sa il testez sa il verific de eventuale erori, Mult Succes.

Pe unele compilatoare s-ar putea sa dea erori sau avertizari.

 

Pe Compilerul din CodeBlocks nu mi-a afisat nimic deci este clean multumim frumos, Mult Succes in continuare.

Mersi!

Edited by Cdorsu
Link to comment
Share on other sites

Pe Compilerul din CodeBlocks nu mi-a afisat nimic deci este clean multumim frumos, Mult Succes in continuare.

Edited by TheLittle
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.