界面布局本應是創造性工作,卻常被繁瑣的座標計算拖累。傳統布局管理器僵化難擴展,可視化工具又喪失語義。本文提出一種**領域特定語言(DSL)**,以 Component、above、beside 為核心原語,構建可組合、可擴展、語義清晰的布局描述體系。
// 原子組件
Component btn = Button().title("button1").at(0,0,200,60).in(container);
// 水平組合:左佔 80%
Component row = beside(TextField(), Button().title("ok"), 0.8)
.at(0,0,300,40).in(container);
// 垂直組合:上佔 50%
Component col = above(TextField(), Button().title("ok"), 0.5)
.at(0,0,300,60).in(container);
// 空白佔位
Component rightAligned = beside(Empty(), Button(), 0.5)
.at(0,0,200,40).in(container);
閉包性:above/beside 返回同樣是 Component,可無限巢狀組合,構建任意複雜佈局。
基於原語封裝可復用樣式:
// 居中佈局(留白比例 hRatio/vRatio)
Component center(Component c, float hRatio, float vRatio) {
float s1 = (1-2*hRatio)/(1-hRatio), s2 = (1-2*vRatio)/(1-vRatio);
Component u = above(Empty(), above(c, Empty(), s2), vRatio);
return beside(Empty(), beside(u, Empty(), s1), hRatio);
}
// 水平/垂直等分序列
Component h_seq(Component[] cs) { ... }
Component v_seq(Component[] cs) { ... }
// N行M列網格(不足補 Empty)
Component block(Component[] cs, int N, int M) { ... }
// 帶間距網格
Component block_with_margin(Component[] cs, int N, int M, float h, float v) {
Component[] ncps = Arrays.stream(cs).map(c -> center(c, h, v)).toArray(Component[]::new);
return block(ncps, N, M);
}
Component[] keys = { "0","1","2","+", "3","4","5","-", "6","7","8","*", "9","=","%","/" }
.stream().map(Button::title).toArray(Component[]::new);
Component opLayout = block(keys, 4, 4); // 4x4 網格
// 整體:輸入框 + 退格鍵/C鍵 + 操作區
above( above( TextField(),
beside(Button().title("Backspace"), Button().title("C"), 0.5), 0.5),
block_with_margin(keys, 4, 4, 0.02, 0.02), 0.3)
.at(0,0,300,200).in(container);
修改間距只需一行變更:block → block_with_margin,體現 DSL 抗變性。

Component、at/in、above/beside 實現;center/h_seq/v_seq/block 等高階 API;ownby(controller) 綁定事件處理,隔離顯示與邏輯。// Fluent Interface 風格
public class Button implements Component {
JButton btn = new JButton();
public Component title(String t) { btn.setText(t); return this; }
public Component at(int x,int y,int w,int h) { btn.setBounds(x,y,w,h); return this; }
public Component in(Container p) { p.add(btn); return this; }
}
// 組合子實現閉包
public class beside implements Component {
Component left, right; float ratio;
public Component at(int x,int y,int w,int h) {
left.at(x, y, (int)(w*ratio), h);
right.at(x+(int)(w*ratio), y, (int)(w*(1-ratio)), h);
return this;
}
public Component in(Container p) { left.in(p); right.in(p); return this; }
}
此 DSL 讓界面開發回歸「描述意圖」而非「計算座標」,顯著提升開發體驗與代碼可維護性。