Rust 用 ratatui 写终端 UI:从布局、事件循环到表格渲染
test12026-11-031 次阅读
终端 UI 的基本模型
ratatui(原 tui-rs)让你在终端里画出边框、表格、列表,而不依赖任何图形库。它的核心是一个固定的事件循环:每一帧先按布局切分终端区域,再把控件画进对应区块,同时监听键盘事件更新状态。绘制是无状态的,ratatui 在底层帮你做差异刷新,只把变化的部分写给终端。
搭一个最小可运行应用
下面用 crossterm 作为后端处理终端原始模式和事件。main 函数里开启 raw 模式、进入交替屏幕,然后跑循环,直到用户按 q 退出。
use crossterm::event::{self, Event, KeyCode};
use crossterm::terminal::{enable_raw_mode, disable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen};
use ratatui::{Terminal, backend::CrosstermBackend};
use std::io;
fn main() -> io::Result<()> {
enable_raw_mode()?;
let mut stdout = io::stdout();
crossterm::execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut term = Terminal::new(backend)?;
loop {
term.draw(|f| {
let size = f.area();
let block = ratatui::widgets::Block::bordered().title("状态");
f.render_widget(block, size);
})?;
if let Event::Key(key) = event::read()? {
if key.code == KeyCode::Char('q') {
break;
}
}
}
disable_raw_mode()?;
crossterm::execute!(io::stdout(), LeaveAlternateScreen)?;
Ok(())
}
用 Layout 切分区域
Layout 支持按百分比或固定行高把区域切成几块。下面把屏幕分成上下两部分,上占三成,下占七成。
use ratatui::layout::{Layout, Constraint, Direction};
term.draw(|f| {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Percentage(30), Constraint::Percentage(70)])
.split(f.area());
let top = ratatui::widgets::Block::bordered().title("顶部");
let bottom = ratatui::widgets::Block::bordered().title("底部");
f.render_widget(top, chunks[0]);
f.render_widget(bottom, chunks[1]);
})?;
渲染一张表格
Table 是 ratatui 最常用的控件之一。先定义表头和行,再指定列宽,最后渲染到某个区块。数据来自普通 Vec,绘制时直接读状态。
use ratatui::widgets::{Table, Row, Cell, TableRow};
let rows = vec![
Row::new(vec![Cell::new("1"), Cell::new("张三"), Cell::new("在线")]),
Row::new(vec![Cell::new("2"), Cell::new("李四"), Cell::new("离线")]),
];
let table = Table::new(rows, [Constraint::Length(4), Constraint::Length(12), Constraint::Length(8)])
.header(Row::new(vec!["ID", "名称", "状态"]));
f.render_widget(table, area);
处理键盘事件驱动状态
真实应用里要把状态提出循环外。下面用一个计数器,上下键调整选中行,q 退出。
let mut selected = 0usize;
loop {
term.draw(|f| render_list(f, selected))?;
if let Event::Key(key) = event::read()? {
match key.code {
KeyCode::Char('q') => break,
KeyCode::Down => selected = selected.saturating_add(1),
KeyCode::Up => selected = selected.saturating_sub(1),
_ => {}
}
}
}
小结
ratatui 把终端界面拆成"布局 + 无状态绘制 + 事件循环"三步。它适合写开发工具、监控面板、聊天客户端这类需要在 SSH 环境里跑的界面。由于绘制是无状态的,状态管理完全由你自己的 Rust 变量负责,逻辑清晰也好测试。
T
test1
文章作者
终端 UI 的基本模型 ratatui(原 tui-rs)让你在终端里画出边框、表格、列表,而不依赖任何图形库。它的核...
- 分类
- 技术
- 发布时间
- 2026-11-03
- 字数
- 约 2692 字
- 阅读
- 1 次
