隨著電腦知識的普及, 越來越多的電腦愛好者開始了解和使用Linux.。Linux的輕松自由之風給了我們不同的感受。
但是我們不能滿足於基本的命令和KDE, Gnome等用戶界面的操作. 我們要干什麼? 編程, 對, 編程! 對於編程愛好者, Linux有著很好的編程環境: gcc(GNU Compiler Collection)能夠編譯C, C++, Java等很多種語言, 而且Linux環境下有很多函數庫可以調用.了解一些這些函數庫的使用, 會給你的編程工具箱裡增加許多有用的工具. 今天, 就讓我們來認識一下curses --- 它不是什麼中世紀巫婆的咒語,而是一個在Linux/Unix下廣泛應用的圖形函數庫.
以前學過TC2.0的朋友肯定還記得TC裡邊有一個圖形庫BGI(Borland Graphics Interface, 還記得那個頭文件嗎:). 用它我們可以繪制在DOS下的用戶界面和漂亮的圖形. 而Linux/Unix編程給人的感覺就比較"cool"一點, 好像Linux編程都是在黑黑的終端下進行的.確實是這樣,許多Linux高手都喜歡在終端方式下工作, 熟悉了一些命令以後,這樣的工作方式效率還是很高的. 但是長久地看著黑黑的屏幕難免讓人感到厭倦, 特別是像我這樣接觸Linux不久的菜鳥:) 有沒有一種工具能讓我們在Linux下編出好看的圖形呢? 答案是肯定的, 它就是curses!
curses的名字起源於"cursor optimization",即光標優化. 它最早由有美國伯克利大學的Bill Joy和Ken Arnold編寫的, 用來處理一個游戲rogue的屏幕顯示. 後來貝爾實驗室的Mark Horton在System III Unix中重新編寫了curses. 現在幾乎所有的Unix, Linux操作系統都帶了curses函數庫, curses也加入了對鼠標的支持, 一些菜單和面板的處理. 可以說, curses是Linux終端圖形編程的不二選擇(比如著名的文字編輯器 vi 就是基於curses編的)
OK, 閒話少說,現在我們開始進入正題:
首先我們應該了解, 在終端使用使用的屏幕模式是基於文本的. 所以在開始使用curses前, 需要用initscr()函數初始化屏幕. 對應的, 程序結束需要調用endwin();函數來關閉curses狀態.
有了這個概念, 我們就可以來寫著名的"Hello, world!"之curses版了:
/*-----------------------------------------------------------------
A very simple example of curses programming
coder: jellen
date: 3-26-2004
----------------------------------------------------------------*/
#include
int main()
{
initscr();
box(stdscr, ACS_VLINE, ACS_HLINE); /*draw a box*/
move(LINES/2, COLS/2); /*move the cursor to the center*/
waddstr(stdscr, "Hello, world!");
refresh();
getch();
endwin();
return 0;
}
呵呵, 剛才忘了說了. 我們調用curses庫一般是用C語言的(沒什麼奇怪, C可以說是Linux的官方語言, 不過你也可以用C++或Python等語言調用curses的, 這無關緊要). 假設我們把這個程序保存為 hello.c
不過不要急著用gcc -o hello hello.c去編譯運行(我知道你會用gcc:) 那樣是不能通過編譯的. 因為curses庫不在標准路徑上, 所以我們要加上 -lcurses連接選項, 像這樣:
gcc -o hello hello.c -lcurses
現在你用 ./hello 運行一下程序看看,是不是出現了你所期望的窗口.
現在我們來一行行分析一下代碼.
#include /*這是每個 curses 程序都必須包含的頭文件,表明使用了curses庫*/
然後主函數中第一句initscr();初始化了屏幕, 使之開始進入curses圖形化工作方式.
其實我們現在沒有自己建立窗口, 用的是標准屏幕 stdscr(就象C裡面標准輸入stdin, 標准輸出stdout一個概念), 它就是我們面前的電腦屏幕(不過現在還是黑黑的)
下面一句: box(stdscr, ACS_VLINE, ACS_HLINE); 畫了一個框. 有了這個框我們才有"窗體"的感覺. stdscr就是標准屏幕, ACS_VLINE和ACS_HLINE代表構成方框兩邊的基本元素, 你也可以用 ''''|''''和''''-''''代替, 不過可能沒有ACS_VLINE, ACS_HLINE好看了.
move(LINES/2, COLS/2);
waddstr(stdscr, "Hello, world!");
這兩句是把光標移到屏幕中間, 然後輸出我們的"Hello, world!"
LINES 和 COLS是curses定義的宏, 代表當前屏幕的最大行數和列數. waddstr()函數的作用是在stdscr上打印字符串"hello, world!"
屏幕分物理屏幕(我們所看到的)和邏輯屏幕(在內存中的), 我們調用函數時修改的是邏輯屏幕,它不會在當前物理屏幕上顯示出來.所以現在屏幕上還是什麼也沒有, 需要調用refresh()把我們對邏輯屏幕的改動在物理屏幕(顯示器)上顯示出來. 然後用getch()讓屏幕暫停一下.
最後調用endwin()結束curses, 恢復原來的屏幕.
好了, 我們完成了第一個例子的分析. 是不是挺簡單的?
不過不盡如人意的是屏幕還是那個樣子, 沒有什麼色彩. 要加色彩? 那也是挺容易的: 首先用start_color()函數開啟顏色模式, 然後設置我們要的顏色就行了.
curses裡的顏色是配對的, 要一個背景色對一個前景色. 使用之前用init_pair()初始化.
比如init_pair(1, COLOR_BLUE, COLOR_GREEN);就定義了一組顏色, COLOR_BLUE為前景色, COLOR_GREEN為背景色. 1是它們的標記號碼(供其他函數調用時使用) 我們來看一個簡單的例子:
/*--------------------------------------------------------------
A simple curses color demo program
Coder: jellen
Date: 3-26-2004
-------------------------------------------------------------*/
#include
int main()
{
initscr(); /*初始化屏幕*/
if(start_color() == OK) /*開啟顏色*/
{
init_pair(1, COLOR_RED, COLOR_GREEN); /*建立一個顏色對*/
attron(COLOR_PAIR(1)); /*開啟字符輸出顏色*/
move(LINES/2, COLS/2);
waddstr(stdscr, "Yet another Hello, world!");
attroff(COLOR_PAIR(1)); /*關閉顏色顯示*/
refresh();
}
else
{
waddstr(stdscr, "Can not init color");
refresh();
}
endwin(); /*關閉curses狀態*/
return 0;
}
這個程序假如保存為color.c
那麼你可以這樣編譯了: gcc -o color color.c -lcurses
用./color一運行個彩色的字? 呵呵, 雖然不好看, 但是說不定你自己以後可以用curses寫出精美的程序。