ncurses
ncurses 是基于终端的十分强大的图形库。 Vim, screen, sl 等终端程序都用到了这个库(足以见其强大)。
安装
部分系统默认安装了 ncurses ,手动安装的方式是:
sudo aptitude install ncurses-dev
。
使用的程序需要 #include <ncurses.h>
。
编译时需要添加 -lncurses
参数进行链接。
开始和结束
调用 initscr 初始化窗口,endwin 结束窗口。
1 |
|
输出
调用 initscr 后调用 endwin 前,printf, std::cout 等标准输出不会显示在屏幕上。 而输出到屏幕上需要 ncurses 提供的相应函数。
函数
1 | int addch(const chtype char_to_add); // 当前位置添加字符 |
输入
调用 scanf, getchar, cin 等标准输入函数同样无效。
函数
1 | int cbreak(); // 字符一键入,直接传给程序(不用按下回车) |
输入函数通常是阻塞的,但是通过调用 nodelay(stdscr, TRUE); 可以关闭阻塞。 此时若输入函数未读取到内容会返回 ERR 。
光标
控制光标。 调用 initscr 后调用 endwin 前,输出终端控制符改变光标是无效的。
函数及示例
1 | int move(int x, int y); // 将光标移动到 [x] 行 [y] 列,左上角为 0 行 0 列 |
指定位置输出
在指定位置输出不必先 move 再 printw , ncurses 提供了 mv
函数前缀在指定位置输出。 例如 mvprintw(1, 2, "%d", 2)
在 1
行 2 列输出 3 。 类似的有 mvaddch, mvaddstr 等。
颜色
初始化
首先需要调用 has_color() 查看当前运行环境是否支持彩色。 调用 start_color() 初始化颜色,成功则返回 OK 。
1 | bool has_colors(void); |
成功后会初始化全局变量 COLORS 表示终端支持的颜色数量 还会有 COLOT_WHITE, COLOR_RED 等 8 个表示颜色的变量。
使用
例如希望打印白底黑字的信息:
1 | void print(const char *info) { |
错误示例
值得注意的是,必须保证 init_pair 的编号不与其他已初始化的编号重复 一个错误的调用如下:
1 | const char *info = "ERROR CODE"; |
上述代码的期望打印出白字和黑字两种不同的颜色, 但事实上只会打印出红色一种。 解决方案便是将白底红字的 pair 编号设为 2 。
窗口
ncurses 有窗口类 WINDOW 并提供了 stdscr 作为默认窗口。 有时一个窗口无法满足需要,此时需要自己新建窗口。
新建窗口
调用 newwin 来新建窗口。
1 | // 从 ([x], [y]) 开始新建 [line] 行 [column] 列的窗口。 |
新建的窗口
通用输出
addch, printw 等输出方式只输出到 stdscr 。 ncurses 提供了 w
前缀来输出到指定窗口。 例如 wprintw(win, "%d", 1)
在 [win]
窗口输出 1 。 但是自己新建的窗口与 stdscr 不同,
若想在屏幕上显示需要调用 wrefresh(win)
刷新窗口。
若想在窗口中指定位置输出,可以用 mvw 前缀函数。 例如
mvwprintw(win, 1, 2, "%d", 3)
在 [win] 窗口的 1 行 2 列(
相对位置 )输出 3 。
子窗口
调用 subwin 创建子窗口。
1 | // 从 ([x], [y]) 开始新建 [line] 行 [column] 列属于 [parent] 的子窗口。 |
子窗口与普通窗口的区别在于它与其父窗口共用屏幕储存空间, 子窗口修改时父窗口会直接受到影响。 比如新建了 stdscr 的子窗口 win , 那么输出到 win 后想显示在屏幕不调用 wrefresh 而是调用 touchwin(stdscr) 。 touchwin 用于标记一个窗口被修改。
销毁窗口
调用 delwin 销毁窗口。
1 | int delwin(WINDOW *win); // 销毁 [win] 窗口 |
窗口销毁后其在屏幕上对应的内容不会改变。
离开
有时候可能需要离开 ncurses 回到行缓冲模式做些事情而且需要在之后回到 ncurses 。 例如 Vim 里面输入 :!ls 就会退出 ncurses 运行 ls 命令,并在用户敲下回车后回到 ncurses。
调用 def_prog_mode 暂存,调用 reset_prog_mode 恢复。
示例
1 | int main() { |
输出中文等非 ASCII 字符
事实上 ncurses 并不支持直接输出中文, 这意味着调用 printw("中文") 会是一堆乱码。 解决方案如下:
安装库
这需要另一个库。 通过
sudo aptitude install libncurses5 libncursesw5 libncursesw5-dbg libncursesw5-dev
安装
头文件
一定是 #include <ncurses.h>
而不是
#include <curses.h>
。 另外在 main.cpp
#include <locale.h>
。
调用
在调用 initscr() 之前 调用 setlocale(LC_ALL, "") 。
编译
将 -lncurses
参数改为 -lncursesw
。