[rustGUI][iced]基于rust的GUI库iced(0.13)的部件学习(00):iced简单窗口的实现以及在窗口显示中文

前言
本文是关于iced库的部件介绍,iced库是基于rust的GUI库,作者自述是受Elm启发。
iced目前的版本是0.13.1,相较于此前的0.12版本,有较大改动。
本合集是基于新版本的关于分部件(widget)的使用介绍,包括源代码介绍、实例使用等。

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

iced窗口实现

1、一个典型的iced窗口程序

根据iced库作者的叙述,他是受到了Elm的启发,而创建了iced。
Elm的架构如下:
image
想要详细了解的,可以去Elm的官网看看:
https://elm-lang.org/
本文不关注Elm的具体,而是关注于iced的实现。我们以iced官方举例的一个典型的计数器程序来说明。
iced的结构如下:

  1. State — the state of your application
  2. Messages — user interactions or meaningful events that you care about
  3. View logic — a way to display your state as widgets that may produce messages on user interaction
  4. Update logic — a way to react to messages and update your state

可以看到,与Elm的架构的确是一脉相承。
程序介绍:这个计数器程序,是这样的,有两个按钮button、一个text文本部件,点击按钮,将产生计数,增加或者减少,数值的增、减体现在文本上。
在此处,数值变量,设置为一个State变量,而按钮的点击将产生message,按钮、文本的显示有view来提供,而点击按钮产生消息,则由update来更新。
先来看一个完整代码(与官方源代码稍有差异):

use iced::widget::{button,text,column};#[derive(Default)]
struct Counter {count:i32,
}
#[derive(Debug,Clone, Copy)]
enum Message {Inc,Dec,
}
fn main() ->iced::Result {iced::run("counter", Counter::update, Counter::view)
}impl Counter {pub fn update(&mut self, message:Message) {match message {Message::Inc =>{self.count += 1;} Message::Dec => {self.count -= 1;}}}pub fn view(&self) -> iced::Element<Message> {column![button("inc").on_press(Message::Inc),text(self.count).size(20),button("dec").on_press(Message::Dec)].padding(20).align_x(iced::Center).into()}  
}

如果你运行程序:cargo run效果如下:
image
我们可以来简单了解一下代码。
首先是要导入需要使用的部件:use iced::widget::{button,text,column};
本例中,我们导入了button、text以及column三个widget,其中column属于布局部件,可以添加子部件,如button、text。
接着,在iced的架构中,我们需要创建State以及Message:

#[derive(Default)]
struct Counter {count:i32,
}
#[derive(Debug,Clone, Copy)]
enum Message {Inc,Dec,
}

可以看到,State是struct类型,而Message是枚举类型,当然本例中是最简单的,我们设置了count为i32整数型变量,而Inc、Dec是枚举的两个元素。
接着,我们需要实现view以及update:

impl Counter {pub fn update(&mut self, message:Message) {match message {Message::Inc =>{self.count += 1;} Message::Dec => {self.count -= 1;}}}pub fn view(&self) -> iced::Element<Message> {column![button("inc").on_press(Message::Inc),text(self.count).size(20),button("dec").on_press(Message::Dec)].padding(20).align_x(iced::Center).into()}  
}

此处我们使用impl来为我们创建的State即Counter结构体,实现view和update函数功能,简单看一下这两个函数,先说update,它是用于接收UI界面的反馈,然后对State进行更新的:

match message {Message::Inc =>{self.count += 1;} Message::Dec => {self.count -= 1;}}

标准的iced代码中,通过对Message进行匹配,以针对不同的UI产生的消息,运行相应的逻辑,当然此处也可以写的更复杂,后续介绍。
而view函数是用于渲染UI部件,包括初始化以及update后的刷新:

text(self.count).size(20),

以text部件的显示值为例,我们绑定了State中定义的变量count,当count值改变时,view会即时将其渲染到text的value中,以在UI上显示,在本例中,当我们点击按钮后,文本值就会增加或者减少。

最后,在主函数中,调用iced::run()

fn main() ->iced::Result {iced::run("counter", Counter::update, Counter::view)
}

iced::run返回的是一个Result,所以需要修改main函数的反馈为iced::Result。

以上,我们完成一个典型的简单的iced窗口程序。

2、如何显示中文

我们对上面的代码做一些改变,将按钮的文本修改为中文的“增加”和“减少”:

 	button("增加").on_press(Message::Inc),text(self.count).size(20),button("减少").on_press(Message::Dec)

然后再运行程序看一下结果:
image
很清楚的看到,按钮文本显示为乱码,如图所示,并没有正确的显示中文,原因是iced的默认字体是:SansSerif

官方源码
 pub const DEFAULT: Font = Font {family: Family::SansSerif,weight: Weight::Normal,stretch: Stretch::Normal,style: Style::Normal,};

所以,如果我们要显示中文,需要修改其字体,而字体属于Settings的参数,所以,我们需要设置Settings。

官方源码
/// The settings of an iced program.
#[derive(Debug, Clone)]
pub struct Settings {/// 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 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,
}

在之前的主函数中,我们调用了iced::run来运行iced应用,接下来我们需要修改它。
如果我们只是需要修改字体,那么有一个简单的方法:

fn main() ->iced::Result {//iced::run("counter", Counter::update, Counter::view)  iced::application("count",Counter::update,Counter::view).default_font(iced::Font::from(Font::with_name("微软雅黑"))).run()}

如上,我们使用iced::application().run()来调用程序,事实上,iced::run()是一种简写。
然后在基础上直接调用default_font函数,为其传入自定义字体:
iced::Font::from(Font::with_name("微软雅黑"))
注意,此处我们使用了字体名称,这是一种“偷懒”的写法,前提是你的电脑中安装了此字体。运行后效果:
image

如果电脑中没有设置的字体,就会使用默认字体。
但通常来说,像宋体、微软雅黑这些字体都是电脑自带的字体,所以我们可以这样来使用。

3、设置窗口位置、尺寸以及icon图标

我们创建了窗口后,很显然希望能够自定义窗口的大小、初始位置以及图标等,这些都是在iced的application的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,
}

我们在主函数中修改:

   iced::application("count",Counter::update,Counter::view).default_font(iced::Font::with_name("微软雅黑")).window(Settings{size:iced::Size{width:300.0,height:300.0},position:Position::Specific(iced::Point{x:100.0,y:100.0}),icon:Some(),..Default::default()}).run()

上述代码中,我们设置了window尺寸、位置以及天剑了icon,但是注意到,我们没有为icon设置具体的图片,此处我们需要单独来说一下,iced中的icon,其参数类型为 Option < Icon >:

官方源码
/// An window icon normally used for the titlebar or taskbar.
#[derive(Debug, Clone)]
pub struct Icon {rgba: Vec<u8>,size: Size<u32>,
}

Icon是一个包含图像数据的u8数组,我们需要提供这样的图片,或者使用其他图片处理库进行转换,所以这里我们要引入image库。
在toml中添加引用:
image="0.25.5"
然后在程序中调用:
extern crate image as eximg;
这里为什么要这样调用?是因为iced中也有一个image的feature,用于处理图片,所以,虽然我们暂时未使用iced中image,但是为了以后调用时二者冲突,所以对于外部导入的image,我们使用别名,本例中为eximg。
我们新建一个函数,用于处理图片,即将普通格式如png、jpg等格式的图片,转为iced中的Icon格式,这个函数我们就命名为:img_to_icon

fn img_to_icon(path:&str,w:u32,h:u32) ->Icon{let img_dyn=eximg::open(path).expect("open fail");let img_rgba=img_dyn.to_rgba8();let img_icon=icon::from_rgba(img_rgba.to_vec(), w, h).expect("to icon err");return img_icon
}

这个转换的代码比较简单,就是根据传入的图片路径,将其转换为Icon然后返回。
调用函数:
let myicon:Icon=img_to_icon("mainicon.png", 256, 256);
此处的图片是从网上下载的:
image

然后将myicon赋予icon:
icon:Some(myicon),
运行看看:
image
注意窗口左上角的图标,是正确显示的。当然,以上的转换函数并不完美,一些图片格式如svg是不能转换的。
当然,rust中是可以对svg进行处理的,但这个不在本文的讨论范围,会在后续介绍。

4、完整代码

最后,贴上完整的代码:

use iced::widget::{button, column, text};
use iced::window::{Settings,Icon,Position};
use iced_widget::core::window::icon;extern crate image as eximg;#[derive(Default)]
struct Counter {count:i32,
}
#[derive(Debug,Clone, Copy)]
enum Message {Inc,Dec,
}
fn main() ->iced::Result {//iced::run("counter", Counter::update, Counter::view) let myicon:Icon=img_to_icon("mainicon.png", 256, 256);iced::application("count",Counter::update,Counter::view).default_font(iced::Font::with_name("微软雅黑")).window(Settings{size:iced::Size{width:300.0,height:300.0},position:Position::Specific(iced::Point{x:100.0,y:100.0}),icon:Some(myicon),..Default::default()}).run()}impl Counter {pub fn update(&mut self, message:Message) {match message {Message::Inc =>{self.count += 1;} Message::Dec => {self.count -= 1;}}}pub fn view(&self) -> iced::Element<Message> {column![button("增加Inc").on_press(Message::Inc),text(self.count).size(20),button("减少Dec").on_press(Message::Dec)].padding(20).align_x(iced::Center).into()}  
}fn img_to_icon(path:&str,w:u32,h:u32) ->Icon{let img_dyn=eximg::open(path).expect("open fail");let img_rgba=img_dyn.to_rgba8();let img_icon=icon::from_rgba(img_rgba.to_vec(), w, h).expect("to icon err");return img_icon
}

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

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

相关文章

飞书lark机器人 自动化发版

开发飞书机器人接收消息并调用构建接口, 实现自动化发版 发送指令 -> 机器人接收指令 -> 调用jenkins-job远程构建与部署飞书lark机器人 自动化发版 #1 介绍开发飞书机器人接收消息并调用构建接口, 实现自动化发版发送指令 -> 机器人接收指令 -> 调用jenkins-job…

CloudflareSpeedTest优选IP

# 1.下载CloudflareSpeedTest CloudflareST_linux_amd64.tar.gz: https://url53.ctfile.com/f/62655553-1442843278-2c1830?p=7311 (访问密码: 7311) # 2.下载generate_hosts.sh generate_hosts.sh: https://url53.ctfile.com/f/62655553-1442843314-4dcbe5?p=7311 (访问密码…

随笔-处理器微架构-测量最大IPC

目录固定cpu运行频率max_ipc_test.shLSD (Loop Stream Detector)arm固定cpu频率方式 固定cpu运行频率 我的测试环境cpu频率管理是intel_pstate: $ lscpu | grep -i hz Model name: Intel(R) Core(TM) i5-10500 CPU @ 3.10GHz CPU max MHz: …

6、RabbitMQ队列之主题【RabbitMQ官方教程】

在前面的教程中,我们改进了日志系统。我们没有使用只能进行虚拟广播的扇出交换机,而是使用了直接交换机,从而有可能选择性地接收日志。 虽然使用直接交换改进了我们的系统,但它仍然有局限性——它不能基于多个标准进行路由。 在我们的日志系统中,我们可能不仅要根据严重性…

石猴授徒-分支2-穿山大王

1-前面跟着任务跑,注意不要碰到"宫女" 2-在幻阵场景内点击各个NPC,战斗获得5个线索后,再重新点击其它NPC,提交线索。 注意:在归墟幻阵中通过传送门能够较快的移动,节约时间。3-提交5个线索后随机位置出现地洞,点击后可传送至“穿山大王府”。 4-在穿山大王府点…

KingbaseES 数据库备份恢复案例之---sys_rman备份进程异常

KingbaseES 、sys_rman案例说明: 执行sys_rman物理备份时,读取backup.info、backup.info.copy文件失败,sys_rman进程异常,无法正常结束服务,进程无法退出,阻塞新的备份任务。 适用版本:KingbaseES V8R6 一、问题现象 如下所示,sys_rman备份结束时,读取backup.info、ba…

养老服务市场潜力大,如何实现效率提升?——看板软件篇

通过引入看板软件,养老行业可以实现任务管理的可视化、协作的便捷化和资源的优化配置。这不仅提高了管理效率和服务质量,还为老年人提供了更加安全、舒适的养老服务环境。未来,随着技术的不断进步和应用的不断深化,看板软件将在养老行业中发挥更加重要的作用,为养老行业的…

易基因:单细胞WGBS揭示母源蛋白Pramel15调控早期胚胎发育的DNA甲基化重编程机制|NC/IF 14.7

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 哺乳动物的早期胚胎发育会经历重要的表观遗传重编程过程,这一过程需要重置从亲本基因组继承的表观遗传信息,以启动胚胎基因表达程序,而全基因组去甲基化对表观遗传重编程至关重要。哺乳动物基因组在CpG位点…

10个技巧,3分钟教会你github高效寻找开源项目(转)

作为程序员,不论是开发还是学习,肯定会用到开源项目,那么怎么快速在开源网站找到这些项目呢?常用的开源网站有:github 和 giteegithub是全球最大的开源社区,今天就以github为例,演示一下github界面一般来说,优秀的项目,维护会比较频繁,提交数也就会多一点。当然,一个…

Excel中使用VLOOKUP对两个单元格关联

一、背景 exl中需要关联两个Excel,根据主键合并两个单元格数据二、使用方法1、表1---列包含在id、姓名、年龄2、表2---列包含姓名、性别3、期望根据【姓名】列为主键,关联两个表数据,补充在【合并-性别】列 首先新增【合并-性别】列,然后选中期望填充的单元格,再点击2位置…