Ncurses学习经历(十一)面板库——用户指针

1. 使用用户指针
    在上面例子中,使用用户指针在循环里查找下一个要显示的面板。我们可以通过指定一个用
户指针给面板添加自定义信息,这个指针可以指向你想要存储的任何信息。在这个例子中,
我们用指针存储了循环中下一个要显示的面板。其中,用户指针可以用set_panel_userptr()
函数设定。要想访问某个面板的用户指针,就必须以该面板作为panel_userprt()函数的参数,
函数就会返回该面板的用户指针。结束面板的查找后, top_panel()函数就会将其置于面板
栈的顶层。要想将任意一个面板置于面板栈的顶层,只需将该面板作为top_panel()函数的
参数。
2.移动面板和改变面板的大小
    move_panel()函数可将面板移动到屏幕上指定的位置,而不是改变面板在栈中的位置。
确保在移动面板窗口时使用move_panel()函数,而不是mvwin()函数。
改变面板大小有点儿复杂,因为没有一个函数可以直接改变面板所关联窗口的大小。一个可
替代的解决方案是按照所需的大小创建一个新窗口,再调用replace_panel()函数来替换相
应面板上的关联窗口。别忘了替换后删除原窗口,使用panel_window() 函数可以找到与该
面板关联的窗口。
    下面这个程序就体现了这种思想。你可以像先前那样,用<Tab>键循环查看窗口。如果要改
变当前面板大小或移动当前面板的位置,就要分别按下‘r’或‘m’键,然后使用方向键来调节,
最后以<Enter>键确定大小或者位置.。这个例子利用用户数据保存程序运行的必要数据。

例16、一个移动和改变面板大小的例子
#include <panel.h>
typedef struct _PANEL_DATA
{
int x, y, w, h;
char label[80];
int label_color;
PANEL *next;
}PANEL_DATA;
#define NLINES 10
#define NCOLS 40
void init_wins(WINDOW **wins, int n);
void win_show(WINDOW *win, char *label, int label_color);
void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype
color);
void set_user_ptrs(PANEL **panels, int n);
NCURSES Programming HOWTO 中文版(第二版)
54
int main()
{ WINDOW *my_wins[3];
PANEL *my_panels[3];
PANEL_DATA *top;
PANEL *stack_top;
WINDOW *temp_win, *old_win;
int ch;
int newx, newy, neww, newh;
int size = FALSE, move = FALSE;
/* 初始化curses */
initscr();
start_color();
cbreak();
noecho();
keypad(stdscr, TRUE);
/* 初始化所有的颜色*/
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_BLUE, COLOR_BLACK);
init_pair(4, COLOR_CYAN, COLOR_BLACK);
init_wins(my_wins, 3);
/* 更新面板栈的顺序。把面板2 置于栈顶*/
my_panels[0] = new_panel(my_wins[0]); /* 把面板0 压入栈,顺序: stdscr0
*/
my_panels[1] = new_panel(my_wins[1]); /* 把面板1 压入栈。顺序: stdscr01
*/
my_panels[2] = new_panel(my_wins[2]); /* 把面板2 压入栈,顺序: stdscr012
*/
set_user_ptrs(my_panels, 3);
/* 更新面板栈的顺序。把面板2 置于栈顶*/
update_panels();
/* 在屏幕上显示出来*/
attron(COLOR_PAIR(4));
mvprintw(LINES 3,
0, "Use 'm' for moving, 'r' for resizing");
mvprintw(LINES 2,
0, "Use tab to browse through the windows (F1 to Exit)");
attroff(COLOR_PAIR(4));
doupdate();
stack_top = my_panels[2];
top = (PANEL_DATA *)panel_userptr(stack_top);
newx = top>
x;
NCURSES Programming HOWTO 中文版(第二版)
55
newy = top>
y;
neww = top>
w;
newh = top>
h;
while((ch = getch()) != KEY_F(1))
{ switch(ch)
{ case 9: /* Tab 对应编号*/
top = (PANEL_DATA *)panel_userptr(stack_top);
top_panel(top>
next);
stack_top = top>
next;
top = (PANEL_DATA *)panel_userptr(stack_top);
newx = top>
x;
newy = top>
y;
neww = top>
w;
newh = top>
h;
break;
case 'r': /* 改变面板大小*/
size = TRUE;
attron(COLOR_PAIR(4));
mvprintw(LINES 4,
0, "Entered Resizing :Use Arrow Keys to resize
and press <ENTER> to end resizing");
refresh();
attroff(COLOR_PAIR(4));
break;
case 'm': /* 移动面板*/
attron(COLOR_PAIR(4));
mvprintw(LINES 4,
0, "Entered Moving: Use Arrow Keys to Move and
press <ENTER> to end moving");
refresh();
attroff(COLOR_PAIR(4));
move = TRUE;
break;
case KEY_LEFT:
if(size == TRUE)
{ newx;
++neww;
}
if(move == TRUE)
newx;
break;
case KEY_RIGHT:
if(size == TRUE)
{ ++newx;
neww;
}
NCURSES Programming HOWTO 中文版(第二版)
56
if(move == TRUE)
++newx;
break;
case KEY_UP:
if(size == TRUE)
{ newy;
++newh;
}
if(move == TRUE) newy;
break;
case KEY_DOWN:
if(size == TRUE)
{ ++newy;
newh;
}
if(move == TRUE)
++newy;
break;
case 10: /* Enter 对应编号*/
move(LINES 4,
0);
clrtoeol();
refresh();
if(size == TRUE)
{ old_win = panel_window(stack_top);
temp_win = newwin(newh, neww, newy, newx);
replace_panel(stack_top, temp_win);
win_show(temp_win, top>
label, top>
label_color);
delwin(old_win);
size = FALSE;
}
if(move == TRUE)
{ move_panel(stack_top, newy, newx);
move = FALSE;
}
break;
}
attron(COLOR_PAIR(4));
mvprintw(LINES 3,
0, "Use 'm' for moving, 'r' for resizing");
mvprintw(LINES 2,
0, "Use tab to browse through the windows (F1 to Exit)");
attroff(COLOR_PAIR(4));
refresh();
update_panels();
doupdate();
}
NCURSES Programming HOWTO 中文版(第二版)
57
endwin();
return 0;
}
/* 显示所有的窗口*/
void init_wins(WINDOW **wins, int n)
{ int x, y, i;
char label[80];
y = 2;
x = 10;
for(i = 0; i < n; ++i)
{ wins[i] = newwin(NLINES, NCOLS, y, x);
sprintf(label, "Window Number %d", i + 1);
win_show(wins[i], label, i + 1);
y += 3;
x += 7;
}
}
/* 把每个面板设置为PANEL_DATA 结构*/
void set_user_ptrs(PANEL **panels, int n)
{ PANEL_DATA *ptrs;
WINDOW *win;
int x, y, w, h, i;
char temp[80];
ptrs = (PANEL_DATA *)calloc(n, sizeof(PANEL_DATA));
for(i = 0;i < n; ++i)
{ win = panel_window(panels[i]);
getbegyx(win, y, x);
getmaxyx(win, h, w);
ptrs[i].x = x;
ptrs[i].y = y;
ptrs[i].w = w;
ptrs[i].h = h;
sprintf(temp, "Window Number %d", i + 1);
strcpy(ptrs[i].label, temp);
ptrs[i].label_color = i + 1;
if(i + 1 == n)
ptrs[i].next = panels[0];
else
ptrs[i].next = panels[i + 1];
set_panel_userptr(panels[i], &ptrs[i]);
}
}
NCURSES Programming HOWTO 中文版(第二版)
58
/* 用一个边框和标题栏来显示窗口*/
void win_show(WINDOW *win, char *label, int label_color)
{
int startx, starty, height, width;
getbegyx(win, starty, startx);
getmaxyx(win, height, width)
box(win, 0, 0);
mvwaddch(win, 2, 0, ACS_LTEE);
mvwhline(win, 2, 1, ACS_HLINE, width 2)
;
mvwaddch(win, 2, width 1,
ACS_RTEE);
print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color));
}
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();
}
    让我们把注意力集中在主while 循环体上。一旦该循环发现某个键被按下,程序就会执行该
键相应的处理。当按下‘r’键时,程序就会执行“更改大小”操作,同时你就可以通过方向键更
改面板的大小,然后按<Enter>键确定大小。在“更改大小”模式下,程序不会显示窗口是怎
样更改大小的。请读者思考一下如何用“点”来打印更改大小后窗口的边框。
当按下‘m’键时,程序就会执行“移动面板”操作。这个操作比“更改大小”简单一点。按下方向
键的同时,面板的位置随之改变,当按下<Enter>键时,程序就会调用move_panel()函数把
面板固定到当前光标的位置。在这个程序中, PANEL_DATA 就是所谓的用户数据,它在查
找面板的相关信息时扮演重要角色,正如说明中所说的那样,PANEL_DATA 保存了面板的
尺寸,标题,标题颜色以及指向下一个面板的指针。

猜你喜欢

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