返回文章列表

文章

关于GUI编程模型(保留式和即时式)

保留式(Retained‐Mode)和即时模式(Immediate‐Mode)UI 在架构设计和渲染流程上有本质区别:

  1. 渲染模型
    • 保留式:UI 框架内部维护一棵“场景图”或“组件树”(widget tree),每个控件(按钮、列表、文本框)都是一个独立对象,框架负责跟踪它们的状态(位置、大小、外观),并在必要时进行重绘。开发者只需要更新状态,框架会自动对比前后状态差异(diff)并高效地重新渲染变化部分。
    • 即时式:每一帧(或每次事件循环)都由开发者的绘制代码“刷一遍”整个 UI,框架不会保存上一帧的信息——状态通常由用户管理并在绘制时直接读取。渲染逻辑更像是在“画布”上直接画:要什么控件就画什么,不再有隐式的控件实例。
  2. 状态管理
    • 保留式:状态(例如按钮是否被按下、文本框内容)通常绑定在控件对象内部或通过绑定机制(binding)与业务逻辑相连。更易于做增量更新和动画,因为框架可以精准跟踪哪个控件的哪个属性改变了。
    • 即时式:所有状态都由应用代码自己保存(比如一个变量记录按钮状态),在渲染函数里根据这个状态决定绘制样式和行为。状态流动更显式,但需要开发者手动处理许多状态到渲染的映射。
  3. 编程范式
    • 保留式:偏“声明式”风格——你声明“我想要一个按钮、一个输入框、一个列表”,然后在回调里处理事件,框架帮你管理布局和更新。示例:Iced、Druid、Slint、GTK‑rs。
    • 即时式:偏“命令式”风格——在每次渲染时你写“先画按钮 A,再画按钮 B,再画文本”,处理输入后再次完整绘制。代码流程更线性,也更灵活。示例:egui、Azul、Dear ImGui(C++)、egui 的 eframe。
  4. 性能与适用场景
    • 保留式:启动时可能需要更复杂的初始化和状态同步,但日常渲染只会更新真正变动的部分,适合控件多、交互复杂、需要丰富原生控件和主题的桌面应用。
    • 即时式:每帧都“重画”一遍 UI,但现代计算机和简洁的渲染管线让这种方式也能保持很高的帧率。更方便做动态工具、编辑器、可视化仪表盘,代码简单、迭代快速。

举例对比

特性保留式(Iced / Druid)即时式(egui / Azul)
渲染方式差分更新,只重绘变更控件每帧全量绘制
状态管理框架内建,控件自带状态用户代码自管理,渲染函数读取状态
编程范式更声明式,组件树+回调更命令式,渲染函数+事件处理
复杂 UI 支持丰富的原生控件、布局、主题需要自己手动布局及样式控制
典型场景传统桌面应用、表单、工具栏、复杂布局实时工具、游戏编辑器、仪表盘、调试工具

选择时,若你需要丰富、原生感强的控件和自动布局,就用保留式;若想快速上手、写少量代码快速迭代界面、或做性能可视化工具,就用即时式。