Rust三方库(ratatui)

TUI库

开始TUI库之前我们先介绍下常用的跨平台终端操作库crossterm。其中常见的模块有四个:

  1. cursor:为终端中的光标提供各种功能。
  2. event:给键盘、鼠标、resize终端提供事件,
  3. style:给输入提供颜色等等属性。
  4. terminal:给正在运行的终端提供功能。

cursor中常见的结构体

  • DisableBlinking:禁用终端光标闪烁。
  • EnableBlinking:开启终端光标闪烁。
  • Hide:隐藏终端的光标。
  • MoveDown:光标向下移动特定的行数。
  • MoveLeft:光标向左移动特定行数。
  • MoveRight:光标向右移动特定的列数。
  • MoveTo:移动终端到给定的行列为止。
  • MoveToColumn:沿列移动当前光标。
  • MoveToNextLine:向下移动当前光标到下一行。
  • MoveToPreviousLine:移动当前光标到上一行。
  • MoveToRow:移动状态光标到给定的行和列。
  • MoveUp:上香移动特定行数。
  • RestorePosition:保存当前光标的位置。
  • SavePosition:保存当前终端光标的位置。
  • Show:显示终端光标。

event事件

事件模块提供了从键盘、鼠标、终端resize获取事件的功能。

  • read函数当事件可用时立马返回事件负责就阻塞到事件可用为止。
  • poll函数允许检查是否事件在特定时间周期可用,换句话说调用poll不会导致事件阻塞。
    不允许从不同的线程调用这些函数或者在EventStream中组合他们。开启raw mode为了键盘事件正常工作。

默认鼠标事件是不开启的你必须通过EnableMouseCapture开启。

结构体:

  • DisableBracketedPaste:禁用括号粘贴模式。
  • DisableFocusChange:禁用focus事件发射。
  • DisableMouseCapture:禁用鼠标事件捕获。
  • EnableBracketedPaste:开启括号粘贴模式。
  • EnableFocusChange:开启focus事件发射。
  • EnableMouseCapture:开启鼠标事件捕获。
  • EventStream:Result的流。
  • KeyEvent:代表键盘事件。
  • KeyEventState:键盘事件的额外状态。
  • KeyModifiers:特殊案件修饰符(shift, control, alt, etc.).
  • KeyboardEnhancementFlags:代表特殊的标记高数兼容的终端添加额外的键盘事件信息。
  • MouseEvent:鼠标事件。
  • PopKeyboardEnhancementFlags:禁用额外的键盘事件。
  • PushKeyboardEnhancementFlags:开启kitty键盘歇息,添加额外的信息到键盘事件移除含糊不清的修饰符。
    常见枚举:
  • Event:代表一个事件。
    • FocusGained
    • FocusLost
    • Key(KeyEvent)
    • Mouse(MouseEvent)
    • Paste(String)
    • Resize(u16, u16)
  • KeyCode:按键代码
    • Backspace
    • Enter
    • Left
    • Right
    • Up
    • Down
    • Home
    • End
    • PageUp
    • PageDown
    • Tab
    • BackTab
    • Delete
    • Insert
    • F(u8)
    • Char(char)
    • Null
    • Esc
    • CapsLock
    • ScrollLock
    • NumLock
    • PrintScreen
    • Pause
    • Menu
    • KeypadBegin
    • Media(MediaKeyCode)
    • Modifier(ModifierKeyCode):案件修饰符,在一些平台(如mac),并不会报告所有的鼠标事件,ctrl+鼠标左键点击为鼠标右键点击。
  • KeyEventKind:按键事件类型。
    • Press:按键按下
    • Repeat:案件重复
    • Replace:案件替换。
    • MediaKeyCode:代表媒体key。(as part of KeyCode::Media).
  • ModifierKeyCode:代表修饰符key。(as part of KeyCode::Modifier).
    • Play
    • Pause
    • PlayPause
    • Reverse
    • Stop
    • FastForward
    • Rewind
    • TrackNext
    • TrackPrevious
    • Record
    • LowerVolume
    • RaiseVolume
    • MuteVolume
  • MouseButton:代表鼠标按键
    • Left,
    • Right
    • Middle
  • MouseEventKind:鼠标事件类型
    • Down(MouseButton)
    • Up(MouseButton)
    • Drag(MouseButton)
    • Moved
    • ScrollDown,
    • ScrollUp
    • ScrollLeft
    • ScrollRigh

style

提供对文本应用属性和颜色的功能。常见结构体:

  • Attibutes:所有个能属性的bit集合。-Colors:用来表示前景和背景颜色。-ContentStyle:作用在内容上的风格。-Print:打印给定的可显示类型的命令。-PrintStyleContent:打印风格化内容的命令。-ResetColor:reset颜色为默认。-SetAttribute:设置属性集合。-SetAttributes:设置多属性集合。-SetBackgroundColor:设置背景颜色集合。-SetForegroundColor:设置外围颜色。-SetStyle:设置风格。-SetUnderlineColor:设置下划线颜色。
    枚举:

  • Attribute:代表属性。

  • Color:代表颜色。

  • Colored:代表前景或者背景颜色。ForegroundColorBackgroundColorUnderlineColor
    属性:

    Attribute Windows UNIX Notes
    Reset
    Bold
    Dim
    Italic ? ? Not widely supported, sometimes treated as inverse.
    Underlined
    SlowBlink ? ? Not widely supported, sometimes treated as inverse.
    RapidBlink ? ? Not widely supported. MS-DOS ANSI.SYS; 150+ per minute.
    Reverse
    Hidden Also known as Conceal.
    Fraktur Legible characters, but marked for deletion.
    DefaultForegroundColor ? ? Implementation specific (according to standard).
    DefaultBackgroundColor ? ? Implementation specific (according to standard).
    Framed ? ? Not widely supported.
    Encircled ? ? This should turn on the encircled attribute.
    OverLined ? ? This should draw a line at the top of the text.

    颜色:

    深色 浅色
    Light Dark
    DarkGrey Black
    Red DarkRed
    Green DarkGreen
    Yellow DarkYellow
    Blue DarkBlue
    Magenta DarkMagenta
    Cyan DarkCyan
    White Grey

终端模块

多数终端行为都可以使用命令执行。

屏幕缓冲区

屏幕缓冲区是一个用来在终端展示二维的特性和颜色数据数组。终端有不同的缓冲区可以相互切换,默认的工作屏幕为主屏幕,其他屏幕为可用屏幕。可用屏幕不同于主屏幕,它有明确的终端窗口维度,没有滚动区域。Crossterm提供了切换到可用屏幕、修改返回主屏幕的功能,在可用屏幕上执行命令的时候主屏幕保持完整。

Raw模式

有时候默认模式是不相关的,在这种情况下,我们可以关闭它。常见的默认模式开启的场景:

  • 输入不转发到屏幕。
  • 输入不在回车后处理。
  • 输入不是缓冲行行。
  • 特殊案件删除backspace和Ctrol+C将不由终端驱动处理。
  • 新行特性将不被println!处理使用write!替换。
    通过ternimal::enable_raw_mode和terminal::disable_raw_mode函数开启或者关闭。

Lazy执行

刷新字节到终端缓冲器是一个很重的系统调用。如果我们在终端中执行一些行为,我们想周期性的做这些工作,我们可以再同一时间刷新更多数据到缓冲区,Crossterm提供了queue做这个事情,你可以调用Write::flush执行写入。你可以传入一个自定义的实现了std::io::Write的buffer到队列操作中。命令在buffer中被执行,常见的buffer是std::io::stdout和std::io::stderr。队列函数返回的是他自己,你可以使用它调用另一个命令:stdout.queue(Goto(5,5)).queue(Clear(CLeareType::All))或者你可以使用队列宏queue!(stdout,MoveTo(5,5),Clear(ClearTyle::All))

直接执行

对多数应用程序来说,高效的刷新操作并不重要。在这个case下使用execute操作,这个操作将立即执行然后调用flush。你可以传递一个自定义的实现了std::io::Write的缓冲器执行execute操作。这个命令将在缓冲器执行。

ratatui

rataui常用的widget:

  • Axis:表格的x或者y轴。
  • Bar:BarChar的bar对象
  • BarChart:在单个widget上显示多个bar。
  • BarGroup:代表多个BarChart的组。
  • Borders:设置边界是否可见。
  • Cell:Cell包含在Table的行中用于展示的Text。
  • Chart:在笛卡尔坐标系下绘制一个或者更多的数据。
  • Clear:clear/reset一个确定的区域允许重写。
  • Dataset:一组数据点。
  • Gauge:任务进程状态展示widget。
  • LineGauge:单行展示的任务进度。
  • List:展示一些可以被选中的元素。
  • Paragraph:展示一些文本。
  • Block:带边界的widget块。
  • Tabs:在多个面板上下文展示可用的tab。

Axis常见属性和方法

  • title:设置title名称。
  • bounds:设置边界。
  • labels:设置label。
  • style:设置风格。
  • labels_alignment:定义标签对齐。

Block相关属性

设置外围边界线

  • Borders::LEFT:展示左边边界。

  • Borders::RIGHT:展示右边边界。

  • Border::ALL:展示包围边界。

  • Border::TOP:展示上边界。

  • Border::NONE:展示无边界。

  • Border::BOTTOM:展示下边界。

  • BorderType::Plain:展示普通边界。

  • BorderType::Double:展示双层边界。

  • BorderType::Rounded:展示圆角边界。

  • BorderType::Thick:展示细边界。

示意图:边界展示。设置风格示例:


terminal.draw(|f| {
        let size = f.size();
        let block = Block::default()
            .title("Block")
            .title_alignment(ratatui::prelude::Alignment::Center) //设置title居中对齐
            .borders(Borders::ALL) //打开边界线
            .border_type(BorderType::Rounded) //边界线周围为圆角
            .style(Style::default().bg(Color::Black).fg(Color::Yellow)); //设置block背景色为黑色,前景色为黄色
    })?;

block风格设置

Tabs常见属性和方法

  • block:设置block风格。
  • select:选中index。
  • style:设置风格。
  • highlight_style:设置高亮风格。
    示例代码:
        let tabs = Tabs::new(vec!["tab1", "tab2"]) //构建Tabs widgets
            .block(
                Block::default()
                    .borders(Borders::ALL)
                    .title("BlockTitle")
                    .title_alignment(ratatui::prelude::Alignment::Left),
            ) //设置包围block的风格,包括边界线,title和title位置
            .highlight_style(Style::default().fg(Color::Cyan).bg(Color::LightGreen)) // 设置tabs的默认前景色为Cyan,背景为LightGreen
            .select(0); //选中第一个tab
        f.render_widget(tabs, size);

Tabs风格设置

List常用函数

  • block:绘制边缘。
  • style:设置list风格。
  • highlight_style:设置高亮风格。
  • highlight_symbol:设置高亮符号。
  • repeat_hightlight_symbol:重复高亮风格。
  • start_corner:设置角起点。
  • len:List元素个数。
  • is_empty:List是否为空。

let items = [ListItem::new("Item1"), ListItem::new("Item2")];
        let lists = List::new(items)
            .block(
                Block::default()
                    .title("List title")
                    .borders(Borders::ALL)
                    .style(
                        Style::default()
                            .fg(Color::LightBlue)
                            .bg(Color::LightMagenta),
                    ),
            )
            .start_corner(Corner::BottomLeft)
            .highlight_style(Style::default().add_modifier(Modifier::BOLD))
            .highlight_symbol(">>");
        f.render_widget(lists, size);

List效果

Table

Table由Row组成,而Row由列表构造。Row中的每个单元称为Cell,Cell可以单独定义风格、颜色。整行也可以单独定义风格。

常用函数

  • block:设置表格边界
  • header:设置表头
  • style:设置表风格
  • highlight_symbol:
  • highlight_style:
  • highlight_spacing:
  • column_spacing:
  • ``
    实现:
let table = Table::new(vec![
            // Row can be created from simple strings.
            Row::new(vec!["Row11", "Row12", "Row13"]), //从列表构建行
            // You can style the entire row.
            Row::new(vec!["Row21", "Row22", "Row23"]).style(Style::default().fg(Color::Blue)),
            // If you need more control over the styling you may need to create Cells directly
            Row::new(vec![
                Cell::from("Row31"),
                Cell::from("Row32").style(Style::default().fg(Color::Yellow)),
                Cell::from(Line::from(vec![
                    Span::raw("Row"),
                    Span::styled("33", Style::default().fg(Color::Green)),
                ])),
            ]),
            // If a Row need to display some content over multiple lines, you just have to change
            // its height.
            Row::new(vec![
                Cell::from("Row\n41"),
                Cell::from("Row\n42"),
                Cell::from("Row\n43"),
            ])
            .height(2),
        ])
        // You can set the style of the entire Table.
        .style(Style::default().fg(Color::White))
        // It has an optional header, which is simply a Row always visible at the top.
        .header(
            Row::new(vec!["Col1", "Col2", "Col3"])
                .style(Style::default().fg(Color::Yellow).bg(Color::LightCyan))
                .bottom_margin(2), //设置表头和其他行之间的间距
        )
        // As any other widget, a Table can be wrapped in a Block.
        .block(
            Block::default()
                .title("Table")
                .borders(Borders::ALL)
                .style(Style::default().fg(Color::LightMagenta)),
        )
        // 设置列宽
        .widths(&[
            Constraint::Length(5), //超过列宽的字符将被截断
            Constraint::Length(5),
            Constraint::Length(7),
        ])
        // 设置列与列之间的间隔
        .column_spacing(5)
        // 当指定方法被选中后你希望强调一行
        .highlight_style(
            Style::default()
                .add_modifier(Modifier::BOLD)
                .fg(Color::LightRed),
        )
        // ...and potentially show a symbol in front of the selection.
        .highlight_symbol(">>");
        f.render_widget(table, size);

table风格设置

Paragraph

常见的方法:

  • block:设置Paragraph的包围风格。
  • style:设置Paragraph的风格。
  • wrap:对widget设置包围配置。
  • scroll:对给定的paragraph设置scroll偏移。
  • alignment:设置文本对齐方式。

Gauge

常见方法:

  • block:
  • percent:设置进度条所占百分比。数字20表示占据进度条20%。
  • ratio:设置进度条所占比例,0.5表示占据进度条一半的位置。
  • label:设置进度条中显示的文字。
  • style:设置外观风格。
  • gauge_style:设置进度条风格。
  • use_unicode:使用unicode编码。
    示例:
use crossterm::terminal::{
    disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use crossterm::{event, event::Event, event::KeyCode, execute, Command};
use ratatui::backend::CrosstermBackend;
use ratatui::prelude::{Color, Modifier, Style};
use ratatui::widgets::{Block, Borders, Gauge, Paragraph};
use ratatui::Terminal;
use std::error::Error;
use std::io::{self, Stdout};
use std::time::Duration;
fn main() -> Result<(), Box<dyn Error>> {
    let mut terminal = setup_terminal()?;
    run(&mut terminal)?;
    restore_terminal(&mut terminal)?;
    Ok(())
}

fn setup_terminal() -> Result<Terminal<CrosstermBackend<Stdout>>, Box<dyn Error>> {
    let mut stdout = io::stdout();
    enable_raw_mode()?;
    execute!(stdout, EnterAlternateScreen)?;
    Ok(Terminal::new(CrosstermBackend::new(stdout))?)
}

fn restore_terminal(
    terminal: &mut Terminal<CrosstermBackend<Stdout>>,
) -> Result<(), Box<dyn Error>> {
    disable_raw_mode()?;
    execute!(terminal.backend_mut(), LeaveAlternateScreen,)?;
    Ok(terminal.show_cursor()?)
}

fn run(terminal: &mut Terminal<CrosstermBackend<Stdout>>) -> Result<(), Box<dyn Error>> {
    let mut p = 20;
    Ok(loop {
        terminal.draw(|frame| {
            let g = Gauge::default()
                .block(
                    Block::default()
                        .title("Gauge Progress")
                        .borders(Borders::ALL),
                )
                .gauge_style(
                    Style::default()
                        .fg(Color::Gray)
                        .bg(Color::LightRed)
                        .add_modifier(Modifier::ITALIC),
                )
                .percent(p)
                .label("Gauge Bar 0x22489")
                .use_unicode(true);
            frame.render_widget(g, frame.size());
        })?;
        if event::poll(Duration::from_millis(250))? {
            if let Event::Key(key) = event::read()? {
                if KeyCode::Char('q') == key.code {
                    break;
                } else if KeyCode::Left == key.code {
                    p = (p - 1) % 100;
                } else if KeyCode::Right == key.code {
                    p = (p + 1) % 100;
                } else {
                }
            }
        }
    })
}

gauge展示效果


   转载规则


《Rust三方库(ratatui)》 bleedingfight 采用 知识共享署名 4.0 国际许可协议 进行许可。
 本篇
Rust三方库(ratatui) Rust三方库(ratatui)
TUI库开始TUI库之前我们先介绍下常用的跨平台终端操作库crossterm。其中常见的模块有四个: cursor:为终端中的光标提供各种功能。 event:给键盘、鼠标、resize终端提供事件, style:给输入提供颜色等等属性。
2023-09-24
下一篇 
Rust三方库(并发) Rust三方库(并发)
threadRust中的执行的程序由操作系统原生线程组成,每个线程由自己的栈和本地状态。线程可以命名、提供一些低级的同步支持。线程之间的通信可以通过channels完成。rust的传入的类型、其它形式的线程同步、共享内存数据结构。线程之间的
  目录