Ncurses学习经历(十三)菜单系统的核心

        如你在上面的例子中所看到的,menu_driver 在更新菜单时有着举足轻重的作用。所以了解
它的各个选项和它们的作用就很有必要了。前面已经解释过,menu_driver()的第二个参数
可以是一个导航请求。一个可打印的字符(ASCII 码)或KEY_MOUSE 键值。我们来剖析
一下各个导航请求:

REQ_LEFT_ITEM 和REQ_RIGHT_ITEM

一个菜单可以用多列的方式显示菜单项,这可以用函数menu_format()来实现。当显示一个
多列菜单时,这两个移动请求可使menu drive()在当前菜单项位置左移或右移一个菜单项。
REQ_UP_ITEM 和REQ_DOWN_ITEM
这两个移动请求在上面的例子中已经出现过。将这两个移动请求传递给menu_driver 时,
menu_driver()从当前菜单项上移或下移一个菜单项。
NCURSES Programming HOWTO 中文版(第二版)
66
REQ_SCR_系列的移动请求
REQ_SCR_ULINE, REQ_SCR_DLINE, REQ_SCR_DPAGE 和REQ_SCR_UPAGE 是有
关屏幕滚动的请求。如果所有的菜单项在当前菜单子窗口中显示不完,菜单就是可滚动的。
当这些请求传给menu_driver 时,将分别向上/下滚动一行/页。
REQ_FIRST_ITEM, REQ_LAST_ITEM, REQ_NEXT_ITEM 和REQ_PREV_ITEM
这些请求的功能从名字上就可以明显的看出来。分别是:移动到第一个菜单项、最后一个菜
单项、下一个菜单项和前一个菜单项。
REQ_TOGGLE_ITEM
当使用这个移动请求时,当前菜单项会被锁定。这个选项仅用于一个多层菜单。因此使用它
时须关闭O_ONEVALUE(通过set_menu_opts()函数关闭或启用)。
样式匹配请求
每个菜单都有一个与之关联的样式匹配缓冲区。通过这个缓冲区,用户可以通过输入ASCII
字符串查找与之匹配的菜单项。任何传给menu_driver 的ASCII 字符都会被送入样式匹配
缓冲区,它同时试着从菜单项列表中查找与之最近的匹配项。然后立刻从当前菜单项跳转到
与匹配样式最近的菜单项上去。REQ_CLEAR_PATTERN 请求用来清空匹配缓冲区。
REQ_BACK_PATTERN 清除模式缓冲区中前一个匹配样式。如果有多个匹配样式,这些匹
配样式就可以通过REQ_NEXT_PATTERN 和REQ_PREV_PATTERN 进行切换,这两个
选项分别从当前菜单项移至下或上一个匹配样式。

17.4 含菜单窗口
每个已创建的菜单都对应着一个窗口和一个子窗口。菜单窗口显示菜单的标题或边框线。菜
单子窗口显示当前可选的菜单项。而在上面的例子里我们并没有指定窗口或子窗口。当窗口
未被指定时,stdscr 将作为菜单窗口。然后菜单系统根据将要显示的菜单项计算子窗口的大
小。菜单项就在这些规划好的子窗口中显示出来。让我们利用这些窗口,来打印一个有边框
线和标题的菜单。
NCURSES Programming HOWTO 中文版(第二版)
67
例19. 一个菜单窗口用法的例子
#include <menu.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define CTRLD 4
char *choices[] = {
"Choice 1",
"Choice 2",
"Choice 3",
"Choice 4",
"Exit",
(char *)NULL,
};
void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype
color);
int main()
{ ITEM **my_items;
int c;
MENU *my_menu;
WINDOW *my_menu_win;
int n_choices, i;
/* 初始化curses */
initscr();
start_color();
cbreak();
noecho();
keypad(stdscr, TRUE);
init_pair(1, COLOR_RED, COLOR_BLACK);
/* 创建菜单项*/
n_choices = ARRAY_SIZE(choices);
my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
for(i = 0; i < n_choices; ++i)
my_items[i] = new_item(choices[i], choices[i]);
/* 创建菜单*/
my_menu = new_menu((ITEM **)my_items);
/* 创建与菜单相关联的窗口*/
my_menu_win = newwin(10, 40, 4, 4);
keypad(my_menu_win, TRUE);
NCURSES Programming HOWTO 中文版(第二版)
68
/* 设置主窗口和子窗口*/
set_menu_win(my_menu, my_menu_win);
set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1));
/* 设置字符串的标记为" * " */
set_menu_mark(my_menu, " * ");
/* 在主窗口的边界打印边框线和标题*/
box(my_menu_win, 0, 0);
print_in_middle(my_menu_win, 1, 0, 40, "My Menu", COLOR_PAIR(1));
mvwaddch(my_menu_win, 2, 0, ACS_LTEE);
mvwhline(my_menu_win, 2, 1, ACS_HLINE, 38);
mvwaddch(my_menu_win, 2, 39, ACS_RTEE);
mvprintw(LINES 2,
0, "F1 to exit");
refresh();
/* 递送菜单*/
post_menu(my_menu);
wrefresh(my_menu_win);
while((c = wgetch(my_menu_win)) != KEY_F(1))
{ switch(c)
{ case KEY_DOWN:
menu_driver(my_menu, REQ_DOWN_ITEM);
break;
case KEY_UP:
menu_driver(my_menu, REQ_UP_ITEM);
break;
}
wrefresh(my_menu_win);
}
/* 取消递送并释放占用的内存*/
unpost_menu(my_menu);
free_menu(my_menu);
for(i = 0; i < n_choices; ++i)
free_item(my_items[i]);
endwin();
}
void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype
color)
{ int length, x, y;
float temp;
NCURSES Programming HOWTO 中文版(第二版)
69
if(win == NULL)
win = stdscr;
getyx(win, y, x);
if(startx != 0)
x = startx;
if(starty != 0)
y = starty;
if(width == 0)
width = 80;
length = strlen(string);
temp = (width length)/
2;
x = startx + (int)temp;
wattron(win, color);
mvwprintw(win, y, x, "%s", string);
wattroff(win, color);
refresh();
}
这个例子创建了这样一个菜单:有标题、边框,以及一根用来分隔开标题和菜单项的线。如
你所见,使用set_menu_win()函数把菜单附加到一个窗口上,之后使用set_menu_sub()
函数把菜单的子窗口也附加到这个窗口上,菜单项就可以在子窗口中显示。使用
set_menu_mark()函数可以来设置标志串,标志串就会出现在所选菜单项的左边。


猜你喜欢

转载自blog.csdn.net/zhanganliu/article/details/80587462
今日推荐