Rust文件对话框库egui-file-dialog的使用:轻量级跨平台GUI文件选择器,支持EGUI集成

egui-file-dialog

功能特性

  • 选择文件或目录
  • 保存文件(提示用户输入目标路径)
    • 询问用户是否覆盖现有文件的对话框
  • 同时选择多个文件和文件夹(在Linux/Windows上使用Ctrl/Shift+点击,在macOS上使用Cmd/Shift+点击)
  • 以普通窗口或模态窗口打开对话框
  • 创建新文件夹
  • 键盘导航
  • 显示或隐藏隐藏文件和文件夹的选项
  • 显示或隐藏系统文件的选项
  • 导航按钮打开父目录或之前的目录
  • 在目录中搜索项目
  • 添加用户可以从下拉菜单中选择的文件过滤器
  • 用户目录(Home、Documents等)和系统磁盘的快捷方式
  • 将文件夹固定到左侧边栏
  • 手动编辑路径
  • 虚拟文件系统支持

示例代码

以下是使用egui-file-dialog的基本示例:

use std::path::PathBuf;

use eframe::egui;
use egui_file_dialog::FileDialog;

struct MyApp {
    file_dialog: FileDialog,
    picked_file: Option<PathBuf>,
}

impl MyApp {
    pub fn new(_cc: &eframe::CreationContext) -> Self {
        Self {
            // 创建一个新的文件对话框对象
            file_dialog: FileDialog::new(),
            picked_file: None,
        }
    }
}

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            if ui.button("Pick file").clicked() {
                // 打开文件对话框选择文件
                self.file_dialog.pick_file();
            }

            ui.label(format!("Picked file: {:?}", self.picked_file));

            // 更新对话框
            self.file_dialog.update(ctx);

            // 检查用户是否选择了文件
            if let Some(path)极速版
            if let Some(path) = self.file_dialog.take_picked() {
                self.picked_file = Some(path.to_path_buf());
            }
        });
    }
}

fn main() -> eframe::Result<()> {
    eframe::run_native(
        "File dialog demo",
        eframe::NativeOptions::default(),
        Box::new(|ctx| Ok(Box::new(MyApp::new(ctx)))),
    )
}

完整示例代码

下面是一个更完整的示例,展示了如何自定义文件对话框:

use std::path::PathBuf;
use std::sync::Arc;

use eframe::egui;
use egui_file_dialog::FileDialog;

struct MyApp {
    file_dialog: FileDialog,
    picked_file: Option<PathBuf>,
    show_file_dialog: bool,
}

impl MyApp {
    pub fn new(_cc: &eframe::CreationContext) -> Self {
        let mut file_dialog = FileDialog::new()
            .initial_directory(PathBuf::from("."))
            .default_size([800.0, 600.0])
            .resizable(true)
            .show_new_folder_button(true)
            .show_search(true)
            .add_quick_access("Workspace", |s| {
                s.add_path("📁 Documents", "Documents");
                s.add_path("📁 Downloads", "Downloads");
            })
            .set_file_icon(
                "📄",
                Arc::new(|path| path.extension().unwrap_or_default() == "txt"),
            )
            .add_file_filter(
                "Text files",
                Arc::new(|p| p.extension().unwrap_or_default() == "txt"),
            )
            .add_file_filter(
                "All files",
                Arc::new(|_| true),
            );

        Self {
            file_dialog,
            picked_file: None,
            show_file_dialog: false,
        }
    }
}

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            if ui.button("打开文件对话框").clicked() {
                self.show_file_dialog = true;
                self.file_dialog.pick_file();
            }

            if ui.button("保存文件").clicked() {
                self.show_file_dialog = true;
                self.file_dialog.save_file();
            }

            ui.label(format!("选择的文件: {:?}", self.picked_file));

            if self.show_file_dialog {
                // 更新对话框
                self.file_dialog.update(ctx);

                // 检查用户是否选择了文件
                if let Some(path) = self.file_dialog.take_picked() {
                    self.picked_file = Some(path.to_path_buf());
                    self.show_file_dialog = false;
                }

                // 检查用户是否取消了对话框
                if self.file_dialog.canceled() {
                    self.show_file_dialog = false;
                }
            }
        });
    }
}

fn main() -> eframe::Result<()> {
    eframe::run_native(
        "文件对话框示例",
        eframe::NativeOptions::default(),
        Box::new(|ctx| Ok(Box::new(MyApp::new(ctx)))),
    )
}

键盘快捷键

文件对话框支持以下键盘快捷键:

名称 描述 默认值
submit 提交当前操作或打开当前选中的文件夹 Enter
cancel 取消当前操作 Escape
parent 打开父目录 ALT + ↑
back 后退 Mouse button 1, ALT + ←, Backspace
forward 前进 Mouse button 2, ALT + →
reload 重新加载文件对话框数据和当前打开的目录 F5
new_folder 打开创建新文件夹的对话框 CTRL + N (Linux/Windows), CMD + N (macOS)
edit_path 文本编辑当前路径 /
home_edit_path 打开主目录并开始文本编辑路径 ~
selection_up 将选择向上移动一项
selection_down 将选择向下移动一项
select_all 当使用文件对话框选择多个文件和文件夹时,选择目录中的所有项目 CTRL + A (Linux/Windows), CMD + A (macOS)

多语言支持

文件对话框的标签可以自定义以支持不同语言:

use egui_file_dialog::{FileDialog, FileDialogLabels};

enum Language {
    English,
    Chinese,
}

fn get_labels_chinese() -> FileDialogLabels {
    FileDialogLabels {
        title_select_directory: "📁 打开文件夹".to_string(),
        title_select_file: "📂 打开文件".to_string(),
        title_save_file: "💾 保存文件".to_string(),
        button_open: "打开".to_string(),
        button_save: "保存".to_string(),
        button_cancel: "取消".to_string(),
        label_name: "名称".to_string(),
        label_size: "大小".to_string(),
        label_modified: "修改日期".to_string(),
        ..Default::default()
    }
}

fn update_labels(language: &Language, file_dialog: &mut FileDialog) {
    *file_dialog.labels_mut() = match language {
        Language::English => FileDialogLabels::default(),
        Language::Chinese => get_labels_chinese(),
    };
}

持久化数据

如果需要保存用户设置(如固定文件夹、显示隐藏文件等),可以使用FileDialogStorage

use egui_file_dialog::FileDialog;

struct MyApp {
    file_dialog: FileDialog,
}

impl MyApp {
    pub fn new(cc: &eframe::CreationContext) -> Self {
        let mut file_dialog = FileDialog::default();

        // 加载文件对话框的持久化数据
        if let Some(storage) = cc.storage {
            *file_dialog.storage_mut() =
                eframe::get_value(storage, "file_dialog_storage").unwrap_or_default()
        }

        Self { file_dialog }
    }
}

impl eframe::App for MyApp {
    fn save(&mut self, storage: &mut dyn eframe::Storage) {
        // 保存文件对话框的持久化数据
        eframe::set_value(
            storage,
            "file_dialog_storage",
            self.file_dialog.storage_mut(),
        );
    }

    // ...其他实现
}

1 回复

egui-file-dialog:轻量级跨平台GUI文件选择器

简介

egui-file-dialog是一个轻量级的Rust文件对话框库,专为EGUI框架设计。它提供了跨平台的文件选择功能,可以轻松集成到你的EGUI应用程序中。

主要特性

  • 轻量级实现
  • 跨平台支持
  • 与EGUI无缝集成
  • 支持文件和目录选择
  • 可自定义的界面

完整示例代码

下面是一个完整的示例,展示了如何使用egui-file-dialog创建一个简单的文件选择器应用:

use eframe::egui;
use egui_file_dialog::FileDialog;

// 定义应用结构体
struct MyApp {
    file_dialog: FileDialog,
    selected_file: Option<String>,
    selected_files: Vec<String>,
    selected_dir: Option<String>,
}

impl MyApp {
    fn new() -> Self {
        Self {
            file_dialog: FileDialog::new()
                .default_directory("~")  // 设置初始目录
                .add_filter("图像文件", &["png", "jpg", "jpeg"])
                .add_filter("文本文件", &["txt", "md"]),
            selected_file: None,
            selected_files: Vec::new(),
            selected_dir: None,
        }
    }
}

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        // 设置自定义样式
        let mut style = (*ctx.style()).clone();
        style.visuals.widgets.inactive.bg_fill = egui::Color32::from_rgb(25, 25, 25);
        ctx.set_style(style);

        // 主面板
        egui::CentralPanel::default().show(ctx, |ui| {
            // 选择单个文件按钮
            if ui.button("选择文件").clicked() {
                self.file_dialog.select_file();
            }

            // 选择多个文件按钮
            if ui.button("选择多个文件").clicked() {
                self.file_dialog.multiple_files(true).select_file();
            }

            // 选择目录按钮
            if ui.button("选择目录").clicked() {
                self.file_dialog.select_directory();
            }

            // 更新文件对话框状态并获取选择结果
            if let Some(path) = self.file_dialog.update(ctx).selected() {
                self.selected_file = Some(path.display().to_string());
            }

            // 显示选择的文件或目录
            if let Some(file) = &self.selected_file {
                ui.label(format!("已选择文件: {}", file));
            }

            if let Some(dir) = &self.selected_dir {
                ui.label(format!("已选择目录: {}", dir));
            }

            if !self.selected_files.is_empty() {
                ui.label("已选择多个文件:");
                for file in &self.selected_files {
                    ui.label(format!("- {}", file));
                }
            }
        });
    }
}

fn main() {
    // 创建原生选项
    let options = eframe::NativeOptions {
        initial_window_size: Some(egui::vec2(400.0, 300.0)),
        ..Default::default()
    };

    // 运行应用
    eframe::run_native(
        "文件选择器示例",
        options,
        Box::new(|_cc| Box::new(MyApp::new())),
    );
}

使用说明

  1. 首先确保在Cargo.toml中添加了必要的依赖:
[dependencies]
egui-file-dialog = "0.3"
egui = "0.24"
eframe = "0.24"
  1. 这个示例展示了如何:
  • 创建基本的文件选择对话框
  • 设置初始目录
  • 添加文件类型过滤器
  • 选择单个文件
  • 选择多个文件
  • 选择目录
  • 自定义界面样式
  1. 运行应用后,你将看到一个简单的窗口,包含三个按钮分别用于选择文件、选择多个文件和选择目录。

  2. 选择结果会显示在窗口下方。

注意事项

  1. 确保在应用程序的主循环中调用file_dialog.update(ctx)
  2. 文件对话框是模态的,打开时会阻止与其他UI元素的交互
  3. 在移动平台上可能需要额外的权限配置
回到顶部