使用 ncurses 在你的 Linux 屏幕上定位文本
使用 ncurses 在 Linux 屏幕上的特定位置放置文本,可以帶來(lái)更友好的用戶界面體驗(yàn)。
大多數(shù)的 Linux 實(shí)用程序僅僅只在屏幕的底部滾動(dòng)文本。如果你想在屏幕中放置你的文本,例如一個(gè)游戲或者一個(gè)數(shù)據(jù)展示,你可以試試 ncurses。
curses 是一個(gè)舊的 Unix 庫(kù),它可以在文本終端界面控制光標(biāo)。curses 的名稱就來(lái)自于術(shù)語(yǔ) “光標(biāo)控制”。多年以后,其他人編寫了新的 curses 版本用來(lái)添加新的功能,新版本被叫做 “new curses” 或者 “ncurses”。你可以在每個(gè)流行的 Linux 發(fā)行版中找到 ncurses。盡管默認(rèn)情況下可能未安裝開發(fā)庫(kù)、頭文件和文檔。例如,在 Fedora 上,你需要使用以下命令安裝 ncurses-devel
包:
$ sudo dnf install ncurses-devel
在程序中使用 ncurses
要在屏幕上直接尋址,你首先需要初始化 ncurses
庫(kù)。大部分程序會(huì)通過以下三行來(lái)做到這一點(diǎn):
initscr()
:初始化窗口對(duì)象和 ncurses 代碼,返回代表整個(gè)屏幕的窗口對(duì)象cbreak()
:禁用緩沖并使鍵入的輸入立即可用noecho()
:關(guān)閉回顯,因此用戶輸入不會(huì)顯示在屏幕上
這些函數(shù)定義在 curses.h
頭文件中,你需要在你的程序中通過以下方式將其包含進(jìn)來(lái):
#include <curses.h>
初始化終端后,你可以自由使用任何 ncurses 函數(shù),我們將在示例程序中探討其中的一些函數(shù)。
當(dāng)你使用完 ncurses 并想返回到常規(guī)終端模式下時(shí),使用 endwin()
重置一切。此命令可以重置任何屏幕顏色,將光標(biāo)移動(dòng)到屏幕的左下角,并使光標(biāo)可見。通常在退出程序之前執(zhí)行此操作。
在屏幕上尋址
關(guān)于 ncurses 首先需要知道的是屏幕的坐標(biāo)分為行和列,左上角的是 0,0
點(diǎn)。ncurses 定義了兩個(gè)全局變量來(lái)幫助你識(shí)別屏幕:LINES
是屏幕的行數(shù),COLS
是屏幕的列數(shù)。屏幕右下角的位置是 LINES-1,COLS-1
。
例如,如果你想要移動(dòng)光標(biāo)到第 10 行和第 30 列,你可以使用 move()
函數(shù),移動(dòng)到此坐標(biāo):
move(10, 30);
之后顯示的任何文本都將從屏幕的該位置開始。要顯示單個(gè)字符,請(qǐng)對(duì)單個(gè)字符使用 addch(c)
函數(shù)。要顯示字符串,將對(duì)字符串使用 addstr(s)
函數(shù)。對(duì)于類似于 printf
的格式化輸出,請(qǐng)使用帶有常用選項(xiàng)的 printw(fmt, ...)
。
移動(dòng)到屏幕指定位置和顯示文本是一件很常見的事情,ncurses 提供了同時(shí)執(zhí)行這兩項(xiàng)操作的快捷方式。mvaddch(row, col, c)
函數(shù)將在屏幕第 row
行,第 col
列的位置顯示一個(gè)字符。而 mvaddstr(row, col, s)
函數(shù)將在屏幕第 row
行,第 col
列的位置顯示一個(gè)字符串。舉個(gè)更直接的例子,在程序中使用 mvaddstr(10, 30, "Welcome to ncurses");
函數(shù)將從屏幕的第 10
行和第 30
列開始顯示文本 Welcome to ncurses
。使用 mvaddch(0, 0, '+')
函數(shù)將在屏幕的左上角第 0
行和第 0
列處顯示一個(gè)加號(hào)(+
)。
在終端屏幕上繪制文本會(huì)對(duì)某些系統(tǒng)產(chǎn)生性能影響,尤其是在較舊的硬件終端上。因此 ncurses 允許你“堆疊”一堆文本以顯示在屏幕上,然后使用 refresh()
函數(shù)使所有這些更改對(duì)用戶可見。
讓我們來(lái)看一個(gè)將以上所有內(nèi)容整合在一起的簡(jiǎn)單示例:
#include <curses.h>
int
main()
{
initscr();
cbreak();
noecho();
mvaddch(0, 0, '+');
mvaddch(LINES - 1, 0, '-');
mvaddstr(10, 30, "press any key to quit");
refresh();
getch();
endwin();
}
程序的開始初始化了一個(gè)終端窗口,然后在屏幕的左上角打印了一個(gè)加號(hào),在左下角打印了一個(gè)減號(hào),在第 10
行和第 30
列打印了 press any key to quit
文本。程序通過使用 getch()
函數(shù)接收了鍵盤輸入的單個(gè)字符,接著,使用 endwin()
函數(shù)在程序完全退出前重置了終端。
getch()
是一個(gè)很有用的函數(shù),你可以使用它來(lái)做很多事情。我經(jīng)常使用它在我退出程序前用來(lái)暫停。與大多數(shù) ncurses 函數(shù)一樣,還有一個(gè)名為 mvgetch(row, col)
的 getch()
版本,用于在等待字符輸入之前移動(dòng)到屏幕位置的第 row
行,第 col
列。
使用 ncurses 編譯
如果你嘗試以通常的方式編譯該示例程序,例如 gcc pause.c
,你可能會(huì)從鏈接器中獲得大量錯(cuò)誤列表。那是因?yàn)?GNU C 編譯器不會(huì)自動(dòng)鏈接 ncurses
庫(kù)。相反,你需要使用 -l ncurses
命令行選項(xiàng)加載它以進(jìn)行鏈接。
$ gcc -o pause pause.c -lncurses
運(yùn)行新程序?qū)⒋蛴∫粭l簡(jiǎn)單的 press any key to quit
消息,該消息差不多位于屏幕中央:
圖 1:程序中居中的 “press any key to quit” 消息。
使用 ncurses 構(gòu)建更好的程序
探索 ncurses
庫(kù)函數(shù)以了解在屏幕上顯示文本的其它方法。你可以在 ncurses
的手冊(cè)頁(yè)中找到所有 ncurses
函數(shù)的列表。這給出了 ncurses 的一般概述,并提供了不同 ncurses
函數(shù)的類似表格的列表,并參考了包含完整詳細(xì)信息的手冊(cè)頁(yè)。例如,在 curs_printw(3X)
手冊(cè)頁(yè)中描述了 printw
,可以通過以下方式查看:
$ man 3x curs_printw
更簡(jiǎn)單點(diǎn):
$ man curs_printw
使用 ncurses,你可以創(chuàng)建更多有趣的程序。通過在屏幕上的特定位置打印文本,你可以創(chuàng)建在終端中運(yùn)行的游戲和高級(jí)實(shí)用程序。