在本文中,我们将探索使用Rust进行文本用户界面(TUI)编程。TUI提供了一种通用的方法来创建具有丰富图形用户界面的交互式命令行应用程序。我们将使用Cursive库,一个流行的用于构建TUI应用程序的Rust库。
Cursive使用声明式UI:用户定义布局,然后Cursive处理事件循环。Cursive还处理大多数输入(包括鼠标点击),并将事件转发到当前聚焦的视图。用户代码更关注“事件”,而不是键盘输入。
它非常适合更复杂的应用程序,具有嵌套的视图树、菜单和弹出窗口。
图片
创建项目
使用以下命令创建一个Rust新项目:
cargo new cursive_example
然后,将Cursive添加到Cargo.toml文件中:
[dependencies]
cursive = "0.20.0"
Cursive应用程序的基本结构
一个典型的Cursive应用程序主要包括三个阶段:
1,创建一个Cursive对象:我们从创建一个Cursive对象开始。cursive::default()方法可以帮助我们完成这项任务。
2,配置Cursive对象:在创建了Cursive对象之后,我们根据应用程序的需要对它进行配置。
3,执行Cursive Object:最后,我们运行Cursive对象来启动应用程序。
下面是一个最简单的Cursive应用:
fn main() {
// 创建一个Cursive对象
let mut siv = cursive::default();
// 执行Cursive对象
siv.run();
}
运行这个程序,你会看到一个空白的应用程序窗口。
图片
增加退出应用程序的方式
Cursive将用户输入作为事件处理,默认情况下,许多事件被忽略。为了允许用户通过按' q '退出应用程序,我们可以在根Cursive对象上使用add_global_callback方法:
siv.add_global_callback('q', |s| s.quit());
此代码片段添加了一个全局回调,该回调监听' q '键并在触发时退出应用程序。
Cursive视图
视图是Cursive应用程序中用户界面的核心构建块,它们定义在终端上显示的内容。视图可以是简单的元素,比如文本,也可以是复杂的小部件,比如复选框。
要显示文本消息,我们可以使用TextView::new("text")构造函数。最初,屏幕是空的,所以我们需要使用add_layer创建一个层。add_layer的参数应该是我们想要作为新图层显示的视图。
下面是一个显示“Hello TUI!”消息,并允许用户通过按' q '退出应用程序:
use cursive::views::TextView;
fn main() {
// 创建一个Cursive对象
let mut siv = cursive::default();
// 添加一个全局回调,当按下'q'时退出应用程序
siv.add_global_callback('q', |s| s.quit());
// 添加一个TextView与我们的消息作为一个新的图层
siv.add_layer(TextView::new("Hello TUI! 按退出."));
// 执行Cursive对象
siv.run();
}
运行此程序将显示“Hello TUI!”,按键退出。
对话框
对话框通常用于在TUI应用程序中创建交互式的和用户友好的基于文本的弹出窗口。它们允许你向用户呈现信息,并通过按钮和回调收集输入,从而增强用户体验。
让我们使用对话框,这是一个封装器,封装另一个视图,包括标题和选择按钮。而不是直接使用TextView。
Dialog::around函数直接接受一个视图,所以我们可以直接提供TextView:
siv.add_layer(Dialog::around(TextView::new("Question 1")));
由于在文本视图中创建对话框窗口是一个常见的任务,dialog::text是一个可以直接完成此任务的函数,使我们的代码更短(并且我们不再需要导入cursive::views::TextView)。
siv.add_layer(Dialog::text("Empty"));
我们可以使用Dialog::title方法添加标题。
use cursive::views::{TextView, Dialog};
fn main() {
// 创建一个Cursive对象
let mut siv = cursive::default();
// 添加一个全局回调,当按下'q'时退出应用程序
siv.add_global_callback('q', |s| s.quit());
siv.add_layer(Dialog::text("did you do the thing?").title("This is the title"));
// 执行Cursive对象
siv.run();
}
如果我们运行这段代码,我们将看到一个没有按钮的对话框窗口。
图片
按钮
我们的对话框看起来比单独的TextView要好,但它仍然缺少一些动作。我们来添加一些按钮。
就像标题一样,Dialog有一个Dialog::button方法,用于添加带有关联动作的按钮。下面是如何使用Dialog::button添加按钮:
use cursive::views::{TextView, Dialog};
fn main() {
// 创建一个Cursive对象
let mut siv = cursive::default();
siv.add_layer(Dialog::text("...").title("Did you do the thing?")
.button("Yes", |s| s.quit())
.button("No", |s| s.quit())
.button("Uh?", |s| s.quit()));
// 执行Cursive对象
siv.run();
}
在这个例子中,对话框包括三个按钮:“是”、“否”和“Uh?”,当点击时,它们都有退出程序的动作。但是,你可以通过使用自定义函数替换“|s| s.quit()”来定制操作。
运行结果如下:
图片
让我们在一个更实际的背景下探讨这个问题:
use cursive::Cursive;
use cursive::views::Dialog;
fn main() {
let mut siv = cursive::default();
siv.add_layer(Dialog::text("This is a survey!\nPress when you're ready.")
.title("Important survey")
.button("Next", show_next));
siv.run();
}
fn show_next(_: &mut Cursive) {
// Leave this function empty for now
}
在这段代码中,在用户单击“Next”之后,我们希望隐藏当前对话框并显示一个新对话框。我们使用Cursive::pop_layer来移除当前图层。
为了更好地理解pop_layer是如何工作的,让我们分解这个过程:
use cursive::views::Dialog;
use cursive::views::TextView;
use cursive::Cursive;
fn main() {
// 创建一个新的Cursive实例
let mut siv = cursive::default();
// 添加一个带有标题、文本和按钮的对话框图层。
siv.add_layer(
Dialog::text("Are you of legal age?")
.title("Question 1")
// 添加一个带有Yes回调函数的按钮
.button("Yes", yes)
// 添加一个带有回调No函数的按钮。
.button("No", no),
);
siv.run(); // Start the Cursive event loop.
}
fn yes(s: &mut Cursive) {
// 移除当前对话框层
s.pop_layer();
// 添加一个带有消息的TextView图层
s.add_layer(TextView::new("Good! You can proceed."));
}
fn no(s: &mut Cursive) {
// 移除当前对话框层
s.pop_layer();
// 添加一个带有消息的TextView图层
s.add_layer(TextView::new("You can't proceed!"));
}
正如你所看到的,Dialog视图是呈现TextView的一种很好的方式,但它也适用于任何其他内容。实际上,大多数的图层都是以一个包含其他视图的对话框开始。
总结
本文为使用Rust和Cursive库构建基于文本的用户界面(TUI)提供了坚实的起点。在此基础上,你可以浏览文档并深入研究更高级的TUI开发。