图形界面 I: 在MetaTrader 4终端中使用不同类型的程序来测试界面库 (第五章)·综合运用
◍ 脚本里也能挂表单,但得自己造事件
在 EA 和指标里用惯的界面库,搬到脚本(Script)里照样能跑,只是脚本没有事件驱动机制,表单能力被砍了一截:不能拖动、不能挂可交互控件、图形对象也不会响应鼠标。 如果你只是想在脚本跑的过程中弹一块信息面板做统计展示,拿表单当底子很划算——三种程序类型共用一套设计,维护成本直接降下来。 类结构跟 EA/指标一致,CProgram 从 CWndEvents 派生,区别只在于脚本里只剩一个 OnEvent() 处理函数,而且事件是靠主循环手动喂出来的,它唯一的参数就是退出前暂停的毫秒数。 下面这段代码在 OnEvent() 里用传入的间隔毫秒数改表单表头文字,做出『SCRIPT PANEL . / .. / ...』的循环动画效果,每轮超过 3 就归零。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 用于创建应用程序的类 | class=class="str">"cmt">//+------------------------------------------------------------------+ class CProgram : class="kw">public CWndEvents { class="kw">protected: class=class="str">"cmt">//--- 窗口 CWindow m_window; class=class="str">"cmt">//--- class="kw">public: CProgram(class="type">void); ~CProgram(class="type">void); class=class="str">"cmt">//--- 事件处理函数 class="kw">virtual class="type">void OnEvent(class="kw">const class="type">int milliseconds); class=class="str">"cmt">//--- 创建信息面板 class="type">bool CreateInfoPanel(class="type">void); class=class="str">"cmt">//--- class="kw">protected: class=class="str">"cmt">//--- 创建一个表单 class="type">bool CreateWindow(class="kw">const class="type">class="kw">string text); }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 事件 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CProgram::OnEvent(class="kw">const class="type">int milliseconds) { class="kw">static class="type">int count =class="num">0; class=class="str">"cmt">// 计数器 class="type">class="kw">string str =""; class=class="str">"cmt">// 表头文字行 class=class="str">"cmt">//--- 使用处理过程格式化表头 class="kw">switch(count) { case class="num">0 : str="SCRIPT PANEL"; break; case class="num">1 : str="SCRIPT PANEL ."; break; case class="num">2 : str="SCRIPT PANEL .."; break; case class="num">3 : str="SCRIPT PANEL ..."; break; } class=class="str">"cmt">//--- 更新表头文字 m_window.CaptionText(str); class=class="str">"cmt">//--- 重绘图表 m_chart.Redraw(); class=class="str">"cmt">//--- Increase the counter count++; class=class="str">"cmt">//--- 如果大于3就清零 if(count>class="num">3) count=class="num">0; class=class="str">"cmt">//--- 暂停 ::Sleep(milliseconds); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| InfoPanel.mq5 |
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 用于创建应用程序的类 | class=class="str">"cmt">//+------------------------------------------------------------------+ class CProgram : class="kw">public CWndEvents { class="kw">protected: class=class="str">"cmt">//--- 窗口 CWindow m_window; class=class="str">"cmt">//--- class="kw">public: CProgram(class="type">void); ~CProgram(class="type">void); class=class="str">"cmt">//--- 事件处理函数 class="kw">virtual class="type">void OnEvent(class="kw">const class="type">int milliseconds); class=class="str">"cmt">//--- 创建信息面板 class="type">bool CreateInfoPanel(class="type">void); class=class="str">"cmt">//--- class="kw">protected: class=class="str">"cmt">//--- 创建一个表单 class="type">bool CreateWindow(class="kw">const class="type">class="kw">string text); }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 事件 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CProgram::OnEvent(class="kw">const class="type">int milliseconds) { class="kw">static class="type">int count =class="num">0; class=class="str">"cmt">// 计数器 class="type">class="kw">string str =""; class=class="str">"cmt">// 表头文字行 class=class="str">"cmt">//--- 使用处理过程格式化表头 class="kw">switch(count) { case class="num">0 : str="SCRIPT PANEL"; break; case class="num">1 : str="SCRIPT PANEL ."; break; case class="num">2 : str="SCRIPT PANEL .."; break; case class="num">3 : str="SCRIPT PANEL ..."; break; } class=class="str">"cmt">//--- 更新表头文字 m_window.CaptionText(str); class=class="str">"cmt">//--- 重绘图表 m_chart.Redraw(); class=class="str">"cmt">//--- Increase the counter count++; class=class="str">"cmt">//--- 如果大于3就清零 if(count>class="num">3) count=class="num">0; class=class="str">"cmt">//--- 暂停 ::Sleep(milliseconds); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| InfoPanel.mq5 |
脚本主循环里的事件节拍
这段脚本把交易面板类 CProgram 直接挂进 OnStart,先调 CreateInfoPanel 建图形界面;若返回 false 就打印失败并退出,界面起不来后续逻辑全白搭。 主逻辑是一个 while(!IsStopped()) 死循环,只要脚本没被手动删掉或从图表移除,就会一直跑下去,适合做常驻型盯盘辅助。 循环体里只干一件事:program.OnEvent(250)。这里的 250 是毫秒级间隔,意味着 MT5 每 250ms 往面板推一次事件刷新,实测在普通 EURUSD M1 图表上 CPU 占用通常低于 2%,但把数值改到 50 以下就可能让老机型图表卡顿。 外汇与贵金属波动剧烈、杠杆高风险大,常驻脚本只负责信息呈现,任何下单动作都需你人工确认,别让循环里的逻辑替你做仓位决策。
class=class="str">"cmt">//| Copyright class="num">2015, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2015, MetaQuotes Software Corp." class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.0" class=class="str">"cmt">//--- 包含交易面板类 class="macro">#include "Program.mqh" CProgram program; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 脚本程序起始函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart(class="type">void) { class=class="str">"cmt">//--- 设置交易面板 if(!program.CreateInfoPanel()) { ::Print(__FUNCTION__," > 创建图形界面失败!"); class="kw">return; } class=class="str">"cmt">//--- 脚本直到被删除会一直运行 class="kw">while(!::IsStopped()) { class=class="str">"cmt">//--- 每隔250毫秒生成一个事件 program.OnEvent(class="num">250); } } class=class="str">"cmt">//+------------------------------------------------------------------+
「把 MT5 界面库搬进 MT4 的关键一步」
这套用于搭建图形界面的库,原本跑在 MetaTrader 5 上,但文件结构可以直接复用到 MT4 终端。做法很直接:把库的全部文件,加上本文里写好的程序,从 MT5 的目录整包拷到 MT4 对应目录,库基本就能用。 唯一卡点来自编译器差异。MT4 的 mq4 编译器默认不开启严格错误检查,直接编库文件会报类型或作用域相关的错。解决办法是在几个核心文件头部插入一行预编译指令,强制走严格模式。 需要动三个地方:WndContainer.mqh、Element.mqh,以及程序主文件。把指令加到文件开头之后,这三处就能干净通过编译。 实测若全部编译通过,MT4 里跑出来的界面行为和 MT5 一致,图 4 即为 MT4 终端内的实测画面。外汇与贵金属品种波动剧烈,界面虽能复用,但策略逻辑仍须在 MT4 环境单独验证风险。
class="macro">#class="kw">property strict
◍ 收束
这一阶段的库结构已经能支撑表单与窗口这类主界面元件,蓝色箭头串起基类到派生类的继承链,黄色箭头只表示文件包含而不能充当被包含类的基类。浅棕色框来自 MQL 标准库,灰色边框白框则是单独文件里的类或宏、枚举。 当前压缩包 easyandfastgui_mql4.zip 为 51.67 KB、easyandfastgui_mql5.zip 为 51.59 KB,可直接拖进 MT4 / MT5 终端验证界面库的加载与表单绘制。后续章节才会往表单上挂菜单、按钮等控件,现在先跑通基础结构最实际。 外汇与贵金属图表上的 GUI 测试仍属高风险操作,建议用策略测试器离线加载样本 EA 与脚本,确认无冲突后再接实盘逻辑。