用Rust進行TUI編程:Cursive庫
在本文中,我們將探索使用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! 按<q>退出."));
// 執行Cursive對象
siv.run();
}
運行此程序將顯示“Hello TUI!”,按<q>鍵退出。
對話框
對話框通常用于在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 <Next> 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開發。