news 2026/9/10 16:56:45

egui Hello World 示例全解析:从 `Label`、`TextEdit`、`Slider` 到 `Button` 的即时模式 GUI 入门

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
egui Hello World 示例全解析:从 `Label`、`TextEdit`、`Slider` 到 `Button` 的即时模式 GUI 入门

egui Hello World 示例全解析:从LabelTextEditSliderButton的即时模式 GUI 入门

【免费下载链接】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 仓库中的 hello_world 示例 为主线,逐行剖析一个最小可运行的 eframe 桌面应用:从cargo run -p hello_world的启动方式,到LabelTextEditSliderButton四大基础控件的用法,再到include_image!宏与图片加载器的接入原理。读完本文,你将掌握如何用 egui 在几分钟内搭起第一个带输入框、滑条、按钮和图片的 Rust 原生窗口应用,并理解其背后的核心 API 调用链。

一、示例概览与快速运行

hello_world 是 egui 仓库中最基础的示例,其 README 只有一句话的定位:展示LabelTextEditSliderButton等基础 UI 控件。该示例属于仓库根目录 Cargo.toml 中examples/*工作区成员,因此可以站在仓库根目录直接用包名运行:

cargo run -p hello_world

运行后会出现一个 320×240 的窗口,标题为 “My egui App”,界面包含:

  • 标题文本 “My egui Application”;
  • 一个 "Your name:" 标签与单行文本输入框(默认内容为Arthur);
  • 一个带 "age" 文字的滑条(范围 0..=120,默认值 42);
  • 一个 "Increment" 按钮,点击后年龄 +1;
  • 一行根据输入实时拼接的问候语Hello 'xxx', age xxx
  • 窗口底部一张内嵌的 egui 吉祥物 ferris 图片。

整个示例的完整源码位于 examples/hello_world/src/main.rs,全部代码约 60 行,非常适合作为新手的第一个 egui 程序。

二、程序入口与原生窗口配置

2.1 隐藏 Windows 控制台窗口

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release

这一行是 Windows 平台惯例:在 release 构建(cfg_attr中的not(debug_assertions))下,将子系统指定为windows,从而隐藏弹出的黑色控制台窗口。调试构建不受影响,控制台仍会保留以便观察日志。

2.2 日志初始化

env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).

env_logger是 egui 生态惯用的日志后端。示例中通过RUST_LOG环境变量控制输出级别,例如:

RUST_LOG=debug cargo run -p hello_world

即可在 stderr 看到 eframe、egui 运行时的调试日志。该依赖在 examples/hello_world/Cargo.toml 中声明,并启用了auto-color(终端着色)与humantime(人类可读时间戳)两个特性。

2.3 ViewportBuilder 与 NativeOptions

let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]), ..Default::default() };

egui::ViewportBuilder负责描述窗口/视口(viewport)的初始属性,with_inner_size设定客户区尺寸为 320×240 逻辑像素。除尺寸外,它还可以配置窗口标题、位置、是否可缩放、图标等;NativeOptions是 eframe 原生后端(基于 winit)的全局选项集合,除viewport外还包含renderer(渲染后端选择)、persist_window(是否记住窗口位置)等字段。示例只覆盖viewport,其余用..Default::default()取默认值。

三、eframe::run_nativeApptrait:应用骨架

3.1 启动函数

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()) }), )

eframe::run_native是原生(桌面)平台的应用入口,声明于 crates/eframe/src/lib.rs,其三个参数依次为:

参数类型作用
app_name&str应用名称,会作为窗口标题与持久化 ID 的一部分
native_optionsNativeOptions上述原生窗口/渲染配置
app_creator闭包创建App实例的工厂,可拿到CreationContext

闭包接收cc: &eframe::CreationContext,其中cc.egui_ctx是全局的egui::Contextinstall_image_loaders正是注册到它上面。注意返回值是eframe::Result,因此main的签名是fn main() -> eframe::Result

从仓库的调用链看,run_native会继续进入run_native_ext(crates/eframe/src/lib.rs),最终由各原生后端(如glow_integration.rswgpu_integration.rs)驱动事件循环与渲染。

3.2 应用状态结构体

struct MyApp { name: String, age: u32, } impl Default for MyApp { fn default() -> Self { Self { name: "Arthur".to_owned(), age: 42, } } }

即时模式(immediate mode)GUI 的核心理念:UI 状态就存放在你的普通 Rust 结构体中,没有独立的控件对象树。MyApp的两个字段分别被TextEditSlider&mut方式直接绑定,这正是Box::<MyApp>::default()能直接作为应用实例的原因——Default提供了初始状态。

3.3 实现eframe::App

impl eframe::App for MyApp { fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ui, |ui| { // ... }); } }

注意:本仓库当前版本(workspace 版本号见 Cargo.toml,为 0.36.2)的Apptrait 把绘制入口统一收口为fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame),而不是更早版本中常见的fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame),这是新版本 API 的显著变化。CentralPanel会占据窗口中央的剩余区域,是所有非面板 UI 的默认容器;ui参数则代表当前正在绘制的面板画布,示例中所有控件都挂在它下面。

四、四大基础控件逐一拆解

4.1Label:静态文本与无障碍绑定

ui.heading("My egui Application");

ui.headingLabel的便捷封装,按TextStyle::Heading样式绘制大标题。随后:

let name_label = ui.label("Your name: "); ui.text_edit_singleline(&mut self.name) .labelled_by(name_label.id);

第一行ui.label创建普通Label,并捕获其返回的Response中的id;第二行通过.labelled_by(...)把输入框与该标签关联。这一做法服务于无障碍(AccessKit)场景:屏幕阅读器可以把标签文本与输入框语义绑定,供依赖辅助技术的用户使用。egui 的Response是所有控件交互结果的统一载体(是否被点击、悬停、拖拽等),也是这类链式配置的入口。

4.2TextEdit:单行文本输入

ui.text_edit_singleline(&mut self.name)

text_edit_singlelineTextEdit的单行便捷构造,直接借用&mut String,用户每次按键都会写回self.name,无需任何手动同步——这是即时模式最直观的体现。对应还有ui.text_edit_multiline多行版本。TextEdit位于 crates/egui/src/widgets/text_edit/ 目录,内部还实现了光标状态、IME 输入法合成等细节,这里按下不表。

4.3Slider:数值拖拽与钳制

ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));

Slider::new的第一个参数是被控数值的可变引用(支持整数、浮点等数值类型),第二个参数是闭区间RangeInclusive,定义滑条两端对应的取值边界。.text("age")会在滑条右侧追加说明文字。其底层实现见 crates/egui/src/widgets/slider.rs:滑条由“滑轨 + 数值显示 + 可选文本”三部分构成,数值显示部分可点击后直接键入;默认SliderClamping::Always会把值钳制在区间内,也可通过.clamping(SliderClamping::Edits)等策略调整(见 slider.rs)。示例用0..=120限定了年龄范围,恰好与u32语义吻合。

4.4Button:点击事件

if ui.button("Increment").clicked() { self.age += 1; }

ui.button创建文本按钮并立即返回Response.clicked()返回“本帧内是否发生点击”。由于即时模式每帧都会重建 UI,这里if clicked()的写法等价于传统事件循环中的回调,但更直白。按钮的完整能力不止于此——crates/egui/src/widgets/button.rs 显示Button还支持.selected()(可选中态,自动添加CLASS_SELECTED)、.fill()(自定义填充色)、.min_size()以及Button::image/Button::image_and_text(带图标按钮)等。点击后self.age += 1,下一帧滑条与问候语会自动反映新值。

4.5 实时反馈输出

ui.label(format!("Hello '{}', age {}", self.name, self.age));

Label接收任意WidgetText可转换类型,format!生成的字符串在这里每帧重新求值,因此输入框内容、年龄变化都会即时反映到这一行文字上——无需任何数据绑定框架。

五、图片加载:install_image_loadersinclude_image!

示例在创建应用时调用了egui_extras::install_image_loaders(&cc.egui_ctx)。该函数定义于 crates/egui_extras/src/loaders.rs,按编译特性注册一系列加载器到egui::Context

egui_extras 特性注册的加载器支持的来源
file(非 Wasm)FileLoaderfile://URI,经std::fs::read读取,扩展名推断类型
httpEhttpLoaderhttp(s)://URI,按Content-Type推断类型
imageImageCrateLoaderpng/jpeg 等,基于imagecrate
svgSvgLoader.svg文件

示例的 Cargo.toml 中egui_extras启用了defaultimage两个特性,因此本示例可解码 png 等位图。函数内部会先检查ctx.is_loader_installed(...)避免重复安装,多次调用是安全的。

绘制部分:

ui.image(egui::include_image!( "../../../crates/egui/assets/ferris.png" ));

include_image!是 egui 提供的编译期图片内嵌宏,定义于 crates/egui/src/lib.rs。它展开为ImageSource::Bytes:URI 固定为bytes://前缀拼接原始路径,字节数据通过include_bytes!在编译期打包进二进制,从而运行时零文件读取,特别适合图标、吉祥物等小体积资源。ui.image(...)则完成解码、上传 GPU 纹理并绘制;示例中的图片是仓库自带的 crates/egui/assets/ferris.png。

注意install_image_loaders只负责“字节 → 图像”的解码管线,include_image!负责“文件 → 字节”的编译期内嵌,二者一前一后配合:前者提供解码能力,后者提供内嵌字节。

六、依赖配置说明

示例的 Cargo.toml 依赖结构如下:

[dependencies] 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是桌面端最上层的开箱即用框架(自带 winit 事件循环与渲染器),版本与 workspace 统一(当前 0.36.2)。__screenshot是一个内部特性:设置环境变量EFRAME_SCREENSHOT_TO指向输出路径后,可自动导出首帧截屏,仓库的截图回归测试与示例截图正是靠它生成的。
  • egui_extras仅在示例中用于install_image_loaders,所以只额外开启了image特性(见 loaders.rs 中关于特性与格式的警告:加载器和图像格式必须同时配置才会生效)。
  • 包本身publish = false,是仓库内部示例,不会发布到 crates.io;edition 为 2024,rust-version要求 1.95。

七、扩展方向:从示例走向真实应用

hello_world 演示的只是最小闭环,想继续深入可以沿着以下路径在仓库中找到更丰富的参照:

  • 更多控件:仓库的 egui_demo_lib 中收录了数十个控件演示(滑条、拖拽值、颜色选择器、表格等),cargo run -p egui_demo_app可运行完整的 demo 应用逐个体验;
  • 布局:除了CentralPanel,egui 还提供TopBottomPanelSidePanel等面板与ui.horizontalui.vertical布局函数,示例中ui.horizontal已用于把标签和输入框排成一行;
  • Web 端:eframe 同时支持编译到 Wasm 在浏览器运行,可参考 crates/eframe/src/web/ 下的 web 后端;
  • 截图自动化:如需为 UI 生成回归快照,可参考 egui_kittest 的 snapshot 测试 以及 scripts/accept_snapshots.sh 工具链。

总而言之,hello_world 用最少的代码串起了“状态结构体 →App::ui→ 各控件读写状态”的完整循环,是理解 egui 即时模式心智模型的最佳起点:你写 UI 就是写普通 Rust 函数,状态变化由控件直接写回你的变量,渲染与事件由框架每帧自动完成

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 16:56:21

使用统计功能测试报告

使用统计功能测试报告 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN 测试环境 操作系统: Windows 11浏览器: Chrome 120后端版本: [按实际填写…

作者头像 李华
网站建设 2026/9/10 16:55:56

MATLAB实现随机游走改进谱聚类算法

1. 项目概述&#xff1a;当随机游走遇见谱聚类在数据科学领域&#xff0c;聚类分析一直是探索性数据分析的利器。传统k-means算法在处理非凸分布数据时往往力不从心&#xff0c;这正是谱聚类大显身手的场景。最近我在MATLAB R2018A环境下实现了一种基于随机游走拉普拉斯算子的改…

作者头像 李华
网站建设 2026/9/10 16:53:34

K8s集群部署Jenkins流水线Pip缓存排查实操

K8s集群部署Jenkins流水线Pip缓存排查实操技术栈&#xff1a;Jenkins 2.440.x Kubernetes v1.32.13 Rocky Linux 8.6 Kubernetes Plugin Kaniko Helm 3.14.x操作环境 / 对接原理 / 详细步骤 / 完整命令 / 配置文件 / 验证流程 / 排错方案K8s集群部署Jenkins流水线Pip缓存排…

作者头像 李华
网站建设 2026/9/10 16:53:04

VMware虚拟机安装Ubuntu Server 22.04最小版完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华