曹旭辉 发表于 2024-5-13 23:41:41

Rust GUI库 egui 的简单应用

目录

[*]简介
[*]简单示例

[*]创建项目
[*]界面设计
[*]切换主题
[*]自定义字体
[*]自定义图标

[*]经典结构

[*]定义导航变量
[*]实现导航界面
[*]实现导航逻辑
[*]实现主框架结构
[*]调试运行

[*]参考资料

简介

egui(发音为“e-gooey”)是一个简单、快速且高度可移植的 Rust 即时模式 GUI 库,跨平台、Rust原生,得当一些小工具和游戏引擎GUI:
文档:https://docs.rs/egui/latest/egui/
演示:https://www.egui.rs/#demo
github:https://github.com/emilk/egui
关于即时模式GUI,可以参考 利用C++界面框架ImGUI开发一个简单步伐 里面的介绍,ImGUI是C++的一个即时模式GUI库。
https://img2024.cnblogs.com/blog/1495663/202403/1495663-20240313161802614-1592510423.gif
简单示例

创建项目

首先利用cargo工具快速构建项目:
cargo new eguitest然后添加依赖:
cargo add eframeegui只是一个图形库,而不是图形界面开发框架,eframe是与egui配套利用的图形框架。
为了静态插入图片,还须要增长egui_extras依赖:
cargo add egui_extras然后在Cargo.toml文件中编辑features:
egui_extras = { version = "0.26.2", features = ["all_loaders"] }界面设计

打开src/main.rc,编写第一个eframe示例步伐:
//隐藏Windows上的控制台窗口
#!

use eframe::egui;

fn main() -> Result<(), eframe::Error> {
    // 创建视口选项,设置视口的内部大小为320x240像素
    let options = eframe::NativeOptions {
      viewport: egui::ViewportBuilder::default().with_inner_size(),
      ..Default::default()
    };

    // 运行egui应用程序
    eframe::run_native(
      "My egui App", // 应用程序的标题
      options, // 视口选项
      Box::new(|cc| {
            // 为我们提供图像支持
            egui_extras::install_image_loaders(&cc.egui_ctx);
            // 创建并返回一个实现了eframe::App trait的对象
            Box::new(MyApp::new(cc))
      }),
    )
}

//定义 MyApp 结构体
struct MyApp {
    name: String,
    age: u32,
}

//MyApp 结构体 new 函数
impl MyApp {
    fn new(cc: &eframe::CreationContext<'_>) -> Self {      
      // 结构体赋初值
      Self {
            name: "Arthur".to_owned(),
            age: 42,
      }
    }
}

//实现 eframe::App trait
impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
      // 在中央面板上显示egui界面
      egui::CentralPanel::default().show(ctx, |ui| {
            // 显示标题
            ui.heading("My egui Application");
            // 创建一个水平布局
            ui.horizontal(|ui| {
                // 显示姓名标签
                let name_label = ui.label("Your name: ");
                // 显示姓名输入框(单行文本框)
                ui.text_edit_singleline(&mut self.name)
                  .labelled_by(name_label.id); // 关联标签
            });

            // 显示年龄滑块
            ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));

            if ui.button("Increment").clicked() {
                // 点击按钮后将年龄加1
                self.age += 1;
            }

            // 显示问候语
            ui.label(format!("Hello '{}', age {}", self.name, self.age));            
            // 显示图片,图片放在main.rs的同级目录下(可以自定义到其它目录)
            ui.image(egui::include_image!("ferris.png"));
      });
    }
}运行结果:
https://img2024.cnblogs.com/blog/1495663/202403/1495663-20240313161336638-1945944636.png
自定义图标

先导入image库,在终端中运行:
impl MyApp {
    // 切换主题
    fn theme_switcher(&mut self, ui: &mut egui::Ui, ctx: &egui::Context) {
      ui.horizontal(|ui| {
            if ui.button("Dark").clicked() {
                ctx.set_visuals(egui::Visuals::dark());
            }
            if ui.button("Light").clicked() {
                ctx.set_visuals(egui::Visuals::light());
            }
      });
    }
}还须要导入std::sync::Arc、eframe::egui::IconData ,库引入区如下:
egui::CentralPanel::default().show(ctx, |ui| {
   //...
   // 切换主题
   self.theme_switcher(ui, ctx);
   // 显示图片
   ui.image(egui::include_image!("ferris.png"));
});在main()函数中将native_options的声明改为可变变量的声明,并加入改变图标代码:
//自定义字体
fn setup_custom_fonts(ctx: &egui::Context) {
    // 创建一个默认的字体定义对象
    let mut fonts = egui::FontDefinitions::default();

    //安装的字体支持.ttf和.otf文件
    //文件放在main.rs的同级目录下(可以自定义到其它目录)
    fonts.font_data.insert(
      "my_font".to_owned(),
      egui::FontData::from_static(include_bytes!(
            "msyh.ttc"
      )),
    );

    // 将字体添加到 Proportional 字体族的第一个位置
    fonts
      .families
      .entry(egui::FontFamily::Proportional)
      .or_default()
      .insert(0, "my_font".to_owned());

    // 将字体添加到 Monospace 字体族的末尾
    fonts
      .families
      .entry(egui::FontFamily::Monospace)
      .or_default()
      .push("my_font".to_owned());

    // 将加载的字体设置到 egui 的上下文中
    ctx.set_fonts(fonts);
}经典结构

在上面示例的基础上,实现一个上中下或左中右的经典三栏结构,main函数不须要修改,只须要修改MyApp结构体的定义即可。
定义导航变量

先定义一个导航枚举,用来在标记当前要体现的界面:
//...
impl MyApp {
    fn new(cc: &eframe::CreationContext<'_>) -> Self {
      //加载自定义字体
      setup_custom_fonts(&cc.egui_ctx);   
      //...
    }
}
//...为了方便理解示例,在 MyApp 中只定义一个 page 字段,并同步修改new函数:
//定义 MyApp 结构体struct MyApp {    page:Page,}//MyApp 结构体 new 函数impl MyApp {    fn new(cc: &eframe::CreationContext
页: [1]
查看完整版本: Rust GUI库 egui 的简单应用