Slint 函数和回调特性

Slint 的函数使用functions关键字声明。每个函数包括作用域(public、protected、private),声明关键字(function),函数名, 以及参数和返回,函数的声明格式与 Rust 类似,如下所示

export component Example {
    in-out property  min;
    in-out property  max;
    protected function set-bounds(min: int, max: int) {
        root.min = min;
        root.max = max
    }
    public pure function inbound(x: int) -> int {
        return Math.min(root.max, Math.max(root.min, x));
    }
}

函数的返回在符号->后指定返回类型,如果没有显式指定返回值,则默认返回最后一条语句的值。函数作用域默认是private,效果与C++中的语法一致。因此:

  • private只能在组件内使用
  • protected可以在继承的组件中使用
  • private可以在其他外部组件中使用

如果函数在作用域后添加pure关键字,则该函数为纯函数,意味着该函数可以被其他属性绑定或被其他组件或后台语言的函数调用,但是无法修改环境中的属性,同时用其绑定的属性也不会更新属性值。Slint 的callback接口声明为其他语言实现的函数接口,该接口在其他语言环境中实现,但只能在 Slint 界面中调用。即Rust将负责实现 callback然后被 Slint 调用,Rust 不能调用该接口。对于函数和回调的区别,以及pure修饰后的区别,也许有点难理解,看以下代码即可明白:Slint 界面如下

import { Button, VerticalBox } from "std-widgets.slint";

export component AppWindow inherits Window {
    width: 480px;
    height: 272px;
    in-out property counter: 0;
    callback request_increase_value();

    // 纯函数可以调用属性
    public pure function get_counter() -> int{
        // request_increase_value();  //不能调用其他非 pure 类型
        // add_counter(); //不能调用其他非 pure 类型
        root.counter
    }
    public function add_counter(){
        root.counter += 1
    }
    // in-out property  id : self.get_id(); //不能编译通过
    public function get_id() -> int{
        2
    }

    in-out property  age: self.request_age();
    pure callback request_age() -> int;

    in-out property  id: 0;
    // 纯函数不能修改属性
    public pure function id_add() {
        // root.id = root.id+1. //编译无法通过
    }

    VerticalBox {
        alignment: LayoutAlignment.center;
        Text {
            text: "Counter: \{root.counter}";
            horizontal-alignment: TextHorizontalAlignment.center;
        }
        Text {
            text: "Age: \{root.age}";
            horizontal-alignment: TextHorizontalAlignment.center;
        }
        Button {
            text: "Click";
            clicked => {
                // pure callback
                root.request_age();
                // callback
                root.request_increase_value();
                // function
                root.add_counter();
            }
        }
    }
}

Rust 后台如下

slint::include_modules!();

fn main() -> Result<(), slint::PlatformError> {
    let ui = AppWindow::new()?;

    ui.on_request_increase_value({
        let ui_handle = ui.as_weak();
        move || {
            let ui = ui_handle.unwrap();
            ui.set_counter(ui.get_counter() + 1);
        }
    });

    let mut age: i32 = 0;
    ui.on_request_age({
        let ui_handle = ui.as_weak();
        move || {
            let ui = ui_handle.unwrap();
            println!("age: {age}");
            age += 1;
            // 返回请求值
            age
        }
    });

    ui.run()
}

初始界面点击 10 次按钮后效果如下:同时后台打印在每次点击按钮后,会进入按钮的点击响应逻辑

clicked => {
    // pure callback
    root.request_age();
    // callback
    root.request_increase_value();
    // function
    root.add_counter();
}

由于Counter的怎普通的 Slint 函数add_counter和普通的回调函数request_increase_value中都会自加 1,因此最后Counter的值显示为 20。而age的值则由pure回调接口绑定,因此即使每次回调接口被调用了,但返回值也没有更新到age属性。基于以上代码可以体验到以下几点

  1. Slint 函数在 Slint 文件中定义和实现
  2. 回调接口 Slint 中声明,但在 Rust 或其他语言中实现。
  3. 函数和回调接口都是在Slint 中被调用, 不能直接在 Rust 中调用。
  4. Pure 函数或接口只能调用 Pure 函数或接口,不能调用其他非 Pure 类型。
ui.on_request_age({
        let ui_handle = ui.as_weak();
        move || {
            let ui = ui_handle.unwrap();
            println!("age: {age}");
            age += 1;
            // 返回请求值
            println!("request age: {}", ui.invoke_request_age());
            // 
            ui.invoke_add_counter();
            age
        }
    });


请使用浏览器的分享功能分享到微信等