Im trying to do a basic menu in C. I'm supposed to do this with ncurses lib. I was working with this tutorial: Video On YouTube
But mine version has some problems: 1)The menu will not print properly, it will reveal only while choosing menu items. Then the highlight won't go off 2)Option made on menu won't print on the top
Can you help me? Is that idea of Menu good or should i look for other tutorial (any help ?).
#include <stdio.h>
#include <ncurses.h>
#include <string.h>
#include <menu.h>
int main(int argc, char **argv)
{
int i, c;
char powitanie[]="SLOWNIK UNIWERSALNY";
int szer, dlug; //wartosci dlugosci i szerokosci terminalu
initscr(); //Inizjalizacja całości ncurses, kolory itp
raw();
noecho();
keypad(stdscr, TRUE);
start_color();
//init_pair(1, COLOR_BLUE, COLOR_BLACK); //wybór kolorów
getmaxyx(stdscr, szer, dlug); //pobranie rozmiarów terminalu
move(szer/2, (dlug-strlen(powitanie))/2); //przesuwamy kursor na środek (tak aby się ładnie wydrukowało)
//attron(COLOR_PAIR(1)); //Aktywujemy wybrane kolory
printw(powitanie); //Drukujemy powitanie
//attroff(COLOR_PAIR(1));//Dezaktywujemy kolory
refresh();//Odswiezamy (inaczej się nie wyswietli)
WINDOW * menuwin=newwin(6, dlug-12, szer-8, 6); //Definiujemy i tworzymy 'okno'
box(menuwin, 0, 0);
refresh();//ponownie odświeżamy aby okno się pojawiło
wrefresh(menuwin);//odświeżamy samo okno
keypad(menuwin, TRUE);//umozliwiamy dzialanie klawiatury w oknie
char *opcje[] = {
"Tlumacz z Polskiego na Angielski",
"Tlumacz z Angielskiego na Polski",
"Edystuj slownik",
"Wybierz slownik",
"Wyjdz",
};
int wybor;
int zaznacz=0;
while(1)//cala ta petla sluzy ciaglemu tworzeniu menu z podswietleniem wybranego elementu
{
for(i=0; i<5; i++)
{
if(i==zaznacz)
{
wattron(menuwin, A_REVERSE);
mvwprintw(menuwin, i+1, 1, opcje[i]);
wattroff(menuwin, A_REVERSE);
}
wybor = wgetch(menuwin);
switch(wybor)
{
case KEY_UP:
zaznacz--;
if(zaznacz==-1) zaznacz=0;//zabezpieczenie przed wyjsciem "poza" menu
break;
case KEY_DOWN:
zaznacz++;
if(zaznacz==5) zaznacz=4;
break;
default:
break;
}
if(wybor==10) break;
}
printw("Wybrano:%s", opcje[zaznacz]);
}
return(0);
}
PS: Code comments are not in English but i hope the won't be necessary
There are quite a few problems here. I have included a modified version of your code that works, and I will attempt to describe the changes.
There were some unused variables, namely argc
, argv
, and c
, so I cast these to void
in order to silence compiler warnings. You can remove the c
and change to int main(void)
, if you like, removing these variables altogether.
I have added the stdlib.h
header file to your #include
s for the exit()
function. This is used in the new error function, fail()
, that I added to your code. You should always check the return values of any function that you call when programming in C. Here it is particularly important to check, first if the terminal supports color with the has_colors()
function, and then if the call to start_color()
is successful. If either of these fail, the fail()
function is called with an error message, and the program exits with the EXIT_FAILURE
value. The function has_colors()
returns a bool
, and the start_color()
function returns an int
(OK
if successful, otherwise ERR
).
Now that colors have been initialized, I see that the lower border of your menu selection window is being overwritten by the menu text. To fix this, I changed the size of your window, making it one line taller:
WINDOW * menuwin=newwin(7, dlug-12, szer-9, 6);
The fundamental problem of improper printing that you reported was because of a misplaced brace in the for
loop controlling the printing of the menu items. I took the opportunity to reorganize the loop a bit; now there is only one call to mvwprintw()
. The A_REVERSE
attribute is set before printing if the current item is also the selected item, and it is again unset after printing.
I also changed the limit tests in the switch
statement from equalities to inequalites. It is better practice to use , e.g., if (zaznacz < 0)
instead of if (zaznacz == -1)
in such cases.
I added a newline character to the beginning of the format string in the final printw()
, since some of the selections are too long to fit in the window at the end of the title. You can move this output wherever you like.
Finally, I added a refresh()
after the final printw()
statement, and a getch()
to wait for the user to hit ENTER before exiting the program. It is very important to cleanup by calling endwin()
before exiting an NCurses program. This function reverses changes made to your terminal by NCurses while your program was running, and failure to do this can lead to terminal unpleasantries.
#include <stdio.h>
#include <ncurses.h>
#include <string.h>
#include <menu.h>
#include <stdlib.h> // added for exit() function
void fail(char *msg) {
endwin();
puts(msg);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
/* Commandline argument currently unused */
(void) argc;
(void) argv;
int i, c;
(void) c; // c is currently unused
char powitanie[]="SLOWNIK UNIWERSALNY";
int szer, dlug; //wartosci dlugosci i szerokosci terminalu
initscr(); //Inizjalizacja całości ncurses, kolory itp
raw();
noecho();
keypad(stdscr, TRUE);
/* Test to see if terminal has colors */
if (has_colors() == false) {
fail("Colors unavailable\n");
}
if (start_color() != OK) {
fail("Unable to start colors\n");
}
//init_pair(1, COLOR_BLUE, COLOR_BLACK); //wybór kolorów
getmaxyx(stdscr, szer, dlug); //pobranie rozmiarów terminalu
move(szer/2, (dlug-strlen(powitanie))/2); //przesuwamy kursor na środek (tak aby się ładnie wydrukowało)
//attron(COLOR_PAIR(1)); //Aktywujemy wybrane kolory
printw(powitanie); //Drukujemy powitanie
//attroff(COLOR_PAIR(1));//Dezaktywujemy kolory
refresh();//Odswiezamy (inaczej się nie wyswietli)
WINDOW * menuwin=newwin(7, dlug-12, szer-9, 6); //Definiujemy i tworzymy 'okno'
box(menuwin, 0, 0);
refresh();//ponownie odświeżamy aby okno się pojawiło
wrefresh(menuwin);//odświeżamy samo okno
keypad(menuwin, TRUE);//umozliwiamy dzialanie klawiatury w oknie
char *opcje[] = {
"Tlumacz z Polskiego na Angielski",
"Tlumacz z Angielskiego na Polski",
"Edystuj slownik",
"Wybierz slownik",
"Wyjdz",
};
int wybor;
int zaznacz=0;
while(1)//cala ta petla sluzy ciaglemu tworzeniu menu z podswietleniem wybranego elementu
{
for(i = 0; i < 5; i++) {
if(i == zaznacz)
wattron(menuwin, A_REVERSE);
mvwprintw(menuwin, i+1, 1, opcje[i]);
if (i == zaznacz)
wattroff(menuwin, A_REVERSE);
}
wybor = wgetch(menuwin);
switch(wybor)
{
case KEY_UP:
zaznacz--;
if(zaznacz < 0) zaznacz = 0;//zabezpieczenie przed wyjsciem "poza" menu
break;
case KEY_DOWN:
zaznacz++;
if(zaznacz > 4) zaznacz = 4;
break;
default:
break;
}
if(wybor==10) break;
}
printw("\nWybrano:%s", opcje[zaznacz]);
refresh();
/* Wait for user to press enter to exit */
getch();
/* Need to cleanup before exit */
endwin();
return 0;
}