小弧光的博客

公众号:小弧光黑板报

导航

为什么 egui 用立即模式?

https://github.com/emilk/egui#why-immediate-mode

 

为什么立即模式

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 库进行窗口布局,定位窗口,然后检查交互(“是否单击了 OK 按钮?”)。

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

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

一种解决方法是存储大小并在下一帧使用它。这会为正确的布局产生帧延迟,偶尔会在出现的第一帧出现闪烁。egui这样做是为了某些事情,例如窗口和网格布局。

您也可以调用布局代码两次(一次获取尺寸,一次进行交互),但这不仅成本更高,而且实现起来也很复杂,在某些情况下两次是不够的。egui从不这样做。

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

CPU使用率

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

如果您在设计 GUI 时考虑到这一点并避免使用巨大的滚动区域(或只布置可见的部分),那么性能损失通常很小。对于大多数情况,您可以期望egui每帧占用 1-2 毫秒,但egui仍有很大的优化空间(这不是我关注的重点)。您还可以设置egui仅在有交互(例如鼠标移动)时重绘。

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

IDs

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

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

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

posted on 2022-12-07 17:30  小弧光  阅读(1929)  评论(0编辑  收藏  举报