有做网站吗,新手如何优化网站排名,校园文化建设,青岛工程造价信息网注#xff1a;此文适合于对rust有一些了解的朋友 iced是一个跨平台的GUI库#xff0c;用于为rust语言程序构建UI界面。 这是一个系列博文#xff0c;本文是第五篇#xff0c;前四篇链接#xff1a; 1、Rust UI开发#xff08;一#xff09;#xff1a;使用iced构建UI时…注此文适合于对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.workspacetrue
iced.features[image,svg]
iced_aw{ workspacetrue, features [card,menu,quad,icon_text] }
image.workspacetrue
num-complex.workspacetrue
serialport.workspacetrue[workspace.dependencies]
iced 0.10
iced_aw{ version 0.7.0, default-features false }
image0.24.7
num-complex0.4.4
serialport4.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_maina(label:str,msg: Message,children: VecMenuTreea, Message, iced::Renderer,
)-MenuTreea,Message,iced::Renderer{menu_tree(debug_button(label,msg),children,)
}menu_main函数设置了3个参数label是菜单文本msg是菜单触发后传递的消息children是包含的子菜单项。
menu_sub函数
///创建一个子菜单(无sub)
fn menu_suba(label:str,msg:Message,
)-MenuTreea,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_suba(label:str,msg: Message,children: VecMenuTreea, Message, iced::Renderer,
)-MenuTreea, 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_sub1menu_sub(新建,Message::MenuXiaoxi(MenuXiaoxi::WjFile)); let menu_wj_sub2menu_sub(打开,Message::MenuXiaoxi(MenuXiaoxi::WjOpen));let menu_wj_sub3menu_sub(保存,Message::MenuXiaoxi(MenuXiaoxi::WjSave));let menu_wj_sub4menu_sub(关闭,Message::MenuXiaoxi(MenuXiaoxi::WjClose)); let menu_wj_mainmenu_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_itema(label:str,option:impl IntoCowa,[Baudrate],selected:OptionBaudrate,on_selected:impl Fn(Baudrate)-Messagea,
)-Rowa,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_groupa(_app:Counter)- Columna,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) - ElementMessage { //文件菜单let menu_wj_sub1menu_sub(新建,Message::MenuXiaoxi(MenuXiaoxi::WjFile)); let menu_wj_sub2menu_sub(打开,Message::MenuXiaoxi(MenuXiaoxi::WjOpen));let menu_wj_sub3menu_sub(保存,Message::MenuXiaoxi(MenuXiaoxi::WjSave));let menu_wj_sub4menu_sub(关闭,Message::MenuXiaoxi(MenuXiaoxi::WjClose)); let menu_wj_mainmenu_main(文件, Message::MenuXiaoxi(MenuXiaoxi::WjMain),vec![menu_wj_sub1,menu_wj_sub2,menu_wj_sub3,menu_wj_sub4], self); //通讯菜单let menu_tx_sub1menu_sub(参数,Message::MenuXiaoxi(MenuXiaoxi::TxParam));let menu_tx_sub2menu_sub(连接,Message::MenuXiaoxi(MenuXiaoxi::TxConnect)); let menu_tx_sub3menu_sub(断开,Message::MenuXiaoxi(MenuXiaoxi::TxDisconenct));let menu_tx_sub4menu_sub(获取端口,Message::MenuXiaoxi(MenuXiaoxi::TxConnect));let menu_tx_mainmenu_main(通讯, Message::MenuXiaoxi(MenuXiaoxi::TxMain),vec![menu_tx_sub4,menu_tx_sub2,menu_tx_sub3,menu_tx_sub1], self);//工具菜单let menu_gj_sub1menu_sub(CRC16,Message::MenuXiaoxi(MenuXiaoxi::GjCRC));let menu_gj_sub2menu_sub(字符转换,Message::MenuXiaoxi(MenuXiaoxi::GjStrConvert));let menu_gj_mainmenu_main(工具,Message::MenuXiaoxi(MenuXiaoxi::GjMain),vec![menu_gj_sub1,menu_gj_sub2], self);//测试菜单let menu_cs_subsub1menu_sub(层级3,Message::Showtext);let menu_cs_sub1menu_sub_sub(层级2,Message::Showtext,vec![menu_cs_subsub1]);let menu_cs_sub2menu_sub_sub(层级1,Message::Showtext,vec![menu_cs_sub1]);//帮助菜单let menu_bz_sub1menu_sub(帮助,Message::MenuXiaoxi(MenuXiaoxi::BzHelper));let menu_bz_sub2menu_sub(检查更新,Message::MenuXiaoxi(MenuXiaoxi::BzAbout));let menu_bz_mainmenu_main(关于, Message::MenuXiaoxi(MenuXiaoxi::BzMain),vec![menu_bz_sub1,menu_bz_sub2,menu_cs_sub2], self);let mbmenu_bar!(menu_wj_main,menu_tx_main,menu_gj_main,menu_bz_main);let sg column![serial_group(self),row![button(text(连接).horizontal_alignment(alignment::Horizontal::Center).vertical_alignment(alignment::Vertical::Center)).width(80).height(40).on_press(Message::Showtext),button(text(断开).horizontal_alignment(alignment::Horizontal::Center).vertical_alignment(alignment::Vertical::Center)).width(80).height(40).on_press(Message::Showtext),//button(获取端口).on_press(Message::Showtext),].spacing(20),//text(format!(当前所选菜单是{:?},self.value)).size(20),//text(format!(菜单消息是{:?},self.menu_xiaoxi)).size(20), ].spacing(20).padding(6);let sg2 column![text(接收数据).size(20),text_input(发送数据,self.value3).width(200).on_input(Message::InputChanged).padding(6),text(发送数据).size(20),text_input(发送数据,self.value3).width(200).on_input(Message::InputChanged).padding(6),].spacing(20);column![ mb,row![sg, sg2,].spacing(10)].spacing(20).padding(1).into() }
view函数看起来可能代码比较多是因为增加了菜单项的代码后续这些菜单的设置可以再用函数来集中但目前暂时按照这样来。
到目前为止我们在程序中所涉及的数据并没有详细说明这些将在后续一起说明本篇主要还是说明部件的布局这其中可以注意到在view函数里用于显示的布局采用的是column和row两种布局方法column就纵向布局row就是横行布局。 以row布局举例如下row![…]方法中添加部件也可以嵌套布局即column和row互相嵌套或者重复嵌套都可以前提是你先想好自己的UI上各个部件的大致位置是纵向还是横向哪些可以组合在一起设置哪些需要分开设置等等 row![button(text(连接).horizontal_alignment(alignment::Horizontal::Center).vertical_alignment(alignment::Vertical::Center)).width(80).height(40).on_press(Message::Showtext),button(text(断开).horizontal_alignment(alignment::Horizontal::Center).vertical_alignment(alignment::Vertical::Center)).width(80).height(40).on_press(Message::Showtext),//button(获取端口).on_press(Message::Showtext),].spacing(20)除了将部件直接添加其中还可以是push功能添加部件。比如这样
let c1column![];
c1.push(text(hello))嵌套使用 column![ mb,row![sg, sg2,].spacing(10)].spacing(20).padding(1).into() 要说明的是iced的布局方面我个人认为现在版本还不是很方便这当然是因为iced库本身就是在发展中的并非是成熟稳定的GUI库。
动态演示
完整代码 完整代码里有一些另外的数据和函数是本篇未提及的但不影响本篇内容的测试。另外所有代码都是测试中的程序所以可能会不够干净清晰。
use iced::widget::{button, column,row, text,text_input,combo_box,pick_list,svg, container};
use iced::{Alignment,theme, Element, Color,Sandbox,Length, Settings, alignment};
use iced::widget::{Column,Row};
use iced::Font;
use iced::font::Family;
use iced::window;
use iced::window::icon;
use std::borrow::Cow;use iced_aw::menu::{menu_tree::MenuTree, CloseCondition, ItemHeight, ItemWidth, PathHighlight};
use iced_aw::quad;
use iced_aw::{helpers::menu_tree, menu_bar, menu_tree};use serialport::{available_ports, SerialPortType};extern crate image;
extern crate num_complex;pub fn main() - iced::Result {//Counter::run(Settings::default()) //此处为使用默认窗口设置 let ff微软雅黑; //设置自定义字体//第二种获取rgba图片的方法利用Image库let img2image::open(../iced_ser/img/dota22.png);let img2_pathmatch img2 {Ok(path)path,Err(error)panic!(error is {},error),};let img2_fileimg2_path.to_rgba8();let ico2icon::from_rgba(img2_file.to_vec(), 64, 64);let ico2_filematch ico2{Ok(file)file,Err(error)panic!(error is {},error),};Counter::run(Settings { window:window::Settings{ //设置自定义窗口尺寸size:(800,600),//icon:Some(ico_file),icon:Some(ico2_file),..window::Settings::default()},default_font:Font{ //设置自定义字体用于显示中文字符family:Family::Name(ff),..Font::DEFAULT},..Settings::default()})
}
//创建结构体struct
struct Counter{value: String,value2:String,value3:String,baudrates:combo_box::StateBaudrate,selected_port:OptionBaudrate,selected_baudrate:OptionBaudrate,selected_databit:OptionBaudrate,selected_pabit:OptionBaudrate,selected_stopbit:OptionBaudrate,text:String,menu_xiaoxi:MenuXiaoxi,
}#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum MenuXiaoxi{//文件菜单WjMain,WjFile,WjOpen,WjSave,WjClose,//通讯菜单TxMain,TxGetPort,TxParam,TxConnect,TxDisconenct,//工具菜单GjMain,GjCRC,GjStrConvert,//帮助菜单BzMain,BzHelper,BzAbout,//无消息Nomenuxx,
}impl MenuXiaoxi {const WJ: [MenuXiaoxi; 5] [MenuXiaoxi::WjMain,MenuXiaoxi::WjFile,MenuXiaoxi::WjOpen,MenuXiaoxi::WjSave,MenuXiaoxi::WjClose,];const TX:[MenuXiaoxi;5][MenuXiaoxi::TxMain,MenuXiaoxi::TxGetPort,MenuXiaoxi::TxParam,MenuXiaoxi::TxConnect,MenuXiaoxi::TxDisconenct,];const GJ:[MenuXiaoxi;3][MenuXiaoxi::GjMain,MenuXiaoxi::GjCRC,MenuXiaoxi::GjStrConvert,];const BZ:[MenuXiaoxi;3][MenuXiaoxi::BzMain,MenuXiaoxi::BzHelper,MenuXiaoxi::BzAbout,];const NM:[MenuXiaoxi;1][MenuXiaoxi::Nomenuxx,];
}
impl std::fmt::Display for MenuXiaoxi {fn fmt(self, f: mut std::fmt::Formatter_) - std::fmt::Result {write!(f,{},match self {Self::WjMainwenjian,Self::WjFile file,Self::WjOpen open,Self::WjSave save,Self::WjCloseclose,//Self::TxMaintongxun,Self::TxGetPortgetport,Self::TxParamparameter,Self::TxConnectconnect,Self::TxDisconenctdisconenct,//Self::GjMaingongjv,Self::GjCRCcrc16,Self::GjStrConvert字符转换,//Self::BzMainbangzhu,Self::BzHelperhelper,Self::BzAboutabout,//Self::Nomenuxxno})}
}#[derive(Debug, Clone)] //为下方的enum添加特性trait
enum Message {MenuXiaoxi(MenuXiaoxi),Showtext,InputChanged(String),SelectedPort(Baudrate),SelectedBaud(Baudrate),SelectedDatabit(Baudrate),SelectedPabit(Baudrate),SelectedStopbit(Baudrate),OptionHovered(Baudrate),Closed,
}//sandbox是一个trait
impl Sandbox for Counter { //impl将sandbox添加给Counter,使Counter具有了sandbox的一些特性type Message Message;fn new() - Self { //初始化sandbox返回初始值Self { value: String::new(),value2:String::new(),value3:String::new(),baudrates: combo_box::State::new(Baudrate::BAUD.to_vec()),selected_port:None,selected_baudrate: None,selected_databit:None,selected_pabit:None,selected_stopbit:None,text: String::new(),menu_xiaoxi:MenuXiaoxi::Nomenuxx,}}fn title(self) - String { //返回sandbox的标题String::from(iced_串口助手)//self.value.clone()}fn update(mut self, message: Message) { //此处书写更新逻辑程序所有UI交互会在这里处理match message {Message::MenuXiaoxi(mxx){self.menu_xiaoximxx;}Message::Showtext { let ssself.value; //新建一个value的引用self.value2ss.to_string(); //将变量的引用字符化后传给value2}Message::InputChanged(value) {self.value3value;//get_serialport_list();let mbmatch self.menu_xiaoxi{MenuXiaoxi::BzMain{self.valuebangzhu.to_string();}MenuXiaoxi::BzHelper{self.valueBangzhu.to_string();}MenuXiaoxi::BzAbout{self.valueguanyu.to_string();}MenuXiaoxi::GjMain{self.valuegongjv.to_string();}MenuXiaoxi::GjCRC{self.valuecrc16.to_string();}MenuXiaoxi::GjStrConvert{self.valuezifu.to_string();}MenuXiaoxi::Nomenuxx{self.valueno xiaoxi.to_string();}MenuXiaoxi::TxMain{self.valuetongxun.to_string();}MenuXiaoxi::TxGetPort{self.valuegetport.to_string();}MenuXiaoxi::TxParam{self.valueparam.to_string();}MenuXiaoxi::TxConnect{self.valueconn.to_string();}MenuXiaoxi::TxDisconenct{self.valuedisc.to_string();}MenuXiaoxi::WjMain{self.valuewenjian.to_string();}MenuXiaoxi::WjFile{self.valuefile.to_string();}MenuXiaoxi::WjOpen{self.valueopen.to_string();}MenuXiaoxi::WjSave{self.valuesave.to_string();}MenuXiaoxi::WjClose{self.valueclose.to_string();}};}Message::SelectedPort(port){self.selected_portSome(port);}Message::SelectedBaud(baudrate){self.selected_baudrateSome(baudrate);self.textbaudrate.hello().to_string();}Message::SelectedDatabit(databit){self.selected_databitSome(databit);}Message::SelectedPabit(pabit){self.selected_pabitSome(pabit);}Message::SelectedStopbit(stopbit){self.selected_stopbitSome(stopbit);}Message::OptionHovered(baudrate){self.textbaudrate.hello().to_string();}Message::Closed{self.text self.selected_baudrate.map(|baudrate| baudrate.hello().to_string()).unwrap_or_default();}}}fn view(self) - ElementMessage { //文件菜单let menu_wj_sub1menu_sub(新建,Message::MenuXiaoxi(MenuXiaoxi::WjFile)); let menu_wj_sub2menu_sub(打开,Message::MenuXiaoxi(MenuXiaoxi::WjOpen));let menu_wj_sub3menu_sub(保存,Message::MenuXiaoxi(MenuXiaoxi::WjSave));let menu_wj_sub4menu_sub(关闭,Message::MenuXiaoxi(MenuXiaoxi::WjClose)); let menu_wj_mainmenu_main(文件, Message::MenuXiaoxi(MenuXiaoxi::WjMain),vec![menu_wj_sub1,menu_wj_sub2,menu_wj_sub3,menu_wj_sub4], self); //通讯菜单let menu_tx_sub1menu_sub(参数,Message::MenuXiaoxi(MenuXiaoxi::TxParam));let menu_tx_sub2menu_sub(连接,Message::MenuXiaoxi(MenuXiaoxi::TxConnect)); let menu_tx_sub3menu_sub(断开,Message::MenuXiaoxi(MenuXiaoxi::TxDisconenct));let menu_tx_sub4menu_sub(获取端口,Message::MenuXiaoxi(MenuXiaoxi::TxConnect));let menu_tx_mainmenu_main(通讯, Message::MenuXiaoxi(MenuXiaoxi::TxMain),vec![menu_tx_sub4,menu_tx_sub2,menu_tx_sub3,menu_tx_sub1], self);//工具菜单let menu_gj_sub1menu_sub(CRC16,Message::MenuXiaoxi(MenuXiaoxi::GjCRC));let menu_gj_sub2menu_sub(字符转换,Message::MenuXiaoxi(MenuXiaoxi::GjStrConvert));let menu_gj_mainmenu_main(工具,Message::MenuXiaoxi(MenuXiaoxi::GjMain),vec![menu_gj_sub1,menu_gj_sub2], self);//测试菜单let menu_cs_subsub1menu_sub(层级3,Message::Showtext);let menu_cs_sub1menu_sub_sub(层级2,Message::Showtext,vec![menu_cs_subsub1]);let menu_cs_sub2menu_sub_sub(层级1,Message::Showtext,vec![menu_cs_sub1]);//帮助菜单let menu_bz_sub1menu_sub(帮助,Message::MenuXiaoxi(MenuXiaoxi::BzHelper));let menu_bz_sub2menu_sub(检查更新,Message::MenuXiaoxi(MenuXiaoxi::BzAbout));let menu_bz_mainmenu_main(关于, Message::MenuXiaoxi(MenuXiaoxi::BzMain),vec![menu_bz_sub1,menu_bz_sub2,menu_cs_sub2], self);let mbmenu_bar!(menu_wj_main,menu_tx_main,menu_gj_main,menu_bz_main);let sg column![serial_group(self),row![button(text(连接).horizontal_alignment(alignment::Horizontal::Center).vertical_alignment(alignment::Vertical::Center)).width(80).height(40).on_press(Message::Showtext),button(text(断开).horizontal_alignment(alignment::Horizontal::Center).vertical_alignment(alignment::Vertical::Center)).width(80).height(40).on_press(Message::Showtext),//button(获取端口).on_press(Message::Showtext),].spacing(20),//text(format!(当前所选菜单是{:?},self.value)).size(20),//text(format!(菜单消息是{:?},self.menu_xiaoxi)).size(20), ].spacing(20).padding(6);let sg2 column![text(接收数据).size(20),text_input(发送数据,self.value3).width(200).on_input(Message::InputChanged).padding(6),text(发送数据).size(20),text_input(发送数据,self.value3).width(200).on_input(Message::InputChanged).padding(6),].spacing(20);column![ mb,row![sg, sg2,].spacing(10)].spacing(20).padding(1).into() }}///用于串口行添加,采用row布局
fn serial_itema(label:str,option:impl IntoCowa,[Baudrate],selected:OptionBaudrate,on_selected:impl Fn(Baudrate)-Messagea,
)-Rowa,Message{row!(text(label).size(16),pick_list(option,selected,on_selected).placeholder(label).width(100).text_size(15)).spacing(10)
}
///serial group 布局
///将同一个布局集中在一个函数中
fn serial_groupa(_app:Counter)- Columna,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()}///自定义按钮样式用于菜单栏使用
struct ButtonStyle;
//让ButtonStyle实现button的StyleSheet功能
impl button::StyleSheet for ButtonStyle {type Style iced::Theme;//生成按钮的激活外观fn active(self, style: Self::Style) - button::Appearance {button::Appearance {text_color: style.extended_palette().background.base.text,border_radius: [2.0; 4].into(),background: Some(Color::TRANSPARENT.into()),..Default::default()}}//生成按钮的悬停外观fn hovered(self, style: Self::Style) - button::Appearance {let plt style.extended_palette();button::Appearance {background: Some(plt.primary.weak.color.into()),text_color: plt.primary.weak.text,border_radius:[6.0; 4].into(), //border_radius:四角倒圆半径..self.active(style)}}
}//基础按钮
fn base_buttona(content: impl IntoElementa, Message, iced::Renderer,msg: Message,
) - button::Buttona, Message, iced::Renderer {button(content).padding([4, 8]).style(iced::theme::Button::Custom(Box::new(ButtonStyle {}))).on_press(msg)
}
//带标签按钮
fn labeled_buttona(label: str, msg: Message) - button::Buttona, Message, iced::Renderer {base_button(text(label).width(Length::Fill).height(Length::Fill).vertical_alignment(alignment::Vertical::Center),msg,)
}//测试按钮
fn debug_buttona(label: str,msg: Message) - button::Buttona, Message, iced::Renderer {labeled_button(label,msg)
}///创建一个子菜单(无sub)
fn menu_suba(label:str,msg:Message,
)-MenuTreea,Message,iced::Renderer{menu_tree!(base_button(text(label).width(Length::Fill).height(Length::Fill).vertical_alignment(alignment::Vertical::Center),msg))}
///创建一个子菜单(带sub)
fn menu_sub_suba(label:str,msg: Message,children: VecMenuTreea, Message, iced::Renderer,
)-MenuTreea, Message, iced::Renderer{let handle svg::Handle::from_path(../iced_ser/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,)}///创建一个主菜单
fn menu_maina(label:str,msg: Message,children: VecMenuTreea, Message, iced::Renderer,_app:Counter
)-MenuTreea,Message,iced::Renderer{menu_tree(debug_button(label,msg),children,)
}#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Baudrate{//portPortCOM0,//baudrateRate9600,#[default]Rate19200,Rate38400,Rate57600,Rate115200,//databitDatabit8,Databit7,Databit6,Databit5,//paritybitPabitnone,Pabiteven,Pabitodd,Pabitspace,Pabitmark,//stopbitStopbit1,Stopbit1dot5,Stopbit2,
}
impl Baudrate {const PORT:[Baudrate;1][Baudrate::PortCOM0,];const BAUD: [Baudrate; 5] [Baudrate::Rate9600,Baudrate::Rate19200,Baudrate::Rate38400,Baudrate::Rate57600,Baudrate::Rate115200,];const DATABIT:[Baudrate;4][Baudrate::Databit8,Baudrate::Databit7,Baudrate::Databit6,Baudrate::Databit5,];const PABIT:[Baudrate;5][Baudrate::Pabitnone,Baudrate::Pabiteven,Baudrate::Pabitodd,Baudrate::Pabitspace,Baudrate::Pabitmark,];const STOPBIT:[Baudrate;3][Baudrate::Stopbit1,Baudrate::Stopbit1dot5,Baudrate::Stopbit2,];fn hello(self) - str {match self {Baudrate::PortCOM0COM0,Baudrate::Rate9600 9600,Baudrate::Rate19200 9600,Baudrate::Rate38400 9600,Baudrate::Rate57600 9600,Baudrate::Rate115200 9600,Baudrate::Databit88,Baudrate::Databit77,Baudrate::Databit66,Baudrate::Databit55,Baudrate::PabitnoneNone,Baudrate::PabitevenEven,Baudrate::PabitoddOdd,Baudrate::PabitspaceSpace,Baudrate::PabitmarkMark,Baudrate::Stopbit11,Baudrate::Stopbit1dot51.5,Baudrate::Stopbit22,}}
}
impl std::fmt::Display for Baudrate {fn fmt(self, f: mut std::fmt::Formatter_) - std::fmt::Result {write!(f,{},match self {Baudrate::PortCOM0COM0,Baudrate::Rate9600 9600,Baudrate::Rate19200 19200,Baudrate::Rate38400 38400,Baudrate::Rate57600 57600,Baudrate::Rate115200 115200,Baudrate::Databit88,Baudrate::Databit77,Baudrate::Databit66,Baudrate::Databit55,Baudrate::PabitnoneNone,Baudrate::PabitevenEven,Baudrate::PabitoddOdd,Baudrate::PabitspaceSpace,Baudrate::PabitmarkMark,Baudrate::Stopbit11,Baudrate::Stopbit1dot51.5,Baudrate::Stopbit22,})}
}///获取可用串口
fn get_serialport_list()-String {let mut pnString::new();match available_ports() {Ok(ports) {match ports.len() {0 println!(No ports found.),1 println!(Found 1 port:),n println!(Found {} ports:, n),};for p in ports {println!( {}, p.port_name);pnp.port_name;match p.port_type {SerialPortType::UsbPort(info) {println!( Type: USB);println!( VID:{:04x} PID:{:04x}, info.vid, info.pid);println!( Serial Number: {},info.serial_number.as_ref().map_or(, String::as_str));println!( Manufacturer: {},info.manufacturer.as_ref().map_or(, String::as_str));println!( Product: {},info.product.as_ref().map_or(, String::as_str));#[cfg(feature usbportinfo-interface)]println!( Interface: {},info.interface.as_ref().map_or(.to_string(), |x| format!({:02x}, *x)));}SerialPortType::BluetoothPort {println!( Type: Bluetooth);}SerialPortType::PciPort {println!( Type: PCI);}SerialPortType::Unknown {println!( Type: Unknown);}}}}Err(e) {eprintln!({:?}, e);eprintln!(Error listing serial ports);}}pn
}