Widget 是 App 内部的可绘制对象,例如文字按钮、数字选择器和曲线图。它和 App 不是同一层:App 由 ViewManager 管理,Widget 通常是 App 的成员,生命周期跟着 App。
一个可操作按钮
1 | class ButtonApp final : public IApplication { |
FocusManager 属于 PixelUI,不再由每个 App 创建。ui.handleInput() 会先给 FocusManager 处理 LEFT / RIGHT / SELECT,未被消耗的事件再交给当前 App。
可聚焦状态
IWidget 默认 focusable = false。TextButton、IconButton、Label 和 NumScroll 在自己的实现中已设为可聚焦;Clock 是纯显示组件。Brace、Histogram 或 CurveChart 需要参与导航时,请显式设置:
1 | chart_.setFocusable(true); |
FocusManager 只会导航同时满足以下条件的节点:可聚焦、可见、已启用,且它的所有祖先也可见并已启用。
Widget 父子树
Widget 树不分配节点,也不拥有子对象。它只在已存在的 Widget 之间建立侵入式父子链接:
1 | class PanelApp final : public IApplication { |
子 Widget 的坐标是相对父 Widget 的局部坐标。父节点移动后,子节点一起移动。默认子节点会被父节点边界裁剪,可通过 setClipChildren(false) 关闭。
Widget 不可拷贝、不可移动。销毁或脱离树时,FocusManager 会收到通知并清理指向它的当前/激活指针。
内置 Widget 速查
| Widget | 用途 | 主要配置 |
|---|---|---|
TextButton |
文字按钮 | setCallback, setText, setPosition, setSize |
IconButton |
XBM 图标按钮 | setSource, setCallback |
Label |
文本与方向入场动画 | setText, setLoadPos, setCallback |
NumScroll |
整数选择 | setRange, setValue, getValue, setFixedIntDigits |
Clock |
模拟时钟 | setHour, setMinute, setSecond, setRadius |
Brace |
边框/容器 | setDrawContentFunction, addChild, setCallback |
Histogram |
柱状历史图 | addData, 窗口/历史统计 |
CurveChart |
曲线历史图 | addData, 窗口/历史统计 |
回调类型是 PixelUI 定义的 VoidCallback,不是 std::function。组件保存的 const char* 和 XBM 指针也是非拥有的,不要指向已经离开作用域的数组。
TextButton 与 Label
| TextButton | Label |
|---|---|
TextButton 用 (x, y, width, height) 描述矩形;Label 的 POS 决定入场动画从哪个方向进入。
NumScroll 与 Clock
| NumScroll | Clock |
|---|---|
NumScroll 的坐标是矩形左上角;Clock 使用圆心 (x, y) 和半径。Clock 默认是纯显示 Widget,不参与 Focus 导航。
Brace
![]()
Brace 既可以用 setDrawContentFunction() 画自定义内容,也可以作为 Widget 树的父容器。图中的坐标和尺寸对应它自身的局部边界。
Chart 的固定缓冲区
Histogram 和 CurveChart 不会自己在堆上分配样本 buffer,调用者提供存储:
1 | float samples_[76]{}; |
buffer 元素数必须等于 expanded width,这个关系由模板 static_assert 在编译时检查。buffer 必须比 Widget 活得更久;把它声明在 Chart 成员之前,可以保证析构顺序正确。
| Histogram | CurveChart |
|---|---|
两种 Chart 共用相同的展开几何概念:EXPAND_BASE 决定哪个角保持不动,ChartExpandSize<W, H> 决定展开后的宽高。Histogram 画柱,CurveChart 画连续折线。
