ncurses皮膚庫:new_panel(),doupdate(),show_panel(),hide_panel(),move_panel(),del_panel()...

Koma_Wong發表於2018-06-22
  • Copyright(C) NCURSES Programming HOWTO

皮膚庫

在精通curses 庫後,你可能會想嘗試著做一些更大的專案。為了讓介面看起來更專業,你可能會建立許多重疊的視窗,但不幸的是,你很快會發現它們變得難以管理,多次的更新視窗使開發變得異常困難。如果你沒有按照適當的順序重新整理那些視窗的話,它們就會給你帶來很多麻煩。

不過別失望,皮膚庫(Panel Library)提供了一個很好的解決方案。用ncureses 的開發者的話來說就是:

如果你的介面設計需要使視窗在執行時置底或者置頂,雖然會為此付出很大代價,但是想要顯示正確的結果仍然很困難。這時候Panels 庫就可以派上用場了。 如果你要處理重疊的視窗,panels 庫就派上用場了。它使程式設計師避免使用大量的wnoutrefresh()doupdate()函式來處理這個問題,並且減輕了由底向上正確處理這些資訊的負擔。這個庫維持著視窗重疊關係以及視窗順序,並在適當的時候更新它們。

那麼還等什麼呢?讓我們開始吧!

基礎知識

皮膚物件實際上是一個視窗,和其它視窗一樣被隱含地處理為容器的一部分。這個容器實際上是一個,棧頂的皮膚是完全可見的。而其它皮膚在棧中所處的位置,決定了它們是否可見。其基本思想是:建立一個棧來儲存那些重疊的皮膚,然後使用皮膚庫來正確的顯示它們。 例如呼叫一個類似於refresh()函式就按正確的順序來顯示這些皮膚。皮膚庫提供了一系列隱藏、顯示、移動、改變大小等皮膚操作的函式,使操作重疊的視窗變得更加簡單。 通常,一個皮膚程式的設計流程如下:

  • 使用newwin()函式建立一個視窗,它將新增到皮膚裡。
  • 建立皮膚(利用所建立的視窗)並將皮膚依據使用者指定的可見順序壓進棧。呼叫new_panel()函式即可建立該皮膚。
  • 呼叫update_panels()函式就可將皮膚按正確的順序寫入虛擬螢幕,呼叫doupdate()函式就能讓皮膚顯示出來。
  • show_panel()hide_panel()move_panel()等函式分別用來對皮膚進行顯示、隱藏、移動等操作時,可以使用panel_hidden()panel_window()這兩個輔助函式。你也可以使用使用者指標來儲存皮膚的資料,set_panel_userptr()panel_userptr()函式分別用來設定和取得一個皮膚的使用者指標。
  • 當一個皮膚使用完畢後,用del_panel()函式就可刪除指定的皮膚。

現在讓我們通過一些程式來加深對這些概念的理解。下面將要看到的程式建立了3 個重疊的皮膚並把它們按次序顯示在螢幕上。

編譯包含皮膚庫的程式

要使用皮膚庫裡的函式,你首先要把panel.h 這個標頭檔案包含到你的程式碼中,同時編譯並連線與皮膚庫相關的程式必須新增-lpanel–lncurses 兩個引數。

#include <panel.h>

編譯和連線: gcc <program file> -lpanel –lncurses

例.一個有關皮膚庫的基礎例子

/*
Compile: gcc main.c -lncurses -lpanel
*/
#include <ncurses.h>
#include <panel.h>

int main()
{
    WINDOW *my_wins[3];
    PANEL *my_panels[3];
    int lines = 10, cols = 40, y = 2, x = 4, i;
    
    initscr();
    cbreak();
    noecho();
    
    /* 為每個皮膚建立視窗*/
    my_wins[0] = newwin(lines, cols, y, x);
    my_wins[1] = newwin(lines, cols, y + 1, x + 5);
    my_wins[2] = newwin(lines, cols, y + 2, x + 10);
    
    /* 為視窗新增建立邊框以便你能看到皮膚的效果*/
    for(i = 0; i < 3; ++i)
        box(my_wins[i], 0, 0);
    /* 按自底向上的順序,為每一個皮膚關聯一個視窗*/
    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*/
    /* 更新棧的順序。把皮膚2 置於棧頂*/
    update_panels();
    /* 在螢幕上顯示*/
    doupdate();
    getch();
    endwin();
}
/**
結果:
    ┌──────────────────────────────────────┐
    │    ┌──────────────────────────────────────┐
    │    │    ┌──────────────────────────────────────┐
    │    │    │                                      │
    │    │    │                                      │
    │    │    │                                      │
    │    │    │                                      │
    │    │    │                                      │
    │    │    │                                      │
    └────│    │                                      │
         └────│                                      │
              └──────────────────────────────────────┘
*/

如你所見,這個程式就是按照16.1 所介紹的流程進行的。用newwin()函式來建立視窗,然後通過new_panel()函式把視窗新增到panels 棧裡面,當那些皮膚一個一個壓進棧的時候,棧就隨之更新了。最後呼叫update_panels()函式和doupdate()函式就可以讓它們在螢幕上顯示出來。

皮膚瀏覽

下面給出一個較複雜的例子。它建立了3 個視窗,通過<TAB> 鍵可以使它們迴圈置頂顯示。讓我們來看一下程式碼:

例 一個皮膚視窗瀏覽的例子

/*
Compile: gcc main.c -lncurses -lpanel
*/
#include <ncurses.h>
#include <panel.h>
#include <string.h>

#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 *top;
    int ch;
    
    /*初始化curses */
    initscr();
    start_color();
    cbreak();
    noecho();
    keypad(stdscr, TRUE);
    
    /* 初始化所有的顏色*/
    init_pair(1, COLOR_RED, COLOR_WHITE);
    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);
    
    /* 按自底向上的順序,把每個視窗新增進一個皮膚*/
    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_panel_userptr(my_panels[0],my_panels[1]);
    set_panel_userptr(my_panels[1],my_panels[2]);
    set_panel_userptr(my_panels[2],my_panels[0]);
    /* 更新皮膚棧的順序。把皮膚2 置於棧頂*/
    update_panels();
    /* 在螢幕上顯示*/
    attron(COLOR_PAIR(4));
    mvprintw(LINES-2, 0, "Use tab to browse through the windows (F1 to Exit)");
    attroff(COLOR_PAIR(4));
    doupdate();
    top = my_panels[2];
    while((ch = getch()) != KEY_F(1))
    { 
        switch(ch)
        { 
            case 9:
                top = (PANEL *)panel_userptr(top);
                top_panel(top);
                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();
}
/**
結果:
          ┌──────────────────────────────────────┐
          │           Window Number 1            │
          ├──────────────────────────────────────┤
          │      ┌──────────────────────────────────────┐
          │      │           Window Number 2            │
          │      ├──────────────────────────────────────┤
          │      │      ┌──────────────────────────────────────┐
          │      │      │           Window Number 3            │
          │      │      ├──────────────────────────────────────┤
          └──────│      │                                      │
                 │      │                                      │
                 │      │                                      │
                 └──────│                                      │
                        │                                      │
                        │                                      │
                        └──────────────────────────────────────┘
Use tab to browse through the windows (F1 to Exit)

*/

使用使用者指標

在上面例子中,使用使用者指標在迴圈裡查詢下一個要顯示的皮膚。我們可以通過指定一個使用者指標給皮膚新增自定義資訊,這個指標可以指向你想要儲存的任何資訊。在這個例子中,我們用指標儲存了迴圈中下一個要顯示的皮膚。其中,使用者指標可以用set_panel_userptr()函式設定。要想訪問某個皮膚的使用者指標,就必須以該皮膚作為panel_userprt()函式的引數,函式就會返回該皮膚的使用者指標。結束皮膚的查詢後, top_panel()函式就會將其置於皮膚棧的頂層。要想將任意一個皮膚置於皮膚棧的頂層,只需將該皮膚作為top_panel()函式的引數。

移動皮膚和改變皮膚的大小

move_panel()函式可將皮膚移動到螢幕上指定的位置,而不是改變皮膚在棧中的位置。確保在移動皮膚視窗時使用move_panel()函式,而不是mvwin()函式。改變皮膚大小有點兒複雜,因為沒有一個函式可以直接改變皮膚所關聯視窗的大小。一個可替代的解決方案是按照所需的大小建立一個新視窗,再呼叫replace_panel()函式來替換相應皮膚上的關聯視窗。別忘了替換後刪除原視窗,使用panel_window() 函式可以找到與該皮膚關聯的視窗。 下面這個程式就體現了這種思想。你可以像先前那樣,用<Tab>鍵迴圈檢視視窗。如果要改變當前皮膚大小或移動當前皮膚的位置,就要分別按下‘r’‘m’鍵,然後使用方向鍵來調節,最後以<Enter>鍵確定大小或者位置.。這個例子利用使用者資料儲存程式執行的必要資料。

例、一個移動和改變皮膚大小的例子

/*
Compile: gcc main.c -lncurses -lpanel
*/
#include <ncurses.h>
#include <panel.h>
#include <string.h>
#include <stdlib.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 壓入棧,順序: 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;
    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"\
                                    "resizeand 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();
}

結果測試

原始:
          ┌──────────────────────────────────────┐
          │           Window Number 1            │
          ├──────────────────────────────────────┤
          │      ┌──────────────────────────────────────┐
          │      │           Window Number 2            │
          │      ├──────────────────────────────────────┤
          │      │      ┌──────────────────────────────────────┐
          │      │      │           Window Number 3            │
          │      │      ├──────────────────────────────────────┤
          └──────│      │                                      │
                 │      │                                      │
                 │      │                                      │
                 └──────│                                      │
                        │                                      │
                        │                                      │
                        └──────────────────────────────────────┘
Use 'm' for moving, 'r' for resizing
Use tab to browse through the windows (F1 to Exit)

Tab鍵功能:
          ┌──────────────────────────────────────┐
          │           Window Number 1            │
          ├──────────────────────────────────────┤
          │                                      │──────┐
          │                                      │      │
          │                                      │──────┤
          │                                      │─────────────┐
          │                                      │3            │
          │                                      │─────────────┤
          └──────────────────────────────────────┘             │
                 │      │                                      │
                 │      │                                      │
                 └──────│                                      │
                        │                                      │
                        │                                      │
                        └──────────────────────────────────────┘
                        
調整大小:
          ┌──────────────────────────────────────┐──────┐
          │           Window Number 1            │      │
          ├──────────────────────────────────────┤──────┤
          │                                      │─────────────┐
          │                                      │3            │
          │                                      │─────────────┤
          └──────────────────────────────────────┘             │
                 │      │                                      │
                 │      │                                      │
                 └──────│                                      │
                        │                                      │
                        │                                      │
                        └──────────────────────────────────────┘

調整位置:
          ┌──────────────────────────────────────┐
          │           Window Number 1            │
          ├──────────────────────────────────────┤
          │   ┌──────────────────────────────────────┐─────────┐
          │   │           Window Number 2            │         │
          │   ├──────────────────────────────────────┤─────────┤
          └───│                                      │         │
              │                                      │         │
              │                                      │         │
              │                                      │         │
              │                                      │         │
              │                                      │         │
              └──────────────────────────────────────┘─────────┘

讓我們把注意力集中在主while 迴圈體上。一旦該迴圈發現某個鍵被按下,程式就會執行該鍵相應的處理。 當按下‘r’鍵時,程式就會執行“更改大小”操作,同時你就可以通過方向鍵更改皮膚的大小,然後按<Enter>鍵確定大小。在“更改大小”模式下,程式不會顯示視窗是怎樣更改大小的。請讀者思考一下如何用“點”來列印更改大小後視窗的邊框。 當按下‘m’鍵時,程式就會執行“移動皮膚”操作。這個操作比“更改大小”簡單一點。按下方向鍵的同時,皮膚的位置隨之改變,當按下<Enter>鍵時,程式就會呼叫move_panel()函式把皮膚固定到當前游標的位置。 在這個程式中, PANEL_DATA 就是所謂的使用者資料,它在查詢皮膚的相關資訊時扮演重要角色,正如說明中所說的那樣,PANEL_DATA儲存了皮膚的尺寸,標題,標題顏色以及指向下一個皮膚的指標。

隱藏和顯示皮膚

使用hide_panel()函式可以隱藏皮膚,它僅僅是把皮膚從皮膚棧中移走,不會破壞被隱藏皮膚所關聯的結構。而要在螢幕上隱藏皮膚需要呼叫update_panels()函式和doupdate()函式。此外,show_panel()函式可以讓顯示已隱藏皮膚。 以下程式展示了皮膚的隱藏。按下’a’ 或’b’ 或‘c’ 鍵分別顯示或隱藏第一、二、三個視窗。使用了使用者資料中一個叫做hide 的變數來跟蹤視窗,標記出該視窗是否被隱藏。由於某些原因,panel_hidden()函式(它用來告訴使用者一個皮膚是否隱藏)不能夠正常工作。MichaelAndres 在這裡提供了一個錯誤報告。

例、一個隱藏和顯示皮膚的例子

/*
Compile: gcc main.c -lncurses -lpanel
*/
#include <ncurses.h>
#include <panel.h>
#include <string.h>
#include <stdlib.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]);
    /* 把皮膚0 壓入棧,順序: stdscr0*/
    my_panels[1] = new_panel(my_wins[1]);
    /* 把皮膚1 壓入棧。順序: stdscr01*/
    my_panels[2] = new_panel(my_wins[2]);
    /* 把皮膚2 壓入棧,順序: stdscr012*/
    
    /* 初始化所有的皮膚並都設為非隱藏的*/
    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'(ThirdWindow)");
    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();
}

測試結果

原始:
          ┌──────────────────────────────────────┐
          │           Window Number 1            │
          ├──────────────────────────────────────┤
          │      ┌──────────────────────────────────────┐
          │      │           Window Number 2            │
          │      ├──────────────────────────────────────┤
          │      │      ┌──────────────────────────────────────┐
          │      │      │           Window Number 3            │
          │      │      ├──────────────────────────────────────┤
          └──────│      │                                      │
                 │      │                                      │
                 │      │                                      │
                 └──────│                                      │
                        │                                      │
                        │                                      │
                        └──────────────────────────────────────┘
Show or Hide a window with 'a'(first window)'b'(Second Window)'c'(ThirdWindow)
F1 to Exit

隱藏window1,press“a”
                 ┌──────────────────────────────────────┐
                 │           Window Number 2            │
                 ├──────────────────────────────────────┤
                 │      ┌──────────────────────────────────────┐
                 │      │           Window Number 3            │
                 │      ├──────────────────────────────────────┤
                 │      │                                      │
                 │      │                                      │
                 │      │                                      │
                 └──────│                                      │
                        │                                      │
                        │                                      │
                        └──────────────────────────────────────┘
同理,隱藏window2和window3按“b”,“c”
          ┌──────────────────────────────────────┐
          │           Window Number 1            │
          ├──────────────────────────────────────┤
          │                                      │
          │                                      │
          │                                      │
          │                                      │─────────────┐
          │                                      │3            │
          │                                      │─────────────┤
          └──────────────────────────────────────┘             │
                        │                                      │
                        │                                      │
                        │                                      │
                        │                                      │
                        │                                      │
                        └──────────────────────────────────────┘
          ┌──────────────────────────────────────┐
          │           Window Number 1            │
          ├──────────────────────────────────────┤
          │      ┌──────────────────────────────────────┐
          │      │           Window Number 2            │
          │      ├──────────────────────────────────────┤
          │      │                                      │
          │      │                                      │
          │      │                                      │
          └──────│                                      │
                 │                                      │
                 │                                      │
                 └──────────────────────────────────────┘

panel_above()panel_below()類函式

panel_above()panel_below()函式可以分別用來檢視某個皮膚的上層和下層皮膚。如果引數為NULL,它們就分別返回皮膚棧中最上層和最下層皮膚的指標。

相關文章