<Rust><iced>基于rust使用iced库构建GUI实例:动态改变主题色

前言
本专栏是Rust实例应用。

环境配置
平台:windows
软件:vscode
语言:rust
库:iced、iced_aw

概述
本篇构建了这样的一个实例,可以动态修改UI的主题,通过菜单栏来选择预设的自定义主题和官方主题,以及实时修改rgba色彩来动态调整主题色。
UI图示:
在这里插入图片描述
如上图,本实例是一个简单的应用,是利用菜单栏来选择窗口的主题色,可以选择预设值,也可以选择自定义值,还可以动态调整:
在这里插入图片描述

本篇内容:
1、动态调整主题色

程序结构介绍

本篇涉及到的crate有iced、iced_aw、image、rfd等,详细看toml文件:

[package]
name = "img-convert"
version = "0.1.0"
edition = "2021"[dependencies]iced={version ="0.12.1",features = ["svg","canvas","image","multi-window"]}
iced_widget={version = "0.12.3"}
iced_aw={version = "0.9.3",features = ["cupertino"]}image={version = "0.25.1",features = []}rfd={version ="0.14.1"}

文件夹结构:
在这里插入图片描述
其中img文件夹提供了UI所需的各种图片:
在这里插入图片描述
本篇所涉及的内容,有一些是公用的,如菜单栏设置、样式设置等,本篇会讲的详细些,后续篇章涉及这些基础内容,就不再赘述。

先说菜单栏的构建的,关于菜单栏的使用,在之前的部件介绍专栏已经介绍过:
RustGUI学习(iced/iced_aw)之扩展小部件(十六):如何使用菜单menu部件来创建菜单栏?
但之前只是简单说了如何使用menu,本篇将详细介绍菜单栏的构建函数。
在这里插入图片描述
如图,菜单的设置,是在一个单独的mod文件中,并没有放在main.rs中,主要是为了方便编写,如果都写在主函数中,显得太拥挤了,也不方便查看。
在menuset.rs中,我们将构建以下函数:
在这里插入图片描述
我们来分别看一下,其中,create_menubar函数,顾名思义,是创建菜单栏主bar的函数,如下:

///
/// 创建一个menu bar
/// 
pub fn create_menubar<'a,Message,Theme,Renderer>(menu:Vec<Item<'a,Message,Theme,Renderer>>,style:iced_aw::style::menu_bar::MenuBarStyle,
)->MenuBar<'a,Message,Theme,Renderer>
whereTheme:iced_aw::menu::StyleSheet+iced_aw::style::menu_bar::StyleSheet,Renderer:iced::advanced::Renderer,<Theme as iced_aw::menu::StyleSheet>::Style: From<MenuBarStyle>
{   MenuBar::new(menu).spacing(4.0).width(Length::Fill).height(40).padding(4).draw_path(menu::DrawPath::Backdrop).style(style)
}

通过传入的menu项,返回一个MenuBar部件,传入参数中还包括自定义的style。关于函数的具体代码就不赘述了,这在之前的部件专栏博文中有说明。

接下来说下菜单项的构建函数,有两种,一个是不带子项的,一个是带子项的。
menu无子项:

///
/// 创建一个menu无子项
/// 
pub fn menu_no_sub<'a,Message:'a,Theme,Renderer>(label:&'a str,msg:Message,
)->Item<'a,Message,Theme,Renderer>
whereTheme:'a+iced_aw::menu::StyleSheet+button::StyleSheet+text::StyleSheet,Renderer: 'a+iced::advanced::Renderer+iced::advanced::text::Renderer,<Theme as iced_widget::button::StyleSheet>::Style: From<iced::theme::Button>,Message: std::clone::Clone
{   let btn:Button<Message,Theme,Renderer>=menubtn_normal(label, msg,176,Horizontal::Left);Item::new(btn)}

可以看到,很简单,就是返回一个Item项,其中菜单button的文本和消息为自定义输入。

menu有子项

///
/// 创建一个menu有子项
/// 
pub fn menu_with_sub<'a,Message:'a,Theme,Renderer>(label:&'a str,msg:Message,arrow:&'a str,sub:Vec<Item<'a,Message,Theme,Renderer>>
)->Item<'a,Message,Theme,Renderer>
whereTheme:'a+iced_aw::menu::StyleSheet+button::StyleSheet+text::StyleSheet+svg::StyleSheet,Renderer: 'a+iced::advanced::Renderer+iced::advanced::text::Renderer+iced::advanced::svg::Renderer,Message: std::clone::Clone,<Theme as iced_widget::button::StyleSheet>::Style: From<iced::theme::Button>{   let item=menubtn_arrow(label, msg, arrow,176);let menu=Menu::new(sub).max_width(180.0).spacing(5.0).offset(3.0);Item::with_menu(item, menu)
}

带子项的menu稍微复杂些,其中Item的项包括了button以及一个箭头(右向,svg格式):
在这里插入图片描述
svg构成:

<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715601105402" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3106" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M256 102.4v819.2l512-409.6L256 102.4z" fill="#333333" p-id="3107"></path></svg>

也可以去一些提供向量图标的网站下载。

通常,菜单项使用的都是button加文字,因为菜单就是用来点击的,但是也可以使用其他部件,如滑动条,本篇为了方便动态调整颜色值,添加了slider构建的menu:

///
/// 创建一个menu无子项(slider样式)
/// 
pub fn menu_no_sub_slider<'a,Message,Theme,Renderer>(label:&'a str,msg:impl Fn(f32) -> Message + 'a,slidervalue:f32,themecolor:Color,
)->Item<'a,Message,Theme,Renderer>
whereTheme:'a+iced_aw::menu::StyleSheet+iced_widget::slider::StyleSheet+iced_widget::text::StyleSheet,Renderer: 'a+iced::advanced::Renderer+iced::advanced::text::Renderer,Message: std::clone::Clone+'a,<Theme as iced_widget::slider::StyleSheet>::Style: From<iced::theme::Slider>,<Theme as iced_widget::text::StyleSheet>::Style: From<iced::theme::Text>
{   let style1=iced::theme::Slider::Custom(Box::new(MySliderStyle{color:themecolor}));let mut r1=0.0;let mut g1=0.0;let mut b1=0.0;let mut a1=1.0;if themecolor.r<=0.1 || themecolor.g<=0.1 || themecolor.b<=0.1{r1=0.9;g1=0.9;b1=0.9;}else if themecolor.r>=0.8 || themecolor.g>=0.8 || themecolor.b>=0.8{r1=0.02;g1=0.02;b1=0.02;}else{r1=themecolor.r;g1=themecolor.g;b1=themecolor.b;}let style2=iced::theme::Text::Color(Color::from_rgba(r1, g1, b1, a1));let text0=text(label).width(20).size(12).style(style2);let slider=slider(0.0..=1.0,slidervalue, msg).step(0.01).width(100).style(style1);let text1=text(format!("{}",slidervalue)).width(30).size(12).style(style2);let row1=row![text0,horizontal_space().height(10),slider,horizontal_space().height(10),text1].align_items(Alignment::Center).spacing(5);Item::new(row1)
}

上面的函数,菜单项中添加的是slider,其中slider的样式可以根据UI的背景色调整而调整,主要是为了背景色调整过程菜单项的可视性。
还有两个函数是构建菜单项button的,之所以将button项单独使用函数构建,也是为了方便修改参数。这两个函数不再细说,但代码会在后面全部贴出来。

菜单项的构建就完成了,然后在主函数里调用菜单项:

 let arrowsvg="..\\img-convert\\img\\arrow\\arrow_right_16.svg";let wj_open=menuset::menu_no_sub("打开",Message::WJ(menuset::WJMessage::Open));// let wj_new_mode1=menuset::menu_no_sub("格式1",Message::WJ(menuset::WJMessage::Open) );// let wj_new_mode2=menuset::menu_no_sub("格式2",Message::WJ(menuset::WJMessage::Open) );let wj_new=menuset::menu_no_sub("新建", Message::WJ(menuset::WJMessage::New));let wj_save=menuset::menu_no_sub("保存",Message::WJ(menuset::WJMessage::Save));let wj_close=menuset::menu_no_sub("关闭",Message::WJ(menuset::WJMessage::Close));let wj_main=menuset::menu_main("文件", Message::WJ(menuset::WJMessage::WenJian), 

通常,菜单项就是菜单栏中添加主菜单项,点击主菜单项,下拉子项,子项还可以附带子项,如上面的代码,是主菜单为“文件”的菜单项,下拉菜单为【打开、新建、保存、关闭】,很常见的对吧。
在这里插入图片描述
注意,上述代码中,调用的函数,其中menuset为mod,需要提前导入:

mod menuset;

以此类推,如果你要构建其他菜单项,按照样式填写即可,当然,其中消息需要自己构建,可以直接写在menuset模块中:

#[derive(Debug,Clone)]
pub enum WJMessage{WenJian,Open,Close,New,Save,
}

注意要使用pub关键字,然后其他文件里调用。
在这里插入图片描述
如上图,主函数调用menuset的菜单项enum。

以上,菜单项的设置就完成了,样式如下:
在这里插入图片描述
在这里插入图片描述
示例只添加了三个主菜单项,如果你想要更多的,自行添加即可。
不过,需要注意的是,本文没有为菜单添加快捷键功能,这涉及到监控键盘的行为,会在后面的高级一点的示例中说到。

下面说下主题修改涉及的函数,即uitheme.rs。
在这里插入图片描述
本模块中,主要包含了一个是自定义预设值,T1、T2、T3,实现的函数是theme_name。
一个是动态调整主题色,实现的函数是get_color。
至于官方预设的颜色值,就无需多次重构,直接使用即可。

来看下自定义预设主题,其实现代码如下:

impl UITheme{pub fn theme_name(&self) -> Theme{match self{UITheme::T1 => {let p1=Palette{background:iced::Color::from_rgba(0.0, 0.65, 0.6, 0.7),text:Color::BLACK,primary:Color::BLACK,success:Color::BLACK,danger:Color::BLACK,};let g1=Extended{background:Background{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},primary:Primary{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},secondary:Secondary{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},success:Success{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},danger:Danger{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},is_dark:false,};let cus1=Arc::new(iced::theme::Custom::new("t1".to_string(),p1));let cus2=Arc::new(iced::theme::Custom::with_fn("t1".to_string(), p1, |_|g1));iced::Theme::Custom(cus1)}UITheme::T2 => {let p1=Palette{//background:iced::Color::from_rgba(0.0, 0.85, 0.8, 0.8),background:Color::from_linear_rgba(0.0, 0.5, 0.6, 0.8),text:Color::BLACK,primary:Color::BLACK,success:Color::BLACK,danger:Color::BLACK,};let cus1=Arc::new(iced::theme::Custom::new("t1".to_string(),p1));iced::Theme::Custom(cus1)},UITheme::T3 => {let p1=Palette{background:iced::Color::from_rgba(0.0, 0.85, 0.8, 0.8),text:Color::BLACK,primary:Color::BLACK,success:Color::BLACK,danger:Color::BLACK,};let cus1=Arc::new(iced::theme::Custom::new("t1".to_string(),p1));iced::Theme::Custom(cus1)},}}}

需要注意的是,本文的代码只是为了演示,一些参数设置只要达到效果即可,所以,并非所有涉及的参数都做了修改。如上代码,我们只是简单的构建了三个自定义样式T1、T2、T3,然后为每个主题都设置自己的颜色,通过菜单选择相应的主题时,获得自定义的颜色效果:
在这里插入图片描述
再来看下动态调整实现:

pub struct UIThemeColor{pub color:Color,
}impl UIThemeColor {pub fn get_color(&self) -> Theme {let p1=Palette{background:self.color,text:Color::BLACK,primary:Color::BLACK,success:Color::BLACK,danger:Color::BLACK,};let cus1=Arc::new(iced::theme::Custom::new("t1".to_string(),p1));iced::Theme::Custom(cus1)
}
}

代码不难,我们构建一个结构体,包含参数color,用于自定义输入,然后实现函数get_color,用于动态调整时,传入外面的颜色值,函数内部使用此color值,来构建自定义的Theme,以此实现主题色的动态调整:
在这里插入图片描述

完整代码

menuset.rs

use iced::advanced::widget::Text;
use iced::alignment::Horizontal;
use iced::widget::{button, text,row,svg,horizontal_space,slider,};
use iced::{Alignment, Background, Border, Color, Length, Theme};
use iced_aw::menu::{self, Item, Menu, MenuBar};
use iced::widget::{Button, Row};
use iced_aw::style::menu_bar::MenuBarStyle;
use iced::widget::slider::{Rail,HandleShape};#[derive(Debug,Clone)]
pub enum WJMessage{WenJian,Open,Close,New,Save,
}
#[derive(Debug,Clone)]
pub enum GJMessage{GongJv,T1,T2,T3,
}#[derive(Debug,Clone)]
pub enum GYMessage{GuanYu,GY,BZ,GX,
}///
/// 创建一个menu bar
/// 
pub fn create_menubar<'a,Message,Theme,Renderer>(menu:Vec<Item<'a,Message,Theme,Renderer>>,style:iced_aw::style::menu_bar::MenuBarStyle,
)->MenuBar<'a,Message,Theme,Renderer>
whereTheme:iced_aw::menu::StyleSheet+iced_aw::style::menu_bar::StyleSheet,Renderer:iced::advanced::Renderer,<Theme as iced_aw::menu::StyleSheet>::Style: From<MenuBarStyle>
{   MenuBar::new(menu).spacing(4.0).width(Length::Fill).height(40).padding(4).draw_path(menu::DrawPath::Backdrop).style(style)
}///
/// 创建一个menu主项
/// 
pub fn menu_main<'a,Message:'a,Theme,Renderer>(label:&'a str,msg:Message,sub:Vec<Item<'a,Message,Theme,Renderer>>
)->Item<'a,Message,Theme,Renderer>
whereTheme:'a+iced_aw::menu::StyleSheet+button::StyleSheet+text::StyleSheet+svg::StyleSheet,Renderer: 'a+iced::advanced::Renderer+iced::advanced::text::Renderer+iced::advanced::svg::Renderer,Message: std::clone::Clone,<Theme as iced_widget::button::StyleSheet>::Style: From<iced::theme::Button>
{   let item: Button<Message, Theme, Renderer>=menubtn_normal(label, msg,60,Horizontal::Center);let menu: Menu<Message, Theme, Renderer>=Menu::new(sub).max_width(180.0).spacing(5.0).offset(5.0);Item::with_menu(item, menu)
}///
/// 创建一个menu无子项(slider样式)
/// 
pub fn menu_no_sub_slider<'a,Message,Theme,Renderer>(label:&'a str,msg:impl Fn(f32) -> Message + 'a,slidervalue:f32,themecolor:Color,
)->Item<'a,Message,Theme,Renderer>
whereTheme:'a+iced_aw::menu::StyleSheet+iced_widget::slider::StyleSheet+iced_widget::text::StyleSheet,Renderer: 'a+iced::advanced::Renderer+iced::advanced::text::Renderer,Message: std::clone::Clone+'a,<Theme as iced_widget::slider::StyleSheet>::Style: From<iced::theme::Slider>,<Theme as iced_widget::text::StyleSheet>::Style: From<iced::theme::Text>
{   let style1=iced::theme::Slider::Custom(Box::new(MySliderStyle{color:themecolor}));let mut r1=0.0;let mut g1=0.0;let mut b1=0.0;let mut a1=1.0;if themecolor.r<=0.1 || themecolor.g<=0.1 || themecolor.b<=0.1{r1=0.9;g1=0.9;b1=0.9;}else if themecolor.r>=0.8 || themecolor.g>=0.8 || themecolor.b>=0.8{r1=0.02;g1=0.02;b1=0.02;}else{r1=themecolor.r;g1=themecolor.g;b1=themecolor.b;}let style2=iced::theme::Text::Color(Color::from_rgba(r1, g1, b1, a1));let text0=text(label).width(20).size(12).style(style2);let slider=slider(0.0..=1.0,slidervalue, msg).step(0.01).width(100).style(style1);let text1=text(format!("{}",slidervalue)).width(30).size(12).style(style2);let row1=row![text0,horizontal_space().height(10),slider,horizontal_space().height(10),text1].align_items(Alignment::Center).spacing(5);Item::new(row1)
}///
/// 创建一个menu无子项
/// 
pub fn menu_no_sub<'a,Message:'a,Theme,Renderer>(label:&'a str,msg:Message,
)->Item<'a,Message,Theme,Renderer>
whereTheme:'a+iced_aw::menu::StyleSheet+button::StyleSheet+text::StyleSheet,Renderer: 'a+iced::advanced::Renderer+iced::advanced::text::Renderer,<Theme as iced_widget::button::StyleSheet>::Style: From<iced::theme::Button>,Message: std::clone::Clone
{   let btn:Button<Message,Theme,Renderer>=menubtn_normal(label, msg,176,Horizontal::Left);Item::new(btn)}///
/// 创建一个menu有子项
/// 
pub fn menu_with_sub<'a,Message:'a,Theme,Renderer>(label:&'a str,msg:Message,arrow:&'a str,sub:Vec<Item<'a,Message,Theme,Renderer>>
)->Item<'a,Message,Theme,Renderer>
whereTheme:'a+iced_aw::menu::StyleSheet+button::StyleSheet+text::StyleSheet+svg::StyleSheet,Renderer: 'a+iced::advanced::Renderer+iced::advanced::text::Renderer+iced::advanced::svg::Renderer,Message: std::clone::Clone,<Theme as iced_widget::button::StyleSheet>::Style: From<iced::theme::Button>{   let item=menubtn_arrow(label, msg, arrow,176);let menu=Menu::new(sub).max_width(180.0).spacing(5.0).offset(3.0);Item::with_menu(item, menu)
}
///
/// 创建一个menu按钮无箭头
/// 
fn menubtn_normal<'a,Message,Theme,Renderer>(label:&'a str,msg:Message,width:u16,align:Horizontal,
)->Button<'a,Message,Theme,Renderer>
whereTheme:'a+iced_aw::menu::StyleSheet+button::StyleSheet+text::StyleSheet,Renderer: 'a+iced::advanced::Renderer+iced::advanced::text::Renderer,<Theme as iced_widget::button::StyleSheet>::Style: From<iced::theme::Button>
{   let tt=text(label).size(15).vertical_alignment(iced::alignment::Vertical::Center).horizontal_alignment(align);button(tt).width(width).height(30).on_press(msg).style(iced::theme::Button::Custom(Box::new(MenuButtonStyle)))
}///
/// 创建一个menu按钮有箭头
/// 
fn menubtn_arrow<'a,Message:'a,Theme,Renderer>(label:&'a str,msg:Message,arrow:&'a str,width:u16,
)->Button<'a,Message,Theme,Renderer>whereTheme:'a+iced_aw::menu::StyleSheet+button::StyleSheet+text::StyleSheet+svg::StyleSheet,Renderer: 'a+iced::advanced::Renderer+iced::advanced::text::Renderer+iced::advanced::svg::Renderer,<Theme as iced_widget::button::StyleSheet>::Style: From<iced::theme::Button>
{let tt:Text<Theme,Renderer>=text(label).size(14).vertical_alignment(iced::alignment::Vertical::Center).horizontal_alignment(iced::alignment::Horizontal::Center);let arrow_svg=svg(svg::Handle::from_path(arrow)).width(16).height(16);let rr:Row<Message,Theme,Renderer>=row![tt,horizontal_space().height(20),arrow_svg,].spacing(10).align_items(iced::Alignment::Center).into();button(rr).width(width).height(30).on_press(msg).style(iced::theme::Button::Custom(Box::new(MenuButtonStyle)))
}
struct MenuButtonStyle;
impl button::StyleSheet for MenuButtonStyle{type Style = iced::Theme;fn active(&self, style: &Self::Style) -> button::Appearance {let backcolor=Color::from_rgb8(167, 218, 220);button::Appearance {text_color:Color::BLACK,background:Some(Background::Color(backcolor)),border:Border{radius:[4.0;4].into(),..Default::default()},..Default::default()}}fn pressed(&self, style: &Self::Style) -> button::Appearance {let backcolor=Color::from_rgb8(16, 137, 177);button::Appearance {text_color:Color::BLACK,background:Some(Background::Color(backcolor)),border:Border{radius:[4.0;4].into(),..Default::default()},..Default::default()}}fn hovered(&self, style: &Self::Style) -> button::Appearance {let backcolor=Color::from_rgb8(0, 164, 230);button::Appearance {text_color:Color::BLACK,background:Some(Background::Color(backcolor)),border:Border{radius:[4.0;4].into(),..Default::default()},..Default::default()}}fn disabled(&self, style: &Self::Style) -> button::Appearance {  let backcolor=Color::from_rgb8(0, 0, 100);    button::Appearance {text_color:Color::BLACK,background:Some(Background::Color(backcolor)),border:Border{radius:[4.0;4].into(),..Default::default()},..Default::default()}}
}pub struct MyMenuBarStyle{pub backcolor:Color,
}
impl iced_aw::style::menu_bar::StyleSheet for MyMenuBarStyle {type Style = iced::Theme;fn appearance(&self, style: &Self::Style) -> iced_aw::style::menu_bar::Appearance {let r=self.backcolor.r;let g=self.backcolor.g;let b=self.backcolor.b;let a=self.backcolor.a;let color1=Color::from_rgba(r+0.2, g+0.2, b+0.2, a+0.1);iced_aw::style::menu_bar::Appearance {//bar_background:Background::Color(Color::from_rgb8(177, 244, 251)),bar_background:Background::Color(self.backcolor),menu_background:Background::Color(color1),..Default::default()}}
}struct MySliderStyle{color:Color,
}
impl slider::StyleSheet for MySliderStyle { type Style = Theme;//激活时外观fn active(&self, style: &Self::Style) -> slider::Appearance {let mut r1=0.0;let mut g1=0.0;let mut b1=0.0;let mut a1=0.0;if self.color.r<=0.1 && self.color.g<=0.1 && self.color.b<=0.1{r1=0.5;g1=0.5;b1=0.5;}else if self.color.r>=0.9 || self.color.g>=0.9 || self.color.b>=0.9{r1=0.2;g1=0.2;b1=0.2;}else{r1=self.color.r;g1=self.color.g;b1=self.color.b;}if self.color.a<=0.1{a1=0.7;}else{a1=self.color.a;}slider::Appearance { rail: Rail{colors:(Color::from_rgba(r1-0.2, g1-0.2, b1-0.2,a1+0.1),Color::from_rgba(r1+0.2, g1+0.2, b1+0.2,a1+0.1)),width:5.0,border_radius:[3.0;4].into(),}, handle: slider::Handle{shape:HandleShape::Rectangle { width: 8, border_radius: [2.0;4].into() },color:Color::from_rgba(r1+0.1, g1+0.1,b1+0.1,a1),border_width:1.0,border_color:Color::BLACK,}}}//悬停时外观fn hovered(&self, style: &Self::Style) -> slider::Appearance {let r1=self.color.r;let g1=self.color.g;let b1=self.color.b;let a1=self.color.a;slider::Appearance { rail: Rail{colors:(Color::from_rgba(r1+0.1, g1+0.1, b1+0.1,a1),Color::from_rgba(r1-0.1, g1-0.1, b1-0.1,a1)),width:5.0,border_radius:[3.0;4].into(),}, handle: slider::Handle{shape:HandleShape::Rectangle { width: 8, border_radius: [2.0;4].into()},color:Color::from_rgba(r1+0.2, g1+0.2,b1+0.2,a1),border_width:1.0,border_color:Color::BLACK,}}}//拖拽时外观fn dragging(&self, style: &Self::Style) -> slider::Appearance {slider::Appearance { rail: Rail{colors:(Color::from_rgb8(20, 48, 210),Color::from_rgb8(151, 155, 175)),width:5.0,border_radius:[3.0;4].into(),}, handle: slider::Handle{shape:HandleShape::Rectangle { width: 8, border_radius: [2.0;4].into() },color:Color::from_rgb8(13, 248,44),border_width:1.0,border_color:Color::BLACK,}}}
}

uitheme.rs

use iced::{theme::{palette::{Background, Danger, Extended, Pair, Primary, Secondary, Success}, Palette}, Color,Theme};
use iced_aw::core::color;
use std::sync::Arc;pub enum UITheme{T1,T2,T3,
}impl UITheme{pub fn theme_name(&self) -> Theme{match self{UITheme::T1 => {let p1=Palette{background:iced::Color::from_rgba(0.0, 0.65, 0.6, 0.7),text:Color::BLACK,primary:Color::BLACK,success:Color::BLACK,danger:Color::BLACK,};let g1=Extended{background:Background{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},primary:Primary{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},secondary:Secondary{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},success:Success{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},danger:Danger{base:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},weak:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},strong:Pair{color:Color::from_rgba(0.1, 0.7, 0.7, 0.8),text:Color::BLACK},},is_dark:false,};let cus1=Arc::new(iced::theme::Custom::new("t1".to_string(),p1));let cus2=Arc::new(iced::theme::Custom::with_fn("t1".to_string(), p1, |_|g1));iced::Theme::Custom(cus1)}UITheme::T2 => {let p1=Palette{//background:iced::Color::from_rgba(0.0, 0.85, 0.8, 0.8),background:Color::from_linear_rgba(0.0, 0.5, 0.6, 0.8),text:Color::BLACK,primary:Color::BLACK,success:Color::BLACK,danger:Color::BLACK,};let cus1=Arc::new(iced::theme::Custom::new("t1".to_string(),p1));iced::Theme::Custom(cus1)},UITheme::T3 => {let p1=Palette{background:iced::Color::from_rgba(0.0, 0.85, 0.8, 0.8),text:Color::BLACK,primary:Color::BLACK,success:Color::BLACK,danger:Color::BLACK,};let cus1=Arc::new(iced::theme::Custom::new("t1".to_string(),p1));iced::Theme::Custom(cus1)},}}}pub struct UIThemeColor{pub color:Color,
}impl UIThemeColor {pub fn get_color(&self) -> Theme {let p1=Palette{background:self.color,text:Color::BLACK,primary:Color::BLACK,success:Color::BLACK,danger:Color::BLACK,};let cus1=Arc::new(iced::theme::Custom::new("t1".to_string(),p1));iced::Theme::Custom(cus1)
}
}

main.rs

#![allow(dead_code)]
#![allow(overflowing_literals)]
//cfg可以实现debug期间无视未使用、未导入等警告信息,但不影响发布后的警告
#![cfg_attr(debug_assertions, allow(dead_code, unused_imports,unused_variables,unused_mut,unused_assignments))]
use core::prelude;use iced::widget::{button, container, slider, text,svg,image,row,column};
use iced::window::{self,Icon};
use iced::{Application, Color, Command, Element, Point, Renderer, Settings, Size, Subscription};
use iced_aw::menu;
use iced_widget::graphics::text::cosmic_text::rustybuzz::ttf_parser::gdef;
use iced_widget::runtime::futures::event;
use rfd::{FileDialog,MessageDialog};
extern crate image as eximage;mod menuset;
mod uitheme;struct Example{slider_value:f32,slider_value2:f32,slider_value3:f32,slider_value4:f32,theme:iced::Theme,
}#[derive(Debug,Clone)]
enum Message{SliderChanged(f32),SliderChanged2(f32),SliderChanged3(f32),SliderChanged4(f32),WJ(menuset::WJMessage),GJ(menuset::GJMessage),GY(menuset::GYMessage),GFTheme(iced::Theme),MenuNone,EventOcu(iced::Event),
}///
/// 图片转为icon格式
fn image_to_icon(file:& str,w:u32,h:u32,) -> Icon {let img=eximage::open(file);let img_path=match img{Ok(path)=>path,Err(e)=>panic!("{}",e),};let img_file=img_path.to_rgba8();let icon=iced::window::icon::from_rgba(img_file.to_vec(), w, h);let icon2=match icon{Ok(iconfile)=>iconfile,Err(e)=>panic!("{}",e),};icon2
}fn main() -> iced::Result {//Example::run(Settings::default())let myfont="微软雅黑";let icon=image_to_icon("../img-convert/img/icon1.png", 500, 500);Example::run(Settings{window:window::Settings{size:Size{width:800.0,height:600.0},position:window::Position::Specific(Point{x:100.0,y:40.0}),icon:Some(icon),..Default::default()},default_font:iced::Font{family:iced::font::Family::Name(myfont),..Default::default()},..Default::default()})}async fn load() -> Result<(),String> {Ok(())
}impl Application for Example {type Executor =iced::executor::Default;type Message =Message;type Theme = iced::Theme;type Flags = ();fn new(flags: Self::Flags) -> (Self, Command<Self::Message>) {(Self{slider_value:0.5,slider_value2:0.5,slider_value3:0.5,slider_value4:0.8,theme:iced::Theme::Light,},Command::none())}fn title(&self) -> String {String::from("图片格式转换器")}fn theme(&self) -> Self::Theme {self.theme.clone()}fn update(&mut self, message: Self::Message) -> Command<Self::Message> {match message{Message::SliderChanged(value)=>{self.slider_value=value;let color1=Color::from_rgba(self.slider_value, self.slider_value2,self.slider_value3, self.slider_value4);self.theme=uitheme::UIThemeColor::get_color(&uitheme::UIThemeColor{color:color1});}Message::SliderChanged2(value)=>{self.slider_value2=value;let color1=Color::from_rgba(self.slider_value, self.slider_value2,self.slider_value3, self.slider_value4);self.theme=uitheme::UIThemeColor::get_color(&uitheme::UIThemeColor{color:color1});}Message::SliderChanged3(value)=>{self.slider_value3=value;let color1=Color::from_rgba(self.slider_value, self.slider_value2,self.slider_value3, self.slider_value4);self.theme=uitheme::UIThemeColor::get_color(&uitheme::UIThemeColor{color:color1});}Message::SliderChanged4(value)=>{self.slider_value4=value;let color1=Color::from_rgba(self.slider_value, self.slider_value2,self.slider_value3, self.slider_value4);self.theme=uitheme::UIThemeColor::get_color(&uitheme::UIThemeColor{color:color1});}Message::WJ(msg)=>{match msg{menuset::WJMessage::New=>{println!("new");}menuset::WJMessage::Open=>{println!("open")}menuset::WJMessage::Close=>{return window::close(window::Id::MAIN)}menuset::WJMessage::Save=>{println!("save")}menuset::WJMessage::WenJian=>{println!("wenjian")}}}Message::GJ(msg)=>{match msg{menuset::GJMessage::GongJv=>{println!("gongjv");}menuset::GJMessage::T1=>{println!("t1");self.theme=uitheme::UITheme::theme_name(&uitheme::UITheme::T1);self.slider_value=self.theme.clone().palette().background.r;self.slider_value2=self.theme.clone().palette().background.g;self.slider_value3=self.theme.clone().palette().background.b;self.slider_value4=self.theme.clone().palette().background.a;}menuset::GJMessage::T2=>{println!("t2");//self.theme=iced::Theme::Custom(Arc::new());let tt=uitheme::UITheme::theme_name(&uitheme::UITheme::T2);self.theme=tt;self.slider_value=self.theme.clone().palette().background.r;self.slider_value2=self.theme.clone().palette().background.g;self.slider_value3=self.theme.clone().palette().background.b;self.slider_value4=self.theme.clone().palette().background.a;}menuset::GJMessage::T3=>{println!("t3");self.theme=uitheme::UITheme::theme_name(&uitheme::UITheme::T3);self.slider_value=self.theme.clone().palette().background.r;self.slider_value2=self.theme.clone().palette().background.g;self.slider_value3=self.theme.clone().palette().background.b;self.slider_value4=self.theme.clone().palette().background.a;}}}Message::GY(msg)=>{match msg{menuset::GYMessage::GuanYu=>{println!("guanyu");}menuset::GYMessage::GY=>{println!("gy");let res=rfd::MessageDialog::new().set_title("关于").set_level(rfd::MessageLevel::Info).set_description("本软件是基于rust和iced的图像处理软件").set_buttons(rfd::MessageButtons::Ok).show();}menuset::GYMessage::BZ=>{println!("bz")}menuset::GYMessage::GX=>{println!("gx")}}}Message::GFTheme(gftheme)=>{self.theme=gftheme;self.slider_value=self.theme.clone().palette().background.r;self.slider_value2=self.theme.clone().palette().background.g;self.slider_value3=self.theme.clone().palette().background.b;self.slider_value4=self.theme.clone().palette().background.a;}Message::MenuNone=>{}Message::EventOcu(event)=>{}}Command::none()}fn subscription(&self) -> Subscription<Self::Message> {event::listen().map(Message::EventOcu)//Subscription::none()}fn view(&self) -> Element<'_, Self::Message, Self::Theme, crate::Renderer> {let themecolor=self.theme.palette().clone().background;//println!("{:?}",themecolor);//menu list setlet arrowsvg="..\\img-convert\\img\\arrow\\arrow_right_16.svg";let wj_open=menuset::menu_no_sub("打开",Message::WJ(menuset::WJMessage::Open));// let wj_new_mode1=menuset::menu_no_sub("格式1",Message::WJ(menuset::WJMessage::Open) );// let wj_new_mode2=menuset::menu_no_sub("格式2",Message::WJ(menuset::WJMessage::Open) );let wj_new=menuset::menu_no_sub("新建", Message::WJ(menuset::WJMessage::New));let wj_save=menuset::menu_no_sub("保存",Message::WJ(menuset::WJMessage::Save));let wj_close=menuset::menu_no_sub("关闭",Message::WJ(menuset::WJMessage::Close));let wj_main=menuset::menu_main("文件", Message::WJ(menuset::WJMessage::WenJian), vec![wj_open,wj_new,wj_save,wj_close]);let gj_title1_1=menuset::menu_no_sub("CatppuccinFrapp",Message::GFTheme(iced::Theme::CatppuccinFrappe));let gj_title1_2=menuset::menu_no_sub("CatppuccinLatte",Message::GFTheme(iced::Theme::CatppuccinLatte));let gj_title1_3=menuset::menu_no_sub("CatppuccinMacchiato",Message::GFTheme(iced::Theme::CatppuccinMacchiato));let gj_title1_4=menuset::menu_no_sub("CatppuccinMocha",Message::GFTheme(iced::Theme::CatppuccinMocha));let gj_title1_5=menuset::menu_no_sub("Dark",Message::GFTheme(iced::Theme::Dark));let gj_title1_6=menuset::menu_no_sub("Light",Message::GFTheme(iced::Theme::Light));let gj_title1_7=menuset::menu_no_sub("Dracula",Message::GFTheme(iced::Theme::Dracula));let gj_title1_8=menuset::menu_no_sub("Nord",Message::GFTheme(iced::Theme::Nord));let gj_title1_9=menuset::menu_no_sub("GruvboxDark",Message::GFTheme(iced::Theme::GruvboxDark));let gj_title1_10=menuset::menu_no_sub("GruvboxLight",Message::GFTheme(iced::Theme::GruvboxLight));let gj_title1=menuset::menu_with_sub("官方主题",Message::MenuNone,arrowsvg,vec![gj_title1_1,gj_title1_2,gj_title1_3,gj_title1_4,gj_title1_5,gj_title1_6,gj_title1_7,gj_title1_8,gj_title1_9,gj_title1_10,]);let gj_title2_1=menuset::menu_no_sub("主题1",Message::GJ(menuset::GJMessage::T1));let gj_title2_2=menuset::menu_no_sub("主题2",Message::GJ(menuset::GJMessage::T2));let gj_title2_3=menuset::menu_no_sub("主题3",Message::GJ(menuset::GJMessage::T3));let gj_title2=menuset::menu_with_sub("自定义主题",Message::MenuNone,arrowsvg,vec![gj_title2_1,gj_title2_2,gj_title2_3,]);let gj_title3_1=menuset::menu_no_sub_slider("R", Message::SliderChanged, self.slider_value,themecolor);let gj_title3_2=menuset::menu_no_sub_slider("G", Message::SliderChanged2, self.slider_value2,themecolor);let gj_title3_3=menuset::menu_no_sub_slider("B", Message::SliderChanged3,self.slider_value3,themecolor);let gj_title3_4=menuset::menu_no_sub_slider("A", Message::SliderChanged4,self.slider_value4,themecolor);let gj_title3=menuset::menu_with_sub("动态调整",Message::MenuNone,arrowsvg,vec![gj_title3_1,gj_title3_2,gj_title3_3,gj_title3_4,]);let gj_main=menuset::menu_main("主题", Message::GJ(menuset::GJMessage::GongJv),vec![gj_title1,gj_title2,gj_title3]);let gy_gy=menuset::menu_no_sub("关于", Message::GY(menuset::GYMessage::GY));let gy_bz=menuset::menu_no_sub("帮助", Message::GY(menuset::GYMessage::BZ));let gy_gx=menuset::menu_no_sub("更新", Message::GY(menuset::GYMessage::GX));let gy_main=menuset::menu_main("帮助", Message::GY(menuset::GYMessage::GuanYu),vec![gy_gy,gy_bz,gy_gx]);let barstyle=iced_aw::style::menu_bar::MenuBarStyle::Custom(Box::new(menuset::MyMenuBarStyle{//backcolor:Color::from_rgba8(106, 195, 251, 0.8),backcolor:themecolor,}));let menu_bar=menuset::create_menubar(vec![wj_main,gj_main,gy_main,],barstyle);let cont1=container(menu_bar).padding(5);cont1.into()}
}
动态演示

rustGUI动态调整演示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/846589.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python列表的扩展操作

列表的扩展操作 zip() 函数 我们先学习 zip() 函数&#xff0c;将排名与分数挂钩。 还记得期中考试的顺序排名和分数吗&#xff1f;我们把排名放在了列表 midterm_rank 中&#xff0c;把分数放在了 scores 中。不过当时 scores 并没有排序&#xff0c;我们要对数据进行预处理…

深入理解文件系统和日志分析

文件是存储在硬盘上的&#xff0c;硬盘上的最小存储单位是扇区&#xff0c;每个扇区的大小是512字节。 inode&#xff1a;存储元信息&#xff08;包括文件的属性&#xff0c;权限&#xff0c;创建者&#xff0c;创建日期等等&#xff09; block&#xff1a;块&#xff0c;连续…

小白跟做江科大32单片机之LED闪烁

原理介绍 原理介绍详见&#xff1a; 【STM32】江科大STM32学习笔记汇总(已完结)_stm32江科大笔记-CSDN博客https://blog.csdn.net/u010249597/article/details/134762513 项目准备 1.在项目文件夹中新建3-1 LED文件夹 2.keil新建项目&#xff0c;打开新建的3-1 LED&#xf…

【CC2530-操作外部flash】

zigbee cc2530操作flash&#xff0c;以cc2530读flash_id为例子&#xff1b; void InitIO() {CLKCONCMD & ~0x40; //设置系统时钟源为32MHZ晶振 while(CLKCONSTA & 0x40); //等待晶振稳定为32M CLKCONCMD & ~0x47; //设置系统主时钟频率为32MHZ…

面试(五)

目录 1. 知道大顶堆小顶端吗&#xff0c;代码怎么区分大顶端小顶端 2. 计算机中栈地址与内存地址增长方向相反吗&#xff1f; 3. %p和%d输出指针地址 4. 为什么定义第二个变量时候&#xff0c;地址反而减了 5. 12&#xff0c;32&#xff0c;64位中数据的占字节&#xff1f;…

物质的量质量,它们可不是一个概念

物质的量&质量&#xff0c;它们可不是一个概念。 物质的量&质量 乍一听物质的量&#xff0c;还以为是和质量有什么关系&#xff0c;是不是&#xff1f;其实物质的量和质量没什么直接的联系。 物质的量是国际单位制中7个基本物理量之一&#xff0c;其符号为n&#xf…

Aras Innovator-Team(群组)的使用方法

当Aras Innovator在处理权限时&#xff0c;在不使用Team的情况下&#xff0c;系统的权限配置可以满足大部分业务场景&#xff0c;如&#xff1a;常见的按照组织架构&#xff0c;成员和角色分配权限&#xff0c;按照生命周期分配权限等。 如果遇到比较复杂的权限需求&#xff0c…

AltiumDesigner/AD添加数据库连接

1.首先确保本机电脑有无对应的数据库驱动&#xff0c;例如我这边要添加MySQL的数据&#xff0c;则需要首先下载MySQL数据驱动&#xff1a;MySQL :: Download MySQL Connector/ODBC (Archived Versions) 2.运行“odbcad32.exe”&#xff0c;如下图添加对应的数据库配置&#xf…

【C/C++】C/C++车辆交通违章管理系统(源码+数据文件)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

面试题:useEffect的Clean Up 什么时候触发?

​ useEffect作为做常用的Hook&#xff0c;以下三个知识点你有必要了解下~ 防止写出奇怪的代码祸害队友&#xff0c;而我不幸就是这个受害者&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; useEffect的依赖项为空 useEffect的dependencyList作为一个可选参数…

Pytest框架中用例用例执行常用参数介绍

pytest 支持通过命令行参数来定制测试运行的方式。以下是一些常用的 pytest 执行参数介绍。 学习目录 -q 或 --quiet: 安静模式&#xff0c;只显示进度和摘要 -s : 选项允许在测试的输出中捕获 stdout 和 stderr。 -v : 选项会使 pytest 的输出更加详细。 -k &#xff1a;…

Git 恢复已删除的branch

六一节晚上改了点code, 做完之后commit, 然后误删了这个branch, 并且新建了branch. 那么怎样恢复已删除的branch呢&#xff1f; 网上查询一番&#xff0c;找到了答案&#xff1a; 1. git reflog 找到被删的branch中最后一笔commit, 记录它的SHA1。 怎么看SHA1是被删除的bra…

鸿蒙应用Stage模型【应用/组件级配置】

应用/组件级配置 在开发应用时&#xff0c;需要配置应用的一些标签&#xff0c;例如应用的包名、图标等标识特征的属性。本文描述了在开发应用需要配置的一些关键标签。 应用包名配置 应用需要在工程的AppScope目录下的[app.json5配置文件]中配置bundleName标签&#xff0c;…

Python PyInstaller打包方法介绍

为了将开发好的Python工具交付给其他人使用&#xff0c;除了在目标电脑部署Python编译环境以外&#xff0c;我们还可以将它打包成可执行文件&#xff0c;这样目标电脑不需要安装Python环境就可以运行。将Python程序打包成可执行文件的方法有多种&#xff0c;比如Nuitka、PyInst…

微博增强-tampermonkey脚本实现网页管理悄悄关注

不是很明白微博为什么不出个x的列表功能&#xff0c;毕竟现在信息洪流&#xff0c;有些东西只是要看要了解&#xff0c;但不希望天天在首页轰炸眼睛&#xff0c;扰乱心智。 这个tampermonkey脚本适配了pc web和手机pwa版本&#xff08;weibo.com/m.weibo.cn&#xff09;,解决了…

golang map部分原理源码个人走读-附个人理解过程图解

近期再写map的demo时出现了下面一段报错&#xff0c;于是带着疑惑去看了一下源码 目的&#xff1a;主要想知道为啥map不让并发读写 fatal error: concurrent map read and map write 一.map的数据结构 先有个印象&#xff0c;后续会详细介绍 // A header for a Go map. ty…

NDIS Filter开发-OID 请求

NDIS 定义对象标识符 (OID) 值来标识适配器参数&#xff0c;其中包括操作参数&#xff0c;例如设备特征、可配置的设置和统计信息。 Filter驱动程序可以查询或设置基础驱动程序的操作参数&#xff0c;或过滤/覆盖顶层驱动程序的 OID 请求。 NDIS 还为 NDIS 6.1 及更高版本的Fi…

Informer

I n f o r m e r Informer Informer 摘要&#xff1a; 长序列时间序列的预测 i n f o r m e r informer informer优点&#xff1a; P r o b s p a r e Probspare Probspare自关注机制&#xff0c;在时间复杂度和内存使用方面达到 O ( N l o g N ) O(NlogN) O(NlogN),在序列依…

IP协议1.0

基本概念&#xff1a; • 主机: 配有IP地址, 但是不进⾏路由控制的设备; • 路由器: 即配有IP地址, ⼜能进⾏路由控制; • 节点: 主机和路由器的统称; IP协议的报头 • 4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4. • 4位头部⻓度(header length): IP头部的⻓…

mybatis增删改查模板设置及设置调用

mybatis增删改查模板设置 系统配置文件完成以及连接好数据之后&#xff0c;就可以用这个mybatis了&#xff0c;首先写这个数据库的增删改查模板StashMapper.xml&#xff0c;这个东西是要放在DAO层中的奥&#xff0c;切记。 1.编写mybatis对应数据库的增删改查模板 在我的Sta…