4. 第一个Slint应用
本章的目标不是“看懂一段示例代码”,而是完整走通一条最小可用链路:创建工程、理解 .slint 文件结构、在桌面端运行与预览、最后把同一个应用交叉编译并部署到嵌入式 Linux 或 RTOS 目标板。走通这条链路后,后续所有复杂界面都可以视为在它之上的增量扩展。
4.1 核心原理:Slint 应用的三层结构
一个 Slint 工程在运行时由三层协作构成:宿主程序负责启动事件循环、加载界面、连接业务逻辑;.slint 界面文件用声明式语法描述组件树、属性、回调与状态;平台后端负责把渲染结果输出到窗口系统或嵌入式显示设备。理解这三层的边界,是排查“界面不显示”“点击无响应”“目标板黑屏”等问题的前提。
4.2 方法流程:创建、运行、预览、部署
推荐使用官方模板快速起步,避免手工拼装构建脚本带来的版本错配。以 Rust 宿主为例,标准流程如下:
# 1. 安装 Slint 模板工具
cargo install cargo-generate
# 2. 基于模板创建工程
cargo generate --git https://github.com/slint-ui/slint-rust-template.git \
--name hello-slint
# 3. 进入工程并运行桌面预览
cd hello-slint
cargo run
# 4. 使用实时预览工具,边改 .slint 边看效果
cargo install slint-viewer
slint-viewer ui/app-window.slint
桌面端跑通后,再进入交叉编译阶段。嵌入式 Linux 目标板通常需要指定目标三元组,并选择与设备匹配的渲染后端:
# 以 ARM64 嵌入式 Linux 为例
rustup target add aarch64-unknown-linux-gnu
# 指定后端为 linuxkms(无桌面环境,直接走 DRM/KMS)
SLINT_BACKEND=linuxkms \
cargo build --release --target aarch64-unknown-linux-gnu
# 将产物与资源拷贝到目标板
scp target/aarch64-unknown-linux-gnu/release/hello-slint root@192.168.1.50:/opt/app/
ssh root@192.168.1.50 "/opt/app/hello-slint"
若目标板没有 GPU 或 DRM 驱动,可改用
SLINT_BACKEND=linuxfb 走 Framebuffer;若运行在 RTOS 上,则需使用 Slint 的 C++ 或 Rust no_std 集成方式,由 RTOS 提供帧缓冲与输入事件。4.3 案例:Hello World 的 .slint 文件逐段解读
下面是一个最小但结构完整的界面文件,它同时覆盖了导入、组件、属性、回调与布局五类要素:
import { Button, VerticalBox } from "std-widgets.slint";
export component AppWindow inherits Window {
title: "Hello Slint";
width: 320px;
height: 200px;
in-out property <int> counter: 0;
callback reset-clicked();
VerticalBox {
alignment: center;
Text {
text: "Hello, Slint!";
font-size: 22px;
horizontal-alignment: center;
}
Text {
text: "点击次数: " + counter;
horizontal-alignment: center;
}
Button {
text: "点我 +1";
clicked => { counter += 1; }
}
Button {
text: "重置";
clicked => { root.reset-clicked(); }
}
}
}
宿主程序只需加载该组件并注册回调,即可完成业务逻辑对接:
slint::include_modules!();
fn main() -> Result<(), slint::PlatformError> {
let ui = AppWindow::new()?;
let weak = ui.as_weak();
ui.on_reset_clicked(move || {
if let Some(ui) = weak.upgrade() {
ui.set_counter(0);
}
});
ui.run()
}
4.4 关键参数与后端选择对照
| 配置项 | 取值示例 | 适用场景 | 注意事项 |
|---|---|---|---|
| SLINT_BACKEND | winit | 桌面开发与调试 | 需要窗口系统,启动最快 |
| SLINT_BACKEND | linuxkms | 无桌面嵌入式 Linux | 需 DRM/KMS 驱动与权限 |
| SLINT_BACKEND | linuxfb | 仅 Framebuffer 的设备 | 刷新率与双缓冲受限 |
| target | aarch64-unknown-linux-gnu | ARM64 Linux 板卡 | 需匹配交叉工具链 |
| target | armv7-unknown-linux-gnueabihf | ARM32 Linux 板卡 | 注意浮点 ABI 一致性 |
| SLINT_SCALE_FACTOR | 1.5 | 高 DPI 或小尺寸屏 | 影响所有逻辑像素尺寸 |
4.5 误区与复盘
- 只改 .slint 不重新构建:嵌入式部署时界面文件会被编译进二进制,修改后必须重新交叉编译,不能只替换单个文件。
- 后端与设备不匹配:在无桌面环境的目标板上使用 winit 后端,会直接启动失败;应优先确认 DRM 或 Framebuffer 是否可用。
- 忽略资源路径:图片、字体等资源若使用相对路径,部署后工作目录变化会导致加载失败,建议使用
@image-url或嵌入资源。 - 回调未注册:界面中声明了 callback 但宿主未绑定,点击后无任何反应,且不会报错,需通过日志或断点确认绑定是否生效。
- 尺寸写死:在目标板上直接使用固定像素尺寸,遇到不同分辨率屏幕会出现裁切或留白,应结合布局与缩放因子处理。
复盘建议:把“桌面预览通过”和“目标板运行通过”作为两个独立验收点。桌面通过只证明界面逻辑正确,目标板通过才证明后端、驱动、资源与交叉编译链路全部打通。