gpui 2
在上一篇文章中,我们创建了一个空白窗口,没有展示任何内容。今天,我们将在这个窗口中显示一个“HelloWorld”。
通过上一篇文章的介绍,我们了解到需要实现一个 Render 的 Trait 才能绘制内容。
我们先给出完整的代码,随后逐步解析:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
use gpui::{
App, Application, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions, div,
prelude::*, px, rgb, size,
};
struct HelloWorld {
text: SharedString,
}
impl Render for HelloWorld {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.flex()
.gap_3()
.bg(rgb(0x505050))
.size(px(500.0))
.justify_center()
.items_center()
.shadow_lg()
.border_1()
.border_color(rgb(0x0000ff))
.text_xl()
.text_color(rgb(0xffffff))
.size_full()
.child(format!("Hello, {}!", &self.text))
}
}
fn main() {
Application::new().run(|cx: &mut App| {
let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx);
cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|_, cx| {
cx.new(|_| HelloWorld {
text: "World".into(),
})
},
)
.unwrap();
cx.activate(true);
});
}
这里我们使用 Bounds 来定义窗口的显示尺寸,并通过 App::new 创建一个 Entity
从示例代码中可以看出,Div 是 GPUI 中的一个基础元素,可用于构建复杂的页面结构。同时,由于 GPUI 的布局设计受到 Tailwind 的启发,其样式和布局方法的命名与 Tailwind 保持一致,便于开发者快速上手和使用。
在 render 函数中使用的许多链式函数与 Tailwind CSS 的类名风格相似,以下是对其中几个关键函数的逐一解析:
flex
Flexbox(弹性盒子布局模型)是 CSS3 中引入的一种强大的布局方式。其核心目标是让容器(Flex container)能够动态且可预测地调整其子元素(Flex items)的大小、顺序和对齐方式,以充分利用可用空间——即使这些子元素的尺寸是未知的或动态变化的。bg
该函数用于设置元素的背景颜色。size
用于设置元素的尺寸。justify_center
在 Flex 布局中,将子元素沿主轴(main axis)居中对齐。items_center
在 Flex 布局中,将子元素沿交叉轴(cross axis,即与主轴垂直的轴)居中对齐。shadow_lg
为元素添加较大的阴影效果。border_1
设置元素的边框宽度为 1 像素。border_color
设置元素的边框颜色。text_xl
将文字大小设置为 extra large(较大尺寸)。text_color
设置文字的颜色。size_full
使元素尺寸占满可用空间。child(format!(“Hello, {}!”, &self.text))
child函数用于向当前元素添加一个子节点,类似于 HTML 中的子元素结构。
此处使用format!宏生成一个字符串。虽然child函数的参数需实现IntoElementtrait,但String类型已实现了该 trait,因此可直接使用。相关实现可在 Zed 源码中找到:
1
2
3
4
5
6
7
8
// zed/crates/gpui/src/elements/text.rs
impl IntoElement for String {
type Element = SharedString;
fn into_element(self) -> Self::Element {
self.into()
}
}