水平布局 Horizontal
如果说 SameLine 是"临时搭伙",Horizontal 就是"正规合租"。BeginHorizontal() / EndHorizontal() 会创建一个完整的水平布局区域,里面所有的子控件都会从左到右依次排列。
一句话理解
SameLine 让下一个控件挤过来;Horizontal 让一整块区域里的所有控件横着排。
函数原型
void BeginHorizontal();
void EndHorizontal();
没有参数,没有返回值。成对使用,中间包裹的所有控件都会水平排列。
与 SameLine 的区别
| 特性 | SameLine | Horizontal |
|---|---|---|
| 作用范围 | 只影响下一个控件 | 影响区域内所有控件 |
| 适用场景 | 临时并排(如两个按钮) | 整行/整区域的横向布局 |
| 宽度分配 | 各控件保持自身大小 | 支持拉伸分配(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();
嵌套使用
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();
嵌套注意事项
每进入一层新的布局区域(Horizontal、Panel、Group 等),框架都会 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 效果:两边固定,中间撑开。这是做工具栏最顺手的方式。