ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

GPUI Kit 快速上手指南:用 Rust 与 GPUI 构建跨平台桌面应用

GPUI Kit 快速上手指南:用 Rust 与 GPUI 构建跨平台桌面应用 GPUI Kit 快速上手指南用 Rust 与 GPUI 构建跨平台桌面应用【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kitGPUI Kit 是围绕 Zed 团队 GPUI 渲染框架构建的 Rust 桌面应用 UI 体系通过gpui-kit单一 crate 聚合 GPUI、gpui-base无样式的行为、状态与基础设施层与gpui-component完整的有样式组件库。本文是官方《Getting Started》的展开版你将学会如何配置Cargo.toml、按需裁剪特性、从零启动一个带主题与组件的窗口理解无状态元素与有状态组件的正确用法并掌握Root窗口根视图、主题、尺寸、视觉变体与图标系统的底层原理。安装与依赖配置在Cargo.toml中添加两个依赖即可开始[dependencies] gpui-kit 0.6 anyhow 1.0其中anyhow用于错误处理gpui-kit是唯一的 UI 依赖。当前仓库中gpui-kit的版本为 0.6.1见 crates/kit/Cargo.toml。单依赖架构一个 crate 重导出整个生态gpui-kit的设计目标是“一个 crate 依赖即可”它在根模块中把底层各 crate 统一重导出见 crates/kit/src/lib.rs因此你的代码只需要use gpui_kit::*;就能拿到 GPUI 的全部 API路径底层 crate对应 featuregpui_kit::*gpui始终启用gpui_kit::platformgpui_platform始终启用gpui_kit::basegpui-base始终启用gpui_kit::componentgpui-componentcomponent默认开启gpui_kit::assetsgpui-kit-assetsassets默认开启gpui_kit::init(cx)会根据启用的特性自动初始化对应层级启用component时调用gpui_component::init它同时初始化gpui-base否则退回gpui_base::init见 crates/kit/src/lib.rs。按需裁剪特性只保留你需要的层gpui-kit默认开启component组件库与assets默认图标集两个特性同时必然引入 GPUI 与gpui-base。如果你的应用需要自己管理资源、或只想用底层行为层可以关掉默认特性gpui-kit { version 0.6, default-features false, features [component] }gpui-kit还透传了gpui-component的全部可选特性包括inspector、decimal、tree-sitter以及各语言高亮特性tree-sitter-rust、tree-sitter-python等数十个完整清单见 crates/kit/Cargo.toml。例如启用代码编辑器能力gpui-kit { version 0.6, default-features false, features [component, assets, tree-sitter] }图标与自定义资源的完整说明见 Icons Assets。快速开始构建第一个窗口下面是一个完整的可运行示例该示例同时存在于仓库的 examples/hello_world/src/main.rsuse gpui_kit::component::button::*; use gpui_kit::component::*; use gpui_kit::*; pub struct HelloWorld; impl Render for HelloWorld { fn render(mut self, _: mut Window, _: mut ContextSelf) - impl IntoElement { div() .v_flex() .gap_2() .size_full() .items_center() .justify_center() .child(Hello, World!) .child( Button::new(ok) .primary() .label(Lets Go!) .on_click(|_, _, _| println!(Clicked!)), ) } } fn main() { let app gpui_kit::application().with_assets(gpui_kit::assets::Assets); app.run(move |cx| { // This must be called before using any GPUI Component features. gpui_kit::init(cx); cx.spawn(async move |cx| { cx.open_window(WindowOptions::default(), |window, cx| { let view cx.new(|_| HelloWorld); // This first level on the window, should be a Root. cx.new(|cx| Root::new(view, window, cx)) }) .expect(Failed to open window); }) .detach(); }); }这段代码演示了 GPUI Kit 应用的固定启动骨架四步缺一不可注册资源源gpui_kit::application().with_assets(gpui_kit::assets::Assets)将默认图标资源注册进应用。Assets内嵌了gpui-component所需的 101 个基础组件图标清单见 crates/assets/default-icons.txt。初始化系统app.run闭包的第一行必须是gpui_kit::init(cx);。它负责注册主题系统、全局状态、Root的按键绑定Tab/Shift-Tab 焦点循环、Cmd/Ctrl-C 复制、输入法、日期选择器、Dock、Sheet、列表、命令面板、通知、弹出层、菜单、表格、Tooltip 等模块的初始化逻辑见 crates/component/src/lib.rs。跳过它会导致主题与全局设置失效。打开窗口在cx.spawn的异步任务里调用cx.open_window创建窗口。包裹 Rootcx.new(|cx| Root::new(view, window, cx))—— 窗口的第一层视图必须是Root。为什么窗口第一层必须是 RootRoot是 GPUI Kit 窗口的顶层视图见 crates/component/src/root.rs它的职责远不止承载你的视图管理弹层内部持有active_sheet、active_dialogs、notification通知列表、tooltip_overlay与native_menu_overlay是 Dialog、Sheet、Notification 等浮层的唯一宿主。注入全局上下文在渲染时设置窗口rem字号window.set_rem_size(cx.theme().font_size)、激活文本选区作用域、绑定key_context(Root)下的按键动作、应用主题背景色与字体见 crates/component/src/root.rs。Linux 客户端装饰默认启用window_border包装可通过.bordered(false)关闭见 crates/component/src/root.rs。因此任何要用到 Dialog、Sheet 或通知的应用都需要让应用内容在渲染时挂载Root::render_dialog_layer、Root::render_sheet_layer、Root::render_notification_layer三个图层下文“有状态组件”一节有完整示例。基本概念无状态元素GPUI Kit 的组件大多是无状态Stateless元素它们实现 GPUI 的RenderOncetrait、是IntoElement类型状态完全由视图层持有因此简单、可预测。用法就是在render里直接构造并组合struct MyView; impl Render for MyView { fn render(mut self, _: mut Window, cx: mut ContextSelf) - impl IntoElement { div() .child(Button::new(btn).label(Click Me)) .child(Tag::secondary().child(Secondary)) } }Button 正是这样的设计它内部委托gpui_base::Button处理交互行为gpui_component::Button只负责外观与主题见 crates/component/src/button/button.rs印证了 README 中“行为属于基础层表现属于应用层”的分层原则。有状态组件Input、List、DataTable 等控件使用保留状态的实体retained state entities。正确做法是把状态实体创建一次在render之外存到持有它的视图上渲染时再从实体构造样式化元素。完整的可参考实现是仓库中的 tested application recipe examples/ai_recipes/src/lib.rs它包含保留订阅、图标与浮层图层的完整窗口。下面是一个典型设置页use gpui_kit::component::{ ActiveTheme, IconName, Root, WindowExt, button::Button, checkbox::Checkbox, form::{Field, Form}, input::{Input, InputEvent, InputState}, radio::RadioGroup, switch::Switch, }; use gpui_kit::{ AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render, SharedString, Styled as _, Subscription, Window, div, }; pub struct Settings { pub name: EntityInputState, pub preview: SharedString, pub changes: usize, enabled: bool, remember: bool, delivery: Optionusize, _subscriptions: VecSubscription, } impl Settings { pub fn new(window: mut Window, cx: mut ContextSelf) - Self { let name cx.new(|cx| InputState::new(window, cx).placeholder(Name)); let subscription cx.subscribe_in(name, window, |this, state, event, _, cx| { if matches!(event, InputEvent::Change) { this.preview state.read(cx).value().to_string().into(); this.changes 1; cx.notify(); } }); Self { name, preview: .into(), changes: 0, enabled: false, remember: false, delivery: Some(0), _subscriptions: vec![subscription], } } } impl Render for Settings { fn render(mut self, window: mut Window, cx: mut ContextSelf) - impl IntoElement { div() .flex() .flex_col() .size_full() .p_4() .gap_3() .bg(cx.theme().background) .text_color(cx.theme().foreground) .child(Profile) .child( Form::new() .child(Field::new().label(Name).child(Input::new(self.name))) .child(Field::new().label(Preview).child(self.preview.clone())) .child( Field::new().label_indent(false).child( Checkbox::new(remember) .label(Remember name) .checked(self.remember) .on_change(cx.listener(|this, value, _, cx| { this.remember *value; cx.notify(); })), ), ) .child( Field::new().label_indent(false).child( Switch::new(enabled) .label(Enable notifications) .checked(self.enabled) .on_change(cx.listener(|this, value, _, cx| { this.enabled *value; cx.notify(); })), ), ) .child( Field::new().label(Delivery).child( RadioGroup::new(delivery) .children([Immediately, Daily summary]) .selected_index(self.delivery) .on_change(cx.listener(|this, value, _, cx| { this.delivery Some(*value); cx.notify(); })), ), ) .footer( Button::new(about) .label(About…) .icon(IconName::Info) .on_click(|_, window, cx| { window.open_dialog(cx, |dialog, _, _| { dialog.title(About).child(A complete GPUI Kit window) }); }), ), ) .children(Root::render_dialog_layer(window, cx)) .children(Root::render_sheet_layer(window, cx)) .children(Root::render_notification_layer(window, cx)) } }几个值得注意的实现细节状态实体的生命周期InputState通过cx.new创建并存入视图字段cx.subscribe_in订阅其事件事件回调里更新preview/changes后调用cx.notify()触发重绘。_subscriptions字段负责在视图销毁时自动取消订阅。受控组件模式Checkbox、Switch、RadioGroup 都是受控的——checked/selected_index读自视图字段on_change回调写回字段并cx.notify()。这正是“状态在视图层而不在组件内部”的体现。浮层层必须显式渲染Root::render_dialog_layer、Root::render_sheet_layer、Root::render_notification_layer必须挂在应用内容里Dialog/Sheet/Notification 才能真正显示。这三个方法从窗口的Root视图读取活动弹层并渲染见 crates/component/src/root.rs。window.open_dialog是WindowExttrait 提供的便捷方法底层调用Root::open_dialog管理焦点链与文本选区作用域见 crates/component/src/root.rs。主题系统所有组件都通过内置Theme系统支持主题化通过ActiveThemetrait 在任意上下文中访问语义色use gpui_kit::component::{ActiveTheme, Theme}; // Access theme colors in your components cx.theme().primary cx.theme().background cx.theme().foregroundcx.theme()返回当前主题令牌背景、前景、主色等语义色会随明暗主题自动切换。仓库在 themes 目录内置了 20 余套主题 JSON如tokyonight.json、gruvbox.json、solarized.json等主题令牌的定义见 crates/component/src/theme_tokens.rsgpui-base 侧与 crates/component/src/theme.rs。组件尺寸多数组件支持多种尺寸。以 Button 为例尺寸方法由Sizabletrait 提供默认值为Size::Medium见 crates/component/src/button/button.rsButton::new(btn).small() Button::new(btn).medium() // default Button::new(btn).large() Button::new(btn).xsmall()视觉变体组件提供不同的视觉变体。Button 的变体由ButtonVariantstrait 与ButtonVariant枚举定义见 crates/component/src/button/button.rs 与 crates/component/src/button/button.rs除文档列出的五种外还有更多选择Button::new(btn).primary() Button::new(btn).danger() Button::new(btn).warning() Button::new(btn).success() Button::new(btn).ghost() Button::new(btn).outline()从源码看变体家族还包括secondary、info、link、text以及通过ButtonCustomVariant自定义颜色的custom(...)outline则是 Button 上的独立样式开关见 crates/component/src/button/button.rs。不同组件共享同一套变体语义如Tag::secondary()保持了整个界面的视觉一致性。图标系统GPUI Kit 的Icon元素与IconName枚举提供了一整套图标能力但图标 SVG 默认不随gpui-component打包以保持库的轻量。默认的assetsfeature 会引入gpui-kit-assets其中内嵌了组件所需的 101 个基础图标清单见 crates/assets/default-icons.txt完整目录则有 1,830 个 Lucide 风格 SVG位于 crates/assets/assets/icons。示例中使用的是 Lucide 风格图标你可以按IconName的命名规则放置任意 SVG 文件把需要的图标加入自己的资源源use gpui_kit::component::{Icon, IconName}; Icon::new(IconName::Check) Icon::new(IconName::Search).small()IconName本身实现了RenderOnce可以直接作为子元素渲染见 crates/assets/src/icon.rs。如果要完全自管资源、精简二进制体积参考 Icons Assets 中的自定义AssetSource方案用rust-embed嵌入自己的 SVGload/list时先查自身再回退到默认Assets并用with_assets注册。对于少量自定义图标还可以用Icon::data直接内嵌 SVG 字节跳过资源路径查找。开发与示例运行运行组件画廊仓库的storycrate 是一个展示全部组件的画廊应用在工作区根目录运行cargo run运行独立示例examples目录下每个示例都是一个独立 crate可通过cargo run -p name或cargo run --example example_name运行例如# Dock 布局系统面板、分屏、标签页 cargo run -p example-dock # Markdown 渲染 cargo run -p example-markdown # HTML 渲染 cargo run -p example-html # 带 LSP 与语法高亮的代码编辑器 cargo run -p example-editor # 本指南的 Hello World cargo run -p hello_world # 实时 CPU/内存图表系统监控器 cargo run -p system_monitor # 窗口标题自定义 cargo run -p window_title最值得通读的是 examples/ai_recipes——它是一份经过测试的可执行应用配方涵盖了本指南的全部要点Root包裹、状态实体、订阅、图标、浮层层并附带 AI 辅助开发的验收检查命令。下一步组件文档可以帮你深入每个控件的用法Button - 可交互按钮组件Input - 带校验的文本输入Dialog - 对话框与模态窗口DataTable - 高性能数据表格更多组件…若想理解三层架构gpui-component/gpui-base/gpui-shell的划分依据可阅读 docs/ARCHITECTURE.md项目全貌见 README.md。【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表