Druid框架入门指南:构建你的第一个Rust GUI应用
druid A data-first Rust-native UI design toolkit. 项目地址: https://gitcode.com/gh_mirrors/drui/druid
前言
Druid是一个基于Rust语言的现代化GUI框架,专注于数据驱动的用户界面开发。本文将带你从零开始构建一个简单的待办事项应用,逐步了解Druid的核心概念和使用方法。
环境准备
Linux系统依赖
在Linux系统上,Druid需要GTK+3作为底层图形支持。根据不同的发行版,安装方式略有不同:
Ubuntu/Debian系列:
sudo apt-get install libgtk-3-dev
Fedora/RHEL系列:
sudo dnf install gtk3-devel glib2-devel
OpenBSD系统依赖
在OpenBSD上同样需要安装GTK+3:
pkg_add gtk+3
创建新项目
使用Cargo创建一个新的二进制项目并添加Druid依赖:
cargo new my-druid-app
cd my-druid-app
cargo add druid
项目结构如下:
.
├── Cargo.lock
├── Cargo.toml
└── src
└── main.rs
第一个窗口程序
让我们从最简单的窗口开始,创建一个显示"Hello World"标签的窗口:
use druid::widget::Label;
use druid::{AppLauncher, LocalizedString, PlatformError, Widget, WidgetExt, WindowDesc};
fn build_ui() -> impl Widget<()> {
Label::new("Hello World").center()
}
fn main() -> Result<(), PlatformError> {
let main_window = WindowDesc::new(build_ui)
.title(LocalizedString::new("hello-demo-window-title").with_placeholder("Hello World"));
AppLauncher::with_window(main_window).launch(())?;
Ok(())
}
这段代码展示了Druid的基本结构:
- 创建
WindowDesc
描述窗口属性 - 使用
build_ui
函数构建界面组件树 - 通过
AppLauncher
启动应用
构建更复杂的界面
容器组件布局
Druid使用容器组件来组织界面布局。让我们创建一个简单的待办事项应用框架:
use druid::widget::{Container, Flex, Split};
use druid::Widget;
fn build_ui() -> impl Widget<()> {
let split = Split::columns(
Container::new(Label::new("待办事项列表").center()).border(),
Container::new(Label::new("操作区域").center()).border(),
);
Flex::column().with_child(split)
}
这里使用了:
Split
:分割面板组件Flex
:弹性布局容器Container
:带边框的容器组件
数据驱动界面
Druid的核心是数据驱动UI。让我们定义待办事项的数据结构:
use im::Vector;
use druid::Data;
type TodoList = Vector<String>;
fn build_ui() -> impl Widget<TodoList> {
// 使用动态标签显示数据
Label::dynamic(|data: &TodoList, _| {
format!("共有{}个待办事项", data.len())
})
}
添加交互功能
为待办事项添加按钮和文本框:
use druid::widget::{Button, TextBox};
use druid::Lens;
#[derive(Clone, Data, Lens)]
struct AppState {
items: Vector<String>,
next_item: String,
}
fn build_ui() -> impl Widget<AppState> {
let list = List::new(|| {
Label::dynamic(|item: &String, _| item.clone())
}).lens(AppState::items);
let textbox = TextBox::new().lens(AppState::next_item);
let button = Button::new("添加").on_click(|_ctx, data: &mut AppState, _env| {
data.items.push_back(data.next_item.clone());
data.next_item.clear();
});
Flex::column()
.with_child(list)
.with_child(Flex::row().with_child(textbox).with_child(button))
}
完整示例代码
将以上所有部分组合起来,我们得到一个完整的待办事项应用:
use druid::{
AppLauncher, Data, Lens, LocalizedString, PlatformError, Widget, WidgetExt, WindowDesc
};
use druid::widget::{Button, Flex, Label, List, Split, TextBox};
use im::Vector;
#[derive(Clone, Data, Lens)]
struct AppState {
items: Vector<String>,
next_item: String,
}
fn build_ui() -> impl Widget<AppState> {
let list = List::new(|| {
Label::dynamic(|item: &String, _| item.clone())
}).lens(AppState::items);
let textbox = TextBox::new().lens(AppState::next_item);
let button = Button::new("添加").on_click(|_ctx, data: &mut AppState, _env| {
data.items.push_back(data.next_item.clone());
data.next_item.clear();
});
let input_area = Flex::row()
.with_child(textbox)
.with_child(button);
let split = Split::columns(list, input_area);
Flex::column().with_child(split)
}
fn main() -> Result<(), PlatformError> {
let main_window = WindowDesc::new(build_ui)
.title(LocalizedString::new("todo-demo").with_placeholder("待办事项"));
let initial_state = AppState {
items: Vector::new(),
next_item: String::new(),
};
AppLauncher::with_window(main_window)
.launch(initial_state)?;
Ok(())
}
关键概念总结
- 数据驱动:UI组件通过
Data
trait与数据绑定 - 组件树:界面由组件树构成,容器组件管理布局
- Lens机制:通过
Lens
访问数据结构中的特定字段 - 响应式更新:数据变更自动触发UI更新
通过这个简单的待办事项应用,你已经掌握了Druid的基本使用方法。下一步可以探索更复杂的组件和自定义绘制功能,构建更丰富的GUI应用。
druid A data-first Rust-native UI design toolkit. 项目地址: https://gitcode.com/gh_mirrors/drui/druid
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考