Rust GUI库Slint初探(二):在.slint和.rs文件间使用回调函数

在上一篇中,我们为GUI窗口实现了一些简单的功能:
Rust GUI库Slint初探(一):编写.slint文件,改变图标和标题栏
但还并没有使用回调函数在slint文件和rs文件中进行交互。
这一次我们来实现一下。

在main.rs中编写回调函数内容

首先我们修改我们的main.slint文件,在MainWindow的定义中,首先将上一次自定义的属性property <int> count:0;前增添in关键字。这表示这一自定义属性的值由外部更新。如果使用out关键字则表示该自定义属性的值由组件内部更新,外部可读。如果关键字为in-out则表示其读写权限完全公开。然后我们再定义一个回调函数,使用:callback button_clicked;。之后我们再于button的clicked=>{}方法中,填入root.button-clicked();。其中root表示该button控件的父级控件。于是button能够调用MainWindow中我们定义的名为button_clicked的回调函数。这里留意到,我们再定义该回调函数时使用的名字为button_clicked,而给button调用时使用的名字为button-clicked。这是因为在slint语言中,_与-是通用的,可以互换使用。
于是,mian.slint文件现在为:

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

export component MainWindow inherits Window {
    in property <int> count:0;
    callback button_clicked;
    height: 600px;
    width: 800px;
    title: "小试牛刀";
    icon: @image-url("icon.png");
    VerticalLayout {
        height: 300px;
        width: 400px;
        Text {
            font-size: 30px;
            text: "你好世界";
            color: green;
        }
        Text {
            font-size: 30px;
            text: "Hello World!";
            color: green;
        }
        Button {
            text:"点击试试";
            height: 50px;
            width: 150px;
            clicked=>{root.button-clicked();}
        }
        Text {
            font-size: 30px;
            text: "Pressed:"+count;
            color: orange;
        }
    }
}

接下来我们可以修改main.rs文件了:

slint::include_modules!();
fn main() {
    let main_window=MainWindow::new().unwrap();
    let weak=main_window.as_weak();
    main_window.on_button_clicked(move||{
        let res=weak.upgrade().unwrap();
        res.set_count(res.get_count()+1);
    });
    main_window.run().unwrap();
}

我们将新建的MainWindow赋值给一个main_window变量,并取它的弱引用,才方便在后续的闭包中进行可变引用的操作。调用main_window变量的on_button_clicked()方法,其中button_clicked为我们在slint文件中定义的回调函数名称。给on_button_clicked()传递一个闭包,该闭包则是回调函数会执行的具体代码实现。使用move取得weak的所有权并upgrade()后赋给res变量。于是可以借助res变量对MainWindow进行操作,改变其count属性的值。
编译运行后,发现和前面在slint单文件中实现的逻辑是一模一样的。
在.slint中,我们定义callback的时候也可以写为callback button_clicked<=>btn.clicked;,然后在定义Button组件时写为:

btn:=Button {
	text:"点击试试";
	height: 50px;
	width: 150px;
}

其中定义Button组件时使用btn:=表示给该组件取了一个名字为btn。定义callback时,使用<=>表示button_clicked这个回调等价于btn组件的clicked方法。这样改写也可以达到和前述代码完全一样的效果。

slint中的按键响应与条件判断

在slint文件中,MainWindow的定义内,新增一个FocusScope组件。该组件表示其父组件获得关注时生效。由于是在MainWindow内定义,所以只要我们的主窗口是激活状态,FocusScope组件就可以一直生效。FocusScope组件内具有key-pressed和key-released函数可以定义。定义FocuseScope及key-pressed函数如下:

FocusScope {
	key-pressed(k) => {
		root.button-clicked();
		accept
	}
}

这样在触发key-pressed事件后,执行MainWindow的button-clicked回调。key-pressed函数需要一个返回值,返回值是一个枚举。所以最后我们写入accept作为返回值。
现在我们编译运行后发现,除了点击界面中的按钮,能够增加计数以外,按下键盘上的任意键,都可以增加计数。
接下来我们想要判断按下的按键是我们想要的,才触发事件。例如按下“F”建,才触发事件,则将上述代码改写为:

FocusScope {
	key-pressed(k) => {
		if(k.text=="f"){root.button-clicked();}
		accept
	}
}

如果我们想要指定组合按键响应事件,如“Ctrl+F”,则改写代码如下:

FocusScope {
	key-pressed(k) => {
		if(k.modifiers.control&&k.text=="f"){
			root.button-clicked();
		};
		accept
	}
}

编译运行,可以验证现在键盘按下我们指定的组合键后,计数才会增加了。
接下来我们试试用组合快捷键改变界面颜色,修改代码如下:

FocusScope {
	key-pressed(k) => {
		if(k.modifiers.control&&k.text=="f"){
			root.button-clicked();
		};
		if(k.modifiers.control&&k.text=="b"){
			root.background=@linear-gradient(45deg,white 0%,blue 100%);
		};
		if(k.modifiers.control&&k.text=="r"){
			root.background=@radial-gradient(circle, red 0%,white 100%)
		};
		accept
	}
}

该段代码增加了按下“Ctrl+B”和“Ctrl+R”的功能:
按下“Ctrl+B”时,效果为调整MainWindow的背景为渐变蓝色,使用45°的线性渐变色。
按下“Ctrl+R”时,效果为调整MainWindow的背景为渐变红色,使用环状的渐变色。
此时编译运行代码,使用快捷键改变界面效果如下:
image
至此,我们就实现了基本的回调函数使用,以及使用回调函数在slint文件和rs文件中进行交互。同时熟悉了slint文件中的if语句以及按键事件的使用。其实slint文件中还能使用for循环实现更为复杂的功能。下一次我们将去熟悉它。

posted @ 2024-01-11 10:46  AbsalomT  阅读(381)  评论(0编辑  收藏  举报