ncurses視窗機制:newwin(),wprintw(),delwin(),box(),wborder(),
- Copyright(C)
NCURSES Programming HOWTO
視窗機制
視窗(Window
)機制是整個curses 系統的核心。通過前面的例子我們看到了基於“標準視窗”(stdscr)
的一些操作函式。即使設計一個最簡單的圖形使用者介面( GUI
),都需要用到視窗。你可能需要將螢幕分成幾個部分並分別處理,然而,將螢幕拆分成各個視窗,然後獨立處理每個視窗是比較高效的方法。使用視窗的另外一個重要原因是:你應當始終在你的程式中追求一種更好的、更易於管理的設計方式。如果你要設計一個大型的、複雜的使用者介面,事先設計好各個部分將會提高你的程式設計效率。
基本概念
一個視窗是通過呼叫newwin()
函式建立的。但當你呼叫這個函式後螢幕上並不會有任何變化。因為這個函式的實際作用是給用來操作視窗的結構體分配記憶體,這個結構體包含了視窗的大小、起始座標等資訊。可見,在curses 裡,視窗是一個假想的概念,用來獨立處理螢幕上的各個部分。newwin()
函式返回一個指向視窗結構的指標,像wprintw()
等函式都需要以視窗指標作為引數。delwin()
函式可以刪除一個視窗,並釋放用來儲存視窗結構的記憶體和資訊。
顯示視窗
可惜的是,當我們建立了一個視窗之後卻無法看見它,所以我們現在要做的就是讓視窗顯示出來。box()
函式可以在已定義的視窗外圍畫上邊框。現在讓我們看看下面程式中的函式:
例:帶邊框的視窗:
/*
Compile: gcc main.c -lncurses
*/
#include <ncurses.h>
WINDOW *create_newwin(int height, int width, int starty, int startx);
void destroy_win(WINDOW *local_win);
int main(int argc, char *argv[])
{
WINDOW *my_win;
int startx, starty, width, height;
int ch;
initscr(); /* 初始化並進入curses 模式*/
cbreak(); /* 行緩衝禁止,傳遞所有控制資訊*/
keypad(stdscr, TRUE); /* 程式需要使用F1 功能鍵*/
height = 3;
width = 10;
starty = (LINES-height)/ 2; /*計算視窗中心位置的行數*/
startx = (COLS-width)/ 2; /*計算視窗中心位置的列數*/
printw("Press F1 to exit");
refresh();
my_win = create_newwin(height, width, starty, startx);
while((ch = getch()) != KEY_F(1))
{
switch(ch)
{
case KEY_LEFT:
destroy_win(my_win);
my_win = create_newwin(height, width, starty,--startx);
break;
case KEY_RIGHT:
destroy_win(my_win);
my_win = create_newwin(height, width, starty,++startx);
break;
case KEY_UP:
destroy_win(my_win);
my_win = create_newwin(height, width, --starty,startx);
break;
case KEY_DOWN:
destroy_win(my_win);
my_win = create_newwin(height, width, ++starty,startx);
break;
}
}
endwin(); /*結束curses 模式*/
return 0;
}
WINDOW *create_newwin(int height, int width, int starty, int startx)
{
WINDOW *local_win;
local_win = newwin(height, width, starty, startx);
box(local_win, 0 , 0); /* 0, 0 是字元預設的行列起始位置*/
wrefresh(local_win); /*重新整理視窗緩衝,顯示box */
return local_win;
}
void destroy_win(WINDOW *local_win)
{
/* box(local_win, ' ', ' ');不會按照預期的那樣清除視窗邊框。
而是在視窗的四個角落留下殘餘字元*/
wborder(local_win, '1', '2', '3','4','5','6','7','8');
/*引數註解9.3:
* 1. win:當前操作的視窗
* 2. ls:用於顯示視窗左邊界的字元
* 3. rs:用於顯示視窗右邊界的字元
* 4. ts:用於顯示視窗上邊界的字元
* 5. bs:用於顯示視窗下邊界的字元
* 6. tl:用於顯示視窗左上角的字元
* 7. tr:用於顯示視窗右上角的字元
* 8. bl:用於顯示視窗左下角的字元
* 9. br:用於顯示視窗右下角的字元
*/
wrefresh(local_win);
delwin(local_win);
}
/**
結果:
┌────────┐66666666666666666666666666666
│ │22222222222222222222222222222
└────────┘88888888888888888888888888888
7444444448
53333333366666666666666 7444444448
53333333362222222222222 7444444448
53333333368888888888888 7444444448
5333333336 7444444448 7444444448
5333333336 7444444448 7444444448
5333333336 7444444448 7444444448
5333333336 7444444448 7444444448
5333333336 7444444448 7444444448
5333333336 7444444448 7444444448
5333333336 7444444448 7444444448
5333333336 7444444448
5333333336 7444444448
5333333336 7444444448
555555555555555555555555555557444444448
111111111111111111111111111117444444448
777777777777777777777777777777444444448
*/
程式解析
別害怕,這的確是一個很大的程式,但它確實講解了一些很重要的東西:它建立了一個視窗,並且可以使用方向鍵來移動它。當使用者按下方向健的時候,它會刪除現有的視窗並在下一個位置建立新視窗,這樣就實現了視窗移動的效果。注意:移動視窗時不能超過視窗行列的限制。下面就讓我們逐行的分析這個程式:
creat_newwin()
函式使用newwin()
函式建立了一個視窗,並且使用box()
函式給視窗新增了邊框。destory_win()
函式首先使用空白字元填充視窗,從而起到清除螢幕的作用。之後呼叫delwin()
函式回收分配給視窗的記憶體。隨著使用者按下方向鍵, startx
和starty
的值就會不斷改變並以新座標為起點建立一個新視窗。 在destory_win()
中,我們使用了wborder
來替代box
。這樣做的原因已經寫到程式註釋裡了(我知道你剛才忽略了,現在趕緊去看看!)。wborder()
函式可以用字元來繪製視窗的邊框。這些邊框是由四條線和四個角組成的。為了理解得更明白一些,你可以試著這樣呼叫wborder()
函式:
wborder(win, '|', '|', '-','-','+', '+', '+', '+');
他所繪製的視窗會是以下這樣子:
+--------------+
| |
| |
| |
| |
| |
| |
+--------------+
更多的說明
從上面的例子中還可以看到,函式使用了COLS
和LINES
作為變數名。在initscr()
函式初始化螢幕以後,這兩個變數分別儲存螢幕初始化後的行數和列數。這樣做是為了方便標記視窗尺寸和計算出螢幕的中心位置座標。getch()
函式依然用來處理使用者的鍵盤輸入。同時,根據使用者的輸入做出程式中定義的操作。這種做法在互動式的圖形介面應用程式中非常普遍。
其它的邊框函式
上面這個例子所使用的方式是通過按下鍵盤上相應的按鈕撤消一個視窗並建立一個新的視窗,但是這樣的工作方式效率太低。現在讓我們來寫一些可以使視窗邊框的使用更加有效率的程式。 下面這個程式使用mvhline()
和mvvline()
函式完成同樣的效果。這兩個函式非常簡單,它們將在指定的位置繪製出指定大小的視窗。
/*
Compile: gcc main.c -lncurses
*/
#include <ncurses.h>
//#define _DEBUG
typedef struct _win_border_struct{
chtype ls, rs, ts, bs,
tl, tr, bl, br;
}WIN_BORDER;
typedef struct _WIN_struct {
int startx, starty;
int height, width;
WIN_BORDER border;
}WIN;
void init_win_params(WIN *p_win);
void print_win_params(WIN*p_win);
void create_box(WIN *win, int boolean);
int main(int argc, char *argv[])
{
WIN win;
int ch;
initscr(); /* 初始化並進入curses 模式*/
start_color(); /* 開啟彩色顯示功能*/
cbreak(); /* 行緩衝禁止,傳遞所有控制資訊*/
keypad(stdscr, TRUE); /* 程式需要使用F1 功能鍵*/
noecho();
init_pair(1, COLOR_CYAN, COLOR_BLACK);
/* 以下程式碼初始化視窗的引數*/
init_win_params(&win);
print_win_params(&win);
attron(COLOR_PAIR(1));
printw("Press F1 to exit");
refresh();
attroff(COLOR_PAIR(1));
create_box(&win, TRUE);
while((ch = getch()) != KEY_F(1))
{
switch(ch)
{
case KEY_LEFT:
create_box(&win, FALSE);
--win.startx;
create_box(&win, TRUE);
break;
case KEY_RIGHT:
create_box(&win, FALSE);
++win.startx;
create_box(&win, TRUE);
break;
case KEY_UP:
create_box(&win, FALSE);
--win.starty;
create_box(&win, TRUE);
break;
case KEY_DOWN:
create_box(&win, FALSE);
++win.starty;
create_box(&win, TRUE);
break;
}
}
endwin(); /* 結束curses 模式*/
return 0;
}
void init_win_params(WIN *p_win)
{
p_win->height = 3;
p_win->width = 10;
p_win->starty = (LINES-p_win->height)/2;
p_win->startx = (COLS-p_win->width)/2;
p_win->border.ls = '|';
p_win->border.rs = '|';
p_win->border.ts = '-';
p_win->border.bs = '-';
p_win->border.tl = '+';
p_win->border.tr = '+';
p_win->border.bl = '+';
p_win->border.br= '+';
}
void print_win_params(WIN*p_win)
{
#ifdef _DEBUG
mvprintw(25, 0, "%d %d %d %d", p_win->startx, p_win->starty,
p_win->width, p_win->height);
refresh();
#endif
}
void create_box(WIN *p_win, int boolean)
{
int i, j;
int x, y, w, h;
x = p_win->startx;
y = p_win->starty;
w = p_win->width;
h = p_win->height;
if(boolean == TRUE)
{
mvaddch(y, x, p_win->border.tl);
mvaddch(y, x + w, p_win->border.tr);
mvaddch(y + h, x, p_win->border.bl);
mvaddch(y + h, x + w, p_win->border.br);
mvhline(y, x + 1, p_win->border.ts, w-1);
mvhline(y + h, x + 1, p_win->border.bs, w-1);
mvvline(y + 1, x, p_win->border.ls, h-1);
mvvline(y + 1, x + w, p_win->border.rs,h-1);
}
else
for(j = y; j <= y + h; ++j)
for(i = x; i <= x + w; ++i)
mvaddch(j, i, ' ');
refresh();
}
/**
結果:
+---------+
| |
| |
+---------+
*/
相關文章
- ncurses視窗機制:wprintw(), wrefresh()
- Flink的視窗處理機制(一)
- android的視窗機制分析------ViewRoot類AndroidView
- 彈出視窗messagebox
- android的視窗機制分析------事件處理Android事件
- 【emWin】例程十九:視窗物件——Checkbox物件
- android的視窗機制分析------UI管理系統AndroidUI
- 【emWin】例程二十六:視窗物件——Listbox物件
- FreeTextBox實現機制
- 【emWin】例程二十九:視窗物件——Messagebox物件
- Android10_原理機制系列_Activity視窗新增到WMS過程Android
- win10怎麼修改引數遊戲強制視窗_win10如何強制把遊戲視窗縮小Win10遊戲
- 理解SVG座標系和變換:視窗,viewBox和preserveAspectRatioSVGView
- JavaScript - 模式視窗和非模式視窗JavaScript模式
- ncurses庫移植
- 編譯 ncurses編譯
- TCP協議三次握手、四次揮手以及TCP視窗滑動機制TCP協議
- 什麼是 Angular 的 banana-in-a-box detection 機制AngularNaN
- Go Qt5 建立空白視窗、視窗居中及關閉視窗事件GoQT事件
- 討論關閉子視窗,重新整理父視窗(非模式視窗)模式
- Windows API視窗程式設計 - 空白視窗WindowsAPI程式設計
- 視窗事件事件
- WPF 自定義MessageBox 彈窗提示 彈窗載入
- Qt 視窗強制禁用系統陰影(自定義選單)QT
- jQuery在子視窗如何操作父視窗元素jQuery
- JS彈出視窗視窗的位置和大小JS
- Chromium 新的彈窗機制以及 HTML 的 <dialog> 元素HTML
- Chrome OS 有了全新的視窗管理機制,向現代化的圖形作業系統Chrome作業系統
- Android應用視窗突破手機侷限性Android
- js如何在子視窗中關閉父視窗JS
- 工作列視窗以及其子視窗結構 (轉)
- JavaScript視窗功能指南之操縱視窗 (轉)JavaScript
- 廣告彈窗/小視窗程式碼
- Qt視窗居中QT
- 視窗函式函式
- 視窗程式框架框架
- 彈出視窗
- QT視窗類QT