跳到主要内容

滚动条 Scroller

当内容太多,一个屏幕塞不下时,我们就需要滚动条。HiEasyX 的 Scroller 是一个容器型控件:它包裹住里面所有的子控件,当它们超出可视区域时,自动提供水平和/或竖直滚动条。

核心概念

BeginScrollerEndScroller 想象成一对括号:中间的所有控件都会被“装”进一个可滚动的盒子里。

函数原型

void BeginScroller(ScrollerProfile &Profile);
void EndScroller(ScrollerProfile &Profile);

参数说明

ScrollerProfile

字段类型默认值说明
SizeHXPoint滚动容器的外部尺寸(可视区域大小)。必须手动设置
ViewSpaceHXPoint{0, 0}内部内容的虚拟尺寸。通常由布局系统根据子控件自动计算,你也可以手动指定。
WhereHXPoint{0, 0}相对当前窗口的偏移。通常由布局系统自动计算。
VerticalVPerfloat0.0f竖直滚动位置(0.0 ~ 1.0)。内部状态
HorizontalVPerfloat0.0f水平滚动位置。内部状态
Visiblebooltrue是否可见。设为 false 时隐藏整个滚动区域及其内容。
VerticalButtonboolfalse竖直滚动条按钮是否被按下。内部状态
HorizontalButtonboolfalse水平滚动条按钮是否被按下。内部状态
ScrollbarThicknessint10滚动条的粗细,单位像素。
WheelGracePeriodMsint500滚轮平滑滚动的“惯性”时间,单位毫秒。设为 0 可关闭惯性。
必须配对且用同一个 Profile

BeginScrollerEndScroller 必须成对出现,而且两个函数要传入同一个 ScrollerProfile 实例。如果你传了不同的对象,或者忘记调用 EndScroller,轻则滚动异常,重则程序崩溃。这是 IMGUI 容器的通用铁律。

返回值

两个函数都返回 void。滚动状态存储在传入的 Profile 中。

完整示例

下面这个例子创建了一个 300x200 的滚动区域,里面塞了 20 个按钮,远远超出可视范围,自然就会出现滚动条。

#include <include/hex.h>
#include <include/impl/EasyX/hex_impl_easyx.h>

// 全局资料结构体,生命周期必须跨帧
static HX::ScrollerProfile g_scroller;

int main() {
static HX::WindowProfile wp;
// 设置滚动容器的外观尺寸
g_scroller.Size = {300, 200};
g_scroller.ScrollbarThickness = 12;

while (true) {
HX::HXBegin();
ExMessage msg;
while (peekmessage(&msg)) {
HX::PushMessage(HX::GetHXMessage(&msg));
}

HX::Window(HXStr("Scroller 示例"), wp);

HX::Text(HXStr("滚动下面的区域:"));

HX::BeginScroller(g_scroller);
{
// 在这个大括号里,所有控件都会被装进滚动容器
for (int i = 0; i < 20; ++i) {
HX::ButtonProfile btn;
HXString label = HXStr("按钮 #") + std::to_wstring(i);
HX::Button(label, btn);
}
}
HX::EndScroller(g_scroller);

HX::Text(HXStr("滚动条上面的文字不会动"));

HX::End();
HX::Render();
}

return 0;
}
大括号是 optional,但强烈推荐

BeginEnd 之间加大括号 {} 可以让代码层次更清晰,也能避免变量命名冲突。在 C++ 里这是一个非常友好的习惯。

滚轮平滑滚动

默认情况下,滚动条支持滚轮惯性:你快速拨一下滚轮,内容不会立刻停住,而是会“滑”一小段距离。这个行为由 WheelGracePeriodMs 控制:

g_scroller.WheelGracePeriodMs = 500;  // 默认,有惯性
g_scroller.WheelGracePeriodMs = 0; // 立刻停止,无惯性

如果你在做像素级精确对齐的工具(比如关卡编辑器),可以把惯性关掉;如果是阅读长文本,保留惯性会更舒服。

水平滚动

当子控件的宽度总和超过 Size.x 时,水平滚动条会自动出现。你也可以在 BeginScroller 内部显式放置一个很宽的 CanvasPanel 来触发它。

常见疑问

Q:滚动条会自动隐藏吗? 目前 HiEasyX 的滚动条在不需要时会自动禁用(变灰),但不会完全消失。如果你追求极简风格,可以把 ScrollbarThickness 设小一点,或者在外层手动判断内容是否溢出。

Q:Scroller 里面可以放 Scroller 吗? 理论上可以嵌套,但不建议太深。嵌套滚动条容易让用户 confused(到底滚的是哪一层?)。通常一层就足够了。

Q:我怎么知道用户滚到了哪里? 读取 g_scroller.VerticalVPer 即可。它是一个 0.0f1.0f 的浮点数,0 表示在顶部,1 表示在底部。你可以用它来做“阅读进度”或者“懒加载触发”。

运行效果

截图占位符:请补充 $name 控件的运行效果截图。

截图占位符:请补充 Scroller 运行效果 的运行效果截图,保存为 ./assets/Scroller_view.png。`n