#tui #default #user-interface #terminal #layout #dashboard #back-end

gradient_tui_fork

这是一个分支,请使用官方仓库

1 个不稳定版本

0.19.0 2023年2月25日

#870命令行界面


2 crates 中使用

MIT 许可证

400KB
12K SLoC

这是一个分支,请使用官方仓库


lib.rs:

tui 是一个用于构建丰富终端用户界面和仪表板的库。

入门

tui 添加为依赖项

[dependencies]
tui = "0.19"
crossterm = "0.25"

默认情况下,该crate使用 crossterm 后端,该后端在大多数平台上运行。但如果你例如想使用 termion 后端,可以通过更改你的依赖项规范来实现

[dependencies]
termion = "1.5"
tui = { version = "0.19", default-features = false, features = ['termion'] }

相同的逻辑适用于所有其他可用的后端。

创建一个 Terminal

使用 tui 的每个应用程序都应该通过实例化一个 Terminal 开始。它是一个轻量级的后端抽象,提供了诸如清屏、隐藏光标等基本功能。

use std::io;
use tui::{backend::CrosstermBackend, Terminal};

fn main() -> Result<(), io::Error> {
    let stdout = io::stdout();
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;
    Ok(())
}

如果你之前选择了 termion 作为后端,终端可以以类似的方式创建

use std::io;
use tui::{backend::TermionBackend, Terminal};
use termion::raw::IntoRawMode;

fn main() -> Result<(), io::Error> {
    let stdout = io::stdout().into_raw_mode()?;
    let backend = TermionBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;
    Ok(())
}

你也可以参考示例来了解如何为每个可用的后端创建一个 Terminal

构建用户界面 (UI)

你的界面中的每个组件都将实现 Widget 特性。该库提供了一系列预定义的组件,可以满足大多数用例。你也可以自由实现自己的。

每个组件都遵循一个 builder 模式 API,提供默认配置以及自定义它们的函数。然后使用 Frame::render_widget 将组件渲染到指定的区域。

以下示例渲染了一个与终端大小相同的块

use std::{io, thread, time::Duration};
use tui::{
    backend::CrosstermBackend,
    widgets::{Widget, Block, Borders},
    layout::{Layout, Constraint, Direction},
    Terminal
};
use crossterm::{
    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};

fn main() -> Result<(), io::Error> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    terminal.draw(|f| {
        let size = f.size();
        let block = Block::default()
            .title("Block")
            .borders(Borders::ALL);
        f.render_widget(block, size);
    })?;

    thread::sleep(Duration::from_millis(5000));

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    Ok(())
}

布局

该库提供了一个基本但有用的布局管理对象,称为 Layout。正如你下面和示例中看到的,该库大量使用 builder 模式来提供完全自定义。而且 Layout 也不例外。

use tui::{
    backend::Backend,
    layout::{Constraint, Direction, Layout},
    widgets::{Block, Borders},
    Frame,
};
fn ui<B: Backend>(f: &mut Frame<B>) {
   let chunks = Layout::default()
        .direction(Direction::Vertical)
        .margin(1)
        .constraints(
            [
                Constraint::Percentage(10),
                Constraint::Percentage(80),
                Constraint::Percentage(10)
            ].as_ref()
        )
        .split(f.size());
    let block = Block::default()
         .title("Block")
         .borders(Borders::ALL);
    f.render_widget(block, chunks[0]);
    let block = Block::default()
         .title("Block 2")
         .borders(Borders::ALL);
    f.render_widget(block, chunks[1]);
}

这允许您通过嵌套布局来描述响应式终端UI。请注意,默认情况下,计算出的布局会尝试完全填充可用空间。因此,如果您可能在某处需要空白空间,请尝试传递额外的约束,并不要使用相应的区域。

依赖项

~2–11MB
~97K SLoC