egui 的开发由 Rerun 赞助,
一家正在构建一个用于可视化多模式数据流的SDK的初创公司
👉 点此运行 Web 样例 👈
egui (读作“e-gooey”,“易古一”) 是一个简单、快速、可移植性强的 Rust 即时模式 GUI 库。egui 可运行于 Web, Native 甚至 你喜欢的的游戏引擎。
egui 旨在成为最易用的 Rust GUI 库,用最简单的方式创建Web应用程序。
egui 可以在任何可以绘制纹理三角形(textured triangles)的地方使用,这意味着你可以轻松地地将它集成到你选择的游戏引擎中。
eframe
是一个官方 egui 框架,支持为Web、Linux、Mac、Windows和Android编写应用程序。
ui.heading("My egui Application");
ui.horizontal(|ui| {
ui.label("Your name: ");
ui.text_edit_singleline(&mut name);
});
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}"));
ui.image(egui::include_image!("ferris.png"));
章节:
示例目录(examples/
)中有一些简单的示例。如果你想写一个 Web App,请按照 https://github.com/emilk/eframe_template/的说明操作。
官方文档位于 https://docs.rs/egui。要获得更多灵感或示例,请查看 egui web 样例 并按照其中的链接访问源代码。
如果你想要将egui集成到现有的引擎中,请前往 集成 一节。
如果有疑问,请访问 GitHub Discussions 或 egui 的 discord 服务器。
如果你想为egui做贡献,请阅读 Contributing Guidelines.
点此运行 Web 样例 (可运行于任何支持 Wasm 和 WebGL 的浏览器)。使用 eframe
。
若要在本地测试样例 App,运行 cargo run --release -p egui_demo_app
。
native 后端是 egui_glow
(使用 glow
),在 Windows 和 Mac 上开箱即用,但如果要在 Linux 上使用,需要先运行:
sudo apt-get install -y libclang-dev libgtk-3-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libssl-dev
在 Fedora Rawhide 上需要运行:
dnf install clang clang-devel clang-tools-extra libxkbcommon-devel pkg-config openssl-devel libxcb-devel gtk3-devel atk fontconfig-devel
注意: 这只针对样例 App —— egui 本身是完全跨平台的!
- 最易用的 GUI 库
- 灵敏:在 debug build 中达到 60 Hz
- 友好:难以发生编码错误,不应该发生 panic
- 可移植:同样的代码可以跨平台使用
- 轻松集成到任意环境中
- 用于自定义绘制的简单 2D 图形 API(
epaint
). - 没有回调
- 纯即时模式
- 可扩展:轻松为 egui 编写自己的 widgets
- 模块化:你可以使用 egui 中的一小部分,并用新的方式将它们组合起来
- 内存安全:egui 中没有
unsafe
关键字 - 依赖最小化
egui 不是框架。egui 是供调用的库,而不是供编程的环境。
注意: egui 还没有实现所有上述目标!egui 仍在开发中。
- 成为最强大的 GUI 库
- 原生外观界面(looking interface)
- 高级灵活的布局(这与即时模式根本不兼容)
egui 在活跃开发中。它工作得很好,但缺少许多特性,接口仍在变化。新的版本会有破坏性的更改。
尽管如此,egui 还是可以用来创建看起来专业的应用程序,比如 the Rerun Viewer.
- 组件(Widgets): label, text button, hyperlink, checkbox, radio button, slider, draggable value, text editing, color picker, spinner
- 图片(Images)
- 布局(Layouts):horizontal, vertical, columns, automatic wrapping
- 文本编辑(Text editing): multiline, copy/paste, undo, emoji supports
- 窗口(Windows):move, resize, name, minimize and close. 自动调整大小和定位。
- 区域(Regions):resizing, vertical scrolling, collapsing headers (sections), panels
- 渲染(Rendering):Anti-aliased rendering of lines, circles, text and convex polygons.
- 悬浮工具提示
- 通过 AccessKit 实现的无障碍访问
- 标签文本选择
- 以及更多!
Light Theme:
egui
具有一组最小的默认依赖项:
egui
中没有重量级依赖, 即使是 opt-in。
egui
中也完全没有非 Wasm 友好的代码。
要想加载图片到 egui
中,你可以使用官方的 egui_extras
crate.
另一方面,eframe
则有许多依赖项,包括 winit
,image
,graphics crates
,clipboard crates
,等等。
如果您想要以最简单的方式创建 GUI 或想要在游戏引擎中添加 GUI, 那么 egui 旨在成为您的最佳选择。
如果您不用 Rust,egui 不适合您。
如果您想要一个看起来是原生的 GUI,egui 不适合您。
如果您想要升级时不会破坏已有项目,egui 暂时不适合您。
但如果您想用 Rust 写一些交互式的东西,需要一个简单的 GUI,egui 可能会适合您。
egui 易于集成到任何你使用的游戏引擎或平台 egui 自身不知道且不关心运行它的操作系统和被渲染到屏幕的方式——这是egui集成的工作
一个集成需要在每一帧都做以下事情:
-
输入: 采集输入(鼠标、触摸、键盘、屏幕大小……)并传递给 egui
-
调用应用程序的 GUI 代码
-
输出: 处理 egui 输出 (光标变化、粘贴、纹理分配(texture allocations)……)
-
绘制:渲染 egui 生成的三角形网格(参考 OpenGL example)
以下是 egui 官方集成:
eframe
将同一份 App 编译为 web/wasm 和 desktop/native。使用egui-winit
和egui_glow
或egui-wgpu
egui_glow
使用 glow 在 native 或 web 上渲染 egui,以及制作 native app。egui-wgpu
用于 wgpu (WebGPU API)egui-winit
用于与 winit 集成
egui-ash
forash
(a very lightweight wrapper around Vulkan)bevy_egui
for the Bevy game engineegui_gl_glfw
for GLFWegui_glium
for compiling native apps with Gliumegui-glutin-gl
for glutinegui_sdl2_gl
for SDL2egui_sdl2_platform
for SDL2egui_vulkano
for Vulkanoegui_winit_vulkano
for Vulkanoegui-macroquad
for macroquadegui-miniquad
for Miniquadegui_speedy2d
for Speedy2degui-tetra2
for Tetra, a 2D game frameworkegui-winit-ash-integration
for winit and ashfltk-egui
for fltk-rsggegui
for the ggez game frameworkgodot-egui
for godot-rustnannou_egui
for nannounotan_egui
for notanscreen-13-egui
for Screen 13egui_skia
for skiasmithay-egui
for smithaytauri-egui
for tauri
您正在做的东西没有集成?创建一个很容易!
参考 https://docs.rs/egui/latest/egui/#integrating-with-egui.
egui
是一个 即时模式 GUI 库,而不是保留模式 GUI 库。 关于它们的区别,最好的例子就是按钮:在一个保留 GUI 中,如果你创建了一个按钮,把它添加入 UI 中,并配套点击处理程序(调用)。这个按钮会被保留在用户界面中,为改变某些界面刷新,需要存储对其调用。而相对之下,在即时模式中,这个按钮会立即显示并与你进行交互,而这对于每一帧来说都可用(每秒60帧)。这意味你不需要任何 on-click 处理程序,也不需要存储对它的任何调用。 在 egui
中按钮是这样表示的 if ui.button("Save file").clicked() { save(file); }
.
译者注:关于即时模式和保留模式的区别可以看看 微软的这篇文章。
有关即时模式的更详细描述,请参见 in the egui
docs.
这两种系统各有优缺点。
简单来说,即时模式 GUI 更容易用,但没那么强大。
即时模式的主要优点是,使得应用程序的代码更为简单。
- 不需要有任何点击处理程序和回调操作,以免耽误你的开发流程。
- 不用担心一个不知所以然的回调调用已经删除的东西。
- GUI代码可以很容易地存在于一个简单的函数中 (无需为用户界面设置对象)。
- 不用担心应用程序状态和 GUI 状态同步问题 ( GUI 显示延迟), 因为 EGUI 不存储任何状态--即时模式。
换言之,减少大量代码、复杂性和错误,你能把时间放在比写 GUI 代码更有趣的事情上。
即时模式的主要缺点是布局更加困难。假设你在屏幕中央显示一个小的对话窗口。为了正确定位该窗口,GUI库必须首先知道它的尺寸。为了知道窗口的大小,GUI库必须首先布局窗口的内容。在保留模式下,实现比较容易:GUI库进行窗口布局,定位窗口,然后检查交互情况 (按钮是否进行点击)。
即时模式下,你会遇到一个悖论:为了知道窗口的大小,我们必须进行布局,但布局代码也会检查交互(按钮是否进行点击),因此在显示窗口内容之前,需要先知道窗口的位置。这意味必须在知道窗口的大小之前就决定在哪里显示窗口。
这是即时GUI的一个基本缺陷,任何试图解决这个问题的努力都会带来自身的弊端。
一种解决方法是提前存储界面尺寸并在下一帧使用。这就产生了一个帧延迟,第一帧就会偶尔出现闪烁。 egui
对于如窗口和网格布局,都是如此。
也可以调用两次布局代码(一次获取尺寸,第二次进行下一次交互),但是成本更高,而且实现起来也更复杂,何况某些情况下两次不够。 egui
不会这样做。
对于"atomic" widgets部件 (例如一个 button) egui
在显示之前就知道尺寸,所以egui
中可以将按钮、标签等放在中间,而不需要任何特殊的操作。
更多请参考 this issue。
由于即时模式的 GUI 每帧都做了完整的布局,布局代码需要快速响应。如果你有一个非常复杂的 GUI ,这可能会对 CPU 造成负担。特别在滚动区域有一个非常大的用户界面(很长的滚动页面)将会变得很慢,因为需要将每一帧都渲染出来。
如果在设计 GUI 时考虑到了这一点,为避免使用巨大的滚动区域(或是只布置在视图中显示的部分),那么对性能影响是相当小的。在大多数情况下,你可以期望egui
每帧占用1-2ms,但egui
仍有很大的优化空间。也可以将egui
设置为只在有交互(如鼠标移动时)或者动画时才进行重绘,因此如果你的 app 是空闲的(idle),则不会浪费 CPU。
如果你的 GUI 是高度交互的,那么与保留模式相比,即时模式可能性能更好。进入任何网页并调整浏览器窗口的大小时候,你会注意浏览器布局非常慢,同时消耗大量 CPU 。相比之下,在 "egui "中调整一个窗口的大小,仍能保持 60FPS 帧率,且没有额外的CPU成本。
在一些 GUI 状态中,如果希望 GUI 库保留,或是在一个即时模式库如egui
中。那么就需要知道窗口的位置和大小,以及在某些界面中滚动了多远。这种情况下,需要为egui
提供唯一标识符的种子(在主 UI 中是唯一的)。例如在默认情况下,egui
使用窗口标题作为唯一的 IDs 来存储窗口位置。如果你想要两个具有相同名称的窗口(或一个具有动态名称的窗口),你必须向egui
提供其他的 IDs 来源(由独特的整数或字符串构成)。
egui
需要跟踪哪个部件被交互(例如哪个滑块被拖动)。egui
也使用唯一的 IDs,但在上述情况下,IDs 是自动生成的,所以不需担心这个问题。对于两个名字相同的按钮也没有问题(这与 Dear ImGui
形成对比).
总的来说,IDs 处理有些不方便,但并不是一个大的缺点。
Also see GitHub Discussions.
是的!但你需要使用 Context::set_fonts
安装自己的字体(.ttf
或 .otf
)。
是的!你可以使用 Context::set_style
自定义所有东西颜色、间距、字体和大小。
这还没有如 CSS 那般强大,不过正在改进.
这是一个例子(来自 https://github.com/a-liashenko/TinyPomodoro):
如果你在 GUI 代码中调用 .await
,UI 会冻结,用户体验将会很差。替代方案是,保持 GUI 线程不阻塞的情况下与并发任务通信(async
任务或任何其他线程)。你可以用下面的方法实现。
- Channels (e.g.
std::sync::mpsc::channel
). Make sure to usetry_recv
so you don't block the gui thread! Arc<Mutex<Value>>
(background thread sets a value; GUI thread reads it)poll_promise::Promise
eventuals::Eventual
tokio::sync::watch::channel
rfd 的异步版本同时支持本机和Wasm。
这里有一些样例 app https://github.com/woelper/egui_pick_file
他还在 gitub pages 上有一个 demo。
egui包含了可选的AccessKit支持,它当前在Windows和macOS上实现了原生的可访问性API。这个特性在dframe中默认启用。对于AccessKit尚未支持的平台,如Web,你可以用实验性的内置屏幕阅读器;在the web demo中你可以在“Backend”选项卡打开它。
egui最开始关于无障碍的讨论在emilk/egui#167。现在,AccessKit支持已合并,为未来的无障碍功能工作提供了强大的基础,请就特定的无障碍问题打开新的issue。
egui
是一个有布局和交互功能的 2D 用户界面库。
egui
无法知道它的运行环境,也不知道如何获取输入/输出到显示器。
这是 集成 或 后端 的任务。
在游戏引擎中使用 egui
是很常见的(比如 bevy_egui
),
但你也可以依靠 eframe
来单独使用 egui
。eframe
有着 Web 和 Native,处理输入和渲染的集成。
eframe
中的 frame 既代表 egui app 中的 帧(frame),又代表框架(framework)(eframe
是个框架, egui
是个库)。
有多种方法可以将 egui 与 3D 相结合。最简单的方法是使用一个3D库,让EGUI 位于 3D 视图的顶部。例如 bevy_egui
or three-d
.
如果想将 3D 嵌入到 egui 视图中,有两种选择:
Examples:
Shape::Callback
will call your code when egui gets painted, to show anything using whatever the background rendering context is. When using eframe
this will be glow
. Other integrations will give you other rendering contexts, if they support Shape::Callback
at all.
You can also render your 3D scene to a texture and display it using ui.image(…)
. You first need to convert the native texture to an egui::TextureId
, and how to do this depends on the integration you use.
Examples:
- Using
egui-miniquad
: https://github.com/not-fl3/egui-miniquad/blob/master/examples/render_to_egui_image.rs
All coordinates are in screen space coordinates, with (0, 0) in the top left corner
All coordinates are in logical "points" which may consist of many physical pixels.
All colors have premultiplied alpha, unless otherwise stated.
egui uses the builder pattern for construction widgets. For instance: ui.add(Label::new("Hello").text_color(RED));
I am not a big fan of the builder pattern (it is quite verbose both in implementation and in use) but until Rust has named, default arguments it is the best we can do. To alleviate some of the verbosity there are common-case helper functions, like ui.label("Hello");
.
Instead of using matching begin/end
style function calls (which can be error prone) egui prefers to use FnOnce
closures passed to a wrapping function. Lambdas are a bit ugly though, so I'd like to find a nicer solution to this. More discussion of this at emilk/egui#1004.
egui uses a single RwLock
for short-time locks on each access of Context
data. This is to leave implementation simple and transactional and allow users to run their UI logic in parallel. Instead of creating mutex guards, egui uses closures passed to a wrapping function, e.g. ctx.input(|i| i.key_down(Key::A))
. This is to make it less likely that a user would accidentally double-lock the Context
, which would lead to a deadlock.
The one and only Dear ImGui is a great Immediate Mode GUI for C++ which works with many backends. That library revolutionized how I think about GUI code and turned GUI programming from something I hated to do to something I now enjoy.
The name of the library and the project is "egui" and pronounced as "e-gooey". Please don't write it as "EGUI".
The library was originally called "Emigui", but was renamed to "egui" in 2020.
egui 的作者与维护者:Emil Ernerfeldt (@emilk).
主要贡献者:
- @n2: Mobile web input and IME support
- @optozorax: Arbitrary widget data storage
- @quadruple-output: Multitouch
- @EmbersArc: Plots
- @AsmPrgmC3: Proper sRGBA blending for web
- @AlexApps99:
egui_glow
- @mankinskin: Context menus
- @t18b219k: Port glow painter to web
- @danielkeller:
Context
refactor - @MaximOsipenko:
Context
lock refactor - @mwcampbell: AccessKit integration
- @hasenbanck, @s-nie, @Wumpf:
egui-wgpu
- @jprochazk: egui image API
- 以及 更多贡献者.
egui使用MIT许可证 或 Apache-2.0许可证。
- 三次贝塞尔曲线和二次贝塞尔曲线的平坦化算法来自 lyon_geom
(原文:The flattening algorithm for the cubic bezier curve and quadratic bezier curve is from lyon_geom )
默认字体:
emoji-icon-font.ttf
: Copyright (c) 2014 John Slegers , MIT LicenseHack-Regular.ttf
: https://github.com/source-foundry/Hack, MIT LicenceNotoEmoji-Regular.ttf
: google.com/get/noto, SIL Open Font LicenseUbuntu-Light.ttf
by Dalton Maag: Ubuntu font licence
egui 的开发由 Rerun 赞助,
一家正在构建一个用于可视化多模式数据流的SDK的初创公司