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