Ir ao conteúdo
  • Cadastre-se

C++ Criar menu em C++


Posts recomendados

Opa, alguem aqui pode me ajudar?? eu preciso criar um menu em C++ SELECIONAVEL, tipo conforme clico nas setas p CIMA ou p Baixo o menu interage, como faço ?

 

Seria um menu para um codigo simples, ex:

 

#include <stdio.h>

 

main(){

int entra;

 

printf("ENTRAR\nSAIR");

scanf("%d", &entra);

 

}

  • Amei 1
Link para o comentário
Compartilhar em outros sites

@OcaraMaisLINDOHAHAH

3 horas atrás, OcaraMaisLINDOHAHAH disse:

conforme clico nas setas p CIMA ou p Baixo o menu interage

Você pode usar a função GetAsyncKeyState() em um loop para determinar se as teclas cima e baixo são pressionadas, os códigos virtuais dessas teclas são VK_UP e VK_DOWN, respectivamente.

Depois, é só usar uma função pra mudar o cursor de posição, você pode usar essa daqui:

void gotoxy(int x, int y)
{
    HANDLE hCon;
    COORD dwPos;

    dwPos.X = x;
    dwPos.Y = y;
    hCon = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hCon,dwPos);
}

Não se esqueça de incluir a biblioteca windows.h.

Talvez seja bom adicionar um pequeno delay depois de mudar o cursor de posição, uns 200 ms, e quem sabe mudar a cor da opção em que o cursor está. Fiz algo assim há um tempo, vou incluir um gif:

ezgif-2-813f4c73d4af.gif.7aab17c29d4fa5edfb36b91c539d0950.gif

  • Amei 1
Link para o comentário
Compartilhar em outros sites

Boa Noite,

 


ACtC-3efnwx1pCLxfCUDkC7pnt1B7QTSnKvo_Oyi

STDIO.H usa linhas de comando para leitura,

a scanf aguarda o sinal que representa sua liberação para gravar, o sinal que libera é o [ENTER ] pressionado no teclado durante o foco na janela, antes disso essa função acessa outro local com memória, caso haja dados nesse local, tem liberação para gravar.

 

Um menu de interação com mouse programado que inclua tão somente as funções de stdio.já foi dito impossível. Menus gerados com a mesma simplicidade e padrões de uma função do tipo scanf, do tipo printf, de quebra com código aberto para estudos etc existem, porém são de terceiros ou encomendados.

 

Boa Sorte.

 

 

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@OcaraMaisLINDOHAHAH    esse menu que o  @Lucca Rodrigues   postou é sensacional ,  até parece  ser um menu de alguma API com interface ,  creio que ele não postou o código por que provavelmente é muito longo ,  mas para começar você pode ver esse exemplo de como usar os comando que detectam as teclas do teclado , e sim usa bibliotecas antigas , mas ainda funciona ,  e então poderia ser assim  :

#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <windows.h>
using namespace std;
void MoveToXY(int x,int y)
{
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),(COORD){x,y});
}
int main()
{
  inivio:
  system("cls");
  int entra,x=8,y=0,a,
      ant_y=0;
  printf("ENTRAR\n");
  printf("opções\n");
  printf("  SAIR"  );
  MoveToXY(x,y);
  printf("<-");
  do{
    a=0;
    if(kbhit())a=getch();
    switch(a)
    {
    case 72:  // Move a Seta para Cima
      y--;
      if( y < 0 )y = 2;
      break;
    case 80:  // Move a Seta para Baixo
      y++;
      if( y > 2 )y = 0;
      break;
    }
    if( y != ant_y )
    {
      printf("\a");
      MoveToXY(x,ant_y);
      printf("  ");
      MoveToXY(x,y);
      printf("<-");
    }
    if( a == 13 && y == 2 )break;
    ant_y = y;
  }while( 1 );
  cout<<"\n\nQuer Realmente Sair Do Programa !\n"
        "\n1 = Sim\n2 = nao"<<endl;
  scanf("%d", &entra);
  if(entra == 2)goto inivio;
  cout<<"\n\n\n\n"<<endl;
  return 32768;
}

 

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@devair1010

44 minutos atrás, devair1010 disse:

esse menu que o  @Lucca Rodrigues   postou é sensacional ,  até parece  ser um menu de alguma API com interface

Um tempo atrás eu tinha criado um tópico a respeito de um programa com o visual dos programas de console dos anos 80, então tentei fazer algo semelhante à imagem que postei no mesmo. Não tem nada de muito especial, são basicamente 2 loops: um para digitar os dados, o outro para acessar o menu. Daí tem lá funções para mudar a cor do texto/background, mudar a posição do cursor, imprimir a moldura, etc, e é isso :)

 

44 minutos atrás, devair1010 disse:

para começar você pode ver esse exemplo de como usar os comando que detectam as teclas do teclado , e sim usa bibliotecas antigas

Uma alternativa à função getch() nesse caso é essa GetAsyncKeyState() que eu tinha mencionado, vou postar aqui um código de um menu (em C) com 3 opções (que não fazem nada) usando essa função:

#include <stdio.h>
#include <windows.h>
#include <locale.h>

void gotoxy(int x, int y)
{
    HANDLE hCon;
    COORD dwPos;

    dwPos.X = x;
    dwPos.Y = y;
    hCon = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hCon,dwPos);
}

int main ()
{
    setlocale(LC_ALL, "Portuguese");
    int y = 0;

    printf(" Opção [1]\n");
    printf(" Opção [2]\n");
    printf(" Opção [3]\n");
    gotoxy(11, y);

    while(1){
        if(GetAsyncKeyState(VK_UP)){
            y--;
            if(y < 0){
                y = 2;
            }
            gotoxy(11, y);
            Sleep(200);
        } else if(GetAsyncKeyState(VK_DOWN)){
            y++;
            if(y > 2){
                y = 0;
            }
            gotoxy(11, y);
            Sleep(200);
        }
    }

    return (0);
}

 

  • Curtir 1
  • Obrigado 2
Link para o comentário
Compartilhar em outros sites

@Mauro Britivaldo nao brother, e so um exemplo basico de como gostaria q fosse esse menu sabe, opção de selecionar a opção ENTRAR e selecionar a opção SAIR

 

adicionado 9 minutos depois

@Lucca Rodrigues CARA ficou bacana assim como o que o  @devair1010 postou, mais como faço a incrementação de por EXEMPLO um Printf em uma das opções ?? em qual parte do codigo mais exato entra essa opção 

 

  • Curtir 1
  • Confuso 1
Link para o comentário
Compartilhar em outros sites

    while(1){
        if(GetAsyncKeyState(VK_UP)){
            y--;
            if(y < 0){
                y = 2;
            }
            gotoxy(11, y);
            Sleep(200);
        } else if(GetAsyncKeyState(VK_DOWN)){
            y++;
            if(y > 2){
                y = 0;
            }
            gotoxy(11, y);
            Sleep(200);
        }
    }

Sobre esse loop e versões modernas de Windows, direto da documentação:

 

  • GetAsyncKeyState() nem sempre funciona e por isso menus que contam com isso às vezes parecem "enroscar" em computadores modernos se o cara fica apertando uma das setas seguidamente. 
    A causa está descrita no manual: Essa função retorna DUAS coisas. Em geral os programas testam --- como esse trecho --- como se ela retornasse verdadeiro ou falso. Só que ela retorna SHORT
    SHORT GetAsyncKeyState(
      int vKey
    );

    ou WORD ou algo com 16 bits. uint16_t é um tipo portável hoje em dia. 
    A função retorna dois bits:

    • o mais significativo indica se a tecla está apertada no momento da chamada. E funciona. No popular é o bit de sinal: se retornar negativo, que é falso, quer dizer que a tecla está apertada no momento da chamada

    • o menos significativo indica se ligado que a tecla foi pressionada desde a chamada anterior a GetAsyncKeyState(). Ou seja, ela pode não estar apertada entre essa chamada e a anterior a essa função. Se houve alguma, claro
      Só que nas versões 32 ou 64 bits de Windows, dos últimos 30 anos, outra aplicação pode ter recebido essa mensagem e o seu menu nunca vai receber. E como a tecla não está mais pressionada os dois bits estão desligados e a função vai retornar zero: em resumo: você perdeu a tecla

Citando a documentação oficial:
 

Citação


Embora o bit menos significativo do retorno indique se a tecla foi pressionada desde a última chamada, devido à natureza multi-tarefa interrompível do Windows, outra aplicação pode ter recebido essa mensagem antes ao invés de sua aplicação. Esse comportamento foi mantido estritamente para compatibilidade com aplicações 16-bits do Windows e não deve ser considerado confiável
 

  • gotoxy() - já postei isso aqui um certo número de vezes, e vamos somar 1 ao contador: se essa função é sempre incluída nos programas que eu vejo e compilada de novo e de novo, como aqui:

void gotoxy(int x, int y)
{
    HANDLE hCon;
    COORD dwPos;
    dwPos.X = x;
    dwPos.Y = y;
    hCon = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hCon,dwPos);
}

Porque não escrever o esperado para programadores e leitores sem formação matemática, esses que não pensam em plano cartesiano ao ler (x,y) como coordenadas, e escrever

void gotoyx(int linha, int coluna)
{   COORD dwPos;
    dwPos.X = coluna;
    dwPos.Y = linha;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),dwPos);
}

usando linha e coluna como sempre? 

 

3 horas atrás, OcaraMaisLINDOHAHAH disse:

CARA ficou bacana assim como o que o  @devair1010 postou, mais como faço a incrementação de por EXEMPLO um Printf em uma das opções ?? em qual parte do codigo mais exato entra essa opção

 

O geral é menu() ser uma função que retorna um valor, possivelmente um valor pequeno afinal é um menu. Ao menos no início do programa o menu costuma vir do disco porque é muito mais fácil editar o texto num arquivo txt no IDE do que ficar lutando com aquela cascata de printf() e aspas e '\n' e o d1@b0

 

Então a função lê as opções, põe na tela uma depois da outra, seleciona a opção padrão e fica num loop, como mostrado acima pelo @Lucca Rodrigues . No loop ela aceita apenas as setas, em geral ESC para cancelar e ENTER para selecionar. Nada mais. 

 

No retorno de menu() um loop testa o valor retornado, em geral em algo como um comando  switch(), e a vida segue. Lembro que não existe um comando switch/case. Trata-se de fake news :D o comando é switch e o case é o prefixo de um label.

 

 

  • Obrigado 2
Link para o comentário
Compartilhar em outros sites

@OcaraMaisLINDOHAHAH 

A tá! Então o único recurso além do padrão necessário é esse que posiciona o cursor com teclado, com as teclas UP/DOWN.

 

Eu faria assim:

Quando pressionar UP +incrementa e DOWN -decremente variável que serve o índice dos vetores; de funções com os comandos do menu, de strings com os nomes ou Tipo de texto que enumera o menu.

 

No caso, não usa *switch (/case e sem /case), somente funções e vetores.

 

*Suponho que a rapidez no acesso de ambos (Array, Switch e IF) seja aproximadamente a mesma então é uma questão de estilo e mal gosto, entretanto o uso vetores pode futuramente ajudar com a manutenção de código sendo assim uma ideia superior, porém o uso de switch aparenta ser a ideia mais comum, eu diria.

 

 

Busquei: gotoxy

https://www.clubedohardware.com.br/search/?q=gotoxy&type=forums_topic&nodes=177&updated_after=any&sortby=relevancy

 

Nessa pesquisa de gotoxy só 99% é @devair1010

 

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@OcaraMaisLINDOHAHAH    para escrever nas opções você pode criar funções de acordo com cada huma ,  e poderia ser assim  :

#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <windows.h>
using namespace std;
void entrar();
void opções();
void Limpa_a_Metade_da_Tela();
void MoveToXY(int coluna,int linha);
int main()
{
  iniciou:
  system("cls");
  int entra,coluna=8,linha=0,a,
      linha_anterior = 0;
  printf("ENTRAR\n");
  printf("opções\n");
  printf("  SAIR"  );
  MoveToXY(coluna,linha);
  printf("<-");
  do{
    a=0;
    if(kbhit())a=getch();
    MoveToXY(coluna,linha);
    switch(a)
    {
    case 72:  // Move a Seta para Cima
      linha--;
      if( linha < 0 )linha = 2;
      break;
    case 80:  // Move a Seta para Baixo
      linha++;
      if( linha > 2 )linha = 0;
      break;
    }
    if( linha != linha_anterior )
    {
      printf("\a");
      MoveToXY(coluna,linha_anterior );
      printf("  ");
      MoveToXY(coluna,linha);
      printf("<-");
    }
    if(     a == 13 )        {
        if( linha ==  0 )entrar();
        if( linha ==  1 )opções();
        if( linha ==  2 )   break;
    }
    linha_anterior = linha;
  }while( 1 );
  cout<<"\n\nQuer Realmente Sair Do Programa !\n"
        "\n1 = Sim\n2 = nao"<<endl;
  scanf("%d", &entra);
  if(entra == 2)goto iniciou;
  cout<<"\n\n\n\n"<<endl;
  return 32768;
}
void MoveToXY(int coluna,int linha)
{
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),(COORD){coluna,linha});
}
void entrar(){
    MoveToXY(1,10);
    printf("Entrou na Opcao   ENTRAR  . . . !\n\n\n");
    system("pause");
    Limpa_a_Metade_da_Tela();
}
void opções(){
    MoveToXY(1,10);
    printf("Estrah na Opcao   opções  . . . !\n\n\n");
    system("pause");
    Limpa_a_Metade_da_Tela();
}
void Limpa_a_Metade_da_Tela(){
    int i;
    MoveToXY(0,9);
    for(i=0; i<1120; i++)
        printf(" ");
}

 

  • Curtir 3
Link para o comentário
Compartilhar em outros sites

void Limpa_a_Metade_da_Tela(){
    int i;
    MoveToXY(0,9);
    for(i=0; i<1120; i++)
        printf(" ");
}

MoveToXY() é legal. Afinal linha e coluna!

 

Limpar metade da tela? Como sabe o tamanho? Identifique antes o tamanho da tela. Veja a documentação no local de sempre

BOOL WINAPI GetConsoleScreenBufferInfo(
  _In_  HANDLE                      hConsoleOutput,
  _Out_ PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
);

Acho que já postei exemplos aqui

 

Se usar o "novo" pós-2018 modelo de programação para a console acho que tem comandos clr_eol clr_eos clr_bol e clear_screen mas eu nunca usei. Esses são previstos para limpar a tela da posição do cursor até o início da linha, até o fim da linha e até o fim da tela. Ou a tela toda, claro

 

Mas 1120 chamadas a printf() pode não ser assim eficiente mesmo em computadores modernos

 

8 horas atrás, Mauro Britivaldo disse:

Busquei: gotoxy

 

Ampliando um pouco sua pesquisa pode ver que gotoxy() era parte de uma biblioteca conio.h fornecida com o compilador TurboC da Borland, hoje Embarcadero, no fim dos anos 80. E tem se mantido viva até hoje. Uma versão mantida desde 2005 em sourceforge.net pode ser baixada hoje ainda em https://sourceforge.net/projects/conio/ 

 

Eis o header para quem quer viajar no tempo :) 
 

Spoiler

/** @file conio2.h
 * A conio implementation for Mingw/Dev-C++.
 *
 * Written by:
 * Hongli Lai <[email protected]>
 * tkorrovi <[email protected]> on 2002/02/26.
 * Andrew Westcott <[email protected]>
 * Michal Molhanec <[email protected]>
 *
 * Offered for use in the public domain without any warranty.
 */

#ifndef _CONIO2_H_
#define _CONIO2_H_

#include <conio.h>
#ifdef UNICODE
    #include <windows.h>    // we need wchar_t
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Colors which you can use in your application.
 */
typedef enum
{
    BLACK,          /**< black color */
    BLUE,           /**< blue color */
    GREEN,          /**< green color */
    CYAN,           /**< cyan color */
    RED,            /**< red color */
    MAGENTA,        /**< magenta color */
    BROWN,          /**< brown color */
    LIGHTGRAY,      /**< light gray color */
    DARKGRAY,       /**< dark gray color */
    LIGHTBLUE,      /**< light blue color */
    LIGHTGREEN,     /**< light green color */
    LIGHTCYAN,      /**< light cyan color */
    LIGHTRED,       /**< light red color */
    LIGHTMAGENTA,   /**< light magenta color */
    YELLOW,         /**< yellow color */
    WHITE           /**< white color */
} COLORS;

/*@{*/
/**
 * This defines enables you to use all MinGW conio.h functions without
 * underscore.
 */
#define cgets   _cgets
#define cprintf _cprintf
#define cputs   _cputs
#define cscanf  _cscanf

#ifdef UNICODE
    #define cgetws   _cgetws
    #define getwch   _getwch
    #define getwche  _getwche
    #define putwch   _putwch
    #define ungetwch _ungetwch
    #define cputws   _cputws
    #define cwprintf _cwprintf
    #define cwscanf  _cwscanf
#endif
/*@}*/

/**
 * Define alias for _conio_gettext.
 * If you want to use gettext function from some other library
 * (e.g. GNU gettext) you have to define _CONIO_NO_GETTEXT_ so you won't get
 * name conflict.
 */
#ifndef _CONIO_NO_GETTEXT_
  #define gettext _conio_gettext
#endif

#define ScreenClear clrscr

/**
 * @anchor cursortypes
 * @name Cursor types
 * Predefined cursor types. */
/*@{*/
#define _NOCURSOR 0         /**< no cursor */
#define _SOLIDCURSOR 100    /**< cursor filling whole cell */
#define _NORMALCURSOR 20    /**< cursor filling 20 percent of cell height */
/*@}*/

/**
 * Structure holding information about screen.
 * @see gettextinfo
 * @see inittextinfo
 */
struct text_info {
    unsigned char curx;          /**< cursor coordinate x */
    unsigned char cury;          /**< cursor coordinate y */
    unsigned short attribute;    /**< current text attribute */
    unsigned short normattr;     /**< original value of text attribute after
                                      start of the application. If you don't
                                      called the <TT>inittextinfo</TT> on the
                                      beginning of the application, this always
                                      will be black background and light gray
                                      foreground */
    unsigned char screenwidth;   /**< screen width */
    unsigned char screenheight;  /**< screen height */
};

/**
 * Structure used by gettext/puttext.
 * @see _conio_gettext
 * @see puttext
 */
struct char_info {
#ifdef UNICODE
    wchar_t letter;        /**< character value */
#else
    char letter;           /**< character value */
#endif
    unsigned short attr;   /**< attribute value */
};

/**
 * Returns information of the screen.
 * @see text_info
 */
void gettextinfo (struct text_info * info);

/**
 * Call this if you need real value of normattr attribute in the text_info
 * structure.
 * @see text_info
 */
void inittextinfo (void);

/**
 * Clears rest of the line from cursor position to the end of line without
 * moving the cursor.
 */
void clreol (void);

/**
 * Clears whole screen.
 */
void clrscr (void);

/**
 * Delete the current line (line on which is cursor) and then moves all lines
 * below one line up. Lines below the line are moved one line up.
 */
void delline (void);

/**
 * Insert blank line at the cursor position.
 * Original content of the line and content of lines below moves one line down.
 * The last line is deleted.
 */
void insline (void);

/**
 * Gets text from the screen. If you haven't defined <TT>_CONIO_NO_GETTEXT_</TT>
 * prior to including <TT>conio2.h</TT> you can use this function also under
 * the <TT>gettext</TT> name.
 * @see char_info
 * @see puttext
 * @param left Left coordinate of the rectangle, inclusive, starting from 1.
 * @param top Top coordinate of the rectangle, inclusive, starting from 1.
 * @param right Right coordinate of the rectangle, inclusive, starting from 1.
 * @param bottom Bottom coordinate of the rectangle, inclusive, starting from 1.
 * @param buf You have to pass buffer of size
 * <TT>(right - left + 1) * (bottom - top + 1) * sizeof(char_info)</TT>.
 */
void _conio_gettext (int left, int top, int right, int bottom,
                     struct char_info * buf);

/**
 * Puts text back to the screen.
 * @see char_info
 * @see _conio_gettext
 * @param left Left coordinate of the rectangle, inclusive, starting from 1.
 * @param top Top coordinate of the rectangle, inclusive, starting from 1.
 * @param right Right coordinate of the rectangle, inclusive, starting from 1.
 * @param bottom Bottom coordinate of the rectangle, inclusive, starting from 1.
 * @param buf You have to pass buffer of size
 * <TT>(right - left + 1) * (bottom - top + 1) * sizeof(char_info)</TT>.
 */
void puttext (int left, int top, int right, int bottom, struct char_info * buf);

/**
 * Copies text.
 * @param left Left coordinate of the rectangle, inclusive, starting from 1.
 * @param top Top coordinate of the rectangle, inclusive, starting from 1.
 * @param right Right coordinate of the rectangle, inclusive, starting from 1.
 * @param bottom Bottom coordinate of the rectangle, inclusive, starting from 1.
 * @param destleft Left coordinate of the destination rectangle.
 * @param desttop Top coordinate of the destination rectangle.
 */
void movetext (int left, int top, int right, int bottom, int destleft,
              int desttop);

/**
 * Moves cursor to the specified position.
 * @param x horizontal position
 * @param y vertical position
 */
void gotoxy(int x, int y);

/**
 * Puts string at the specified position.
 * @param x horizontal position
 * @param y vertical position
 * @param str string
 */
void cputsxy (int x, int y, char * str);

/**
 * Puts char at the specified position.
 * @param x horizontal position
 * @param y vertical position
 * @param ch char
 */
void putchxy (int x, int y, char ch);

/**
 * Sets the cursor type.
 * @see @ref cursortypes
 * @param type cursor type, under Win32 it is height of the cursor in percents
 */
void _setcursortype (int type);

/**
 * Sets attribute of text.
 * @param _attr new text attribute
 */
void textattr (int _attr);

/**
 * Sets text attribute back to value it had after program start.
 * It uses text_info's normattr value.
 * @see text_info
 */
void normvideo (void);

/**
 * Sets text background color.
 * @see COLORS
 * @param color new background color
 */
void textbackground (int color);

/**
 * Sets text foreground color.
 * @see COLORS
 * @param color new foreground color
 */
void textcolor (int color);

/**
 * Reads the cursor X position.
 * @returns cursor X position
 */
int wherex (void);

/**
 * Reads the cursor Y position.
 * @returns cursor Y position
 */
int wherey (void);

/**
 * Reads password. This function behaves like cgets.
 *
 * @see cgets
 * @param prompt prompt which will be displayed to user
 * @param str string for the password. <TT>str[0]</TT> have to contain
 * length of the <TT>str</TT> - 3
 * @returns <TT>&str[2]</TT>, the password will be stored in <TT>str</TT>
 * beginning at <TT>str[2]</TT>, in <TT>str[1]</TT> will be length of the
 * string without <TT>\\0</TT>, at <TT>str[2 + str[1]]</TT> will be \\0.
 */
char * getpass (const char * prompt, char * str);

/**
 * Makes foreground colors light.
 * If the current foreground color is less than <TT>DARKGRAY</TT> adds
 * 8 to the its value making dark colors light.
 * @see COLORS
 * @see lowvideo
 */
void highvideo (void);

/**
 * Makes foreground colors dark.
 * If the current foreground color is higher than <TT>LIGHTGRAY</TT> substracts
 * 8 from its value making light colors dark.
 * @see COLORS
 * @see highvideo
 */
void lowvideo (void);

/*@{*/
/*
 * You may need to link with libmsvcr70.a or libmsvcr70d.a or libmsvcr71.a
 *  or libmsvcr71d.a if you want any of these functions.
 */
#ifdef UNICODE
_CRTIMP wchar_t * __cdecl         _cgetws(wchar_t *);
_CRTIMP unsigned short __cdecl    _getwch(void);
_CRTIMP unsigned short __cdecl    _getwche(void);
_CRTIMP unsigned short __cdecl    _putwch(wchar_t);
_CRTIMP unsigned short __cdecl    _ungetwch(unsigned short);
_CRTIMP int __cdecl               _cputws(const wchar_t *);
_CRTIMP int __cdecl               _cwprintf(const wchar_t *, ...);
_CRTIMP int __cdecl               _cwscanf(const wchar_t *, ...);
#endif
/*@}*/

/**
 * Pauses program execution for a given time.
 * @see switchbackground
 * @param ms miliseconds
 */
void delay (int ms);

/**
 * Replaces background color in the whole window. The text however
 * is left intact. Does not modify textbackground().
 * @see flashbackground
 * @param color background color
 */
void switchbackground (int color);

/**
 * Changes background color for a given time and then it restores it back.
 * You can use it for visual bell. Does not modify textbackground().
 * @see switchbackground
 * @see delay
 * @param color background color
 * @param ms miliseconds
 */
void flashbackground (int color, int ms);

/**
 * Clears the keyboard buffer.
 * To see it in effect run <TT>conio_test</TT> and try to press a key during
 * the 'Flashing...' phase.
 */
void clearkeybuf (void);

#ifdef __cplusplus
}
#endif

#endif /* _CONIO2_H_ */

 

Não sei qual a origem dessa conio.h nos exemplos de @devair1010 e talvez ela não inclua essa função e por isso essa e algumas outras apareçam reescritas várias vezes, como textcolor() que também deveria estar lá

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

18 minutos atrás, Mauro Britivaldo disse:

SystemSetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),(COORD){0, 0});

 

pode usar um typedef :D 

 

Tente algo assim

	typedef BOOL (_stdcall *SystemSetConsoleCursorPosition) (HANDLE, COORD);
	SystemSetConsoleCursorPosition MinhaSystemSetConsoleCursorPosition = SetConsoleCursorPosition;

E aí poderá chamar

	MinhaSystemSetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){ 0,0 });

:D:D :D 

 

Ou estava falando sério?

 

  • Curtir 1
  • Haha 1
Link para o comentário
Compartilhar em outros sites

Em 06/09/2020 às 00:19, Lucca Rodrigues disse:

Talvez seja bom adicionar um pequeno delay depois de mudar o cursor de posição, uns 200 ms, e quem sabe mudar a cor da opção em que o cursor está. Fiz algo assim há um tempo, vou incluir um gif

 

Em geral eu digo que não vale a pena escrever em C ou C++ em modo texto a menos que tenha um dinheiro, uma nota ou alguma busca incansável por problemas. Mas um menu acaba aparecendo toda hora :) e aí vem

  • o scanf() com especificadores de um metro
  • aquela fila de chamadas para as funções de console
  • os ENTER que zoam a tela
  • a fgets() que aparece com o '\n'.
  • as vinte religiões de como "limpar o buffer"
  • os mitos e lendas do lixo do buffer
  • a dificuldade em controlar o teclado mesmo sendo um programa monolítico

E por aí vai.

image.png.2436241d627bfaec467d62e46519cb8e.png

Se você escreveu um programa para usar o menu assim espero que tenha criado um mecanismo para poder usar SEMPRE isso, porque programas são assim:

  •  Se você fez para vender vai querer vender para outro
  • Se você comprou vai querer poder usar para outra coisa
  • Se fez para um curso está sabendo que na semana seguinte o instrutor vêm com algo parecido
  • Se fez para dar de presente sempre tem alguém fazendo aniversário

Menus e Windows


Toda janela em Windows tem acesso a um menu e o suporte é excelente. Tem tudo pronto. Submenus, Teclas de Atalho, barras separadoras, ícones nas opções, o d1@b0. Exceto para a console. Isso porque a console é compartilhada por possíveis vários programas.


Quando não existia console um menu era como esse que escreveu. Na verdade a AMI a Lenovo e a Dell usam uma tela assim com essas cores até na programação do BIOS das máquinas deles. Sim, BIOS é masculino, abreviatura de sistema afinal.

 

Imaginando a pergunta do autor do tópico, uma técnica bem anos 90 de menu de seleção era usar apenas as setas como disse o autor. 

 

Em 06/09/2020 às 00:19, Lucca Rodrigues disse:

conforme clico nas setas p CIMA ou p Baixo o menu interage

 

Pois é.

 

Então um menu assim teria

  • uma lista de opções
  • uma opção padrão
  • uma posição na tela
  • um timeout para a leitura, em milissegundos
  • umas opções. Exemplos
    • limpa a tela antes e depois do menu?
    • usa uma borda em torno das opções? Com que letra?
    • usa uma cor de fundo diferente?
    • usa uma cor de texto diferente

E como navegar pelo menu sem chance de zoar a tela e sem muito stress para programar?

Anos 80: inverte as letras entre as opções

Exemplo
 

image.png.98ffdce7c11f52ae0d627087af83fa34.pngAlgo assim.

Que o usuário pode fazer?

Como o autor mencionou, seta para cima, seta para baixo, ENTER e ESCAPE.  E o menu retorna a opção. O número. Só isso. -1 se cancelou, 1 a 9 para a opção selecionada

 

E o que mais?

 

Não é porque é só um exemplo bobinho que precisa ser inútil. função deve aceitar

  • 0 zero para voltar para a opção padrão se o usuário esqueceu qual era e quer usar o padrão
  • '+' e '-' também no lugar das setas porque... porque sim. com '-' vai para a opção de cima e com mais para a opção de baixo. Afinal tem as teclas lá no teclado numérico
  • a lista é circular: avançar além da última vai para a primeira e voltar aquém da primeira vai para a última porque... porque sim
  • O título é a primeira opção e aparece sempre em reverso
  • o reverso sempre respeita as cores em uso ao entrar no programa
  • sem usar read() ou scanf() ou fgets() porque aí é um inferno controlar como esse forum é testemunha :D 
  • tem que ter uma opção para ler do disco porque é um 1nfern0 ficar alinhando opções num menu que a gente não sabe nunca se está completo
  • tem que ter uma opção para usar a partir do programa mesmo porque tem horas em que não dá pra ter um arquivo a mais
  • claro que não vamos usar coisas como puts() ou printf() ou cout() ou cerr() porque só daria trabalho

É uma especificação?
 

Sim, é suficiente para escrever algo. Mas tem que ser algo simples e um componente ou não adiantaria de nada. Eu não preciso disso mas se eu precisar não vou querer escrever de novo ;) E se não der pra ninguém usar espero que não tenha ninguém lendo isso até aqui.


Em C, C++ ou C#


Em C e C++. Porque queremos usar o Terminal do Windows ou a console e não .Net

 

Como seria usar em C?

 

Algo assim para ler do disco
 

int main(void)
{
    // menu vem do disco
    const char* arquivo = "outro-menu.txt";
    MenuConfig menu;
    _m_carrega_do_arquivo( arquivo, &menu);

    int asw = _m_menu(&menu);
    
    if (asw > 0)
        printf("\n\nOpcao: %d '%s'\n", asw, menu.argv[asw]);
    else
        printf("\n\nCancelado\n");
     
    return 0;
};    // main();


Uma linha só: 
 

    int            _m_menu(MenuConfig*);

 

Mostra o menu e devolve a opção.

 

E um arquivo como pode ser?
 

** Menu com opções lidas do arquivo **
 1 - Essas opções vieram do
 2 - disco
 3 - nesse teste
 4 - eh um simples arquivo
 5 - txt com as opções
 6 - a serem mostradas no menu
 7 - Nao precisa de numero
 8 - porque o sistema devolve a posicao
 9 - delas a partir de 1
10 - a primeira opcao e' o titulo
11 - do menu, como em main()
#teste

15,15,3,50,1

 

  • claro que precisa das opções, e elas são lidas até ter uma linha em branco
  • a primeira linha sem surpresas é o título
  • as seguintes são opções a menos que comecem por '#' que é um comentário. É importante ter um comentário porque assim pode deixar alguma opção para usar depois e já fica no arquivo, ou alguma instrução
  • não precisa ter números porque é um programa de computador e ele sabe contar a opção e devolver o número
  • o primeiro 15 é a linha
  • o segundo 15 é a coluna
  • o 3 é a opção padrão, que vai aparecer pré selecionada na tela
  • o 50 é o tempo em ms para a "leitura". Não vamos usar leitura propriamente
  • o 1 é uma opção de uma série. É um int e são 32 bits de opções. Eu usava muitas mas por hora vamos usar apenas o bit 1, o primeiro: então se 1 vai limpar a tela antes e depois de cada menu. com zero deixa tudo como estava

E é só isso.

 

E a estrutura MenuConfig?

 

Isso é só um brinquedo. A estrutura tem o mínimo, o que estava no arquivo:

 

typedef struct
{
	int         argc; // opções + titulo
	char**      argv; // as tais opções do menu
	int         dflt; // opcao padrão
	unsigned    opt; // parametros
	int         timeout_ms;

	int         linha; // posicao
	int         coluna;

}	MenuConfig;

 

Claro, as opções são como os argumentos de main() então porque não usar os mesmos nomes?E a função 

    int            _m_carrega_do_arquivo(const char*, MenuConfig*);


claro que preenche a estrutura todinha a  partir do arquivo:
 

    const char* arquivo = "outro-menu.txt";
    MenuConfig menu;
    _m_carrega_do_arquivo( arquivo, &menu);


No exemplo acima...

 

E se fosse para fazer SEM arquivo?
 

    char**		_m_carrega_da_memoria(const int, const char* []);

 

Essa função simples devolve o parâmetro arrumadinho para colocar no argv.

 

Um exemplo sem arquivo, em C?

 

Nesse caso tem mais de 10 linhas :) Afinal precisa das opções e preencher a configuração, já que não tem o arquivo.

 

O Exemplo

 

int main(void)
{
	const char* opções[] =
	{
		" Menu - Um exemplo de opções ",
		" 1 - See also ",
		" 2 - Console Functions ",
		" 3 - FlushConsoleInputBuffer ",
		" 4 - Low - Level Console Input Functions ",
		" 5 - PeekConsoleInput ",
		" 6 - ReadConsole ",
		" 7 - ReadConsoleInput ",
		" 8 - ReadFile ",
		" 9 - MenuConfig um_teste "
	};	// um teste 9 opções
	int		n_opt = sizeof(opções) / sizeof(char*);

	MenuConfig  cfg =
	{
	  .argc = n_opt,
	  .argv = _m_carrega_da_memoria(n_opt, opções),
	  .dflt = 4,
	  .opt = 0,
	  .timeout_ms = 100,
	  .linha = 10,
	  .coluna = 10
	};

	int asw = _m_menu(&cfg);
	
	if (asw > 0)
		printf("\n\nSelecionada opcao: %d '%s'\n", asw, cfg.argv[asw]);
	else
		printf("\n\nCancelado\n");

	return 0;
};	// main();

 

O óbvio: as opções você digita lá no vetor. A estrutura é preenchida logo depois. argc é calculado ali porque as opções são um vetor constante. O argv a função acima cria o chato char** prontinho. O resto é o esperado: se você não souber a linha, a coluna e a opção padrão não há razão para escrever o menu. Para o timeout qualquer coisa perto de 100 está bem.

 

E a rotina que chama o menu é claro a mesma.

 

E em C++?

 

Em C++ é bem mais fácil, claro

A bem da verdade poderia chamar as funções em C já que elas foram escritas e estão bem aqui, mas não faria sentido porque o forum é pra esse tipo de dúvida.
 

Em C++ lendo do arquivo
 

int main(void)
{
    // nornal: menu a partir do disco
    Menu teste;
    teste.carrega_do_arquivo("menu.txt");
    int asw = teste.select();
    cout << "\nRetornou " << asw << " \"" << teste.getopt(asw) << "\"" << endl;
    return 0;
};  // main()

 

Em C++ declarando as opções no programa
 

int main()
{
	// um teste sem arquivo: as opções estão no programa
	vector<string> outro
	{
		" Menu - Um exemplo de opções ",
		" 1 - See also ",
		" 2 - Console Functions ",
		" 3 - FlushConsoleInputBuffer ",
		" 4 - Low - Level Console Input Functions ",
		" 5 - PeekConsoleInput ",
		" 6 - ReadConsole ",
		" 7 - ReadConsoleInput ",
		" 8 - ReadFile ",
		" 9 - MenuConfig um_teste "
	};
	Menu menu2(outro.size(), outro, 12, 12, 2, 1, 80);
	int asw = menu2.select();
	cout << "\nRetornou " << asw << " \"" << menu2.getopt(asw) << "\"" << endl;
	return 0;
};

 

Em C++ tem classes e polimorfismo então podemos ter uma classe Menu e um construtor para ler do disco e outro para ler de um vetor no próprio programa.

 

E select() devolve a opção. Claro que usa o arquivo que funciona em C funciona em C++. Eu não iria fazer dois programas similares e de graça. São o mesmo, confesso. 

 

E como funciona o select() em C++ e _m_menu() em C?

 

Entenda que as funções de console são as mesmas, escritas em C há mais de 30 anos. Claro que a nova console do Windows, de 2018, tem centenas de milhares de linhas de programa e trouxe muito de C++ para a história, mas em geral na forma de novas API e o conceito de CONPTY. Fora do tópico...

 

Eu escrevi esse exemplo em duas camadas e na primeira camada não tem nenhuma chamada de sistema. Eis por exemplo a versão em C de menu() --- eu usei esse prefixo _m_ nas funções em C porque eram nomes muito comuns.
 

int			_m_menu(MenuConfig* C)
{
	// limpa a tela
	// mostra o menu inicial
	// usa menu_helper para navegar
	// retorna a opcao para quem chamou
	if (C->argc == 0) return -1;
	if (C->argv == NULL) return -2;
	char clear = C->opt & _CLS_;
	if (clear) _m_cls();
	COORD Pos = { .X = (SHORT)C->coluna, .Y = (SHORT)C->linha };
	int res = 0;

	_m_mensagem_YX(Pos, C->argv[0], 1); // O titulo
	Pos.Y += 2; // vai mostrar as opções
	for (int i = 1; i < C->argc; i += 1, Pos.Y += 1)
		_m_mensagem_YX(Pos, C->argv[i], (i == C->dflt));
	// navega
	int opt = C->dflt; // a opcao selecionada
	Pos.Y = (SHORT)(C->linha + C->dflt + 1);
	while ((res = _m_menu_helper(C)) != 'R')
	{
		if (res == 'E')
		{
			if (clear) _m_cls();
			return -1;
		};
		// vai mudar a opcao
		_m_mensagem_YX(Pos, C->argv[opt], 0);
		if (res == '+')	opt = (opt >= C->argc - 1) ? 1 : opt + 1;
		else
			if (res == '-')	opt = (opt < 2) ? C->argc - 1 : opt - 1;
			else
				if (res == '0')	opt = C->dflt;
		Pos.Y = (SHORT)(C->linha + opt + 1);
		_m_mensagem_YX(Pos, C->argv[opt], 1);
	};	// while()
	if (clear) _m_cls();
	return opt;
};	// _m_menu()

 

A lógica é linear: a estrutura C tem todo o necessário. C->argc é como em main(), o total de argumentos. Se em main() argv[0] é o nome de programa aqui C->argv[0] é o título do menu. Sem inventar. E as opções vem em seguida. E o resto é o óbvio. Para encapsular o resto, a função mensagemYX() escreve uma linha na posição Pos. O texto é a opção do menu e o terceiro parâmetro indica se vai escrever em reverso ou não.


Em mais um caso de encapsulamento a função mensagemYX() é genérica e nada tem a ver com o menu
 

    void        _m_mensagem_YX(COORD Pos, const char* msg, char opt)

 

E o código é o mesmo em C ou C++. Algo assim:
 

void		_m_mensagem_YX(COORD Pos, const char* msg, char opt)
{
	CONSOLE_SCREEN_BUFFER_INFO info;
	DWORD total = 0;
	HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleScreenBufferInfo(Console, &info);
	WORD Reverso = (info.wAttributes & 0xF0) | (info.wAttributes & 0xF) << 4;
	SetConsoleCursorPosition(Console, Pos);

	if (opt == 0)
		SetConsoleTextAttribute(Console, info.wAttributes);
	else
		SetConsoleTextAttribute(Console, Reverso);

	WriteConsoleA(Console, (void*)msg, strlen(msg), &total, NULL);

	SetConsoleTextAttribute(Console, info.wAttributes); // reeset
	return;
}	// _m_mensagem_em_video_reverso()

 

Para portar para outro sistema ou técnica bastaria mudar essa função, que é a única que escreve na tela.

 

Mas afinal e o menu? Onde lê as teclas sem ler?

 

A leitura foi colocada em uma função auxiliar, menu_helper(), a mesma em C e C++

 

Não é nada sofisticada mas assume certos conhecimentos de como é a infraestrutura de console no Windows. Eis a versão C/C++, escrita com foco em legibilidade porque afinal é um forum público frequentado por estudantes

 

int			_m_menu_helper(MenuConfig* cfg)
{	// valores de retorno
#define		_DEFAULT_  '0'
#define		_DESCE_    '-'
#define		_ENTER_    'R'
#define		_ESCAPE_   'E'
#define		_SOBE_     '+'
	// desce e sobe no indice das opções
	typedef struct _INPUT_RECORD Input;
	if (cfg == NULL) return 0;
	Input	buffer[32];
	char	c = 0;
	HANDLE	Console = GetStdHandle(STD_INPUT_HANDLE);
	DWORD	tempo = cfg->timeout_ms;
	DWORD	tem_tecla = WAIT_OBJECT_0;
	int		total = 0;
	int		sem_escolha = 1;
	WORD	v = 0; // a tecla
	do
	{
		FlushConsoleInputBuffer(Console);
		if (WaitForSingleObject(Console, tempo) != tem_tecla) continue;
		PeekConsoleInput(Console, buffer, 32, (LPDWORD)&total);
		if (total == 0) break;
		for (int i = 0; i < total; i += 1)
		{
			if (buffer[i].Event.KeyEvent.bKeyDown) continue;
			v = buffer[i].Event.KeyEvent.wVirtualKeyCode;
			c = buffer[i].Event.KeyEvent.uChar.AsciiChar;
			// todos os testes sao definitivos entao so retorna
			if (v == VK_ADD) return _SOBE_;
			if (v == VK_SUBTRACT) return _DESCE_;
			if (v == VK_DOWN) return _SOBE_;
			if (v == VK_UP) return _DESCE_;
			if (v == VK_OEM_PLUS) return _SOBE_;
			if (v == '0') return _DEFAULT_;
			if (v == '+') return _SOBE_;
			if (v == VK_ESCAPE) return _ESCAPE_;
			if (v == VK_RETURN) return _ENTER_;
			if (c == '+') return _SOBE_;
			if (c == '-') return _DESCE_;
			if (c == '0') return _DEFAULT_;
		}
	} while (sem_escolha);
	return 0;
};	// _m_menu_helper()

 

Resumo da lógica

 

É uma bobagem afinal só vamos ler umas teclas e retornar, com ou sem teclas.
 

WaitForSingleObject() é o foco: usando o valor do timeout ela verifica se teve algum evento na console depois da chamada. E se teve verifica se foi uma das teclas que estamos tratando e retorna de acordo.


Nada mais

 

E o programa todo?

 

Programas completos em C e C++ estão disponíveis aqui neste link e podem ser baixados direto, com arquivos de teste e alguma discussão além dessa novela aqui. É de domínio público. Se alguém tiver alguma questão pode postar o trecho aqui em outro tópico e eu posso ver. E se alguém encontrar um erro ou quiser alterar algo pode abrir uma solicitação lá mesmo no GitHub.
 

Para ver 1 programa apenas: o exemplo em C lendo da memória
Para ver 1 programa apenas: o exemplo em C lendo do disco
Para ver 1 programa apenas: o exemplo em C++ lendo da memória
Para ver 1 programa apenas: o exemplo em C++ lendo do disco o menu


Não implementei ainda as opções de cor e moldura por preguiça, mas é trivial.

 

Sem discussões religiosas aqui: usei apenas o compilador CL 19.27 da Microsoft, em Windows 10, compilado para 32-bits.

  • Curtir 1
  • Obrigado 1
  • Amei 1
Link para o comentário
Compartilhar em outros sites

@arfneto

9 horas atrás, arfneto disse:

Se você escreveu um programa para usar o menu assim espero que tenha criado um mecanismo para poder usar SEMPRE isso

Sim, naquele caso lá que mostrei por meio de um gif, apertando ESC você vai pro menu, apertando backspace no menu você volta pro campo de digitar os dados, e é isso. Pra sair, basta apertar ESC no menu, pode não ser o melhor jeito de implementar um menu, mas de qualquer forma, eu fiz só pra teste.

  

9 horas atrás, arfneto disse:

e aí vem

  • o scanf() com especificadores de um metro
  • aquela fila de chamadas para as funções de console
  • os ENTER que zoam a tela
  • a fgets() que aparece com o '\n'.
  • as vinte religiões de como "limpar o buffer"
  • os mitos e lendas do lixo do buffer
  • a dificuldade em controlar o teclado mesmo sendo um programa monolítico

É bem isso mesmo kkkk

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

2 horas atrás, Lucca Rodrigues disse:

Sim, naquele caso lá que mostrei por meio de um gif, apertando ESC você vai pro menu, apertando backspace no menu você volta pro campo de digitar os dados, e é isso. Pra sair, basta apertar ESC no menu, pode não ser o melhor jeito de implementar um menu, mas de qualquer forma, eu fiz só pra teste

 

:) Pois é: foi por isso que eu escrevi aquilo Lucca

 

Eu sei como funciona, ou como se espera que funcione. O melhor jeito é sempre discutível, mas se pode sempre olhar como se faz em todos os sistemas, como esse que estamos usando.

 

O que eu quiz dizer então com isso?
 

Citação

Se você escreveu um programa para usar o menu assim espero que tenha criado um mecanismo para poder usar SEMPRE isso

 

Eu quiz dizer que quando você escreveu o seu teste poderia ter gerado uma função, como eu mostrei, _lucca_menu() :) e ter continuado usando isso ao invés de lutar com as ferramentas erradas, o que levou você a escrever
 

2 horas atrás, Lucca Rodrigues disse:

É bem isso mesmo kkkk

 

Na lista de problemas que eu mostrei. Se fez isso, escreveu uma simples função,  e continua usando scanf() e read() write() fgets() puts() para ler opções em menus e tal me desculpe.

É muito mais simples preencher a tabela de opções como eu mostrei e chamar uma função em uma linha que resolve sempre e nunca zoa a tela. Ou usar uma simples classe. Olhou o código? É mínimo. E não lê do teclado então não tem como dar problema com o buffer de entrada.

 

U ma generalização importante

 

Entenda que esse menu como eu mostrei pode ser generalizado em um questão de horas para algo em duas dimensões: aumenta umas teclas na seleção e cria um vetor de argv como está lá na estrutura

 

Era isso em C
 

typedef struct
{
	int         argc; // opções + titulo
	char**      argv; // as tais opções do menu
	int         dflt; // opcao padrão
	unsigned    opt; // parametros
	int         timeout_ms;

	int         linha; // posicao
	int         coluna;

}	MenuConfig;


E assim veja o que dá pra fazer:

 

Esse menu

 

image.png.794307717520e0f97ff796691a4f52de.png

 

É da opção Tools do Visual Studio. Daria pra fazer fácil com o que mostrei porque é só digitar. E ele até faz igual ao exemplo invertendo as cores conforme usa as setas :) 

 

Mas e aí?

Pois é: veja o menu na horizontal com as opções

 

image.png.9499dcfb5fcac94d098c834297fb2850.png

 

Então se você usa um vetor de argv como aquele que está na estrutura que te mostrei e trata as setas para a esquerda e para a direita para passar de uma opção para a outra e as setas para cima e para baixo para navegar na opção, como a de Tools acima, tem um menu. E a função menu() retorna o par. Exemplo: (9,3) se o cara escolher a opção 3 na nona coluna, Tools | Connect to Database no exemplo. Note que o Windows faz exatamente isso e aceita as setas. Veja no arcaico Code::Blocks ou todo programa do Windows.

 

Os menus saíram da moda estão sumindo dos programas modernos. Mas o Firefox ainda tem menus, ou o Office. F10 é a tecla que em geral mostra o menu se não aparece por padrão no Windows.

 

E se você escreve essa generalização, que deve levar umas horas, vai poder ter um menu de duas dimensões em qualquer programa em C ou C++. Só que SEMPRE. É isso o que estou tentando mostrar: preenche a tabela porque tem que ter as opções afinal, chama a função, pega o valor. Como em todo framework que tem menus.
 

Citação

Desde os anos 80 o menu no Windows é assim. E ninguém precisou reescrever. Programar mais que uma vez a mesma coisa quase sempre é um erro. Mas sempre é um desperdício.

 

 

image.png

image.png

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

  • 5 meses depois...

@arfneto      

Em 10/09/2020 às 10:14, arfneto disse:

Não sei qual a origem dessa conio.h nos exemplos de @devair1010 e talvez ela não inclua essa função e por isso essa e algumas outras apareçam reescritas várias vezes, como textcolor() que também deveria estar lá

 

    essa conio.h

 

/*
 * conio.h
 * This file has no copyright assigned and is placed in the Public Domain.
 * This file is a part of the mingw-runtime package.
 * No warranty is given; refer to the file DISCLAIMER within the package.
 *
 * Low level console I/O functions. Pretty please try to use the ANSI
 * standard ones if you are writing new code.
 *
 */

#ifndef	_CONIO_H_
#define	_CONIO_H_

/* All the headers include this file. */
#include <_mingw.h>

#ifndef RC_INVOKED

#ifdef	__cplusplus
extern "C" {
#endif

_CRTIMP char* __cdecl __MINGW_NOTHROW	_cgets (char*);
_CRTIMP int __cdecl __MINGW_NOTHROW	_cprintf (const char*, ...);
_CRTIMP int __cdecl __MINGW_NOTHROW	_cputs (const char*);
_CRTIMP int __cdecl __MINGW_NOTHROW	_cscanf (char*, ...);

_CRTIMP int __cdecl __MINGW_NOTHROW	_getch (void);
_CRTIMP int __cdecl __MINGW_NOTHROW	_getche (void);
_CRTIMP int __cdecl __MINGW_NOTHROW	_kbhit (void);
_CRTIMP int __cdecl __MINGW_NOTHROW	_putch (int);
_CRTIMP int __cdecl __MINGW_NOTHROW	_ungetch (int);


#ifndef	_NO_OLDNAMES

_CRTIMP int __cdecl __MINGW_NOTHROW	getch (void);
_CRTIMP int __cdecl __MINGW_NOTHROW	getche (void);
_CRTIMP int __cdecl __MINGW_NOTHROW	kbhit (void);
_CRTIMP int __cdecl __MINGW_NOTHROW	putch (int);
_CRTIMP int __cdecl __MINGW_NOTHROW	ungetch (int);

#endif	/* Not _NO_OLDNAMES */


#ifdef	__cplusplus
}
#endif

#endif	/* Not RC_INVOKED */

#endif	/* Not _CONIO_H_ */

          é a que vem por padrão no codeblocks ,  e creio que essa você postou  seja a conio2.h ,  e normalmente quem usa o codeblocks são iniciantes e não sabem instalar bibliotecas e nem configurar o compilador , e o usam ao naturaL , e sendo assim eu não quis usar a conio2.h por que senão poucos conseguiriam rodar os códigos com gotoYX e textcolor ,  pois precisa instalar a conio2 , que tem essas duas funções , e outras , e essas duas funções eu aprendi quando comecei a estudar Lógica de Programação , onde usam o compilador turbo pascaL , da biblioteca crt .

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

6 minutos atrás, devair1010 disse:

conio2.h

 

Essa não :D conio2! fuja disso. Essas coisas vem desde o Apple II e o TurtleGraphics dos anos 80, passando pelo Turbo Pascal e Turbo C, que vinham em dois diskettes de 1.44mb pouco depois, para DOS

 

Não é possível que alguém precise disso 40 anos depois, numa época em que um telefone comum chega a ter oito processadores e um processador Core i7 meio antigo tem 3 bilhões de transistores.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@arfneto    a função getch é boa ,  e ela precisa da conio ,  então para não usa-la ,  coloquei essa função que você postou 

 

#include <stdio.h>
#include <windows.h>

void		getch();

int main(void)
{
	printf("\
Se essa versao funciona o programa para aqui\
... Tecle algo para continuar \n");
	getch();
	printf("Se parou, tem uma versao que serve\n");
	return 0;
}

void	getch()
{
  FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
  WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), INFINITE);
};

 

ela tem uma das funções da getch original , que é esperar até que qualquer tecla seja pressionada e sem precisar teclar enter ,  mas para pegar o valor da tecla pressionada  , não consigo saber .

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@devair1010 Se o propósito é esperar por algo do teclado, então imagino que o caminho seria esse mesmo.

No github do colega @arfneto tem uma função que ele criou usando a Peek(), acho que chamou de choice(). O comportamento parece ser semelhante ao da getch(), só não mando o link porque não sei se tenho autorização :D

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Em 15/09/2020 às 02:17, arfneto disse:

E o programa todo?

 

Programas completos em C e C++ estão disponíveis aqui neste link e podem ser baixados direto, com arquivos de teste e alguma discussão além dessa novela aqui. É de domínio público. Se alguém tiver alguma questão pode postar o trecho aqui em outro tópico e eu posso ver. E se alguém encontrar um erro ou quiser alterar algo pode abrir uma solicitação lá mesmo no GitHub

 

1 hora atrás, Lucca Rodrigues disse:

só não mando o link porque não sei se tenho autorização :D

 

Juntando os dois posts tem a resposta. :D 

 

int			_m_menu_helper(MenuConfig* cfg)
{	// valores de retorno
#define		_DEFAULT_  '0'
#define		_DESCE_    '-'
#define		_ENTER_    'R'
#define		_ESCAPE_   'E'
#define		_SOBE_     '+'
	// desce e sobe no indice das opções
	typedef struct _INPUT_RECORD Input;
	if (cfg == NULL) return 0;
	Input	buffer[32];
	char	c = 0;
	HANDLE	Console = GetStdHandle(STD_INPUT_HANDLE);
	DWORD	tempo = cfg->timeout_ms;
	DWORD	tem_tecla = WAIT_OBJECT_0;
	int		total = 0;
	int		sem_escolha = 1;
	WORD	v = 0; // a tecla
	do
	{
		FlushConsoleInputBuffer(Console);
		if (WaitForSingleObject(Console, tempo) != tem_tecla) continue;
		PeekConsoleInput(Console, buffer, 32, (LPDWORD)&total);
		if (total == 0) break;
		for (int i = 0; i < total; i += 1)
		{
			if (buffer[i].Event.KeyEvent.bKeyDown) continue;
			v = buffer[i].Event.KeyEvent.wVirtualKeyCode;
			c = buffer[i].Event.KeyEvent.uChar.AsciiChar;
			// todos os testes sao definitivos entao so retorna
			if (v == VK_ADD) return _SOBE_;
			if (v == VK_SUBTRACT) return _DESCE_;
			if (v == VK_DOWN) return _SOBE_;
			if (v == VK_UP) return _DESCE_;
			if (v == VK_OEM_PLUS) return _SOBE_;
			if (v == '0') return _DEFAULT_;
			if (v == '+') return _SOBE_;
			if (v == VK_ESCAPE) return _ESCAPE_;
			if (v == VK_RETURN) return _ENTER_;
			if (c == '+') return _SOBE_;
			if (c == '-') return _DESCE_;
			if (c == '0') return _DEFAULT_;
		}
	} while (sem_escolha);
	return 0;
};	// _m_menu_helper()

 

E essa é a estrutura importante
 

typedef struct _INPUT_RECORD {
  WORD  EventType;
  union {
    KEY_EVENT_RECORD          KeyEvent;
    MOUSE_EVENT_RECORD        MouseEvent;
    WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
    MENU_EVENT_RECORD         MenuEvent;
    FOCUS_EVENT_RECORD        FocusEvent;
  } Event;
} INPUT_RECORD;

 

 

A ideia é sempre a mesma: WaitForSingleObject() retornou por algum objeto. Deve ter sido uma tecla e como a função acima era para um menu aceita apenas as setas, o ENTER --- os ENTER porque são teclas diferentes --- ESCAPE e 0 para voltar paa a opçõ padrão do menu.

 

No fundo getch() é igual. Mas pode ser melhor: no fundo poderia ser algo como

 

    int getch( char* opções[] );

 

onde você passa um vetor com as teclas aceitas e a função retorna com a que veio ou -1 se não tinha nenhuma dessas, e volta com o buffer já vazio. Assim pode usar de vários modos...

 

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...