Linux中國

ncurses 入門指南

雖然圖形界面非常酷,但是不是所有的程序都需要點擊式的界面。例如,令人尊敬的 Vi 編輯器在第一個 GUI 出現之前在純文本終端運行了很久。

Vi 編輯器是一個在「文本」模式下繪製的 面向屏幕 screen-oriented 程序的例子。它使用了一個叫 curses 的庫。這個庫提供了一系列的編程介面來操縱終端屏幕。curses 庫產生於 BSD UNIX,但是 Linux 系統通過 ncurses 庫提供這個功能。

[要了解 ncurses 「過去曾引起的風暴」,參見 ncurses: Portable Screen-Handling for Linux, September 1, 1995, by Eric S. Raymond.]

使用 curses 創建程序實際上非常簡單。在這個文章中,我展示了一個利用 curses 來在終端屏幕上繪圖的示常式序。

謝爾賓斯基三角形

簡單展示一些 curses 函數的一個方法是生成 謝爾賓斯基三角形 Sierpinski's Triangle 。如果你對生成謝爾賓斯基三角形的這種方法不熟悉的話,這裡是一些產生謝爾賓斯基三角形的規則:

  1. 設置定義三角形的三個點。
  2. 隨機選擇任意的一個點 (x,y)

然後:

  1. 在三角形的頂點中隨機選擇一個點。
  2. 將新的 x,y 設置為先前的 x,y 和三角頂點的中間點。
  3. 重複(上述步驟)。

所以我按照這些指令寫了這個程序,程序使用 curses 函數來向終端屏幕繪製謝爾賓斯基三角形:

/* triangle.c */

#include <curses.h>
#include <stdlib.h>

#include "getrandom_int.h"

#define ITERMAX 10000

int main(void)
{
  long iter;
  int yi, xi;
  int y[3], x[3];
  int index;
  int maxlines, maxcols;

  /* initialize curses */

  initscr();
  cbreak();
  noecho();

  clear();

  /* initialize triangle */

  maxlines = LINES - 1;
  maxcols = COLS - 1;

  y[0] = 0;
  x[0] = 0;

  y[1] = maxlines;
  x[1] = maxcols / 2;

  y[2] = 0;
  x[2] = maxcols;

  mvaddch(y[0], x[0], &apos;0&apos;);
  mvaddch(y[1], x[1], &apos;1&apos;);
  mvaddch(y[2], x[2], &apos;2&apos;);

  /* initialize yi,xi with random values */

  yi = getrandom_int() % maxlines;
  xi = getrandom_int() % maxcols;

  mvaddch(yi, xi, &apos;.&apos;);

  /* iterate the triangle */

  for (iter = 0; iter < ITERMAX; iter++) {
      index = getrandom_int() % 3;

      yi = (yi + y[index]) / 2;
      xi = (xi + x[index]) / 2;

      mvaddch(yi, xi, &apos;*&apos;);
      refresh();
  }

  /* done */

  mvaddstr(maxlines, 0, "Press any key to quit");

  refresh();

  getch();
  endwin();

  exit(0);
}

讓我一邊解釋一邊瀏覽這個程序。首先,getrandom_int() 函數是我對 Linux 系統調用 getrandom() 的包裝器。它保證返回一個正整數(int)值。(LCTT 譯註:getrandom() 系統調用按照位元組返回隨機值到一個變數中,值是隨機的,不保證正負,使用 stdlib.hrandom() 函數可以達到同樣的效果)另外,按照上面的規則,你應該能夠辨認出初始化和迭代謝爾賓斯基三角形的代碼。除此之外,我們來看看我用來在終端上繪製三角形的 curses 函數。

大多數 curses 程序以這四條指令開頭。 initscr() 函數獲取包括大小和特徵在內的終端類型,並設置終端支持的 curses 環境。cbreak() 函數禁用行緩衝並設置 curses 每次只接受一個字元。noecho() 函數告訴 curses 不要把輸入回顯到屏幕上。而 clear() 函數清空了屏幕:

  initscr();
  cbreak();
  noecho();

  clear();

之後程序設置了三個定義三角的頂點。注意這裡使用的 LINESCOLS,它們是由 initscr() 來設置的。這些值告訴程序在終端的行數和列數。屏幕坐標從 0 開始,所以屏幕左上角是 00 列。屏幕右下角是 LINES - 1 行,COLS - 1 列。為了便於記憶,我的程序里把這些值分別設為了變數 maxlinesmaxcols

在屏幕上繪製文字的兩個簡單方法是 addch()addstr() 函數。也可以使用相關的 mvaddch()mvaddstr() 函數可以將字元放到一個特定的屏幕位置。我的程序在很多地方都用到了這些函數。首先程序繪製三個定義三角的點並標記為 &apos;0&apos;&apos;1&apos;&apos;2&apos;

  mvaddch(y[0], x[0], &apos;0&apos;);
  mvaddch(y[1], x[1], &apos;1&apos;);
  mvaddch(y[2], x[2], &apos;2&apos;);

為了繪製任意的一個初始點,程序做了類似的一個調用:

  mvaddch(yi, xi, &apos;.&apos;);

還有為了在謝爾賓斯基三角形遞歸中繪製連續的點:

      mvaddch(yi, xi, &apos;*&apos;);

當程序完成之後,將會在屏幕左下角(在 maxlines 行,0 列)顯示一個幫助信息:

  mvaddstr(maxlines, 0, "Press any key to quit");

注意 curses 在內存中維護了一個版本的屏幕顯示,並且只有在你要求的時候才會更新這個屏幕,這很重要。特別是當你想要向屏幕顯示大量的文字的時候,這樣程序會有更好的性能表現。這是因為 curses 只能更新在上次更新之後改變的這部分屏幕。想要讓 curses 更新終端屏幕,請使用 refresh() 函數。

在我的示常式序中,我選擇在「繪製」每個謝爾賓斯基三角形中的連續點時更新屏幕。通過這樣做,用戶可以觀察三角形中的每次迭代。(LCTT 譯註:由於 CPU 太快,迭代過程執行就太快了,所以其實很難直接看到迭代過程)

在退出之前,我使用 getch() 函數等待用戶按下一個鍵。然後我調用 endwin() 函數退出 curses 環境並返回終端程序到一般控制。

  getch();
  endwin();

編譯和示例輸出

現在你已經有了你的第一個 curses 示常式序,是時候編譯運行它了。記住 Linux 操作系統通過 ncurses 庫來實現 curses 功能,所以你需要在編譯的時候通過 -lncurses來鏈接——例如:

$ ls
getrandom_int.c  getrandom_int.h  triangle.c

$ gcc -Wall -lncurses -o triangle triangle.c getrandom_int.c

(LCTT 譯註:此處命令行有問題,-lncurses 選項在我的 Ubuntu 16.04 系統 + gcc 4.9.3 環境下,必須放在命令行最後,否則找不到庫文件,鏈接時會出現未定義的引用。)

在標準的 80x24 終端運行這個 triangle 程序並沒什麼意思。在那樣的解析度下你不能看見謝爾賓斯基三角形的很多細節。如果你運行終端窗口並設置非常小的字體大小,你可以更加容易地看到謝爾賓斯基三角形的不規則性質。在我的系統上,輸出如圖 1。

圖 1. triangle 程序的輸出

雖然迭代具有隨機性,但是每次謝爾賓斯基三角形的運行看起來都會很一致。唯一的不同是最初繪製到屏幕的一些點的位置不同。在這個例子中,你可以看到三角形開始的一個小圓點,在點 1 附近。看起來程序接下來選擇了點 2,然後你可以看到在圓點和「2」之間的星號。並且看起來程序隨機選擇了點 2 作為下一個隨機數,因為你可以看到在第一個星號和「2」之間的星號。從這裡開始,就不能繼續分辨三角形是怎樣被畫出來的了,因為所有的連續點都屬於三角形區域。

開始學習 ncurses

這個程序是一個怎樣使用 curses 函數繪製字元到屏幕的簡單例子。按照你的程序的需要,你可以通過 curses 做得更多。在下一篇文章中,我將會展示怎樣使用 curses 讓用戶和屏幕交互。如果你對於學習 curses 有興趣,我建議你去讀位於 Linux 文檔計劃 Linux Documentation Project 的 Pradeep Padala 寫的 NCURSES Programming HOWTO

關於作者

Jim Hall 是一個自由及開源軟體的倡議者,他最有名的工作是 FreeDOS 計劃,也同樣致力於開源軟體的可用性。Jim 是在明尼蘇達州的拉姆齊縣的首席信息官。

via: http://www.linuxjournal.com/content/getting-started-ncurses

作者:Jim Hall 譯者:leemeans 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國