[rustGUI][iced]基于rust的GUI库iced(0.13)的部件学习(03):图像的导入 ...

打印 上一主题 下一主题

主题 861|帖子 861|积分 2583

媒介
本文是关于iced库的部件先容,iced库是基于rust的GUI库,作者自述是受Elm启发。
iced现在的版本是0.13.1,相较于此前的0.12版本,有较大改动。
本合集是基于新版本的关于分部件(widget)的使用先容,包括源代码先容、实例使用等。
情况配置
系统:window10
平台:visual studio code
语言:rust
库:iced 0.13
图像导入及显示

iced中显示图像,可以使用image部件,但image部件不是默认启用的,需要启用feature。在toml文件添加:
  1. iced={version="0.13.1", features=["image"]}
复制代码
然后在代码中导入:
  1. use iced::widget::{button,column,text,row,container,slider,image};
复制代码
之前我们在先容为iced窗口设置图标时还提到过一个外部图像库image:
  1. image="0.25.5"
复制代码
导入image,为了不与iced的image部件名称辩论,需要为image改个名称:
  1. extern crate image as eximg;
复制代码
1、图像导入


图像导入,通常需要使用文件对话框来导入文件,在iced中并没有提供对应的部件,因此,我们需要使用一个外部库,RFD,起首在toml中添加:
  1. rfd="0.15.2"
复制代码
下面是rfd库支持的功能:

包括了文件导入、保存、文件夹选择等,当然rfd也可以支持消息对话框。
  1. use rfd::{FileDialog,MessageDialog};
复制代码
本文的目的是实现图像文件的导入与显示,并可以调整一些图像属性,如巨细、透明度等,因此,我们将添加一个按钮用于触发文件选中对话框,获取图像文件的路径并显示。
我们为结构体添加一个变量用于记录图像路径:
  1. #[derive(Clone)]
  2. struct Counter {
  3.     slidervalue:f32,
  4.     slidervalue2:f32,
  5.     imgpath:String,
  6. }
复制代码
上述imgpath即图像路径变量,另外两个变量用于继承slider部件的实时值,因为我们需要调整图像的巨细和透明度,正好可以适应slider,而关于slider的使用先容,我们在上一篇博文里有单独先容:
[rustGUI][iced]基于rust的GUI库iced(0.13)的部件学习(02):滑动条部件实现部件(文本或其他)缩放(slider)
然后我们添加按钮触发消息:
  1. #[derive(Debug,Clone, Copy)]
  2. enum Message {
  3.     SliderChange(f32),
  4.     SliderChange2(f32),
  5.     BtnLoad,
  6. }
复制代码
上述的BtnLoad是按钮触发消息,另外两个是slider的滑动时触发,就不多说了。
我们希望的是,点击按钮时弹出文件对话框,因此需要在view函数里添加:
  1. let btn_load=button(text("加载图片").size(15)).width(80).height(40)
  2.                     .on_press(Message::BtnLoad);
复制代码
然后在update函数里更新状态:
  1. Message::BtnLoad =>{
  2.                 if let Some(file)=FileDialog::new()
  3.                             .set_title("选择图片")
  4.                             .add_filter("Image",&["png","jpg","jpeg","bmp"])
  5.                             .add_filter("png",&["png"])
  6.                             .set_directory("C://")
  7.                             .pick_file(){
  8.                                 
  9.                                 println!("当前选择的文件:{:?}",file);
  10.                                 self.imgpath=file.display().to_string();
  11.                             };
  12.                
  13.             }
复制代码
上述代码中,FileDialog::new()是rfd库中文件夹选择的用法,看rfd的官方示例:

我们在实例中,将获取的图像路径传递给我们设置的变量imgpath。
2、图像显示

当我们获取到了图像的当地路径之后,就可以使用iced的image部件来显示图像,我们起首来看下iced中image的界说:
官方源码
  1. #[derive(Debug)]
  2. pub struct Image<Handle = image::Handle> {
  3.     handle: Handle,
  4.     width: Length,
  5.     height: Length,
  6.     content_fit: ContentFit,
  7.     filter_method: FilterMethod,
  8.     rotation: Rotation,
  9.     opacity: f32,
  10. }
复制代码
我们主要关注的就是handle这个参数,它的类型是Handle,可以理解为图像的原始数据来源,Handle在iced中的界说:
官方源码
  1. pub enum Handle {
  2.     /// A file handle. The image data will be read
  3.     /// from the file path.
  4.     ///
  5.     /// Use [`from_path`] to create this variant.
  6.     ///
  7.     /// [`from_path`]: Self::from_path
  8.     Path(Id, PathBuf),
  9.     /// A handle pointing to some encoded image bytes in-memory.
  10.     ///
  11.     /// Use [`from_bytes`] to create this variant.
  12.     ///
  13.     /// [`from_bytes`]: Self::from_bytes
  14.     Bytes(Id, Bytes),
  15.     /// A handle pointing to decoded image pixels in RGBA format.
  16.     ///
  17.     /// Use [`from_rgba`] to create this variant.
  18.     ///
  19.     /// [`from_rgba`]: Self::from_rgba
  20.     Rgba {
  21.         /// The id of this handle.
  22.         id: Id,
  23.         /// The width of the image.
  24.         width: u32,
  25.         /// The height of the image.
  26.         height: u32,
  27.         /// The pixels.
  28.         pixels: Bytes,
  29.     },
  30. }
复制代码
可以看到,Handle界说了三种获取图像原始数据的方式,一种是直接从图像路径获取,一种是图像的字节数组获取,一种是从rgba数据获取。
我们在本文显然是使用第一种方式,即图像路径来获取handle,用于显示。iced官方给了典范的image使用代码:
  1. image("ferris.png")
复制代码
这是最简朴的应用,不过我们在实例使用时,因为希望能调整图像的巨细与透明度,所以可以这样写:
  1. let img_handle=image::Handle::from_path(self.imgpath.clone());
  2. let img1=image(img_handle).opacity(opacity).width(img_w).height(img_h);
复制代码
此中,opacity用于调整透明度,width和height用于调整图像尺寸。
我们来看下实际显示效果:

3、图像调整

有了之前slider调整text文字巨细的经验,此处就比力简朴了,因为我们已经获取了图像路径,显然也就能获取图像尺寸了,这里,我们使用外部的image库来处理。image库的功能还是很强盛的,看下它支持的图像处理格式:

为了方便管理,我们将获取图像尺寸封装为一个函数,与此前的img_to_icon函数放到一起,使用时直接调用即可:
  1. ///
  2. /// 获取图片大小
  3. ///
  4. /// 例:jpg or png -> (w,h)
  5. pub fn get_img_size(path:&str) ->(f32,f32){
  6.     if path != "" {
  7.         let img_re=eximg::open(path);
  8.         match img_re{
  9.             Ok(img)=>{
  10.                 return (img.width() as f32,img.height() as f32)
  11.             },
  12.             Err(e)=>{
  13.                 let res=MessageDialog::new()
  14.                         .set_title("错误")
  15.                         .set_level(rfd::MessageLevel::Error)
  16.                         .set_buttons(rfd::MessageButtons::Ok)
  17.                         .set_description(&e.to_string())
  18.                         .show();
  19.                 if res == rfd::MessageDialogResult::Yes{
  20.                     return (0.0,0.0)
  21.                 }
  22.                 return (0.0,0.0)
  23.             }
  24.         }
  25.         //return  (img.width() as f32,img.height() as f32)
  26.     }
  27.     return (0.0,0.0)
  28. }
复制代码
  1. let img_size=imgprocess::get_img_size(&self.imgpath);
复制代码
看下完整的view函数:
  1. let btn_load=button(text("加载图片").size(15)).width(80).height(40)
  2.                    .on_press(Message::BtnLoad);
  3.        let sl1=slider(
  4.            0.0..=1.0,
  5.            self.slidervalue,
  6.            Message::SliderChange)
  7.                                .height(40).width(200)
  8.                                .step(0.01);
  9.       
  10.        let opacity= self.slidervalue;
  11.        let tt1=text("透明度:").size(15);
  12.        let tt2=text(format!("{:.2}",opacity)).size(15);
  13.        let row1=row![tt1,sl1,tt2,].spacing(10)
  14.                                                .align_y(iced::Center);
  15.        let slider_scale=slider(0.1..=2.0,self.slidervalue2,Message::SliderChange2)
  16.                                                        .height(40).width(200)
  17.                                                        .step(0.01);
  18.        let tt3=text("缩放:").size(15);
  19.        let tt4=text(format!("{:.2}",self.slidervalue2)).size(15);
  20.        let row2=row![tt3,slider_scale,tt4,].spacing(10);
  21.        let tt_imgpath=text("当前图片路径:").size(15);
  22.        let tt_imgpath2=text(format!("{}",self.imgpath)).size(15);
  23.        let row3=row![tt_imgpath,tt_imgpath2,].spacing(10);
  24.        let img_handle=image::Handle::from_path(self.imgpath.clone());
  25.        let img_size=imgprocess::get_img_size(&self.imgpath);
  26.        let img_w=img_size.0 * self.slidervalue2;
  27.        let img_h=img_size.1 * self.slidervalue2;
  28.        let tt_imgsize=text(format!("图片大小:{:?}",img_size)).size(15);
  29.        //let row4=row![].spacing(10);
  30.        let img1=image(img_handle).opacity(opacity).width(img_w).height(img_h);
  31.        //let cont_color=Color::from_rgb(120.0, 120.0, 0.0);
  32.        let cont_color2=iced::color!(0xE9E7E7,0.5);//#E9E7E7FF
  33.        let cont_img=container(img1)
  34.                .width(1000).height(1000)
  35.                .align_x(iced::Center).align_y(iced::Center)
  36.                .style(move |t|styles::mycontainerstyle(t, cont_color2));
  37.       
  38.        column![
  39.            btn_load,
  40.            row1,
  41.            row2,
  42.            row3,
  43.            tt_imgsize,
  44.            cont_img,
  45.        ].align_x(iced::Center)
  46.        .padding(20)
  47.        .into()
复制代码
它整体显示效果如下:

4、综述

先来看看动态演示:

结合前文slider的使用,本文先容了如安在iced中导入图像、显示图像以及调整图像,当然也是很简朴的示例。比如导入按钮,后续将会使用菜单替代。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

曂沅仴駦

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表