欢迎光临
我们一直在努力

用Rust写一个文件管理树

文章目录

    • 目录树
    • 目录结构
    • UI树
    • 主程序
  • egui初步教程
  • egui基础组件的使用

目录树

egui并没有提供树结构,但实现起来并不复杂,如下图所示

在这里插入图片描述

想要实现这个功能可以分

3

3

3步走

  • 实现目录树结构(非GUI)
  • 实现GUI上的树形图
  • 主程序
  • 目录结构

    在目录树中,每个节点都代表一个路径,如想递归式地实现节点结构,那么需要为当前节点,关联其所有子节点,即所有子路径。这种结构可被存储为字典形式,其key和value分别是父路径和子路径列表。为此,实现【FileTreeState】结构,其内部成员【dir_cache】就是这个路径字典,代码如下。

    use std::path::{Path, PathBuf};
    use std::collections::HashMap;
    use eframe::egui;

    struct FileTreeState {
    dir_cache: HashMap<PathBuf, Vec<PathBuf>>,
    }

    impl FileTreeState {
    fn get_dir_children(&mut self, dir: &Path) -> Vec<PathBuf> {
    self.dir_cache
    .entry(dir.to_path_buf())
    .or_insert_with(|| {
    let mut children = Vec::new();
    if let Ok(entries) = std::fs::read_dir(dir) {
    for entry in entries.filter_map(|e| e.ok()) {
    children.push(entry.path());
    }
    }
    children.sort_by(|a, b| {
    match (a.is_dir(), b.is_dir()) {
    (true, false) => std::cmp::Ordering::Less,
    (false, true) => std::cmp::Ordering::Greater,
    _ => a.file_name()
    .unwrap_or_default()
    .cmp(b.file_name().unwrap_or_default()),
    }});
    children
    }).clone()
    }
    }

    【dir_cache】中,用PathBuf来表示路径。

    【get_dir_children】用于获取父路径的子路径。首先用【entry】添加父路径key,然后用【or_insert_with】插入父路径的所有子路径。生成子路径的过程分为两个步骤,先用read_dir获取所有子路径,并添加到childern列表;在通过sort_by对其进行排序,将文件夹放在前面,文件放在后面。

    UI树

    egui并没有提供树结构,因此需要自行实现其展开逻辑。而其基本组件,采用【CollapsingHeader】和【label】来实现。即每个目录都是一个可以展开的【CollapsingHeader】,而文件作为叶节点,只需一个label即可,代码如下

    fn render_tree_node(ui: &mut egui::Ui, state: &mut FileTreeState, path: &Path) {
    let display_name = path
    .file_name()
    .map(|n| n.to_string_lossy().to_string())
    .unwrap_or_else(|| path.to_string_lossy().to_string());

    if path.is_dir() {
    let id = egui::Id::new(path.to_string_lossy().to_string());

    egui::CollapsingHeader::new(&display_name)
    .id_salt(id)
    .default_open(false)
    .show(ui, |ui| {
    let children = state.get_dir_children(path);
    for child_path in children {
    render_tree_node(ui, state, &child_path);
    }
    });
    } else {
    ui.label(display_name);
    }
    }

    上述代码中,先获取输入路径的最后一截名字,然后判断该路径是文件还是文件夹,如果是文件夹,就递归式地渲染【CollapsingHeader】,否则添加一个label作为叶节点。

    主程序

    在实现了文件系统的基础结构以及GUI的节点渲染方案后,事实上就已经实现了目录树组件,接下来要做的,就是和其他egui程序一样,将其塞进一个App中,代码如下。

    struct FileTreeApp {
    state: FileTreeState,
    root_path: PathBuf,
    }

    impl FileTreeApp {
    fn new(_cc: &eframe::CreationContext<'_>) -> Self {
    Self {
    state: FileTreeState {
    dir_cache: HashMap::new(),
    },
    root_path: std::env::current_dir().unwrap_or_default(),
    }
    }
    }

    impl eframe::App for FileTreeApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
    egui::CentralPanel::default().show(ctx, |ui| {
    egui::ScrollArea::vertical().show(ui, |ui| {
    render_tree_node(ui, &mut self.state, &self.root_path);
    });
    });
    }
    }

    fn main() -> eframe::Result<()> {
    let options = eframe::NativeOptions::default();
    eframe::run_native(
    "Egui File Tree",
    options,
    Box::new(|cc| Ok(Box::new(FileTreeApp::new(cc)))),
    )
    }

    在【new】中,将当前所在文件夹设为根目录;在update中,调用了render_tree_node,递归式地渲染文件管理系统。

    本文介绍了如何使用Rust的egui库实现一个目录树组件。主要分为三个步骤:1) 构建目录树数据结构,使用HashMap缓存父子路径关系;2) 实现UI渲染逻辑,通过CollapsingHeader和label组件递归显示目录结构;3) 集成到主程序中。核心代码包括路径缓存处理、目录排序以及递归渲染UI节点。最终实现了一个可展开/折叠的图形化目录树,支持显示当前工作目录下的所有文件和子目录。

    赞(0)
    未经允许不得转载:171主机测评 » 用Rust写一个文件管理树
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址