【egui】官方示例 hello_world 完全解析

这是 egui 最简单的入门示例,展示了基本的 UI 控件:LabelTextEditSliderButton 和图片显示。

📁 文件结构

复制代码
hello_world/
├── Cargo.toml          # 项目依赖配置
├── src/
│   └── main.rs         # 主程序代码
└── screenshot.png      # 运行截图

📦 Cargo.toml 详解

toml 复制代码
[package]
name = "hello_world"                    # 项目名称
version = "0.1.0"                       # 版本号
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]  # 作者(egui 作者)
license = "MIT OR Apache-2.0"           # 双许可证
edition = "2024"                        # Rust 2024 版次
rust-version = "1.92"                   # 最低 Rust 版本要求
publish = false                          # 不发布到 crates.io

[lints]
workspace = true                         # 继承工作区的 lint 配置

[dependencies]
# eframe 主依赖,使用工作区配置,启用 __screenshot 功能用于截图
eframe = { workspace = true, features = [
  "default",
  "__screenshot",  # 可通过 EFRAME_SCREENSHOT_TO 环境变量输出截图
] }

# 图片支持扩展库
egui_extras = { workspace = true, features = ["default", "image"] }

# 日志库,支持彩色输出和时间戳
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

关键点解析

依赖 作用
eframe 应用框架,提供窗口、事件循环和渲染
eframe/__screenshot 特殊功能,运行时设置 EFRAME_SCREENSHOT_TO=path.png 可保存截图
egui_extras 扩展功能,这里启用 image 功能加载图片
env_logger 日志输出,通过 RUST_LOG=debug 控制日志级别

🚀 main.rs 逐行解析

1. 文件头属性

rust 复制代码
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
#![expect(rustdoc::missing_crate_level_docs)]
属性 说明
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 发布模式(--release)下在 Windows 隐藏控制台窗口,只显示 GUI 窗口
#![expect(rustdoc::missing_crate_level_docs)] 允许缺少 crate 级别文档(因为是示例)

2. 引入依赖

rust 复制代码
use eframe::egui;  // 通过 eframe 重新导出使用 egui

3. main 函数

rust 复制代码
fn main() -> eframe::Result {
    // 初始化日志系统,可以通过 RUST_LOG=debug 查看详细日志
    env_logger::init();
    
    // 配置窗口选项
    let options = eframe::NativeOptions {
        // viewport 字段:设置窗口大小 320x240
        viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
        ..Default::default()  // 其余使用默认值
    };
    
    // 运行应用
    eframe::run_native(
        "My egui App",                    // 窗口标题
        options,                           // 窗口配置
        Box::new(|cc| {                     // 应用创建闭包
            // 安装图片加载器,支持显示图片
            egui_extras::install_image_loaders(&cc.egui_ctx);
            
            // 返回默认的 MyApp 实例
            Ok(Box::<MyApp>::default())
        }),
    )
}

4. 应用状态结构体

rust 复制代码
struct MyApp {
    name: String,  // 姓名
    age: u32,      // 年龄
}

impl Default for MyApp {
    fn default() -> Self {
        Self {
            name: "Arthur".to_owned(),  // 默认姓名
            age: 42,                     // 默认年龄
        }
    }
}

5. 实现 eframe::App trait

rust 复制代码
impl eframe::App for MyApp {
    // ui 方法:每帧调用,绘制界面
    fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
        // 创建一个中央面板(带背景和边距)
        egui::CentralPanel::default().show_inside(ui, |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);  // 关联标签,辅助功能
            });
            
            // 滑块控件,绑定 age,范围 0-120
            ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));
            
            // 按钮,点击时 age+1
            if ui.button("Increment").clicked() {
                self.age += 1;
            }
            
            // 显示当前值
            ui.label(format!("Hello '{}', age {}", self.name, self.age));
            
            // 显示图片(使用 include_image! 宏在编译时嵌入图片)
            ui.image(egui::include_image!(
                "../../../crates/egui/assets/ferris.png"  // 路径相对于 hello_world 示例
            ));
        });
    }
}

🎨 界面控件详解

1. Label(标签)

rust 复制代码
ui.label("Your name: ");
ui.heading("My egui Application");  // 大标题样式

2. TextEdit(文本编辑框)

rust 复制代码
ui.text_edit_singleline(&mut self.name)  // 绑定到 String
    .labelled_by(name_label.id);          // 关联标签 ID

3. Slider(滑块)

rust 复制代码
egui::Slider::new(&mut self.age, 0..=120)  // 绑定到 u32,范围 0-120
    .text("age")                            // 显示文本

4. Button(按钮)

rust 复制代码
if ui.button("Increment").clicked() {  // 点击检测
    self.age += 1;
}

5. Image(图片)

rust 复制代码
ui.image(egui::include_image!("path/to/image.png"));
// include_image! 宏在编译时嵌入图片,无需运行时加载

🧠 关键概念理解

即时模式(Immediate Mode)

  • 每帧都重新构建 UI
  • 状态保存在 MyApp 结构体中
  • 控件通过返回值(如 .clicked())响应用户操作

布局系统

  • CentralPanel:占据剩余空间,提供默认背景
  • horizontal:水平排列子控件
  • 嵌套布局:CentralPanel 包含 horizontal

数据绑定

  • 控件直接修改应用状态:&mut self.name&mut self.age
  • 无需手动更新 UI,框架自动重绘

图片处理

  • egui_extras::install_image_loaders 初始化图片支持
  • include_image! 宏在编译时嵌入图片,适合小图片
  • 图片路径相对于当前文件

🏃 运行方式

bash 复制代码
# 普通运行
cargo run -p hello_world

# 带日志调试运行
RUST_LOG=debug cargo run -p hello_world

# 生成截图(需要 __screenshot 功能)
EFRAME_SCREENSHOT_TO=screenshot.png cargo run -p hello_world

📸 运行效果

界面包含:

  • 标题 "My egui Application"
  • "Your name:" 标签 + 文本输入框(默认 "Arthur")
  • 年龄滑块(0-120,默认 42)
  • "Increment" 按钮,点击年龄+1
  • 显示 "Hello '姓名', 年龄"
  • Ferris 螃蟹图片

💡 一句话总结

hello_world 示例展示了 egui 最核心的编程模式:状态存在结构体里,ui 方法每帧重新构建界面,控件直接读写状态,布局通过嵌套 Panel 和 horizontal 实现。

相关推荐
Amos_Web1 天前
Solana开发(1)- 核心概念扫盲篇&&扫雷篇
前端·rust·区块链
golang学习记2 天前
VS Code官宣:全面支持Rust!
开发语言·vscode·后端·rust
叹一曲当时只道是寻常2 天前
Tauri v2 + Rust 实现 MCP Inspector 桌面应用:进程管理、Token 捕获与跨平台踩坑全记录
开发语言·后端·rust
怪我冷i2 天前
Rust错误处理之unwrap
rust·cloudflare·unwrap
楚国的小隐士3 天前
为什么说Rust是对自闭症谱系人士友好的编程语言?
java·rust·编程·对比·自闭症·自闭症谱系障碍·神经多样性
Tomhex3 天前
Rust智能指针使用指南
rust
AI自动化工坊4 天前
Claw Code技术深度解析:Python+Rust混合架构的设计与实现
开发语言·人工智能·python·ai·架构·rust·开源
web前端进阶者4 天前
Rust初学知识点快速记忆
开发语言·后端·rust
一只幸运猫.4 天前
Rust实用工具特型-Clone
开发语言·后端·rust
咚为4 天前
深入浅出 Rust 内存顺序:从 CPU 重排到 Atomic Ordering
开发语言·后端·rust