Curses学习
1.1什么是curses
curses實際上是一個函數(shù)開發(fā)包,專門用來進(jìn)行UNIX下終端環(huán)境下的屏幕界面處理以及I/O處理。
通過這些函數(shù)庫,C和C++程序就可以控制終端的視頻顯示以及輸入輸出。
使用curses包中的函數(shù),用戶可以非常方便的創(chuàng)建和操作窗口,使用菜單以及表單,而且最為重要的一點是使用curses包編寫的程序?qū)ⅹ毩⒂诟鞣N具體的終端,這樣的一個直接的好處就是程序具有良好的移植性。
這一點在網(wǎng)絡(luò)上顯得尤其重要,因為你面對的可能是上百種終端,如果為每一個終端都專門重新編寫一套新的程序,那么復(fù)雜程度出乎想象,而且?guī)缀醪豢赡堋?/p>
為了能夠達(dá)到這樣的目的,curses包使用了終端描述數(shù)據(jù)庫(TerminalDescriptionDatabases)
terminfo(TERMinalINFOrmationdatabase)或者termcap(TERMinalCAPabilitiedatabase),這兩個數(shù)據(jù)庫里存放了不同終端的操作控制碼和轉(zhuǎn)義序列以及其余相關(guān)信息,這樣當(dāng)使用每一個終端的時候,curses將首先在終端描述數(shù)據(jù)庫中查找是否存在該類型的終端描述信息,如果找到則進(jìn)行適當(dāng)?shù)奶幚怼?/p>
如果數(shù)據(jù)庫中沒有這種終端信息,則程序無法在該終端上運行,除非用戶自己增加新的終端描述。
1.1.1curses發(fā)展歷史
curses是怎么來的?
curses的名稱起源于“cursoroptimization”,即光標(biāo)優(yōu)化的意思。
它最早是由巴克利大學(xué)的BillJoy和KenArnold發(fā)展而來,主要是處理游戲rogue的屏幕界面。
rogue是一個古老的基于文本的的冒險類游戲。
在當(dāng)時,僅僅控制游戲屏幕的外觀顯示就需要編寫大量的代碼,因為它們使用的是古老的termios甚至是tty接口。
巨大的工作量迫使BillJoy和KenArnold將rogue游戲中的所有的屏幕處理和光標(biāo)移動的函數(shù)匯集到一個函數(shù)庫中。
這就形成了最早的也是最簡單的curses處理庫的雛形。
它最終隨著BSDUNIX的早期版本發(fā)行開來。
在這個版本中使用的是當(dāng)時業(yè)已存在的termcap數(shù)據(jù)庫來描述終端信息。
后來貝爾實驗室的MarkHorton在SystemIIIUNIX中重新編寫了curses。
它相對以前的版本有了很大的擴(kuò)展和提高,增加了一些非常新的特性。
它首先將termcap數(shù)據(jù)庫改進(jìn)為terminfo數(shù)據(jù)庫。
terminfo數(shù)據(jù)庫完全由Horton開發(fā)編寫,它是從termcap發(fā)展而來,而且更為中要重要的是其中引進(jìn)了參數(shù)化性能的概念,這樣使得描述多視頻屬性以及彩色終端成為可能。
在后來的AT&TSystemV版本中,curses就擴(kuò)展了更多功能和性能,包括了對窗體、菜單、面板、表單等組件以及對鼠標(biāo)的支持。
這時候的curses內(nèi)容以及設(shè)計與最初的BSD版本的curses在功能和復(fù)雜性上已經(jīng)相去甚遠(yuǎn)。
1.1.2curses包內(nèi)容
curses包主要包括下面的四個開發(fā)庫:
| curses | 最早的curses包只包含這部分,主要控制屏幕的輸入輸出,光標(biāo)操作,窗口創(chuàng)建和操作等。 |
| panel | 類似于窗口堆棧,不同的窗口可以存放于其中,并且可以在其中進(jìn)行移動。 |
| menu | 新增的部分,主要包括創(chuàng)建菜單并且與之交互的函數(shù),主要用來接受用戶的選擇。 |
| form | 包括創(chuàng)建表單以及與之進(jìn)行交互的函數(shù),主要用來接受用戶數(shù)據(jù)輸入。 |
1.1.3curses包移植性
使用curses包與使用低層終端函數(shù)編寫的程序最主要的差別在于curses程序是獨立于具體終端的,也就是說在某個終端上編寫的程序可以完整的移植到另外的終端上而不需要進(jìn)行任何改動。
curses包的可移植性是curses包的最大特性。
curses包的這種終端獨立性歸根于終端描述數(shù)據(jù)庫terminfo和termcap。
terminfo和termcap數(shù)據(jù)庫中包含了所有終端的描述信息。
termcap數(shù)據(jù)庫是在最早的的BSDUNIX中使用,在后來的SystemIII中則使用terminfo數(shù)據(jù)庫。
terminfo數(shù)據(jù)庫是從termcap數(shù)據(jù)庫發(fā)展而來,組織方式相對于termcap來說有了進(jìn)一步的優(yōu)化,而且描述的終端信息有了進(jìn)一步的增加。
需要使用的數(shù)據(jù)庫可以在程序編譯的時候通過cc命令指定。
正如前面所說,curses正是通過使用terminfo數(shù)據(jù)庫使得程序可以在不同的終端上可以移植,那么系統(tǒng)是如何做到這一點的呢?
對于使用curses進(jìn)行處理的程序員來說他實際上處理的是虛擬終端。
curses完成了物理終端到虛擬終端的“映射”。
用curses編寫的程序在它們每次被調(diào)用的時候都需要引用終端描述數(shù)據(jù)庫。
數(shù)據(jù)庫中的終端描述信息包括了終端的一系列的性能參數(shù),在curses包中我們定義了很多的變量與這些性能參數(shù)對應(yīng)。
當(dāng)程序執(zhí)行的時候,程序首先獲取終端類型,然后根據(jù)終端類型獲取終端描述數(shù)據(jù)庫中具體的性能,最后將這些性能參數(shù)讀進(jìn)curses中預(yù)定義的相應(yīng)的變量中。
當(dāng)程序與終端進(jìn)行交互從而需要調(diào)用相應(yīng)的函數(shù)的時候,它將從頭文件的性能變量中為終端獲取必要的控制碼,一旦需要某個性能參數(shù),只要找到相應(yīng)的變量即可,從而達(dá)到以不變應(yīng)萬變的效果。
例如在curses包中我們定義了LINES和COLS變量對應(yīng)終端能夠顯示的最大行數(shù)和最大列數(shù)這兩個性能,不同的終端的LINES和COLS的值可能不同,比如通常的終端的行數(shù)為39行,如果使用了軟標(biāo)簽,行數(shù)將減一變?yōu)?8。
但這種變化都由curses幕后自動完成,用戶完全不需要理會,用戶需要記住的僅是LINES和COLS以及它們代表的含義。
這樣,程序就可以運行在各種不同的終端上,唯一的缺陷就是這種終端首先必須在終端信息描述庫中存在,否則就無法直接使用curses包,彌補的辦法就是需要自己在終端信息描述庫中增加終端描述信息。
安裝
sudo yum install libncurses5-devcurses的基本用法
1. 包含頭文件:curses.h
2. 編譯時應(yīng)加上鏈接語句-lcurses,如:gcc temp.c -o temp -lcurses
3. 重要的函數(shù):
initscr():初始化curses庫和ttty。
(在開始curses編程之前,必須使用initscr()這個函數(shù)來開啟curses模式)
endwin():關(guān)閉curses并重置tty。
(結(jié)束curses編程時,最后調(diào)用的一個函數(shù))
cbreak():開啟cbreak模式,除了 DELETE 或 CTRL 等仍被視為特殊控制字元外一切輸入的字元將立刻被一一讀取。
crmode():使得終端進(jìn)入到cbreak模式。
==raw()和cbreak()==都可以禁止行緩沖。
區(qū)別是:
在raw()函數(shù)模式下,處理掛起(CTRLZ)、終端或退出(CTRLC)等控制字符時,將直接傳送給程序去處理而不產(chǎn)生終端信號;
而在cbreak()函數(shù)模式下,控制字符被終端驅(qū)動程序解釋成其它字符。
move(y,x): 將游標(biāo)移動至 x,y 的位置。
getyx(win,y,x): 得到目前游標(biāo)的位置。(請注意! 是 y,x 而不是&y,&x )
clear() and erase(): 將整個螢?zāi)磺宄?請注意配合refresh() 使用)
echochar(ch): 顯示某個字元.
== int noecho(void)==: 用戶輸入字符不回顯。
nl()/nonl():輸出時,換行是否作為回車字符。
nl函數(shù)將換行作為回車符,而nonl作用相反。
addch(ch): 在當(dāng)前位置畫字符ch。
mvaddch(y,x,ch): 在(x,y) 上顯示某個字元。
相當(dāng)于呼叫move(y,x);addch(ch);
addstr(str): 在當(dāng)前位置畫字符串str。
mvaddstr(y,x,str): 在(x,y) 上顯示一串字串。相當(dāng)于呼叫move(y,x);addstr(str);
printw(format,str): 類似 printf() , 以一定的格式輸出至螢?zāi)弧?/p>
mvprintw(y,x,format,str): 在(x,y) 位置上做 printw 的工作.。
相當(dāng)於呼叫move(y,x);printw(format,str);
getch(): 從鍵盤讀取一個字元.。(注意! 傳回的是整數(shù)值)
getstr(): 從鍵盤讀取一串字元。
scanw(format,&arg1,&arg2…): 如同 scanf, 從鍵盤讀取一串字元.
int mvhline(int x, int y, chtype ch, int n):在光標(biāo)(x,y)位置畫n個ch組成的線。
mvhlin畫水平線,mvvline畫豎線。
光標(biāo)位置不變。
調(diào)用成功返回OK,否則返回ERR。
beep(): 發(fā)出一聲嗶聲.
box(win,ch1,ch2): 自動畫方框
intrflush(WINDOW *win,bool bf): win為標(biāo)準(zhǔn)輸出。
當(dāng)bf為true時輸入Break,可以加快中斷的響應(yīng)。
但是,有可能會造成屏幕輸出信息的混亂。
refresh(): 使屏幕按照你的意圖顯示。
比較工作屏幕和真實屏幕的差異,然后refresh通過終端驅(qū)動送出那些能使真實屏幕于工作屏幕一致的字符和控制碼,把虛擬屏幕上的圖像輸出到終端屏幕上。
(工作屏幕就像磁盤緩存,curses中的大部分的函數(shù)都只對它進(jìn)行修改)
調(diào)用成功返回OK,否則返回ERR。
standout(): 啟動standout模式(一般使屏幕發(fā)色)
測試
include <unistd.h> #include <stdlib.h> #include <curses.h>int main() {initscr();move( 5, 15 );printw( "%s", "Hello world" );refresh();sleep(2);endwin();exit(EXIT_SUCCESS); }執(zhí)行:
g++ HelloCurses.c -lncurses總結(jié)
- 上一篇: C / C++ 软件项目的目录结构
- 下一篇: Curses 中的 noecho() 函