Rust终端UI开发库ncurses的使用,ncurses提供跨平台终端界面控制和文本模式图形化编程
Rust终端UI开发库ncurses的使用,ncurses提供跨平台终端界面控制和文本模式图形化编程
ncurses-rs 是一个非常轻量级的 ncurses TUI 库的 Rust 封装。
注意: ncurses 库本身非常不安全,而 ncurses-rs 只是最轻量的封装。如果你想要一个安全且符合 Rust 惯用法的 TUI 库,请考虑其他选择。如果你想要一个 C 到 Rust 的 1:1 移植,或者想用 C 风格的方式在 Rust 中快速开发 TUI,那么这个库会很适合。
构建
编译后的库会放在 target
目录下。
cargo build
注意你需要安装 ncurses 库并确保它可以被链接才能使用 ncurses-rs。在 Linux 上这很简单。在 macOS 上,可以考虑使用 Homebrew 安装 ncurses。(注意你需要强制 Homebrew 将库链接到 /usr/local/lib
:brew link --force ncurses
并将该路径设置为环境变量 LIBRARY_PATH
。)
示例
示例通过 cargo build
构建。要运行它们,使用 cargo run --example ex_<NUMBER>
。示例编号越大,示例越复杂。
当前示例:
- Hello World
- Basic Input & Attributes
- Simple Pager
- Window Movement
- Menu Library (需要 Rust nightly)
- Pager & Syntax Highlighting
- Basic Input & Attributes (Unicode)
- Special ACS Characters
环境变量
build.rs
会读取一些环境变量:
如果设置了 NCURSES_RS_RUSTC_LINK_LIB
,它将用于 NCURSES_RS_RUSTC_LINK_LIB
。
如果设置了 NCURSES_RS_RUSTC_FLAGS
,它将用于 cargo:rustc-flags
。
如果设置了 NCURSES_RS_CFLAGS
,它将用于编译测试程序 chtype_size.c
。
完整示例代码
下面是一个使用 ncurses-rs 的完整 “Hello World” 示例:
extern crate ncurses;
use ncurses::*;
fn main() {
// 初始化 ncurses
initscr();
// 打印字符串到标准屏幕
printw("Hello, world!");
// 刷新屏幕
refresh();
// 等待用户输入
getch();
// 结束 ncurses
endwin();
}
另一个更复杂的示例,展示基本输入和属性:
extern crate ncurses;
use ncurses::*;
fn main() {
// 初始化 ncurses
initscr();
raw();
keypad(stdscr(), true);
noecho();
// 打印欢迎信息
printw("Type any character to see it in bold\n");
// 获取字符并显示
let ch = getch();
// 如果不是 F1 键
if ch == KEY_F(1) {
printw("F1 Key pressed");
} else {
// 开启属性
attron(A_BOLD);
printw(&format!("Key pressed is: {}\n", ch as u8 as char));
// 关闭属性
attroff(A_BOLD);
}
printw("Press any key to exit");
refresh();
getch();
endwin();
}
要运行这些示例,你需要先在你的 Cargo.toml 中添加 ncurses 依赖:
[dependencies]
ncurses = "6.0.1"
然后使用 cargo run
来运行你的程序。
更完整的示例:创建颜色窗口
下面是一个完整的示例,展示如何创建带颜色的窗口:
extern crate ncurses;
use ncurses::*;
fn main() {
// 初始化ncurses
initscr();
start_color(); // 启用颜色功能
cbreak(); // 行缓冲禁用,直接传递所有输入
noecho(); // 关闭输入回显
keypad(stdscr(), true); // 启用功能键
// 初始化颜色对
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
// 创建新窗口
let height = 10;
let width = 30;
let y = 5;
let x = 10;
let win = newwin(height, width, y, x);
// 在窗口中打印带颜色的文本
box_(win, 0, 0); // 绘制边框
wattr_on(win, COLOR_PAIR(1)); // 启用颜色对1
mvwprintw(win, 1, 1, "This is a red text");
wattr_off(win, COLOR_PAIR(1)); // 关闭颜色对1
wattr_on(win, COLOR_PAIR(2)); // 启用颜色对2
mvwprintw(win, 2, 1, "This is a green text");
wattr_off(win, COLOR_PAIR(2));
// 刷新窗口
wrefresh(win);
// 在主窗口打印信息
mvprintw(0, 0, "Press any key to exit");
refresh();
// 等待用户输入
getch();
// 删除窗口
delwin(win);
// 结束ncurses
endwin();
}
这个示例展示了:
- 如何初始化ncurses并启用颜色功能
- 如何创建新的窗口
- 如何使用颜色对来显示不同颜色的文本
- 如何在特定位置打印文本
- 如何绘制窗口边框
- 如何清理资源
要运行这个示例,同样需要先在Cargo.toml中添加ncurses依赖。
Rust终端UI开发库ncurses的使用指南
ncurses简介
ncurses是一个用于终端UI开发的C语言库,提供了跨平台的终端界面控制和文本模式图形化编程功能。在Rust中,我们可以通过ncurses
crate来使用这个强大的库。
ncurses主要功能包括:
- 创建基于文本的用户界面
- 控制终端光标位置
- 处理键盘和鼠标输入
- 创建窗口和面板
- 支持颜色和属性(如粗体、下划线等)
使用方法
1. 添加依赖
首先在Cargo.toml
中添加依赖:
[dependencies]
ncurses = "5.101.0"
2. 基本使用示例
use ncurses::*;
fn main() {
// 初始化ncurses
initscr();
// 启用颜色支持
start_color();
// 打印欢迎信息
printw("欢迎使用ncurses Rust示例!");
// 刷新屏幕显示
refresh();
// 等待用户输入
getch();
// 清理ncurses
endwin();
}
3. 窗口管理
use ncurses::*;
fn main() {
initscr();
cbreak(); // 禁用行缓冲
noecho(); // 不显示输入字符
keypad(stdscr(), true); // 启用功能键
// 创建一个新窗口
let win = newwin(10, 30, 5, 5);
box_(win, 0, 0); // 给窗口添加边框
// 在窗口中打印文本
mvwprintw(win, 1, 1, "这是一个子窗口");
// 刷新窗口
wrefresh(win);
// 主窗口显示信息
mvprintw(0, 极狐,0, "按任意键退出...");
refresh();
getch();
endwin();
}
4. 颜色使用
use ncurses::*;
fn main() {
initscr();
start_color();
// 初始化颜色对
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
// 使用颜色
attron(COLOR_PAIR(1));
printw("红色文本");
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(2) | A_BOLD);
printw(" 粗体绿色文本");
attroff(COLOR_PAIR极狐(2) | A_BOLD);
refresh();
getch();
endwin();
}
5. 键盘输入处理
use ncurses::*;
fn main() {
initscr();
cbreak();
noecho();
keypad(stdscr(), true);
printw("按方向键测试 (按q退出)...");
loop {
let ch = getch();
match ch {
KEY_UP => mvprintw(1, 0, "上方向键 "),
KEY_DOWN => mvprintw(1, 0, "下方向键 "),
KEY_LEFT => mvprintw(1, 0, "左方向键 "),
KEY_RIGHT => mvprintw(1, 0, "右方向键 "),
b'q' => break,
_ => mvprintw(1, 0, "未知按键: {} ", ch),
}
refresh();
}
endwin();
}
高级功能
1. 创建多窗口应用
use ncurses::*;
fn main() {
initscr();
cbreak();
noecho();
curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE); // 隐藏光标
// 创建两个窗口
let win1 = newwin(10, 30, 1, 1);
let win2 = newwin(10, 30, 1, 35);
// 填充窗口内容
box_(win1, 0, 0);
mvwprintw(win1, 1, 1, "窗口1");
box_(win2, 0, 0);
mvwprintw(win2, 1, 1, "窗口2");
// 刷新窗口
wrefresh(win1);
wrefresh(win2);
// 主窗口信息
mvprintw(0, 0, "多窗口示例 (按q退出)");
refresh();
// 事件循环
loop {
let ch = getch();
if ch == b'q' {
break;
}
}
// 删除窗口
delwin(win1);
delwin(win2);
endwin();
}
2. 使用鼠标事件
use ncurses::*;
fn main() {
initscr();
cbreak();
noecho();
keypad(stdscr(), true);
// 启用鼠标支持
mousemask(ALL_MOUSE_EVENTS, None);
printw("点击鼠标测试 (按q退出)...");
refresh();
loop {
let ch = getch();
match ch {
KEY_MOUSE => {
// 处理鼠标事件
let mut event: MEVENT = MEVENT {
id: 0, x: 0, y: 0, z: 0, bstate: 0
};
if getmouse(&mut event) == OK {
mvprintw(1, 0, &format!(
"鼠标点击: x={}, y={}, 按钮={:b} ",
event.x, event.y, event.bstate
));
refresh();
}
}
b'q' => break,
_ => (),
}
}
endwin();
}
完整示例:带菜单的终端应用
use ncurses::*;
fn main() {
// 初始化ncurses
initscr();
start_color();
cbreak();
noecho();
keypad(stdscr(), true);
curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
// 初始化颜色
init_pair(1, COLOR_WHITE, COLOR_BLUE); // 菜单选中项
init_pair(2, COLOR_BLACK, COLOR_WHITE); // 菜单未选中项
// 创建菜单窗口
let menu_win = newwin(10, 30, 5, 5);
box_(menu_win, 0, 0);
let title = "Rust ncurses菜单";
mvwprintw(menu_win, 0, (30 - title.len() as i32) / 2, title);
// 菜单选项
let menu_items = ["选项1", "选项2", "选项3", "退出"];
let mut selected = 0;
// 主循环
loop {
// 绘制菜单
for (i, item) in menu_items.iter().enumerate() {
if i == selected {
wattron(menu_win, COLOR_PAIR(1));
mvwprintw(menu_win, i as i32 + 2, 2, &format!("> {}", item));
wattroff(menu_win, COLOR_PAIR(1));
} else {
wattron(menu_win, COLOR_PAIR(2));
mvwprintw(menu_win, i as i32 + 2, 2, &format!(" {}", item));
wattroff(menu_win, COLOR_PAIR(2));
}
}
wrefresh(menu_win);
// 处理输入
match getch() {
KEY_UP => {
if selected > 0 {
selected -= 1;
}
}
KEY_DOWN => {
if selected < menu_items.len() - 1 {
selected += 1;
}
}
10 => { // 回车键
if selected == menu_items.len() - 1 {
break;
}
mvprintw(15, 5, &format!("你选择了: {}", menu_items[selected]));
refresh();
getch();
}
_ => {}
}
}
// 清理
delwin(menu_win);
endwin();
}
注意事项
- 总是调用
endwin()
来正确清理终端状态 - 在修改窗口内容后记得调用
refresh()
或wrefresh()
- 考虑使用
panel
crate来管理重叠窗口 - 对于更现代的替代方案,可以考虑
tui-rs
或cursive
等库
总结
ncurses为Rust提供了强大的终端UI开发能力,虽然API是C风格的,但通过Rust的包装,我们可以安全地使用它来创建丰富的终端应用程序。从简单的文本显示到复杂的多窗口界面,ncurses都能胜任。