文章

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 对象,该对象即为 HelloWorld 结构体的实例。需要注意的是,HelloWorld 结构体实现了 Render trait,在该 trait 中需实现一个 render 函数。

从示例代码中可以看出,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 函数的参数需实现 IntoElement trait,但 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()
    }
}
本文由作者按照 CC BY 4.0 进行授权