跳到主要内容

水平布局 Horizontal

如果说 SameLine 是"临时搭伙",Horizontal 就是"正规合租"。BeginHorizontal() / EndHorizontal() 会创建一个完整的水平布局区域,里面所有的子控件都会从左到右依次排列。

一句话理解

SameLine下一个控件挤过来;Horizontal一整块区域里的所有控件横着排。


函数原型

void BeginHorizontal();
void EndHorizontal();

没有参数,没有返回值。成对使用,中间包裹的所有控件都会水平排列。


与 SameLine 的区别

特性SameLineHorizontal
作用范围只影响下一个控件影响区域内所有控件
适用场景临时并排(如两个按钮)整行/整区域的横向布局
宽度分配各控件保持自身大小支持拉伸分配(Stretch)
嵌套能力强,可嵌套 Panel/Vertical 等
兼容性部分控件不支持几乎所有控件都支持
什么时候用哪个?
  • 只是两个按钮挨着放 → SameLine
  • 做一个完整的表单行、工具栏、左右分栏 → Horizontal

子控件的宽度分配

Horizontal 区域内,子控件的默认行为是保持自身固有宽度(比如按钮按文字长度、输入框按默认尺寸)。

如果你想让某个控件填满剩余空间,可以在该控件前使用 SetNextItemWidth(-1) 配合容器的 ItemAlign = HXLayoutAlign::Stretch,或者配合 Spacer 来推挤位置:

HX::BeginHorizontal();

HX::Button(HXStr("左侧固定"), bp); // 保持自身宽度

HX::Spacer({0, 0}); // 弹性占位,把右边推到头

HX::Button(HXStr("右侧固定"), bp); // 靠右对齐

HX::EndHorizontal();
更优雅的左右分栏

如果你需要稳定的左右(或上下)分栏,推荐直接使用 SplitterDockSpaceHorizontal 更适合内容级的横向排列,而不是窗口级的区域分割。


嵌套使用

Horizontal 的强项在于嵌套。你可以在一个水平区域里放入垂直区域,或者在 Panel 里放 Horizontal,组合出任意复杂的布局:

HX::BeginHorizontal();

// 左侧面板:垂直堆叠
static HX::PanelProfile leftPanel;
leftPanel.Size = {200, -1};
if (HX::BeginPanel(HXStr("left"), leftPanel)) {
HX::Text(HXStr("导航项 1"));
HX::Text(HXStr("导航项 2"));
HX::Text(HXStr("导航项 3"));
HX::EndPanel(leftPanel);
}

// 右侧面板:也是垂直堆叠
static HX::PanelProfile rightPanel;
rightPanel.Size = {-1, -1}; // -1 表示填满剩余空间
if (HX::BeginPanel(HXStr("right"), rightPanel)) {
HX::Text(HXStr("主内容区"));
HX::Button(HXStr("操作"), bp);
HX::EndPanel(rightPanel);
}

HX::EndHorizontal();
嵌套注意事项

每进入一层新的布局区域(HorizontalPanelGroup 等),框架都会 push 一个新的 HXLayoutContext。子控件的坐标、BaseLine、间距都是相对于这层上下文的。你不需要手动计算,框架会处理好一切。


完整示例代码

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

int main() {
initgraph(800, 600);
setbkcolor(WHITE);
cleardevice();

HX::HXInitForEasyX();
HX::SetBuffer(GetWorkingImage());

BeginBatchDraw();

static HX::WindowProfile wp;
wp.Size = {550, 450};

static HX::ButtonProfile bp;
static HX::TextInputProfile tip;
static float val = 0.5f;
static HX::SliderProfile1f sp;

while (true) {
HX::HXBegin();

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

HX::Window(HXStr("Horizontal 演示"), wp);

// ---------- 第一行:工具栏 ----------
HX::BeginHorizontal();
HX::Button(HXStr("新建"), bp);
HX::Button(HXStr("打开"), bp);
HX::Button(HXStr("保存"), bp);
HX::Spacer({0, 0}); // 把后面的按钮推到右侧
HX::Button(HXStr("设置"), bp);
HX::EndHorizontal();

HX::Separator();

// ---------- 第二行:标签 + 滑块 ----------
HX::BeginHorizontal();
HX::Text(HXStr("音量:"));
HX::Slider1f(HXStr(""), val, sp);
HX::EndHorizontal();

// ---------- 左右分栏 ----------
HX::BeginHorizontal();

// 左侧:功能列表
static HX::PanelProfile leftPp;
leftPp.Size = {180, 250};
leftPp.BackgroundColor = HXColor{40, 40, 45, 255};
if (HX::BeginPanel(HXStr("sidebar"), leftPp)) {
HX::Text(HXStr("功能 A"));
HX::Text(HXStr("功能 B"));
HX::Text(HXStr("功能 C"));
HX::EndPanel(leftPp);
}

// 右侧:详情区
static HX::PanelProfile rightPp;
rightPp.Size = {-1, 250};
rightPp.Padding = 10;
if (HX::BeginPanel(HXStr("detail"), rightPp)) {
HX::Text(HXStr("这里是详情内容"));
HX::SetNextItemWidth(200);
HX::TextInput(tip);
HX::EndPanel(rightPp);
}

HX::EndHorizontal();

HX::End();
HX::Render();
FlushBatchDraw();
Sleep(16);
}

closegraph();
return 0;
}
小建议

Horizontal 配合 Spacer 可以实现类似 CSS Flexbox 的 space-between 效果:两边固定,中间撑开。这是做工具栏最顺手的方式。