📄 ch17.htm
字号:
{ 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;
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();
}
</pre>
</font>
<p>
<dd>
这个例子创建了这样一个菜单:有标题、边框,用一根线分隔开标题和菜单项。如你所见,使用函数set_menu_win()来把一个窗口附加到一个菜单。同样也把子窗口附加进来。这样就可以在子窗口中显示菜单和菜单项了。你也可以使用set_menu_mark()来设置标志串,让它显示在在所选菜单项的左边。
</dd>
</p>
<br>
<br>
<h3 align="left">
<a name="roll">
17.5 滚动菜单
</a>
</h3>
<br>
<p>
<dd>
如果设置的子窗口面积不够显示所有的菜单项,菜单将变成可滚动的。在当前列的最后一个菜单项时,如果你把参数REQ_DOWN_ITEM传递过去,它将会变成REQ_SCR_DLINE,将菜单滚动一个菜单项。你也可以手动地用REQ_SCR_操作来滚动菜单。我们来看看怎么做。
</dd>
</p>
<p>
例20.一个滚动菜单的例子
</p>
<font color="Maroon">
<pre>
#include <curses.h>
#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",
"Choice 5",
"Choice 6",
"Choice 7",
"Choice 8",
"Choice 9",
"Choice 10",
"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);
init_pair(2, COLOR_CYAN, 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);
/* 设置主窗口和子窗口 */
set_menu_win(my_menu, my_menu_win);
set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1));
set_menu_format(my_menu, 5, 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);
/* 传递菜单 */
post_menu(my_menu);
wrefresh(my_menu_win);
attron(COLOR_PAIR(2));
mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scoll down or up a page of items");
mvprintw(LINES - 1, 0, "Arrow Keys to navigate (F1 to Exit)");
attroff(COLOR_PAIR(2));
refresh();
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;
case KEY_NPAGE:
menu_driver(my_menu, REQ_SCR_DPAGE);
break;
case KEY_PPAGE:
menu_driver(my_menu, REQ_SCR_UPAGE);
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;
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();
}
</pre>
</font>
<p>
<dd>
这个程序本身已经有了很好地注解。在这个例子中,菜单项的数量增加到了10个,大于我们设置的子窗口的大小——6项,这个信息可以通过函数set_menu_format()显式地传递给菜单系统。在这里我们指定了在一页中可以显示的行数和列数。如果小于子窗口的高度,我们可以任意地指定每页可以显示的行数和列数。如果用户按了键PAGE UP或PAGE DOWN,请求REQ_SCR_UPAGE和REQ_SCR_PATTERN就传递给了menu_driver(),菜单则会滚动。
</dd>
</p>
<br>
<br>
<h3 align="left">
<a name="mulcols">
17.6 多列菜单
</a>
</h3>
<p>
<dd>
在上面的例子中你知道了函数set_menu_format()的用法。我并没有提及列变量(第三个参数)的用法。如果子窗口够宽的话,你可以选择显示每行显示多个菜单项。这可以在列变量里面设置。为简化问题起见,下面的这个例子没有对菜单项进行描述。
</dd>
</p>
<p>
例21.一个多列菜单的例子
</p>
<font color="Maroon">
<pre>
#include <curses.h>>
#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", "Choice 5",
"Choice 6", "Choice 7", "Choice 8", "Choice 9", "Choice 10",
"Choice 11", "Choice 12", "Choice 13", "Choice 14", "Choice 15",
"Choice 16", "Choice 17", "Choice 18", "Choice 19", "Choice 20",
"Exit",
(char *)NULL,
};
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);
init_pair(2, COLOR_CYAN, 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);
/* 设置菜单选项,不显示描述 */
menu_opts_off(my_menu, O_SHOWDESC);
/* 创建与菜单相关联的窗口 */
my_menu_win = newwin(10, 70, 4, 4);
keypad(my_menu_win, TRUE);
/* 设置主窗口和子窗口 */
set_menu_win(my_menu, my_menu_win);
set_menu_sub(my_menu, derwin(my_menu_win, 6, 68, 3, 1));
set_menu_format(my_menu, 5, 3);
set_menu_mark(my_menu, " * ");
/* 在主窗口的边界打印边框线和标题 */
box(my_menu_win, 0, 0);
attron(COLOR_PAIR(2));
mvprintw(LINES - 3, 0, "Use PageUp and PageDown to scroll");
mvprintw(LINES - 2, 0, "Use Arrow Keys to navigate (F1 to Exit)");
attroff(COLOR_PAIR(2));
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;
case KEY_LEFT:
menu_driver(my_menu, REQ_LEFT_ITEM);
break;
case KEY_RIGHT:
menu_driver(my_menu, REQ_RIGHT_ITEM);
break;
case KEY_NPAGE:
menu_driver(my_menu, REQ_SCR_DPAGE);
break;
case KEY_PPAGE:
menu_driver(my_menu, REQ_SCR_UPAGE);
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();
}
</pre>
</font>
<p>
<dd>
我们仔细看一下函数set_menu_format()的调用。它指定行数为3,因此每行就显示3个菜单项。我们已经用函数menu_opts_off()关闭了描述显示。其他几个函数:set_menu_opts(),menu_opts_on()和menu_opts()也可以用来控制菜单选项。下面的菜单选项可以用来指定:
</dd>
</p>
<pre>
O_ONEVALUE
在菜单中只能选一个菜单项。
O_SHOWDESC
当菜单被传递时显示对菜单项的描述。
O_ROWMAJOR
以行为主序显示菜单。
O_IGNORECASE
在样式匹配时忽略大小写。
O_SHOWMATCH
样式匹配时光标移到菜单项上。
O_NONCYCLIC
上移或下移一个菜单项时,不能跳到菜单另一端的菜单项上去。
</pre>
<p>
<dd>
默认情况下,这些选项都是打开的。你可以通过函数menu_opts_on()和menu_opts_off()用来开关某个属性。你也可以使用函数set_menu_opts()直接指定这些选项。这个函数的参数应该是上面那些常量的或(OR)值。函数menu_opts()可以用来查看当前菜单的选项。
</dd>
</p>
<br>
<br>
<h3 align="left">
<a name="mulchoice">
17.7 多选菜单
</a>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -