RustGUI学习(iced)之小部件(一):如何使用按钮和文本标签部件

2024-04-25 07:20

本文主要是介绍RustGUI学习(iced)之小部件(一):如何使用按钮和文本标签部件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言
本专栏是学习Rust的GUI库iced的合集,将介绍iced涉及的各个小部件分别介绍,最后会汇总为一个总的程序。
iced是RustGUI中比较强大的一个,目前处于发展中(即版本可能会改变),本专栏基于版本0.12.1.

概述
这是本专栏的第一篇,主要讲述按钮(button)和文本标签(text)两个部件的使用,会结合实例来说明。

环境配置:
系统:windows
平台:visual studio code
语言:rust
库:iced

在这里插入图片描述
注:iced是一个受Elm启发而编写,适用于rust语言的跨平台的GUI库。

本篇内容:
1、button
2、text

一、按钮部件

按钮部件在iced中的定义如下:

/// Creates a new [`Button`] with the provided content.  
///
/// [`Button`]: crate::Button
pub fn button<'a, Message, Theme, Renderer>(content: impl Into<Element<'a, Message, Theme, Renderer>>,
) -> Button<'a, Message, Theme, Renderer>
whereRenderer: core::Renderer,Theme: button::StyleSheet,
{Button::new(content)
}

上面是官方的代码,可以知道,button其实是Button来创建的。而Button来自于iced_widget库:

#[allow(missing_debug_implementations)]
pub struct Button<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>      
whereTheme: StyleSheet,Renderer: crate::core::Renderer,
{content: Element<'a, Message, Theme, Renderer>,on_press: Option<Message>,width: Length,height: Length,padding: Padding,clip: bool,style: Theme::Style,
}

我们可以看到,一个新建的button,拥有以下属性或者方法:
content、on_press、width、height、padding、clip、style
其中,content按照定义,是一个Element,即可以是任何元素,但一般情况下,我们会给content赋为纯文本(即按钮名称)或者文本部件(即text)。
width、height这两个属性好理解,即按钮的宽、高,宽、高属性既可以设置为预设值,也可以设置为自定义的大小。
padding是指的按钮的content与按钮整个框架的间距。
clip是指当按钮尺寸小于文字时,多出的文字是显示还是隐藏。
style是设置按钮的外观样式,可以使用库预设的样式,也可以使用自定义的样式,下文将会详述。
我们先来看一下button实际的代码:

button("按钮1").clip(false).width(80).height(40).style(style6).padding(4)    .on_press(Message::Clicked),

这是一个典型的button实例,上面的代码中,“按钮1”即content,其他属性则显而易见,其中style的参数style6如下:

let style6=theme::Button::Custom(Box::new(MyButtonStyle));

此处使用的是自定义外观,库预设的样式如下:

let style1=theme::Button::Primary;let style2=theme::Button::Secondary;let style3=theme::Button::Positive;let style4=theme::Button::Destructive;let style5=theme::Button::Text;

看一下这五种预设的按钮样式实际是什么样的:
在这里插入图片描述
如果预设样式足够使用,那么直接使用即可,如果预设样式不满足,那么还可以使用自定义样式,比如要设置按钮边框,添加圆角,改变颜色等,我们来看一下如何设置自定义按钮样式:
我们查看iced源码可知,按钮的样式是在StyleSheet这个特性下设置的:

pub trait StyleSheet {/// The supported style of the [`StyleSheet`].type Style: Default;/// Produces the active [`Appearance`] of a button.fn active(&self, style: &Self::Style) -> Appearance;/// Produces the hovered [`Appearance`] of a button.fn hovered(&self, style: &Self::Style) -> Appearance {let active = self.active(style);Appearance {shadow_offset: active.shadow_offset + Vector::new(0.0, 1.0),..active}}/// Produces the pressed [`Appearance`] of a button.fn pressed(&self, style: &Self::Style) -> Appearance {Appearance {shadow_offset: Vector::default(),..self.active(style)}}/// Produces the disabled [`Appearance`] of a button.fn disabled(&self, style: &Self::Style) -> Appearance {let active = self.active(style);Appearance {shadow_offset: Vector::default(),background: active.background.map(|background| match background {Background::Color(color) => Background::Color(Color {a: color.a * 0.5,..color}),Background::Gradient(gradient) => {Background::Gradient(gradient.mul_alpha(0.5))}}),text_color: Color {a: active.text_color.a * 0.5,..active.text_color},..active}}
}

如果我们要设置自定义的样式,那么新建一个样式结构体,然后将StyleSheet赋予我们新建的样式,在其中修改即可,如下:
1、新建样式:

struct MyButtonStyle;

2、实现StyleSheet特性

impl  StyleSheet for MyButtonStyle{      type Style = Theme;//激活时外观fn active(&self, style: &Self::Style) -> button::Appearance {Appearance{shadow_offset:Vector{x:0.0,y:0.0},background:Some(style.extended_palette().primary.base.color.into()),text_color:style.extended_palette().background.base.text,border:Border{color:Color::BLACK,width:1.0,radius:[3.0;4].into(),},shadow:Shadow { color: Color::WHITE, offset: Vector{x:0.0,y:0.0},blur_radius:0.0 },}}//悬停时外观fn hovered(&self, style: &Self::Style) -> Appearance {Appearance{shadow_offset:Vector{x:0.0,y:0.0},background:Some(style.extended_palette().primary.weak.color.into()),text_color:style.extended_palette().primary.weak.text,border:Border{color:Color::BLACK,width:1.0,radius:[3.0;4].into(),},shadow:Shadow {color: Color::WHITE,offset: Vector{x:0.0,y:0.0},blur_radius:0.0,}}}//按下时外观fn pressed(&self, style: &Self::Style) -> Appearance {Appearance{shadow_offset:Vector{x:0.0,y:0.0},background:Some(style.extended_palette().primary.strong.color.into()),text_color:style.extended_palette().primary.weak.text,border:Border{color:Color::BLACK,width:1.0,radius:[3.0;4].into(),},shadow:Shadow {color: Color::BLACK,offset: Vector{x:0.0,y:0.0},blur_radius:0.0,}}}
}

可以看到,我们在此处设置了按钮的激活、悬停、按压三种状态下的外观,具体来说,就是修改Appearance这个属性,其子属性如下:

pub struct Appearance {     /// The amount of offset to apply to the shadow of the button.pub shadow_offset: Vector,/// The [`Background`] of the button.pub background: Option<Background>,/// The text [`Color`] of the button.pub text_color: Color,/// The [`Border`] of the buton.pub border: Border,/// The [`Shadow`] of the butoon.pub shadow: Shadow,
}

这是官方定义的按钮的Appearance属性,我们只要一一修改,就可以得到我们自己的Appearance。如上面的示例代码中,我们修改了背景色、圆角半径等,其中shadow可以设置按钮的阴影,有兴趣的可以去尝试,可以做出不同的效果,当然,对于普通的UI界面来说,不需要那么复杂的效果,那么只要修改背景色、文字颜色、边框、圆角半径等即可。
当我们新建样式完成后,就可以在创建按钮时调用了:

let style6=theme::Button::Custom(Box::new(MyButtonStyle));

此处,Custom的参数形式,在官方定义中如下:

Custom(Box<dyn button::StyleSheet<Style = Theme>>), 

来看一下自定义样式和预设样式有什么不一样:
在这里插入图片描述
按钮的样式说的差不多了,下面说一下按钮最重要的一个属性,on_press,这是按钮能够进行交互的基础,当用户点击按钮时,就会触发on_press,然后将on_press的消息Message传递给后台,根据按钮传递的消息,运行相应的逻辑,然后再更新UI。
示例代码中如下:

 button("按钮1").clip(false).width(80).height(40).style(style1).padding(4).on_press(Message::Clicked),

on_press的参数为Message::Clicked,此处的Message::Clicked需要自己创建,是enum枚举:

#[derive(Debug,Clone,Copy)]
enum Message{  Clicked,
}

当按钮被点击时,Message::Clicked就会被触发,然后在iced的update函数中,我们可以处理这个message:

 fn update(&mut self,message:Message){   match message{Message::Clicked => {self.value +=1;}    }}

即,当Message::Clicked触发一次,就会执行一次当前Message::Clicked下对应的程序,本例中即将value这个值加1.

那么,当我点击了按钮,value值也加1了,该如何将这个变化反应到UI界面,使其直观显示出来呢?

我们会用到iced的view函数:

fn view(&self) -> Element<Message>{           }

view函数实时显示当前UI,所以,我们要将部件都写在view函数中,比如,本例中我添加一个按钮、一个文本标签,然后当点击按钮时,文本的值加1.

fn view(&self) -> Element<Message>{     let style6=theme::Button::Custom(Box::new(MyButtonStyle));let  style7=theme::Text::Color(Color::BLACK);column![button("按钮6").clip(false).width(80).height(40).style(style6).padding(4).on_press(Message::Clicked),text(format!("value:{}",self.value)).size(15).width(40).height(40).style(style7),].padding(20).spacing(20).into()}

如上,我们添加了按钮,这不用多说,又添加了一个text部件,其中,text部件的text属性部分,我们将其设置为与value值绑定,这样,每当value值变化,view函数都会刷新text部件的文本部分。
这其中,column是一种排列方式,即区域内的部件按照纵向排列,另一种方式是row,即横向排列。
看一下实际效果:
在这里插入图片描述

二、文本标签

再来说一下文本标签的使用,相比于按钮,文本标签要简单许多,在官方的定义中,text部件如下:

/// Creates a new [`Text`] widget with the provided content. 
///
/// [`Text`]: core::widget::Text
pub fn text<'a, Theme, Renderer>(text: impl ToString,
) -> Text<'a, Theme, Renderer>
whereTheme: text::StyleSheet,Renderer: core::text::Renderer,
{Text::new(text.to_string())
}

可以看到,其来自于Text:

/// A paragraph of text.                  
#[allow(missing_debug_implementations)]
pub struct Text<'a, Theme, Renderer>
whereTheme: StyleSheet,Renderer: text::Renderer,
{content: Cow<'a, str>,size: Option<Pixels>,line_height: LineHeight,width: Length,height: Length,horizontal_alignment: alignment::Horizontal,vertical_alignment: alignment::Vertical,font: Option<Renderer::Font>,shaping: Shaping,style: Theme::Style,
}

其中content是文本要显示的字符,size是文字的尺寸,width和height是宽、高,horizontal_alignment是设置文字的水平样式,有左、中、右可选,而vertical_alignment是设置文字的垂直样式,顶部、中间、底部可选,font是设置字体,如果不设置,则和主窗体保持一致,shaping应该指的是文字的显示质量。style是指文字样式,在text的style中,只有颜色可以修改,如下:

/// The style sheet of some text. 
pub trait StyleSheet {/// The supported style of the [`StyleSheet`].type Style: Default + Clone;/// Produces the [`Appearance`] of some text.fn appearance(&self, style: Self::Style) -> Appearance;
}
/// The apperance of some text.   
#[derive(Debug, Clone, Copy, Default)]
pub struct Appearance {/// The [`Color`] of the text.////// The default, `None`, means using the inherited color.pub color: Option<Color>,
}

可以看到,text的样式就是修改颜色。
我们在上面的示例中如下:

text(format!("value:{}",self.value)).size(15).shaping(Shaping::Advanced) .width(40).height(40).style(style7),

如果要设置文字的排列样式,可以添加:

text(format!("value:{}",self.value)).size(15).shaping(Shaping::Advanced)     .horizontal_alignment(alignment::Horizontal::Center).vertical_alignment(alignment::Vertical::Center).width(40).height(40).style(style7),

如上代码,文字就会一直保持在中心位置。

下面再来简单说一下窗体的属性问题,iced建立窗体,有两种样式,一种是比较简单的呈现,是sandbox,另一种是application。
在前期,我们会使用sandbox来演示。

pub fn main() -> iced::Result {    Counter::run(Settings::default())
}

以上是官方的默认主程序,此处运行主窗体,其中的参数设置皆为默认,但默认的参数不一定适用,所以需要对其进行修改。
如果要修改默认参数,需要先导入:

use iced::font::Family; 
use iced::window::{self,icon,Position};

以及:

extern crate image;
use image::GenericImageView;

此处的image库是用来处理图像的。

接下来看一下如何修改窗口参数:

pub fn main() -> iced::Result {//Counter::run(Settings::default())let myfont="微软雅黑";let ico=image_to_icon("..\\gui-btn\\img\\ico1.png");Counter::run(Settings{window:window::Settings{size:Size{width:800.0,height:600.0},position:Position::Specific(Point{x:100.0,y:20.0}),icon:Some(ico),..window::Settings::default()},default_font:Font { family:Family::Name(myfont),..Font::DEFAULT},..Settings::default()})}

如上代码,可以看到,我们设置了窗体尺寸、窗体显示位置、窗体图标、字体,事实上程序参数如下:

/// The settings of an application.    
#[derive(Debug, Clone)]
pub struct Settings<Flags> {/// The identifier of the application.////// If provided, this identifier may be used to identify the application or/// communicate with it through the windowing system.pub id: Option<String>,/// The window settings.////// They will be ignored on the Web.pub window: window::Settings,/// The data needed to initialize the [`Application`].////// [`Application`]: crate::Applicationpub flags: Flags,/// The fonts to load on boot.pub fonts: Vec<Cow<'static, [u8]>>,/// The default [`Font`] to be used.////// By default, it uses [`Family::SansSerif`](crate::font::Family::SansSerif).pub default_font: Font,/// The text size that will be used by default.////// The default value is `16.0`.pub default_text_size: Pixels,/// If set to true, the renderer will try to perform antialiasing for some/// primitives.////// Enabling it can produce a smoother result in some widgets, like the/// [`Canvas`], at a performance cost.////// By default, it is disabled.////// [`Canvas`]: crate::widget::Canvaspub antialiasing: bool,
}

其中,window参数又如下:

/// The window settings of an application.    
#[derive(Debug, Clone)]
pub struct Settings {/// The initial logical dimensions of the window.pub size: Size,/// The initial position of the window.pub position: Position,/// The minimum size of the window.pub min_size: Option<Size>,/// The maximum size of the window.pub max_size: Option<Size>,/// Whether the window should be visible or not.pub visible: bool,/// Whether the window should be resizable or not.pub resizable: bool,/// Whether the window should have a border, a title bar, etc. or not.pub decorations: bool,/// Whether the window should be transparent.pub transparent: bool,/// The window [`Level`].pub level: Level,/// The icon of the window.pub icon: Option<Icon>,/// Platform specific settings.pub platform_specific: PlatformSpecific,/// Whether the window will close when the user requests it, e.g. when a user presses the/// close button.////// This can be useful if you want to have some behavior that executes before the window is/// actually destroyed. If you disable this, you must manually close the window with the/// `window::close` command.////// By default this is enabled.pub exit_on_close_request: bool,
}

我们并不是每一个参数都需要修改,这里我们只是修改了尺寸、位置、图标以及字体这种常用的参数,其余的参数可以全部默认。
在我们上面的代码中,有一句处理图像的程序:

let ico=image_to_icon("..\\gui-btn\\img\\ico1.png");

其中的image_to_icon是我们自定义的函数,用于将图像转为icon,函数如下:

///
/// 将图片转为窗口图标
/// 
fn image_to_icon(img:&str)-> icon::Icon {           let img=image::open(img).unwrap();let img_de=img.dimensions();//println!("img_de is {:?}",img_de);let w1=img_de.0;let h1=img_de.1;let img_file=img.to_rgba8();let ico=icon::from_rgba(img_file.to_vec(),w1,h1);let ico_file=match ico{Ok(file)=>file,Err(e)=>panic!("error is {}",e),};ico_file
}

这里用到image库,需要在toml中添加:

image="0.25.1"

以上就是本篇的内容,其中涉及窗口的内容,在以后的篇章中将不再赘述。

这篇关于RustGUI学习(iced)之小部件(一):如何使用按钮和文本标签部件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/934038

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi