写 GUI 小工具时,最容易出现的一个问题是:功能越加越多,窗口也越塞越满。刚开始只是几个按钮、几个输入框,后来多了配置项、说明文字、结果列表、链接入口,最后整个窗口像一张临时拼出来的表格,自己维护累,别人使用也累。
这种时候,我一般不会急着去美化界面,而是先把控件按用途分组。少量控件可以用 GroupBox,命令入口太多可以考虑菜单;如果一屏里已经放不下,或者几个功能明显属于不同页面,那就可以用 Tab 控件做分页。
Tab 的好处很直接:窗口大小不用无限变大,用户也不用在一堆控件里找东西。每一页只放一类内容,界面自然就清楚了。
最小的 Tab 示例
先看一个最小例子。这里把常用操作和高级设置分成两个分页,代码的关键是 Gui, Add, Tab3 和 Gui, Tab。
#Requires AutoHotkey v1.1 Gui, Add, Tab3, x10 y10 w360 h180 vMainTab, 常用操作|高级设置 Gui, Tab, 常用操作 Gui, Add, Text, x30 y50, 这里放最常用的按钮和输入项: Gui, Add, Button, x30 y80 w100 gDoStart, 开始处理 Gui, Add, Button, x140 y80 w100 gDoStop, 停止处理 Gui, Tab, 高级设置 Gui, Add, Text, x30 y50, 这里放不常改的配置: Gui, Add, Checkbox, x30 y80 h20 vKeepLog, 保存日志 Gui, Add, Checkbox, x30 y110 h20 vAutoRun, 开机启动 Gui, Tab Gui, Add, Button, x280 y205 w90 gSubmitSetting, 确定 Gui, Show, w390 h250, Tab 分页示例 return DoStart: MsgBox, 开始处理 return DoStop: MsgBox, 停止处理 return SubmitSetting: Gui, Submit, NoHide MsgBox, % "保存日志:" KeepLog "`n开机启动:" AutoRun return GuiClose: ExitApp
这里有一个容易忽略的点:Gui, Tab, 常用操作 后面添加的控件,会属于“常用操作”这一页;Gui, Tab, 高级设置 后面添加的控件,会属于“高级设置”这一页。
写完 Tab 页里的控件之后,最好再写一行 Gui, Tab。这样后面添加的按钮、状态栏之类,就不会被误放进某一个分页里。
什么时候适合用 Tab
我觉得 Tab 适合解决这几类问题:
- 设置项很多,但不是每一项都需要经常修改。
- 同一个工具里有几组互相独立的功能。
- 说明、链接、日志、结果列表不适合全部堆在首页。
- 控件数量会动态增加,窗口又不想做得很高。
如果只是三五个按钮,不需要上 Tab;如果是表格数据,优先考虑 ListView;如果只是命令入口太多,可以先考虑右键菜单、托盘菜单或顶部菜单。Tab 更适合“页面分组”,不是为了把所有东西都藏起来。
把一批项目自动分到多个分页
原文里最有价值的思路,是把数量很多的控件按固定数量切开,每满一组就换一个 Tab 页。这个方法适合放链接、说明项、快捷动作,也适合一些临时工具的批量入口。
下面这个例子演示每 8 个项目放到一页。实际使用时,可以把 items 换成文件列表、网址列表、动作列表,或者你自己整理出来的一组常用命令。
items := []
Loop, 26
items.Push("示例项目 " A_Index)
perPage := 8
pageCount := Ceil(items.Length() / perPage)
tabNames := ""
Loop, % pageCount
tabNames .= (A_Index = 1 ? "" : "|") "第 " A_Index " 页"
Gui, Add, Tab3, x10 y10 w380 h260, % tabNames
for index, text in items
{
page := Ceil(index / perPage)
row := Mod(index - 1, perPage)
Gui, Tab, % page
y := 45 + row * 25
Gui, Add, Text, x35 y%y% w160, % text
Gui, Add, Button, x210 y%y% w90 h22 gRunItem vBtn%index%, 执行
}
Gui, Tab
Gui, Add, Button, x300 y285 w90 gGuiClose, 关闭
Gui, Show, w410 h330, 自动分页示例
return
RunItem:
StringTrimLeft, index, A_GuiControl, 3
MsgBox, % "你点击的是:" items[index]
return
GuiClose:
ExitApp
这个例子的重点不是按钮本身,而是分页算法:
perPage决定每一页放几个项目。pageCount根据项目总数算出需要几页。Gui, Tab, % page决定当前项目放到哪一页。row决定项目在当前页里的第几行。
如果后续项目数量变了,代码不用重新手工调整坐标,只要改数据源和每页数量即可。对经常维护的小工具来说,这比手动复制几十行 Gui, Add 要舒服很多。
Tab、GroupBox、ListView 怎么选
这几个控件经常会被混在一起用,但它们解决的问题不一样。
GroupBox 适合在同一个页面里做小范围分组,比如“热键设置”“窗口选项”“输出格式”。它不会减少控件数量,只是让界面更有层次。
Tab 适合把不同类别的内容分到不同页面。它能让主窗口保持一个比较稳定的大小,也能把不常用的功能放到后面的页里。
ListView 适合多行、多列、可选中、可排序的数据。如果你要展示的是一批文件、一批窗口、一批结果,那就不要用很多 Text 或 Edit 硬拼,直接用 ListView 会更合适。
简单说:一页里做小分组,用 GroupBox;内容明显分几页,用 Tab;数据像表格,用 ListView。
几个小经验
Tab 用起来不难,但有几个地方值得注意。
- 每个分页的内容尽量保持同一类,不要把“设置”“日志”“执行按钮”混在同一页。
- Tab 页名称要短,最好一眼能看懂,不要写成很长的说明句。
- 分页太多也会乱,一般 3 到 6 个比较舒服,超过太多就要重新考虑界面结构。
- 公共按钮可以放在 Tab 外面,比如“确定”“取消”“关闭”。
- 动态生成控件时,变量名要有规律,后面事件处理会省很多事。
GUI 写到后面,真正麻烦的往往不是某个控件不会用,而是界面结构没有提前分好。Tab 不是高级技巧,但它能把很多“小工具越写越乱”的问题提前压住。尤其是配置项多、链接多、动作入口多的工具,用它做一层分页整理,维护起来会轻松很多。
延伸阅读

评论(0)