Rust UI开发(五):iced中如何进行页面布局(pick_list的使用)?(串口调试助手)

注:此文适合于对rust有一些了解的朋友
iced是一个跨平台的GUI库,用于为rust语言程序构建UI界面。
在这里插入图片描述
这是一个系列博文,本文是第五篇,前四篇链接:
1、Rust UI开发(一):使用iced构建UI时,如何在界面显示中文字符
2、Rust UI开发(二):iced中如何为窗口添加icon图标
3、Rust UI开发(三):iced如何打开图片(对话框)并在窗口显示图片?
4、Rust UI开发(四):iced中如何添加菜单栏(串口调试助手)

本篇是系列第五篇,本篇主要说明如何制作关于“串口调试助手”的界面布局,包括菜单栏的创建、UI主界面picklist的使用、以及如何排布。
实际效果预览:
在这里插入图片描述

界面分为两个部分,一个是菜单栏,暂时设置了四个主菜单项:
1、文件:新建、打开、保存、关闭
2、通讯:获取端口、连接、断开、参数
3、工具:CRC16、字符转换
4、关于:帮助、检测更新、层级(用于测试)

虽然菜单的子项功能不一定会用到,但作为一个演示功能会添加以上菜单项,其中一些菜单项会在后续篇章中赋予实际功能。
二是串口通讯的参数设置及收发数据部件:
在这里插入图片描述

以上部分主要由文本、按钮、下拉列表框(pic-klist)组合实现。

cargo.toml
依赖部分:

[dependencies]
iced.workspace=true
iced.features=["image","svg"]
iced_aw={
    workspace=true, features = ["card","menu","quad","icon_text"] }
image.workspace=true
num-complex.workspace=true
serialport.workspace=true

[workspace.dependencies]
iced = "0.10"
iced_aw={
    version = "0.7.0", default-features = false }
image="0.24.7"
num-complex="0.4.4"
serialport="4.2.2"

项目文件结构:
在这里插入图片描述

页面布局

一 菜单布局

先说菜单,我在上篇博文中已经说明了如何创建菜单栏,是使用iced-aw库,但上篇中只是简单说明了如何创建,并没有针对性的创建实用菜单。所以,本篇将会按照实际布局来创建菜单。
先简要回顾一下菜单的创建,是使用menu_bar和menu_tree!两个方法和menu_tree函数,来实现菜单和子菜单的创建及组合,以及对其样式进行设置(后续篇章说明)。
官方的menu示例其实是非常好的参考,但是在实际使用时,会觉得有所不便,所以,我在上篇博文中也介绍了通过创建自定义函数来创建菜单,好处是函数的参数可以自己调整。
本篇中,我们继续创建自己的函数,综合来说,将会有3个菜单函数,分别是menu_main、menu_sub和menu_sub_sub,其中:
menu_main:用于创建一个主菜单
menu_sub:用于创建一个子菜单,但没有下级菜单
menu_sub_sub:用于创建一个子菜单,可以附加下级菜单
这样做的好处是,可以随意定义菜单项,是否需要子菜单,组合使用即可。
menu_main函数:

///创建一个主菜单
fn menu_main<'a>(label:&str,
    msg: Message,
    children: Vec<MenuTree<'a, Message, iced::Renderer>>,
)->MenuTree<'a,Message,iced::Renderer>{
   
    menu_tree(
        debug_button(label,msg),
        children,
    )
}

menu_main函数设置了3个参数,label是菜单文本,msg是菜单触发后传递的消息,children是包含的子菜单项。

menu_sub函数:

///创建一个子菜单(无sub)
fn menu_sub<'a>(label:&str,
    msg:Message,
)->MenuTree<'a,Message,iced::Renderer>{
   
    menu_tree!(
        base_button(text(label)
        .width(Length::Fill)
        .height(Length::Fill)
        .vertical_alignment(alignment::Vertical::Center),msg))
      }

menu_sub设置了2个参数,label是菜单文本,msg是菜单触发传递的消息值。

menu_sub_sub函数:

///创建一个子菜单(带sub)
fn menu_sub_sub<'a>(label:&str,
    msg: Message,
    children: Vec<MenuTree<'a, Message, iced::Renderer>>,
)->MenuTree<'a, Message, iced::Renderer>{
   
    let handle = svg::Handle::from_path("../iced_test/img/caret-right-fill.svg");
        let arrow = svg(handle)
            .width(Length::Shrink)
            .style(theme::Svg::custom_fn(|theme| svg::Appearance {
   
                color: Some(theme.extended_palette().background.base.text),
            }));
    
        menu_tree(
            base_button(
                row![
                    text(label)
                        .width(Length::Fill)
                        .height(Length::Fill)
                        .vertical_alignment(alignment::Vertical::Center),
                    arrow
                ]
                .align_items(iced::Alignment::Center),
                msg,
            )
            .width(Length::Fill)
            .height(Length::Fill),
            children,
        )
    }

menu_sub_sub函数设置了3个参数,分别是label、msg、children,这和主菜单函数很像,只是内部代码稍有不同,这里的内部函数,是参考的官方示例,有子菜单的子菜单会有一个箭头图标。
在这里插入图片描述

利用以上三个函数,就可以创建自定义的菜单项了。以本篇中文件菜单项为例,看一下其创建代码:

//文件菜单
        let menu_wj_sub1=menu_sub("新建",
        Message::MenuXiaoxi(MenuXiaoxi::WjFile)); 
        let menu_wj_sub2=menu_sub("打开",
        Message::MenuXiaoxi(MenuXiaoxi::WjOpen));
        let menu_wj_sub3=menu_sub("保存",
        Message::MenuXiaoxi(MenuXiaoxi::WjSave));
        let menu_wj_sub4=menu_sub("关闭",
        Message::MenuXiaoxi(MenuXiaoxi::WjClose));  
        let menu_wj_main=menu_main("文件", 
        Message::MenuXiaoxi(MenuXiaoxi::WjMain),
        vec![menu_wj_sub1,menu_wj_sub2,menu_wj_sub3,menu_wj_sub4]);  

子菜单的顺序可以调整,然后按照你的顺序加入主菜单函数中即可。

二 picklist布局

一般串口调试助手中,设置波特率、数据位等串口参数,都是用下拉列表框来选择参数。下拉列表框一般是combobox,但iced-aw中的combobox稍有不同,所以这里我们选择pick-list部件来构建参数选择UI。
与创建菜单类似,因为参数设置的UI也是比较整齐的文本框+picklist部件,所以,我们也使用自定义函数,以便于构建单个可重复布局。
针对于波特率、数据位等单个项,我们创建serial_item函数:

///用于串口行添加,采用row布局
fn serial_item<'a>(label:&str,
                option:impl Into<Cow<'a,[Baudrate]>>,
                selected:Option<Baudrate>,
                on_selected:impl Fn(Baudrate)->Message+'a,
)->Row<'a,Message>{
   
    row!(
        text(label).size(16),
        pick_list(option,selected,on_selected)
        .placeholder(label)
        .width(100)
        .text_size(15)
    ).spacing(10)
}

可以看到,其实也很简单,就是包括一个文本框和picklist,然后参数中设置了label、option、selected、on_selected,主要用于针对每个项进行单独设置。这里,label是用于文本的设置,而后三个参数,是pick-list的参数:
option:如波特率的9600、19200这些预设项,用于picklist下拉显示。
selected:当选择一项时,将值传给此参数
on_selected:消息参数,pick-list选择时,触发消息,用于更新函数

然后我们为所有项创建一个serial_group函数:

///serial group 布局,
///将同一个布局集中在一个函数中,
fn serial_group<'a>(_app:&Counter)-> Column<'a,Message>{
   

    column![
            serial_item("端口   :",&Baudrate::PORT[..],_app.selected_port,Message::SelectedPort),       
            serial_item("波特率:",&Baudrate::BAUD[..],_app.selected_baudrate,Message::SelectedBaud),
            serial_item("数据位:",&Baudrate::DATABIT[..],_app.selected_databit,Message::SelectedDatabit),
            serial_item("校验位:",&Baudrate::PABIT[..],_app.selected_pabit,Message::SelectedPabit),
            serial_item("停止位:",&Baudrate::STOPBIT[..],_app.selected_stopbit,Message::SelectedStopbit),                                         
        ]
        .spacing(10)
        .padding(4)
        .align_items(Alignment::Start)
        .into()

}

正如函数的注释所说,serial_group函数只是为了将类似的项集中在一起布局。方便和其他部件在同一个界面上时,使程序结构看起来更加清晰。

基本上,以上两部分就能够实现整个UI的创建了,当然,现在看起来整个界面比较朴素和简单,那是因为并没有对其进行美化,这不是现在的重点。在实现基本的通信功能之前,UI界面将一直保持这种朴素。
将布局设置好后,可以在view函数里使其显示:

fn view(&self) -> Element<Message> {
       
        //文件菜单
        let menu_wj_sub1=menu_sub("新建",
        Message::MenuXiaoxi(MenuXiaoxi::WjFile)); 
        let menu_wj_sub2=menu_sub("打开",
        Message::MenuXiaoxi(MenuXiaoxi::WjOpen));
        let menu_wj_sub3=menu_sub("保存",
        Message::MenuXiaoxi(MenuXiaoxi::WjSave));
        let menu_wj_sub4=menu_sub("关闭",
        Message::MenuXiaoxi(MenuXiaoxi::WjClose));  
        let menu_wj_main=menu_main("文件", 
        Message::MenuXiaoxi(MenuXiaoxi::WjMain),
        vec![menu_wj_sub1,menu_wj_sub2,menu_wj_sub3,menu_wj_sub4], self);  
        //通讯菜单
        let menu_tx_sub1=menu_sub("参数",
        Message::MenuXiaoxi(MenuXiaoxi::TxParam));
        let menu_tx_sub2=menu_sub("连接",
        Message::MenuXiaoxi(MenuXiaoxi::TxConnect));  
        let menu_tx_sub3=menu_sub("断开",
        Message::MenuXiaoxi(MenuXiaoxi::TxDisconenct));
        let menu_tx_sub4=menu_sub("获取端口",
    Message::MenuXiaoxi(MenuXiaoxi::TxConnect));
        let menu_tx_main=menu_main("通讯", 
        Message::MenuXiaoxi(MenuXiaoxi::TxMain),
        vec![menu_tx_sub4,menu_tx_sub2,menu_tx_sub3,menu_tx_sub1], self);
        //工具菜单
        let menu_gj_sub1=menu_sub("CRC16",
        Message::MenuXiaoxi(MenuXiaoxi::GjCRC));
        let menu_gj_sub2=menu_sub("字符转换",
        Message::MenuXiaoxi(MenuXiaoxi::GjStrConvert));
        let menu_gj_main=menu_main("工具",
        Message::MenuXiaoxi(MenuXiaoxi::
  • 15
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

机构师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值