[rustGUI][iced]基于rust的GUI库iced(0.13)的部件学习(06):基于iced实现一个简单的图片浏览器

前言

本文是关于iced库的部件介绍,iced库是基于rust的GUI库,作者自述是受Elm启发。

iced目前的版本是0.13.1,相较于此前的0.12版本,有较大改动。

本合集是基于新版本的关于分部件(widget)的使用介绍,包括源代码介绍、实例使用等。

环境配置

系统:window10

平台:visual studio code

语言:rust

库:iced 0.13

扩展库:iced_aw

概述

图片浏览器的实现,我们的设想是可以通过文件夹导入所有图片,然后获取的图片在界面上排布显示,其中有一个是主图片,其他图片以缩略图形式在下方,可以通过按钮切换图片的显示。

前提条件

为了实现文件夹导入,需要添加一个对话框库,即RFD:

1、新建iced项目

关于如何新建iced窗口并设置窗口参数,可以参考博文:
基于rust的GUI库iced的学习(00):一个典型的iced窗口的实现

本文不再赘述。

本文的目的是创建一个能够导入图片并进行浏览的窗口,所以我们需要先添加以下模块:

toml 复制代码
rfd = "0.15.2"
image = "0.25.5"

我们的窗口基本布局如下:

如图,通过导入文件夹 按钮导入图片文件夹,获取了图片列表后,在窗口动态添加并显示,而上一张下一张 按钮则可以切换图片的显示。

我们先来看view函数的基本布局:

rust 复制代码
let img_main_h=image::Handle::from_path(&self.img_main_p);
        
        //let img_main= image(self.handle.clone());
        let img_main = image(img_main_h).width(300).height(300)
                                .content_fit(iced::ContentFit::Contain);
        let img_sub_view = self.updateview();
        let cont1=container(
    column![
                row![
                    //button(text("打开").size(20)).width(80).on_press(Message::Open),
                    button(text("导入文件夹").size(14)).width(100).on_press(Message::OpenFolder),
                ],
                row![
                    button(text("上一张").size(14)).width(100).on_press(Message::Last),
                    button(text("下一张").size(14)).width(100).on_press(Message::Next),
                ].spacing(10),
                img_main,
                img_sub_view,
               
            ].padding(10).spacing(10).align_x(Center)
        ).align_x(Center)
        .align_y(Center)
        .width(iced::Length::Fill).height(iced::Length::Fill)
        .style(|t| styles::mycontainerstyle(t));
        cont1.into()

上面的代码中,updateview函数如下:

rust 复制代码
fn updateview(&self) ->Column<Message>{
        let row1 = match self.imgs.len() {
            0 => Self::contcont("无图片"),
            n => {
                //println!("图片数量:{}",n);
                let mut row1 = row![].spacing(20);
                for i in 0..n {
                    row1 = row1.push(
                        container(
                        image(image::Handle::from_path(self.imgs[i].display().to_string())).width(100).height(100)
                        ).style(move |t| styles::mycontainerstyle_border(t,i.to_string(),self.current_index))
                    );
                };
                Self::contcont("图片列表").push(row1)
            },
        };
        row1
    }

为什么要使用这个函数,主要目的是为了动态添加图片元素,这个函数会根据获取的图片数量,生成相应的image元素并显示在窗口(如果图片太多则会非常卡,本文未作优化)。

2、文件夹导入和遍历

在iced中,文件夹导入,我们使用rfd库来创建对话框:

rust 复制代码
if let Some(folder) = FileDialog::new()
                                        .set_directory("E:\\100rust2\\iced-img")
                                        .set_title("打开文件夹")
                                        .pick_folder() {
                                            println!("打开文件夹: {:?}", folder);
                                            let paths = folderbrowser(folder).unwrap();
                                            if paths.len() > 0 {
                                                self.imgs.clear();
                                                self.current_index = 0;
                                                for path in paths {
                                                    println!("文件夹中的文件: {:?}", path);
                                                    self.imgs.push(path);
                                                };
                                                self.img_main_p = self.imgs[self.current_index].display().to_string();
                                            } else {
                                                MessageDialog::new()
                                                    .set_title("提示")
                                                    .set_description("文件夹中无图片文件!")
                                                    .show();
                                                println!("文件夹为空");
                                            }
                                            
                                        }

注意到,我们获取了文件夹的路径后,使用folderbrowser函数进行了遍历:

rust 复制代码
///
///遍历文件夹
/// 
pub fn folderbrowser(path:std::path::PathBuf) ->Result<Vec<std::path::PathBuf>,String> {
        match std::fs::read_dir(path) {
            Ok(dirs) => {
                let paths = dirs.filter_map(
                    |dir| {
                        dir.ok().map(|dir_dir| dir_dir.path())
                                .filter(|path| {
                                    if let Some(ext) = path.extension() {
                                        ext == "png" || ext == "jpg" || ext == "webp" || ext == "bmp" || ext == "jpeg"
                                    } else {
                                        false
                                    }
                                })
                    }
                ).collect();
                Ok(paths)
            },
            Err(e) =>{
                Err(format!("Error:{}",e))
            }
        }
}

如上,我们使用rust的标准库std的fs来处理文件路径,将文件夹中的每个图片路径都提取出来,而不符合图片后缀名的文件,则忽略。

3、样式实现

注意上述图片红色箭头所指,当前主图片对应的缩略图,其边框是与其他边框不一样的,如果是在前端项目中,实现这样的效果是非常简单的,而在iced中,如果我们希望实现这样的效果,就需要为图片进行自定义样式的设置。

在iced中,image元素本身是没有样式设置的,因此,我们的处理办法是在image元素外面套一层container元素:

rust 复制代码
container(
                        image(image::Handle::from_path(self.imgs[i].display().to_string())).width(100).height(100)
                        ).style(move |t| styles::mycontainerstyle_border(t,i.to_string(),self.current_index))

针对于container元素,我们就可以设置其style参数,具体来说,对于缩略图的图片,我们为其添加了一层套壳,通过设置套壳的样式来展现区别。

我们新建一个styles.rs 文件,在其中添加mycontainerstyle_border函数:

rust 复制代码
pub fn mycontainerstyle_border(t:&Theme,s:String,index:usize) ->iced::widget::container::Style {
   
   if s == index.to_string() {
        iced::widget::container::Style {
            border:iced::Border{
                color:iced::color!(0x669EF1), //#669EF1FF
                width:3.0,
                radius:iced::border::Radius::default(),
            },
            ..Default::default()
        }
   } else {
    iced::widget::container::Style {
        border:iced::Border{
            color:Color::BLACK,
            width:1.0,
            radius:iced::border::Radius::default(),
        },
        ..Default::default()
    }
   }
    
}

注意看上面的代码,我们实现缩略图边框变化的方法是,通过比较当前主图片的索引与图片列表的索引,如果一致,则表示当前图片是主图片,则设置其边框为蓝色加粗,否则其边框为默认。

经过验证,这个方法是简单有效的。

4、动态演示

相关推荐
Source.Liu23 分钟前
【学Rust写CAD】26 图形像素获取(pixel_fetch.rs)
rust·cad
zhu128930355623 分钟前
用Rust和WebAssembly打造轻量级前端加密工具
前端·rust·wasm
Yeauty10 小时前
Rust 中的高效视频处理:利用硬件加速应对高分辨率视频
开发语言·rust·ffmpeg·音视频·音频·视频
zhu128930355611 小时前
基于Rust与WebAssembly实现高性能前端计算
前端·rust·wasm
关山月12 小时前
Rust 如何处理闭包:Fn、FnMut 和 FnOnce
rust
Vitalia19 小时前
从零开始学Rust:枚举(enum)与模式匹配核心机制
开发语言·后端·rust
一只小松许️21 小时前
Rust闭包详解
开发语言·rust
SoFlu软件机器人1 天前
Go/Rust 疯狂蚕食 Java 市场?老牌语言的 AI 化自救之路
java·golang·rust
小白学大数据1 天前
异步读取HTTP响应体的Rust实现
网络协议·http·rust
Source.Liu1 天前
【学Rust写CAD】24 扫描渐变(sweep_gradient.rs)
后端·rust