第十六章:面板库(下)——(NCURSES Programming HOWTO中文版)

类别:编程语言 点击:0 评论:0 推荐:
第十六章:面板库(下)16.5 移动面板和改变面板的大小  

函数move_panel()可以将面板移动到你想移动的地方。它不改变面板在栈里的位置。务必使用move_panel()而不是用来移动窗口的函数mvwin() 来移动面板。

改变面板的大小有一点点复杂,没有哪个函数可以用来直接改变和面板关联的窗口的大小。要改变面板的大小,只有创建一个大小为你所需的新窗口。用函数replace_panel()可以替换和相应面板关联的窗口。但是别忘了要删除旧的窗口。和面板关联的窗口可以使用函数panel_window()来创建。

下面这个程序就用简单的方式体现了这个概念。同样,你可以用<TAB>键来使它们循环。要改变大小或移动当前的面板你可以按下 ' r' 或 ' m '键。然后使用方向键来改变大小和移动。在具体操作时,为获得需要的结果这个例子利用了用户已有的数据。

例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);

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压入栈,顺序: stdscr-0 */
 my_panels[1] = new_panel(my_wins[1]);  /* 把面板1压入栈。顺序: stdscr-0-1 */
 my_panels[2] = new_panel(my_wins[2]);  /* 把面板2压入栈,顺序: stdscr-0-1-2 */

 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;
 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;
    }
    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();
 }
 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]);
 }
}
/* 用一个边框和标题栏来显示窗口 */
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();
}

我们把注意力集中在主循环上。一旦程序捕获某个键被按下,它就执行相应的动作。如果按下了'r'键,"更改大小"模式就启动了。用户可以通过按方向键来更改面板的大小。当用户按<ENTER>键时,就确定了面板的新尺寸,程序就依照上面介绍的方法更改大小。不过在"更改大小"模式中,程序并没有真正显示出面板更改大小后的边框。这就留给读者一个作业:用点来显示新尺寸面板的边框。
当用户按'm'键时"移动面板"模式就启动了。这个操作会比"更改大小"简单一点。随着方向键的按下,新面板的位置也随之移动,当<ENTER>键按下时,程序就调用panel()函数把面板移动到光标的当前位置
在这个示范程序中,用户数据就代表PANEL_DATA,在查找面板的相关信息时扮演重要角色。就象在说明中所写,PANEL_DATA保存了面板的尺寸,标题,标题颜色和循环中指向下一个面板的指针。

16.6 隐藏和显示面板

隐藏一个面板可以使用函数hide_panel()。这个函数仅仅是把它从面板栈中移走,因此,要在屏幕上隐藏的话只要调用函数update_panels() 和 doupdate()就可以了。它不会破坏面板结构和这个隐藏的面板。函数show_panel()可以让它重新显示。

下面的程序显示了如何隐藏面板。按键 'a' 或 'b' 或 'c'来分别实现显示或隐藏第一,二,三个窗口,其它的依此类推。它使用了一个用户给定的一个带有隐藏的变量的数据,用来跟踪窗口是否是隐藏的。因为某些原因,按理用来告诉用户一个面板是否隐藏的函数panel_hidden没有起作用。Michael Andres 在这里提供了一个错误报告。

例17、 一个隐藏和显示面板的例子
#include <panel.h>

typedef struct _PANEL_DATA {
 int hide; /* 如果面板是隐藏的时候为真  */
}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);

int main()
{ WINDOW *my_wins[3];
 PANEL  *my_panels[3];
 PANEL_DATA panel_datas[3];
 PANEL_DATA *temp;
 int ch;

 /* 初始化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]);  /* Push 0, order: stdscr-0 */
 my_panels[1] = new_panel(my_wins[1]);  /* Push 1, order: stdscr-0-1 */
 my_panels[2] = new_panel(my_wins[2]);  /* Push 2, order: stdscr-0-1-2 */

 /* 初始化所有的面板并都设为非隐藏的 */
 panel_datas[0].hide = FALSE;
 panel_datas[1].hide = FALSE;
 panel_datas[2].hide = FALSE;

 set_panel_userptr(my_panels[0], &panel_datas[0]);
 set_panel_userptr(my_panels[1], &panel_datas[1]);
 set_panel_userptr(my_panels[2], &panel_datas[2]);

 /* 更新面板栈的顺序,第二个面板将置于栈顶 */
 update_panels();

 /* 在屏幕上显示 */
 attron(COLOR_PAIR(4));
 mvprintw(LINES - 3, 0, "Show or Hide a window with 'a'(first window)  'b'(Second Window)  'c'(Third Window)");
 mvprintw(LINES - 2, 0, "F1 to Exit");

 attroff(COLOR_PAIR(4));
 doupdate();
 
 while((ch = getch()) != KEY_F(1))
 { switch(ch)
  { case 'a':   
    temp = (PANEL_DATA *)panel_userptr(my_panels[0]);
    if(temp->hide == FALSE)
    { hide_panel(my_panels[0]);
     temp->hide = TRUE;
    }
    else
    { show_panel(my_panels[0]);
     temp->hide = FALSE;
    }
    break;
   case 'b':
    temp = (PANEL_DATA *)panel_userptr(my_panels[1]);
    if(temp->hide == FALSE)
    { hide_panel(my_panels[1]);
     temp->hide = TRUE;
    }
    else
    { show_panel(my_panels[1]);
     temp->hide = FALSE;
    }
    break;
   case 'c':
    temp = (PANEL_DATA *)panel_userptr(my_panels[2]);
    if(temp->hide == FALSE)
    { hide_panel(my_panels[2]);
     temp->hide = TRUE;
    }
    else
    { show_panel(my_panels[2]);
     temp->hide = FALSE;
    }
    break;
  }
  update_panels();
  doupdate();
 }
 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;
 }
}

/* 通过边框和标题显示窗口 */
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();
}

16.7、 panel_above()和panel_below()类函数

函数panel_above() 和 panel_below() 可以用来查看某一个面板的上面和下面的面板。如果函数的参变量为NULL,它们就分别返回一个指向最底层和最上层面板的指针。

本文地址:http://com.8s8s.com/it/it21700.htm