文章目录
  1. 1. 初始化slint的helloworld项目
  2. 2. 安装VsCode插件
  3. 3. .slint语法
  4. 4. 开发一个简单的应用

Slint是一个声明式UI框架,用于构建多个平台上的原生GUI界面的应用,支持windows/macos/linux以及嵌入式linux与mcu微控制器,支持编译为wasm,当前已经发布版本为1.4。它使用一种DSL语言.slint来描述界面,类似于Qt中的QML,响应式,可以编译时转换为代码或者在运行时进行解析,支持Vscode插件实时预览界面显示;而业务逻辑也支持多编程语言,比如c++/javascript/rust等,这里主要探索使用rust来开发。

参考:

slint支持的平台,截图自slint github页面:
slint支持的平台

slint架构, 截图自slint github页面。左侧.slint描述语言文件经过slint编译器编译为native原生语言代码,在slint runtime运行时的基础上运行;右侧C++/Rust/Javascript语言实现的业务与slint runtime进行交互; slint使用GPU/软件实现的渲染器将UI代码渲染显示出来, 接收处理输入事件。
slint架构

初始化slint的helloworld项目

已经安装完rust工作链,就可以直接使用cargo命令新建项目,添加slint信赖。也可以使用cargo generate从模板创建项目。

1
2
3
cargo new slint-hello
cd slint-hello
cargo add slint@1.4.1

然后编辑rust项目文件,将如下内容粘贴到src/main.rs中来替换默认生成的代码:

1
2
3
4
5
6
7
8
9
10
11
12
fn main() {
MainWindow::new().unwrap().run().unwrap();
}

slint::slint! {
export component MainWindow inherits Window {
Text {
text: "hello world";
color: green;
}
}
}

然后使用cargo run命令来编译运行程序,将会弹出一个小窗口, 显示绿色文字的hello world

slint window

前面rust代码中slint::slint!宏后面的内容即是slint中声明界面的DSL语言,使用component关键字声明组件MainWindow, 使用inherits声明继承于slint内置的Window组件; MainWindow内部声明了子组件Texttextcolor是组件Text的属性。

然后在main()方法中内容,先使用new()创建组件MainWindow,接着调用run()方法进行执行。slint::slint!宏会将声明的界面信息转换rust代码,所以在main()中可以直接引用到MainWindow类型。

安装VsCode插件

开发代码离不开编辑器/IDE的支持。 slint官方提供了VS Code插件,支持.slint描述语言的语法高亮及显示实时预览。VS Code插件可以直接从左侧栏的扩展中直接安装,建议安装。

vscode plugin

安装完插件后, slint::slint!后的代码已经有语法高亮,并且上面多出Show Preview的按钮,点击后弹出预览窗口。预览功能是通过命令行工具slint-viewer实现,可以选择显示风格。

vscode plugin

.slint语法

Slint文档上有.slint文件格式的参考,且提供网页版工具SlintPad来编辑、预览。 Slint描述文件在rust中有三种使用方式, 1-使用宏slint::slint!直接写在rust代码中,2-保存在文件中以.slint结尾,3-在程序运行时从文件系统中动态加载,需要使用解释器API。

一个.slint文件中可以声明一个或者多个组件,每个组件包含属性及子组件树,如同Javascript框架ReactJS中声明组件树。如下列出了.slint描述文件的一些重点:

  • component声明组件,inherits继承,export导出组件在外部可用,import导入组件;使用:=给子组件命名,命名需满足标识符规则,非首字母可以使用短横线-, 生成代码时会转换为下划线_;组件内部可以使用预定义的名字,root最外层组件, self当前元素,parent父组件元素
  • 组件内可以给属性赋值, 使用:冒号分隔; 组件内声明属性使用property, 默认是只有内部可以访问,可以使用private(默认),in,out, in-out进行修饰; 如in-out property <bool> checked;
  • 属性值中可以使用表达式进行计算,响应式方式实现, 如果依赖的值发生变化,属性值会重新计算然后刷新显示内容。
  • 使用callback声明回调函数, 使用=>来设置回调函数的值如clicked => {root.hello()}<=>来绑定回调与元素的事件调用callback clicked <=> area.clicked
  • 使用function声明函数,函数无负作用时可使用pure来修饰
  • Slint提供了一些内置组件,如Window/Rectangle/HorizontalLayout/HorizontalLayout,可以直接使用; 提供的标准控件Widgets如Button等可以从std-widgets.slint中引入,import { Button, VerticalBox } from "std-widgets.slint";
  • Slint提供了类似于CSS中的属性,元素位置使用x,y, width, height等, 背景色background: #3960D5;, 图片使用组件Image, 图片路径使用source: @image-url("icons/bus.png");animate声明属性值的转换动画
  • 使用c/c++风格的注释,//单行注释, /**/多行注释且可以嵌套
  • 支持for-in循环,if判断,..?..:..三元表达式

参考:

开发一个简单的应用

开发一个简单的应用,演示下property与callback使用,界面上先显示一行文本,然后三个按钮,分别是重置、加1、加2。加1是在.slint中实现,而加2使用rust实现。

主组件MainWindow中定义属性count用于计数,回调callback inc-count-2(int) -> int用于在rust中计算新的count值,使用win.on_inc_count_2()来设置回调方法的逻辑,注意方法名的差异,以on开始,.slint中的短横换成了下划线。
在button的clicked回调中使用root.count引用属性。

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
48
49
50
51
52
53
54
fn main() {
let win = MainWindow::new().unwrap();

win.on_inc_count_2(|count| -> i32 {
count + 2
});
win.run().unwrap();
}

slint::slint! {
import { VerticalBox, Button, TextEdit } from "std-widgets.slint";
export component MainWindow inherits Window {
in-out property <int> count: 0;
callback inc-count-2(int) -> int;

width: 300px;
height: 100px;

VerticalBox {
HorizontalLayout {
alignment: center;
text1 := Text {
text: "The counter is "+ root.count;
color: green;
}
}

HorizontalLayout {
height: 40px;
spacing: 4px;

Button {
text: "重置";
width: 80px;
clicked => { root.count = 0; }
}

Button {
text: "加1";
width: 80px;
clicked => { root.count = root.count + 1; }
}

btnMag := Button {
text: "加2";
width: 80px;
clicked => { root.count = root.inc-count-2(root.count);}
}
}

}

}
}

显示效果如下

show

文章目录
  1. 1. 初始化slint的helloworld项目
  2. 2. 安装VsCode插件
  3. 3. .slint语法
  4. 4. 开发一个简单的应用