基本 Ncurses 菜单
Basic Ncurses Menu
我正在尝试用 C 语言做一个基本菜单。我应该用 ncurses 库做这个。我正在使用本教程:
Video On YouTube
但是我的版本有一些问题:
1)菜单打印不正常,只有在选择菜单项时才会显示。那么高光就不会消失
2)菜单上的选项不会打印在顶部
你能帮帮我吗?菜单的想法好还是我应该寻找其他教程(有帮助吗?)。
#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: 代码注释不是英文的,但我希望没有必要
这里有不少问题。我已经包含了您的代码的修改版本,我将尝试描述这些更改。
有一些未使用的变量,即 argc
、argv
和 c
,因此我将它们转换为 void
以消除编译器警告。您可以删除 c
并更改为 int main(void)
,如果您愿意,可以完全删除这些变量。
我已将 stdlib.h
header 文件添加到您的 #include
中用于 exit()
函数。这在我添加到您的代码中的新错误函数 fail()
中使用。在 C 语言中编程时,您应该始终检查您调用的任何函数的 return 值。这里特别重要的是检查,首先如果终端支持带有 has_colors()
函数的颜色,然后如果调用至 start_color()
成功。如果其中任何一个失败,将调用 fail()
函数并显示一条错误消息,程序将以 EXIT_FAILURE
值退出。函数 has_colors()
return 是 bool
,start_color()
函数 return 是 int
(OK
如果成功,否则 ERR
).
现在颜色已经初始化,我看到菜单选择 window 的下边框被菜单文本覆盖。为了解决这个问题,我更改了 window 的大小,使其高了一行:
WINDOW * menuwin=newwin(7, dlug-12, szer-9, 6);
您报告的不正确打印的根本问题是由于控制菜单项打印的 for
循环中的大括号放错了位置。我借此机会重新组织了一下循环;现在只有一次调用 mvwprintw()
。 A_REVERSE
属性在打印前设置,如果当前项目也是选定的项目,并且在打印后再次取消设置。
我还将 switch
语句中的极限测试从等式更改为不等式。在这种情况下,最好使用 if (zaznacz < 0)
而不是 if (zaznacz == -1)
。
我在最后的 printw()
中的格式字符串的开头添加了一个换行符,因为某些选择太长而无法放入标题末尾的 window 中。您可以将此输出移动到任何您喜欢的地方。
最后,我在最后的 printw()
语句之后添加了一个 refresh()
和一个 getch()
等待用户点击 ENTER在退出程序之前。在退出 NCurses 程序之前通过调用 endwin()
进行清理非常重要。当您的程序 运行 时,此功能会撤消 NCurses 对您的终端所做的更改,否则可能会导致终端不愉快。
#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;
}
我正在尝试用 C 语言做一个基本菜单。我应该用 ncurses 库做这个。我正在使用本教程: Video On YouTube
但是我的版本有一些问题: 1)菜单打印不正常,只有在选择菜单项时才会显示。那么高光就不会消失 2)菜单上的选项不会打印在顶部
你能帮帮我吗?菜单的想法好还是我应该寻找其他教程(有帮助吗?)。
#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: 代码注释不是英文的,但我希望没有必要
这里有不少问题。我已经包含了您的代码的修改版本,我将尝试描述这些更改。
有一些未使用的变量,即 argc
、argv
和 c
,因此我将它们转换为 void
以消除编译器警告。您可以删除 c
并更改为 int main(void)
,如果您愿意,可以完全删除这些变量。
我已将 stdlib.h
header 文件添加到您的 #include
中用于 exit()
函数。这在我添加到您的代码中的新错误函数 fail()
中使用。在 C 语言中编程时,您应该始终检查您调用的任何函数的 return 值。这里特别重要的是检查,首先如果终端支持带有 has_colors()
函数的颜色,然后如果调用至 start_color()
成功。如果其中任何一个失败,将调用 fail()
函数并显示一条错误消息,程序将以 EXIT_FAILURE
值退出。函数 has_colors()
return 是 bool
,start_color()
函数 return 是 int
(OK
如果成功,否则 ERR
).
现在颜色已经初始化,我看到菜单选择 window 的下边框被菜单文本覆盖。为了解决这个问题,我更改了 window 的大小,使其高了一行:
WINDOW * menuwin=newwin(7, dlug-12, szer-9, 6);
您报告的不正确打印的根本问题是由于控制菜单项打印的 for
循环中的大括号放错了位置。我借此机会重新组织了一下循环;现在只有一次调用 mvwprintw()
。 A_REVERSE
属性在打印前设置,如果当前项目也是选定的项目,并且在打印后再次取消设置。
我还将 switch
语句中的极限测试从等式更改为不等式。在这种情况下,最好使用 if (zaznacz < 0)
而不是 if (zaznacz == -1)
。
我在最后的 printw()
中的格式字符串的开头添加了一个换行符,因为某些选择太长而无法放入标题末尾的 window 中。您可以将此输出移动到任何您喜欢的地方。
最后,我在最后的 printw()
语句之后添加了一个 refresh()
和一个 getch()
等待用户点击 ENTER在退出程序之前。在退出 NCurses 程序之前通过调用 endwin()
进行清理非常重要。当您的程序 运行 时,此功能会撤消 NCurses 对您的终端所做的更改,否则可能会导致终端不愉快。
#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;
}