egui 与 eframe 官方示例仓库指南:从 Hello World 到自定义渲染的完整实践路线
2026/9/10 15:18:37 网站建设 项目流程

egui 与 eframe 官方示例仓库指南:从 Hello World 到自定义渲染的完整实践路线

【免费下载链接】eguiegui: an easy-to-use immediate mode GUI in Rust that runs on both web and native项目地址: https://gitcode.com/GitHub_Trending/eg/egui

本指南围绕 egui 仓库中的 examples 目录展开,它是学习和复用 egui 即时模式 GUI 最直接的一手素材库:每个示例都以eframe搭建原生窗口,覆盖 UI 控件、自定义字体、文件对话框、多窗口、3D 渲染与 Web 运行等常见场景。读完本文,你将掌握示例的运行方式、目录结构、每个示例的核心技术与适用场景,并能基于hello_world模板快速搭建自己的 egui 应用。

examples 目录是什么

examples/目录是 egui 官方维护的示例集合,其定位在 examples/README.md 中写得很清楚:

  • 该目录下所有示例都使用eframe来为一个egui应用创建窗口,完成"窗口托管 + 事件循环 + 渲染后端"这一整套引导工作;
  • 部分示例是eframe特有的(例如自定义原生窗口装饰、多视口),但绝大多数 UI 代码对所有 egui 集成方式(如 egui-winit、egui_glow、egui-wgpu 或纯 Web 环境)同样适用;
  • 每个示例都是一个独立可cargo run的 crate,带独立的Cargo.tomlREADME.md与运行截图。

从仓库结构看(Cargo.toml 工作区 + examples/ 目录),每个子目录即一个独立示例 crate,命名即主题,例如hello_worldcustom_3d_glowmultiple_viewports。全部示例可通过 examples/run_all.sh 一键顺序运行:

for example_name in *; do if [ -d "$example_name" ]; then cargo run --quiet -p $example_name fi done

该脚本用cargo run -p <crate名>的方式逐个启动目录下的示例,要求在当前工作区根目录(或 examples 目录)执行cargo,这也是各示例 README 中统一推荐的运行方式,例如:

cargo run -p hello_world cargo run -p custom_3d_glow

版本与文档配套说明

原 README 特别强调了两点使用前提,本仓库现状与其完全吻合:

  • main 分支的示例对应最新开发版 egui:仓库根目录的 rust-toolchain 指定了工具链,示例 crate 的Cargo.toml(如 examples/hello_world/Cargo.toml)声明rust-version = "1.95"edition = "2024",且依赖以workspace = true方式引用 Cargo.toml 中定义的eframeegui_extras等 crate。因此这些示例依赖较新的 Rust 版本与最新 API,请使用较新的工具链编译。
  • 若要针对特定版本查找示例:需切换到对应版本的 tag(如latest)再查看该 tag 下的examples目录,而不是在 main 分支上直接套用旧版本代码。

官方还提供两类补充资料:egui.rs 官网的在线示例(每个都附源码链接),以及 egui 与 eframe 的 API 文档(docs.rs)。本仓库内的文档如 ARCHITECTURE.md、RELEASES.md 也可帮助你理解版本演进与架构背景。

最小可运行示例:hello_world 与 hello_world_simple

经典模板 hello_world

examples/hello_world/src/main.rs 是"控件演示"与"模板"双重定位的最小完整应用,完整代码如下:

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release #![expect(rustdoc::missing_crate_level_docs)] // it's an example use eframe::egui; fn main() -> eframe::Result { env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`). let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]), ..Default::default() }; eframe::run_native( "My egui App", options, Box::new(|cc| { // This gives us image support: egui_extras::install_image_loaders(&cc.egui_ctx); Ok(Box::<MyApp>::default()) }), ) } struct MyApp { name: String, age: u32, } impl Default for MyApp { fn default() -> Self { Self { name: "Arthur".to_owned(), age: 42, } } } impl eframe::App for MyApp { fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(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); }); ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age")); if ui.button("Increment").clicked() { self.age += 1; } ui.label(format!("Hello '{}', age {}", self.name, self.age)); ui.image(egui::include_image!( "../../../crates/egui/assets/ferris.png" )); }); } }

这个示例浓缩了 egui 应用的完整骨架,逐段拆解如下:

  • 平台引导eframe::run_native(name, options, app_creator)是原生桌面入口。eframe::Result是统一的错误返回类型;NativeOptions通过viewport: egui::ViewportBuilder配置窗口属性(此处设with_inner_size([320.0, 240.0])指定初始窗口大小)。
  • 应用状态即结构体MyApp { name, age }直接作为即时模式 UI 的状态载体,Default提供初始值。即时模式的核心特征就在这里——每次帧重绘时 UI 都会按当前状态重建,状态由你的结构体持有。
  • UI 组装CentralPanel提供中央面板布局;headinglabeltext_edit_singlelineSliderbutton覆盖文本、输入、滑动条、按钮四类基础控件;Slider::new(&mut self.age, 0..=120)双向绑定状态与范围。
  • 图片资源egui_extras::install_image_loaders(&cc.egui_ctx)安装图片加载器,随后用egui::include_image!宏把仓库内的 crates/egui/assets/ferris.png 编译进二进制并直接绘制。

Cargo.toml(examples/hello_world/Cargo.toml)的依赖结构同样值得借鉴:

eframe = { workspace = true, features = [ "default", "__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO ] } # For image support: egui_extras = { workspace = true, features = ["default", "image"] } env_logger = { workspace = true, features = ["auto-color", "humantime"] }

要点:eframe自带egui(代码里直接use eframe::egui);需要图片显示时启用egui_extrasimagefeature;__screenshotfeature 配合环境变量EFRAME_SCREENSHOT_TO可在 CI 中自动输出截图(这正是仓库 scripts/generate_example_screenshots.sh 批量生成示例截图所依赖的机制)。

更精简的 hello_world_simple

如果你只想看"最少的 egui 程序",examples/hello_world_simple/src/main.rs 只用了约 30 行:它省去自定义App结构体,改用eframe::run_ui_native直接以闭包形式书写 UI,局部变量nameage由闭包捕获,功能与hello_world完全一致:

eframe::run_ui_native("My egui App", options, move |ui, _frame| { egui::CentralPanel::default().show(ui, |ui| { ui.heading("My egui Application"); ui.horizontal(|ui| { let name_label = ui.label("Your name: "); ui.text_edit_singleline(&mut name) .labelled_by(name_label.id); }); ui.add(egui::Slider::new(&mut age, 0..=120).text("age")); if ui.button("Increment").clicked() { age += 1; } ui.label(format!("Hello '{name}', age {age}")); }); })

对比可见:当应用逻辑简单、无需保留结构化状态时,run_ui_native是更轻量的选择;当应用复杂(多窗口、需要CreationContext做初始化、需要on_exit清理资源)时,run_native+impl eframe::App才是正确姿势。

进阶示例导读:按主题挑选你的参考实现

examples 目录覆盖了从"控件用法"到"渲染后端深度定制"的完整梯度,以下按主题梳理每个示例的核心价值(对应源码均在各自src/main.rs,运行命令见各目录 README):

窗口与视口管理

示例主题关键技术点
confirm_exit退出确认拦截关闭事件、弹出确认对话框
custom_window_frame自定义窗口装饰ViewportBuilder::with_decorations(false)with_transparent(true)隐藏系统边框,配合clear_color返回透明色,用ViewportCommand::StartDrag/Maximized/Close等命令自绘标题栏与窗口按钮
multiple_viewports多窗口一个进程中创建多个原生窗口视口
serial_windows顺序窗口依次弹出多个窗口的流程控制
window_options(在 demo lib 中)窗口选项窗口参数调节参考

custom_window_frameeframe特有的高级用法,其实现思路值得细读(examples/custom_window_frame/src/main.rs):先用with_decorations(false)隐藏系统标题栏、with_transparent(true)启用透明以支持圆角,然后在App::clear_color中返回egui::Rgba::TRANSPARENT避免圆角外区域被底色覆盖;自绘标题栏时用ui.interact(rect, Id::new("title_bar"), Sense::click_and_drag())捕获拖拽,双击切换最大化(ViewportCommand::Maximized(!is_maximized)),拖拽时发送ViewportCommand::StartDrag让系统接管窗口移动。

输入与系统集成

示例主题关键技术点
keyboard_events键盘事件事件回调与按键状态查询
file_dialog文件对话框与拖放rfd::FileDialog::new().pick_file()打开原生对话框;with_drag_and_drop(true)启用拖放,从ui.input(|i| i.raw.dropped_files / hovered_files)读取拖入与悬停文件,并用LayerId::new(Order::Foreground, ...)绘制拖放悬停遮罩预览
custom_keypad自定义输入面板组合自定义按键 UI 与文本输入
user_attention窗口注意力闪烁/提醒用户注意的窗口操作

file_dialog同时展示了原生与 Web 两种文件处理路径(examples/file_dialog/src/main.rs):原生端用file.path()拿路径;wasm32目标下改用file.web_file()获取文件名、MIME 类型与大小,#[cfg(...)]条件编译分平台实现。

字体与主题

示例主题关键技术点
custom_font自定义字体两种方式:ctx.add_font(FontInsert::new(...))增量添加字体并指定家族优先级;ctx.set_fonts(fonts)整体替换FontDefinitions,把自定义字体insert(0, ...)Proportional首位、pushMonospace末尾作回退。include_bytes!内嵌仓库中的 crates/epaint_default_fonts/fonts/Hack-Regular.ttf,.ttf/.otf均支持
custom_font_style字体样式字号、字重、斜体等样式控制
font_variations可变字体使用仓库内的 examples/font_variations/data/Recursive-VariableFont.ttf 演示字重连续变化
custom_style自定义样式修改Style/Visuals全局换肤
styling_engine样式引擎类(class)与原子样式等新样式系统的应用

渲染与特效

示例主题关键技术点
custom_3d_glow自定义 3D 渲染(OpenGL)eframe::Renderer::Glow指定后端,通过egui::PaintCallbackglow的 GPU 绘制注入 egui 渲染流程;资源放在Arc<Mutex<...>>中以便在回调里使用,App::on_exit中销毁 GL 程序
images图片显示仓库内 examples/images/src/ferris.svg、examples/images/src/cat.webp、examples/images/src/ferris.gif 分别演示 SVG / WebP / GIF 三种格式的加载与动画
screenshot截图功能ScreenshotCallback把当前帧保存为图片
puffin_profiler性能分析集成 puffin 对 egui 应用做 CPU 采样分析
fractal_clock(在 demo lib 中)分形时钟动画动画驱动的绘制参考

custom_3d_glow是"egui 中嵌入原生 GPU 渲染"的范本(examples/custom_3d_glow/src/main.rs):用ui.allocate_exact_size(egui::Vec2::splat(300.0), egui::Sense::drag())预留 300×300 的画布并接收拖拽输入,把旋转角写入egui_glow::CallbackFn闭包,构造egui::PaintCallback { rect, callback }交给ui.painter().add(...);渲染闭包内直接调用glowAPI 编译着色器、gl.draw_arrays绘制三角形。注意着色器版本按平台分支:wasm32 用#version 300 es,原生用#version 330

事件循环与异步

示例主题关键技术点
external_eventloop外部事件循环不依赖run_native,自行驱动事件循环,将 egui 集成进既有主循环
external_eventloop_async异步事件循环在异步运行时(pollster/async)中驱动 eframe,代码拆分在 examples/external_eventloop_async/src/main.rs 与 examples/external_eventloop_async/src/app.rs
hello_androidAndroid 平台egui/eframe 在移动端(Android)的最小运行示例
hello_world_par并行渲染多线程(rayon 风格)渲染参考

弹层与交互

示例主题关键技术点
popups弹出层Area/Popup相关弹层组合用法
hello_world基础控件LabelTextEditSliderButton入门(见上文完整代码)

示例之外:把 demo 跑起来与进一步深入

更丰富的演示应用

examples/外,仓库还提供了体量更大、覆盖更全的演示程序,适合系统性探索 egui 能力:

  • egui_demo_app:完整的演示应用,含egui_demo_lib中数十个 demo 页面(widget 画廊、窗口选项、文本布局、绘图、表格、颜色选择器等),源码在 egui_demo_lib/src/demo/ 按主题分文件组织;其 tests/snapshots/ 下的渲染快照既是回归测试也是视觉效果合集;
  • examples/run_all.sh 可一次跑遍全部 examples;
  • 仓库 scripts/ 下的build_demo_web.shsetup_web.sh等脚本说明了如何把 demo 编译到 Web(wasm)运行,这也印证了 README 中"许多示例适用于任何 egui 集成"的说法——同一套 UI 代码可在原生与浏览器两种环境复用。

阅读顺序建议

  1. 先跑hello_world(或更精简的hello_world_simple),对照上文代码理解run_native+App::ui骨架;
  2. 按业务需求横向取用进阶示例:做工具软件看custom_window_framefile_dialogconfirm_exit;做展示/游戏类看custom_3d_glowimages;做跨平台/Web 应用看external_eventloop系列与hello_android
  3. 需要深挖某类控件或布局时,回到 egui_demo_lib/src/demo/ 查找对应 demo 页源码,并结合 crates/egui/src/ 的widgets/containers/源码理解实现细节。

小结

examples/目录是 egui 官方维护的"可运行文档":它用一个统一入口(eframe 窗口)+ 众多主题化示例,覆盖了从最小可运行程序到窗口定制、字体替换、文件拖放、GPU 3D 渲染、多视口、外部事件循环与 Android 部署的完整实践路径。阅读时记住 README 的两条准则——main 分支示例对应最新开发版 API、按需切换到对应版本 tag——再结合每个示例目录内的 README 与截图,即可高效定位并复用你需要的参考实现,快速搭建自己的 egui 应用。

【免费下载链接】eguiegui: an easy-to-use immediate mode GUI in Rust that runs on both web and native项目地址: https://gitcode.com/GitHub_Trending/eg/egui

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询