MQL 作为 MQL 程序图形界面的标记工具。 第一部分·综合运用
(3/3)· 从平铺魔幻数字到 XML 式标记,最后一篇把前两步拼成可维护的交互窗口
「用布局对象替代传统对话框建窗」
在 CSlidingPuzzleDialog 里,把 OnInit 中常规的 Create 换成 CreateLayout 后,整个窗体框架和内部控件都靠一套基于 MQL 的标记语言在方法内声明。对话框本身是最外层布局对象,标准框架会在 StdLayoutBase::create 里自动调它的 Create,所以替换不会破坏生命周期。 嵌套关系是两层:dialog 包住 m_main 客户区,客户区里再放 16 个按钮、一个 New 按钮和消息标签。局部布局变量(dialog、clientArea、block、start、label)在代码块结束时自动把控件注册进上层容器,顺序和传统手写自底向上 Add 是反的,但结果一致。 按钮块用生成器批量填,不用手写循环。SimpleSequenceGenerator 给 16 个 CButton 连续分配 ID 和标题字符串 "0" 到 15,背景色由 block["background"] <= clrCyan 统一设定。对比 SlidingPuzzle3.mqh 和 SlidingPuzzle4.mqh,原来散在 Create / CreateMain / CreateButton 等五个方法里的代码,压缩成唯一一个 CreateLayout,源文件明显变紧凑。 CGridTkEx 相对旧版 CGridTk 把关系建立和属性调整拆开:SetGridConstraints 单独设子控件约束,Pack 负责实际排版。m_main.Init(5,4,2,2) 建 5 列 4 行、间距 2 像素,再把 New 按钮和标签钉到右下两格。 外汇与贵金属 GUI 工具开发属高风险辅助环节,界面逻辑错误不会直接爆仓,但可能误导下单信号。 别把自动布局当黑盒 布局对象在作用域结束才把控件挂进父容器,若你在块外提前用 m_buttons[0].Text() 这类方法,对象虽在但可能还未完成注册。开 MT5 把 CreateLayout 里的花括号顺序改一下,能直观看到按钮丢失。
class="type">bool CSlidingPuzzleDialog::CreateLayout(class="kw">const class="type">long chart, class="kw">const class="type">class="kw">string name, class="kw">const class="type">int subwin, class="kw">const class="type">int x1, class="kw">const class="type">int y1, class="kw">const class="type">int x2, class="kw">const class="type">int y2) { { _layout<CSlidingPuzzleDialog> dialog(this, name, x1, y1, x2, y2); { _layout<CGridTkEx> clientArea(m_main, NULL, class="num">0, class="num">0, ClientAreaWidth(), ClientAreaHeight()); { SimpleSequenceGenerator<class="type">long> IDs; SimpleSequenceGenerator<class="type">class="kw">string> Captions("class="num">0", class="num">15); _layout<CButton> block(m_buttons, "block"); block["background"] <= clrCyan <= IDs <= Captions; _layout<CButton> start(m_button_new, "New"); start["background;font"] <= clrYellow <= "Arial Black"; _layout<CEdit> label(m_label); label <= "click new" <= true <= ALIGN_CENTER; } m_main.Init(class="num">5, class="num">4, class="num">2, class="num">2); m_main.SetGridConstraints(m_button_new, class="num">4, class="num">0, class="num">1, class="num">2); m_main.SetGridConstraints(m_label, class="num">4, class="num">2, class="num">1, class="num">2); m_main.Pack(); } } m_empty_cell = &m_buttons[class="num">15]; SelfAdjustment(); class="kw">return true; } class="kw">template<class="kw">typename T> class Generator { class="kw">public: class="kw">virtual T class="kw">operator++() = class="num">0; }; class="kw">template<class="kw">typename T> class SimpleSequenceGenerator: class="kw">public Generator<T> { class="kw">protected: T current; class="type">int max; class="type">int count; class="kw">public: SimpleSequenceGenerator(class="kw">const T start = NULL, class="kw">const class="type">int _max = class="num">0): current(start), max(_max), count(class="num">0) {} class="kw">virtual T class="kw">operator++() class="kw">override { class="type">class="kw">ulong ul = (class="type">class="kw">ulong)current; ul++; count++; if(count > max) class="kw">return NULL; current = (T)ul; class="kw">return current; } }; _layout<CButton> start(m_button_new, "New"); start["background;font"] <= clrYellow <= "Arial Black";
◍ 给新建按钮套上黄底黑体并落格
在 MT5 的 GUI 面板里,想让「NEW」按钮从默认灰底跳出来,直接改 background 与 font 两个属性即可:把背景设成 clrYellow、字体指定 Arial Black,视觉权重立刻拉开。 下方代码把按钮和标签塞进 5 行 4 列、行列间距均为 2 的网格,按钮占第 4 行前两列,标签占同天后两列并居中,最后 Pack() 自动收口。 你可以在 MT5 自建 EA 的 resources 面板里原样贴入这段代码,编译后拖到图表,看到黄底黑字按钮即说明网格约束生效;外汇与贵金属图表叠加此类控件需注意点差滑点带来的高频误触风险。
start["background"] <= clrYellow; start["font"] <= "Arial Black"; m_button_new.ColorBackground(clrYellow); m_button_new.Font("Arial Black"); _layout<CEdit> label(m_label); label <= "click new" <= true <= ALIGN_CENTER; m_main.Init(class="num">5, class="num">4, class="num">2, class="num">2); m_main.SetGridConstraints(m_button_new, class="num">4, class="num">0, class="num">1, class="num">2); m_main.SetGridConstraints(m_label, class="num">4, class="num">2, class="num">1, class="num">2); m_main.Pack();
一点提醒
这套用 MQL 做 GUI 标记的思路,核心类已经跑通,但作者原话也点明:更复杂、更具建设性的示例还远未穷尽。ZIP 包 MQL5GUI1.zip 体积 86.86 KB,是验证标记语言概念的最小可运行样本,建议直接下到 MT5 的 MQL5/Include 里编译试错。 外汇与贵金属市场高杠杆、高波动,任何基于自定义 GUI 的信号或脚本都只是辅助,实盘前务必在策略测试器用历史数据回测,参数错了可能连续踏空。 代码能跑和能赚钱之间隔着的,是你对事件坐标、拖放逻辑的理解深度——评论区里连按钮「按下又反悔」的边界情况都吵了三页,这就是真实复杂度。