【Rust】Iced GUI库初使用及踩坑——写一个计数器

(该文写于去年8月份,目前iced更新到0.7已有些许API改动,本文内容已有部分错误,但仍有借鉴价值)

写在前面

从5月份起,我一直在寻找一个可用的,稳定的,开发者友好的Rust GUI框架,试图做到All in Rust,即一切的一切都可以靠Rust实现,其中GUI是相当重要的一部分,但找了许久,大部分给我答案是使用tauri,可我不是一个前端程序员,也没有深入学习前端的想法,故寻找计划只好搁置,直到9月份我发现PopOS团队使用Iced框架制作了发行版的桌面,证明该框架已经得到了生产的认证,于是我开始尝试使用Iced进行GUI的制作。

劝退警告

Iced 作为一款正在高速发展的框架,其API有极大的不确定性,用来自开发团队的话就是

Iced is currently experimental software.Iced moves fast and the master branch can contain breaking changes!

指不定啥时候你平时用着的API就没了,或者一个lib突然出现了极大的变化,导致之前的代码完全推翻,如果你能承受此风险,可以继续往下学习。我在接触这个框架是碰到了如下问题

  • 文档和crate实际使用时出现严重的不符合,当我试图在文档中搜索时,文档的结果和实际有较大出入
  • 文档和crate和官方示例有极大的出入,体现在一些库成员已经deprecated或者move到了别的子库中,以及rust本身的不断更新导致代码也有一定的差异。

Iced框架介绍

Iced是一个简单的,易于理解的,高度模块化的GUI框架,其整个框架可以被简单的描述为4点

  • 状态(State)
  • 消息(Messages)
  • 界面逻辑(View Logic)
  • 更新逻辑(Update Logic)

根据本人自己的使用体验,这4者之间大概的关系如下

在这里插入图片描述

其中 view()中的控件布局逻辑会绑定应用结构体里的控件状态,这样在交互时也会改变控件的状态。
可以发现其实是很好理解的,使用逻辑十分分明,接下来将用本人结合官方的例子来具体说明。

Iced-rs相关链接:
github
API文档
crate.io主页

成果展示

在这里插入图片描述

代码讲解

新建一个工程

进入命令行,输入

> cargo new counter
> cd counter

打开Cargo.toml,向dependencies中添加

iced = "0.4"

然后执行

cargo run

完成对crate的获取以及看到输出Hello,World

建立一个Iced应用

首先引入Iced库

use iced::widget::{button, Column, Text};
use iced::{ Element, Length, Sandbox, Settings};

当我们需要实现一个计数器时,我们先想想,他大概由哪几部分组成,首先计数,那么他需要一个文本控件来显示数字,既然要实现数字的变化,那么就需要有两个按钮来使他增加或减少。于是我们建立结构体

struct Counter {
    Value: i32,
    increment_button: button::State,
    decrement_button: button::State,
}

其中Value为计数器的计数值,剩余两个为两个按钮的状态,这样就完成了我们的应用的“建模”。

给大伙发两条信息

根据上面的框图我们知道,你得让程序知道你点击了按钮,那么我们就需要定义Message

#[derive(Debug, Clone, Copy)]
pub enum Message {
    IncementPressed,
    DecrementPressed,
}

将结构体转变为真正的iced应用

根据官方文档知道,我们要为结构体实现(implement)一些 trait 让其成为应用

impl Sandbox for counter {
    ...
}

fn new

这个比较好理解,实例化一个counter结构体

fn new() -> Self {
        Self {
            Value: 0,
            increment_button: button::State::new(),
            decrement_button: button::State::new(),
        }
    }

fn update

首先你需要告诉iced你的消息枚举叫啥名字,所以

type Message = Message;

注意!第一个Message是Sandbox trait中定义的,而后一个是你自己在上面定义的,注意区分!

然后书写更新逻辑

fn update(&mut self, message: Self::Message) {
        match message {
            Message::IncementPressed => {
                self.Value += 1;
            }
            Message::DecrementPressed => {
                self.Value -= 1;
            }
        }
    }

可以看到,当收到IncrementPressed消息时,结构体自身的Value就会 +1

fn view

这个便是书写界面布局和实例化控件的步骤了,直接上代码!

fn view(&mut self) -> Element<'_, Self::Message> {
        Column::new()
            .push(
                button::Button::new(&mut self.increment_button, Text::new("+"))
                    .on_press(Message::IncementPressed),
            )
            .push(Text::new(self.Value.to_string()).size(50))
            .push(
                button::Button::new(&mut self.decrement_button, Text::new("-"))
                    .on_press(Message::DecrementPressed),
            )
            .into()
    }

代码中,首先我实例化了一个Column控件,用来容纳按钮和文本控件,然后通过push将控件添加到Column中,注意控件的push顺序,会影响布局的顺序。最后的into()相当重要,他负责把Column转换为Element类型,否则编译不通过。

大功告成

最后在main中对结构体执行run函数即可

fn main() -> {
    Counter::run(Settings::default());
}

运行cargo run则会出现一个简单的计数器界面。

写在最后

这篇文章主要是为了加深我对Iced GUI框架的认识,将技术与思考细节记录下来,如果能够帮助到你,真是不胜荣幸
(不过在跑通这个例子前,我真的碰到了一堆莫名其妙的问题,才有了这份结晶,大概率能帮助减少碰壁的概率)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值