egui - egui:Rust 中易于使用的即时模式 GUI,可在 Web 和本机上运行

Created at: 2019-01-13 23:39:15
Language: Rust
License: Apache-2.0

🖌 egui:纯 Rust 中易于使用的 GUI

github 最新版本 文档 不安全的禁止 构建状态  MIT  Apache 不和

👉 单击以运行网络演示 👈

egui(发音为“e-gooey”)是一个简单、快速且高度可移植的 Rust 即时模式 GUI 库。egui 在 Web 上运行,本机运行,并在你最喜欢的游戏引擎中运行(或即将运行)。

egui 旨在成为最容易使用的 Rust GUI 库,也是在 Rust 中制作 Web 应用程序的最简单方法。

egui 可以在任何可以绘制纹理三角形的地方使用,这意味着你可以轻松地将其集成到你选择的游戏引擎中。

部分:

(egui 的中文翻译文档)

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("Click each year").clicked() {
    age += 1;
}
ui.label(format!("Hello '{}', age {}", name, age));

快速入门

examples/ 文件夹中有简单的例子。如果要编写 Web 应用,请转到 https://github.com/emilk/eframe_template/ 并按照说明进行操作。官方文档在 https://docs.rs/egui。有关灵感和更多示例,请查看 egui Web 演示并按照其中的链接访问其源代码。

如果要将 egui 集成到现有引擎中,请转到集成部分。

如有疑问,请使用 GitHub 讨论。还有一个 egui 不和谐服务器。如果你想为 egui 做出贡献,请阅读贡献指南

演示

单击以运行egui Web演示(适用于任何支持WASM和WebGL的浏览器)。使用 eframe

要在本地测试演示应用程序,请运行 。

cargo run --release -p egui_demo_app

本机后端是egui_glow的(使用glow),应该在Mac和Windows上开箱即用,但在Linux上,你需要首先运行:

sudo apt-get install -y libclang-dev libgtk-3-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libssl-dev

在Fedora Rawhide上,你需要运行:

dnf install clang clang-devel clang-tools-extra speech-dispatcher-devel libxkbcommon-devel pkg-config openssl-devel libxcb-devel

注意:这仅适用于演示应用程序 - egui 本身完全与平台无关!

目标

  • 最容易使用的图形用户界面库
  • 响应式:调试版本中的目标为 60 Hz
  • 友好:难以犯错误,不应惊慌
  • 可移植:相同的代码适用于网络和本机应用程序
  • 易于集成到任何环境中
  • 用于自定义绘画 (epaint) 的简单 2D 图形 API。
  • 无回调
  • 纯即时模式
  • 可扩展:易于为 egui 编写自己的小部件
  • 模块化:你应该能够使用 egui 的小部分并以新的方式组合它们
  • 安全:egui 中没有代码
    unsafe
  • 最小依赖:ab_glyph ahash nohash-hasher parking_lot

egui 是一个框架。egui 是你调用的库,而不是你为其编程的环境。

注意:egui 并没有声称已经达到了所有这些目标!egui 仍在进行中。

非目标

  • 成为最强大的图形用户界面库
  • 原生外观界面
  • 高级和灵活的布局(从根本上与即时模式不兼容)

埃吉是为谁准备的?

egui 旨在成为你想要一种创建 GUI 的简单方法或想要将 GUI 添加到游戏引擎时的最佳选择。

如果你没有使用 Rust,egui 不适合你。如果你想要一个看起来原生的 GUI,egui 不适合你。如果你想要在升级时不会损坏的东西,egui 不适合你(还)。

但是,如果你正在用 Rust 编写一些需要简单 GUI 的交互式东西,egui 可能适合你。

埃吉 vs 亲爱的伊姆吉

egui 的明显替代品是 imgui-rs,它是围绕C++库 Dear ImGui 的 Rust 包装器。Dear ImGui 是一个很棒的库(也是 egui 的主要灵感来源),具有更多的功能和润色。但是,egui 为 Rust 用户提供了一些好处:

  • egui 是纯粹的 Rust
  • egui 很容易编译到 WASM
  • egui 允许你使用本机 Rust 字符串类型(强制你使用烦人的宏和包装器来处理以零结尾的字符串)
    imgui-rs
  • 在 egui 中编写自己的小部件很简单

egui 还尝试以其他小方式改善你的体验:

  • 窗口根据其内容自动调整大小
  • 窗口自动定位为彼此不重叠
  • 一些微妙的动画让 egui 变得生动起来

所以总结一下:

  • egui:纯锈,新的,令人兴奋的,正在进行的工作
  • 亲爱的ImGui:功能丰富,经过充分测试,繁琐的Rust集成

egui 正在积极开发中。它适用于它的功能,但它缺乏许多功能,并且界面仍在不断变化。新版本将具有重大更改。

特征

  • 小部件:标签、文本按钮、超链接、复选框、单选按钮、滑块、可拖动值、文本编辑、组合框、颜色选择器
  • 布局:水平、垂直、列、自动换行
  • 文本编辑:多行,复制/粘贴,撤消,表情符号支持
  • 窗口:移动,调整大小,命名,最小化和关闭。自动调整大小和定位。
  • 区域:调整大小、垂直滚动、折叠标题(部分)
  • 渲染:线条、圆形、文本和凸多边形的抗锯齿渲染。
  • 悬停时的工具提示
  • 更多

灯光主题:

集成

egui 易于集成到你正在使用的任何现有游戏引擎或平台中。egui 本身不知道也不关心它正在运行什么操作系统或如何将内容呈现到屏幕上 - 这是 egui 集成的工作。

集成需要在每个帧中执行以下操作:

  • 输入:收集输入(鼠标、触摸、键盘、屏幕大小等)并将其提供给 egui
  • 运行应用程序代码
  • 输出:处理 egui 输出(光标更改、粘贴、纹理分配等)
  • 绘画:渲染 egui 生成的三角形网格(参见 OpenGL 示例)

官方集成

这些是官方的 egui 集成:

第三方集成

缺少你正在处理的事情的集成?创建一个,这很容易!

编写自己的 egui 集成

你需要收集 egui::RawInput 并处理 egui::FullOutput。基本结构是这样的:

let mut egui_ctx = egui::CtxRef::default();

// Game loop:
loop {
    // Gather input (mouse, touches, keyboard, screen size, etc):
    let raw_input: egui::RawInput = my_integration.gather_input();
    let full_output = egui_ctx.run(raw_input, |egui_ctx| {
        my_app.ui(egui_ctx); // add panels, windows and widgets to `egui_ctx` here
    });
    let clipped_primitives = egui_ctx.tessellate(full_output.shapes); // creates triangles to paint

    my_integration.paint(&full_output.textures_delta, clipped_primitives);

    let platform_output = full_output.platform_output;
    my_integration.set_cursor_icon(platform_output.cursor_icon);
    if !platform_output.copied_text.is_empty() {
        my_integration.set_clipboard_text(platform_output.copied_text);
    }
    // See `egui::FullOutput` and `egui::PlatformOutput` for more
}

有关 OpenGL 后端的参考,请参阅egui_glium画家或egui_glow画家。

调试集成

事情看起来参差不齐

  • 关闭背面剔除。

我的文字模糊不清

  • 确保在输入中将正确的设置为 egui。
    pixels_per_point
  • 确保纹理采样器没有偏离半个像素。尝试使用最近邻采样器进行检查。

我的窗户太透明或太暗

  • egui 使用预乘 alpha,因此请确保你的混合函数为 。
    (ONE, ONE_MINUS_SRC_ALPHA)
  • 确保纹理采样器已夹紧()。
    GL_CLAMP_TO_EDGE
  • egui 更喜欢线性色彩空间进行所有混合,因此:
    • 使用可识别 sRGBA 的纹理(如果可用)(例如 )。
      GL_SRGB8_ALPHA8
      • 否则:请记住在片段着色器中解码伽玛。
    • 在顶点着色器中解码传入顶点颜色的灰度系数。
    • 打开 sRGBA/线性帧缓冲(如果可用)()。
      GL_FRAMEBUFFER_SRGB
      • 否则:在再次写入颜色之前对颜色进行 gamma 编码。

为什么选择即时模式

egui
即时模式 GUI 库,而不是保留模式 GUI 库。保留模式和即时模式之间的区别最好地用按钮示例来说明:在保留的 GUI 中,你创建一个按钮,将其添加到某个 UI 并安装一些单击处理程序(回调)。该按钮保留在 UI 中,要更改其上的文本,你需要存储对它的某种引用。相比之下,在即时模式下,你可以立即显示按钮并立即与之交互,并且每帧都这样做(例如每秒 60 次)。这意味着不需要任何单击处理程序,也不需要存储对它的任何引用。这看起来像这样: .
egui
if ui.button("Save file").clicked() { save(file); }

有关即时模式的更详细说明,请参阅 egui 文档

这两种系统都有优点和缺点。

简而言之:即时模式 GUI 库更易于使用,但功能不那么强大。

即时模式的优点

可用性

即时模式的主要优点是应用程序代码变得简单得多:

  • 你永远不需要有任何中断代码流的单击处理程序和回调。
  • 你不必担心挥之不去的回调会调用已消失的东西。
  • 你的 GUI 代码可以轻松地存在于一个简单的函数中(不需要仅用于 UI 的对象)。
  • 你不必担心应用程序状态和 GUI 状态不同步(即 GUI 显示过时的内容),因为 GUI 不存储任何状态 - 它会立即显示最新状态。

换句话说,大量的代码、复杂性和错误都消失了,你可以把时间集中在比编写GUI代码更有趣的事情上。

即时模式的缺点

布局

即时模式的主要缺点是它使布局更加困难。假设你想在屏幕中央显示一个小的对话窗口。要正确定位窗口,GUI 库必须首先知道窗口的大小。要知道窗口的大小,GUI 库必须首先布局窗口的内容。在保留模式下,这很容易:GUI 库执行窗口布局,定位窗口,然后检查交互(“是否单击了”确定“按钮?

在即时模式下,你会遇到一个悖论:要知道窗口的大小,我们必须进行布局,但布局代码还会检查交互(“是否单击了”确定“按钮?”),因此它需要在显示窗口内容之前知道窗口位置。这意味着我们必须在知道窗口大小之前决定在哪里显示窗口!

这是即时模式 GUI 的一个根本缺点,任何解决它的尝试都有其自身的缺点。

一种解决方法是存储大小并在下一帧使用它。这会为正确的布局产生帧延迟,偶尔会在显示第一帧时闪烁。 对某些内容(如窗口和网格布局)执行此操作。

egui

你也可以调用布局代码两次(一次是为了获取大小,一次是为了进行交互),但这不仅更昂贵,而且实现起来也很复杂,在某些情况下两次是不够的。 从不这样做。

egui

对于“原子”小部件(例如按钮)在显示之前就知道大小,因此可以在没有任何特殊解决方法的情况下居中按钮、标签等。

egui
egui

中央处理器使用率

由于即时模式 GUI 每帧都会执行完整布局,因此布局代码需要快速。如果你有一个非常复杂的GUI,这可能会给CPU带来负担。特别是,在滚动区域中具有非常大的 UI(具有很长的回滚)可能会很慢,因为内容需要对每一帧进行布局。

如果你在设计 GUI 时考虑到这一点,并且避免使用巨大的滚动区域(或仅布置视图中的部分),那么性能影响通常很小。在大多数情况下,你可以期望每帧占用 1-2 毫秒,但仍有很大的优化空间(我还没有关注它)。你还可以设置为仅在有交互(例如鼠标移动)时重新绘制。

egui
egui
egui

如果你的 GUI 是高度交互的,那么与保留模式相比,即时模式实际上可能性能更高。转到任何网页并调整浏览器窗口的大小,你会注意到浏览器进行布局的速度非常慢,并且消耗了大量的 CPU。相比之下,调整窗口大小,你将获得流畅的 60 FPS,而无需额外的 CPU 成本。

egui

身份证件

你希望 GUI 库保留某些 GUI 状态,即使在即时模式库(如 )中也是如此。这包括窗口的位置和大小以及用户在某些 UI 中滚动的距离。在这些情况下,你需要提供唯一标识符的种子(在父 UI 中唯一)。例如:默认情况下,使用窗口标题作为唯一 ID 来存储窗口位置。如果需要两个具有相同名称的窗口(或一个具有动态名称的窗口),则必须提供一些其他 ID 源(一些唯一的整数或字符串)。

egui
egui
egui
egui

egui
还需要跟踪正在与哪个小部件交互(例如,正在拖动哪个滑块)。 对此井使用唯一的 id:s,但在这种情况下,ID 是自动生成的,因此用户无需担心。特别是,拥有两个同名按钮是没有问题的(这与亲爱的ImGui形成鲜明对比)。
egui

总的来说,ID处理是一个罕见的不便,而不是一个很大的缺点。

常见问题

另请参阅 GitHub 讨论

我可以与非拉丁字符一起使用吗?
egui

是的!但是你需要使用 安装自己的字体(或 )。

.ttf
.otf
Context::set_fonts

我可以自定义 egui 的外观吗?

是的!你可以使用 自定义所有内容的颜色、间距、字体和大小。

Context::set_style

下面是一个示例(来自 https://github.com/AlexxxRu/TinyPomodoro):

如何将 egui 与 ?
async

如果你调用 GUI 代码,UI 将冻结,这是非常糟糕的用户体验。相反,请保持 GUI 线程无阻塞,并使用如下内容与任何并发任务(任务或其他线程)进行通信:

.await
async

辅助功能(如屏幕阅读器)如何?

egui 包括对 AccessKit 的可选支持,该支持目前在 Windows 和 macOS 上实现了本机辅助功能 API。默认情况下,此功能在 eframe 中处于启用状态。对于 AccessKit 尚不支持的平台(包括 Web),有一个实验性的内置屏幕阅读器;在网络演示中,你可以在“后端”选项卡中启用它。

关于 egui 中可访问性的原始讨论在 https://github.com/emilk/egui/issues/167.现在,AccessKit 支持已合并,为未来的辅助功能工作奠定了坚实的基础,请针对特定的辅助功能问题打开新问题。

eguieframe 有什么区别?

egui
是一个 2D 用户界面库,用于布局按钮、滑块等并与之交互。 不知道它是在网络上运行还是在本地运行,也不知道如何收集输入或在屏幕上显示内容。这是集成后端的工作。
egui

通常从游戏引擎使用(例如使用 bevy_egui),但你也可以单独使用 . 集成了 Web 和本机,并处理输入和渲染。中的框架既代表你的 egui 应用程序所在的框架,也代表“框架”(是一个框架,是一个库)。

egui
egui
eframe
eframe
eframe
frame
egui

如何在 egui 区域中渲染 3D 内容?

有多种方法可以将 egui 与 3D 相结合。最简单的方法是使用 3D 库并让 egui 位于 3D 视图的顶部。例如,请参阅bevy_egui三维

如果要将 3D 嵌入到 egui 视图中,有两个选项。

Shape::Callback

例子:

Shape::Callback
将在绘制 EGUI 时调用你的代码,以使用任何背景渲染上下文显示任何内容。使用 eframe 时,这将发光。其他集成将为你提供其他渲染上下文(如果它们支持的话)。
Shape::Callback

渲染到纹理

你还可以将 3D 场景渲染为纹理并使用 ui.image(...) 显示它。你首先需要将原生纹理转换为 egui::TextureId,如何执行此操作取决于你使用的集成。

例子:

其他

约定和设计选择

所有坐标均采用屏幕空间坐标,左上角为 (0, 0)

所有坐标都在“点”中,这些“点”可能包含许多物理像素。

所有颜色都有预乘字母。

EGUI 将构建器模式用于构造小部件。例如:我不是构建器模式的忠实粉丝(它在实现和使用中都非常冗长),但在 Rust 命名之前,默认参数是我们能做的最好的事情。为了缓解一些冗长的问题,可以使用常见的帮助程序函数,例如 。

ui.add(Label::new("Hello").text_color(RED));
ui.label("Hello");

egui 不使用匹配样式函数调用(容易出错),而是更喜欢使用传递给包装函数的闭包。Lambdas有点丑,所以我想找到一个更好的解决方案。https://github.com/emilk/egui/issues/1004#issuecomment-1001650754 对此进行更多讨论。

begin/end
FnOnce

灵感

唯一的Dear ImGui是一个很棒的即时模式GUI,适用于C++,适用于许多后端。该库彻底改变了我对 GUI 代码的看法,并将 GUI 编程从我讨厌做的事情变成了我现在喜欢的事情。

名字

图书馆和项目的名称是“egui”,发音为“e-gooey”。请不要将其写成“EGUI”。

该图书馆最初被称为“Emigui”,但在 2020 年更名为“egui”。

捐赠

egui 作者和维护者:Emil Ernerfeldt (@emilk)。

值得注意的贡献:

egui 根据 MITApache-2.0 获得许可。

  • 三次贝塞尔曲线和二次贝塞尔曲线的展平化算法来自lyon_geom

默认字体:


egui 开发由 Rerun 赞助,Rerun 是一家为计算机视觉和机器人技术提供
可视化的初创公司。