图形界面 X: 简单快速开发库的更新 (版本 2)(基础篇)
📘

图形界面 X: 简单快速开发库的更新 (版本 2)(基础篇)

第 1/3 篇

◍ 用现成库给 MT5 界面提速

给 MT5 写自定义面板,最磨人的从来不是逻辑,而是按钮、标签、输入框这些控件的布局代码。Anatoli Kazharski 维护的「图形界面 X」简单快速开发库在 2016-10-21 发布了 2.0 更新,把这类重复劳动压到了最低。 该库在站内的示例帖累计获得 4175 次查看、42 条讨论,说明做 EA 界面的人确实吃这套封装。更新后控件创建改为声明式调用,少写一半样板代码,新手也能在半小时内拼出一个带参数输入的交易小面板。 外汇与贵金属交易自带高杠杆高风险,界面只是工具,信号逻辑错了再好看的面板也救不了账户。开 MT5 把库拖进 Include 目录,先跑通示例里的测试程序,比直接抄网上的散装代码稳得多。

「库结构演进与文件落位」

这套图形界面库在前面章节发布后做过一轮轻量重构:原本散落在多个控件类里、重复率高的成员方法,已经统一收进 CElement 基类。对交易者来说,直接好处是 CPU 负载有所下降,具体降幅随控件数量而异,在数十个面板元素同屏时体感更明显。 随重构还塞进了若干外观微调和小修,不属于功能级变更,但会影响你肉眼看到的控件边距与配色。库的目标在第一篇《图形界面 I》里已拆解过,这里不重复。 每章末尾都附有当前阶段库的完整压缩包。解压后务必按归档内的目录层级原样丢进 MT5 的 MQL5/Include 对应路径,放错一级目录编译就会报找不到头文件。 想验证优化是否生效,可以开 MT5 随便挂一个用了该库旧版的面板,再换新版同控件数量跑一下,对着专家日志里的 tick 处理耗时做对比。外汇与贵金属行情高波动时 GUI 卡顿会放大,这类底层减负在高风控场景里值得盯。

GUI 库重构:鼠标参数集中与窗体自适应

这次库更新把默认配色改成最浅色层,无论图表是浅色还是深色背景都能拉开对比。这样做的好处是自定义控件类在构造时只需指定极少属性,开发时不用反复调色,直接借用标准调色板即可。 新增的 CMouse 类把鼠标和光标参数收拢到单一对象里。它依赖标准库 CChart 的 SubwindowY() 算相对 Y 坐标,构造时绑定图表、析构时解绑。以往每个控件都自己处理 CHARTEVENT_MOUSE_MOVE,现在统一在 CMouse 内填充字段,所有控件只读取一次——CPU 负载降了,类代码也更干净。 CElement 基类吃进了三块重复逻辑:按图形对象名取控件 ID 的方法、CheckWindowPointer() 检查表单指针、以及 AutoXResizeMode() 控件右边界绑窗体模式。以自动宽度为例,设了模式后右边距跟随表单右边,默认关闭、偏移 0,表单因 CHARTEVENT_CHART_CHANGE 变宽时,ON_WINDOW_CHANGE_SIZE 消息驱动 CWndEvents::OnWindowChangeSize() 批量改宽。已落地到 CTabs、CStatusBar、CTreeView 等 12 个控件类。 顺带补了俩实用接口:CTabs/CIconTabs 的 SelectTab() 支持代码切页;CTable 再点已选行可取消,且禁编辑单元被点时抛事件带字符串参数。外汇与贵金属 EA 界面开发高风险,MT4/MT5 某些错误仅前者复现,跨平台编译前务必本地验证。

MQL5 / C++
class="macro">#include <Charts\Chart.mqh>
class CMouse
  {
class="kw">private:
   CChart            m_chart;
class="kw">public:
                     CMouse(class="type">void);
                    ~CMouse(class="type">void);
  };
class=class="str">"cmt">// 中文逐行拆解:
class=class="str">"cmt">// class="macro">#include <Charts\Chart.mqh>  引入标准库图表类,供后续算坐标
class=class="str">"cmt">// class CMouse  声明鼠标参数管理类
class=class="str">"cmt">// class="kw">private:  私有段开始
class=class="str">"cmt">//   CChart m_chart;  图表实例,用于子窗口Y坐标换算
class=class="str">"cmt">// class="kw">public:  公有段
class=class="str">"cmt">//   CMouse(class="type">void);  构造函数,内部绑定图表
class=class="str">"cmt">//   ~CMouse(class="type">void); 析构函数,解除绑定

◍ 把鼠标坐标封装成可复用的类

在 MT5 里做价格行为辅助工具,第一步往往是把鼠标在图表上的位置变成代码里能直接读的数据。下面这套 CMouse 类的构造与析构,演示了如何把图表对象绑定到生命周期:构造时 Attach() 拿到当前图表 ID,析构时 Detach() 解除绑定,避免指标卸载后还挂着引用。 类内部用 m_x / m_y 存像素坐标,m_subwin 存光标所在子窗口编号,m_time 和 m_level 分别把 X 映射成时间、Y 映射成价格——这意味着你点一下图表,就能同时知道「什么时间、什么价位」。m_left_button_state 记录左键按下或松开,做手动标注类脚本时直接用。 对外只暴露只读 getter:X()、Y() 回坐标,SubWindowNumber()、Time()、Level() 回窗口号与时间价格,LeftButtonState() 回按键状态。全部 const 修饰,调用侧不能改内部状态,减少副作用。 事件入口只留了一个 OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam),后续把 CHARTEVENT_MOUSE_MOVE 等事件喂进来,就能在 lparam/dparam 里解出坐标并写进成员变量。开 MT5 新建 EA,把这段类骨架贴进头文件,编译通过即代表绑定逻辑没问题,可接着补事件分支。

MQL5 / C++
CMouse::CMouse(class="type">void)
  {
class=class="str">"cmt">//--- 取得当前的图表 ID
   m_chart.Attach();
  }
CMouse::~CMouse(class="type">void)
  {
class=class="str">"cmt">//--- 解除与图表的绑定
   m_chart.Detach();
  }
class CMouse
  {
class="kw">private:
   class=class="str">"cmt">//--- 坐标
   class="type">int               m_x;
   class="type">int               m_y;
   class=class="str">"cmt">//--- 光标所在窗口的编号
   class="type">int               m_subwin;
   class=class="str">"cmt">//--- 对应 X 坐标的时间
   class="type">class="kw">datetime          m_time;
   class=class="str">"cmt">//--- 对应 Y 坐标的水平(价格)
   class="type">class="kw">double            m_level;
   class=class="str">"cmt">//--- 鼠标左键的状态 (按下/松开)
   class="type">bool              m_left_button_state;
class="kw">public:
   class=class="str">"cmt">//--- 返回坐标
   class="type">int               X(class="type">void)                const { class="kw">return(m_x);               }
   class="type">int               Y(class="type">void)                const { class="kw">return(m_y);               }
   class=class="str">"cmt">//--- 返回 (class="num">1) 光标当前所在窗口的编号, (class="num">2) 对应 X 坐标的时间,
   class=class="str">"cmt">//    (class="num">3) 对应 Y 坐标的价格水平
   class="type">int               SubWindowNumber(class="type">void) const { class="kw">return(m_subwin);           }
   class="type">class="kw">datetime          Time(class="type">void)             const { class="kw">return(m_time);            }
   class="type">class="kw">double            Level(class="type">void)            const { class="kw">return(m_level);           }
   class=class="str">"cmt">//--- 返回鼠标左键的状态 (按下/松开)
   class="type">bool              LeftButtonState(class="type">void) const { class="kw">return(m_left_button_state); }
  };
class CMouse
  {
   class=class="str">"cmt">//--- 事件处理函数
   class="type">void              OnEvent(const class="type">int id,const class="type">long &lparam,const class="type">class="kw">double &dparam,const class="type">class="kw">string &sparam);
  };

常见问题

直接用现成的图形界面开发库,里面封装了窗体、控件和鼠标处理,复制文件到本地包含目录就能调用,省去底层绘图代码。
把库文件按新的结构放到 MQL5 的 Include 对应子目录,覆盖旧版同名文件,并在代码里调整引用路径即可编译通过。
小布可以读取你的界面截图或描述,对照常见窗体自适应规则指出可能错位的地方,并提示鼠标坐标类是否漏写边界判断。
把鼠标坐标相关计算封装成一个可复用类,集中管理偏移与缩放参数,之后任何控件直接调用该类拿正确坐标。
新版把窗体自适应逻辑收进了统一模块,需确认你创建的控件都挂到自适应容器下,而非写死绝对坐标,否则缩放时就会脱节。