我目前正在编写一个函数,该函数创建一个菜单窗口,该菜单窗口的文本根据参数的不同放置方式。当水平打印数组的内容时,menu()的第一次调用按预期工作(单词以水平方式打印,单词之间带有空格)。但是,如果再次调用该函数,则printf的x位置不会改变,从而导致mvwprintw覆盖前一个字。这至少暗示了我的for循环出了点问题,但是创建垂直菜单的工作与预期的一样,每个单词都印在最后一个单词的下面。
nmenu.c
#include "nmenu.h"
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
int menu(char title[], char description[], char *choices[], int choicesSize, bool vertical, bool centered)
{
int menuXMax = 0;
int highlight = 0;
int menuHeight = 9;
int menuWidth = 30;
int choicesLength = 0;
int yMax, xMax;
getmaxyx(stdscr, yMax, xMax);
for(int i; i < choicesSize; i++)
{
if(strlen(choices[i]) > choicesLength)
{
choicesLength = strlen(choices[i]);
}
}
if(vertical)
{
menuHeight = choicesSize+8;
menuWidth = choicesLength+4;
} else
{
menuWidth = choicesLength*choicesSize+choicesSize;
}
if(strlen(description) > menuWidth)
{
menuWidth = strlen(description)+4;
}
WINDOW *menu = newwin(menuHeight, menuWidth, yMax/2-menuHeight/2, xMax/2-menuWidth/2);
box(menu, 0, 0);
refresh();
wrefresh(menu);
keypad(menu, true);
wattron(menu, A_REVERSE);
mvwprintw(menu, 0, 2, title);
wattroff(menu, A_REVERSE);
mvwprintw(menu, 2, menuWidth/2-strlen(description)/2, description);
mvwprintw(menu, menuHeight-3, menuWidth/2-4, "[C]ancel");
menuXMax = getmaxx(menu);
while(true)
{
for(int i = 0; i < choicesSize; i++)
{
if(i == highlight)
{
wattron(menu, A_REVERSE);
}
if(vertical)
{
if(centered)
{
mvwprintw(menu, i+4, menuXMax/2-strlen(choices[i])/2, choices[i]);
} else
{
mvwprintw(menu, i+4, 2, choices[i]);
}
} else
{
if(centered)
{
mvwprintw(menu, 4, (menuXMax/2-choicesLength*choicesSize/2)+choicesLength*i, choices[i]);
} else
{
mvwprintw(menu, 4, 2+choicesLength*i, choices[i]);
}
}
wattroff(menu, A_REVERSE);
}
switch(wgetch(menu))
{
... // User input
}
}
MenuBreak: ;
return 0;
}
test.c
#include "nmenu.h"
#include <ncurses.h>
char *choices[4] = {"Yes", "No", "Maybe", "Sometimes"};
int main()
{
// Start ncurses
initscr();
noecho();
cbreak();
curs_set(0);
menu("Ver 1", "Choices should be uncentered and presented vertically", choices, 4, true, false);
menu("Ver 2", "Choices should be centered and presented vertically", choices, 4, true, true);
// End ncurses
getch();
endwin();
return 0;
}
test.c将正常输出第一个菜单,而第二个菜单具有重叠的文本。当呼叫顺序切换时,也会发生这种情况。我只是看不到为什么再次运行该函数时for循环无法正确迭代。
在下一行:
for(int i; i < choicesSize; i++)
变量i未初始化。应该将其设置为零,以使其看起来像:
for(int i = 0; i < choicesSize; i++)
然后将正确计算choicesLength,并且水平布局也适用。
Demo
结果的屏幕快照如下:
未定义行为
未初始化的变量会导致C中的undefined behavior,因此应尽可能避免使用。
例如,打开编译器警告会很有帮助。使用
时gcc -Wextra -Wall main.c nmenu.c -o tst -lncurses
显示此有用信息:
nmenu.c:16:16: warning: variable 'i' is uninitialized when used here [-Wuninitialized]
for(int i; i < choicesSize; i++)
^