MQL5图形界面基础:复选框与编辑框控件的类封装实战(基础篇)
(1/3)·从零搭出可复用的复选框与编辑框,告别每次手搓图形对象的重复劳动
本文是图形界面系列的第 1 部分(共 3 篇),聚焦最基础的两种表单控件:复选框与编辑框,以及它们的组合形态。我们将从类的结构设计讲起,让你在 MetaTrader 5 里用统一接口管理开关参数和文本输入,而不是在每个 EA 里重写一遍对象创建逻辑。
用类封装复选框与编辑框控件
在 MT5 自定义指标或 EA 的图形界面里,复选框(Checkbox)和编辑框(Edit)是最常被组合使用的两类基础控件。原文示例发布于 2016 年 6 月 30 日,至今仍是理解标准库 GUI 封装逻辑的入门参照。 为复选框单独开发一个封装类,可以把「选中状态读取」「点击事件绑定」从主逻辑里剥离。这样在主程序中只需关心业务,不用反复写 CreateWindow 那一堆参数。 编辑框同理:封装后你能直接拿到用户输入的字符串并做类型转换(比如把 "1.5" 转成 double 手数)。原文给出的测试代码在 MT5 里跑通后,会在图表左上角弹出可交互面板。 外汇与贵金属交易界面涉及实盘参数输入,这类 GUI 改错一个参数就可能下错单,属于高风险操作,建议在策略测试器里先验证再接真账户。
「这套界面库怎么取和放」
这个系列文章配套了一个可复用的 MQL5 图形界面库,每一章末尾都给出当前阶段库的完整下载档。解压后必须按压缩包里的目录层级,把文件原样放进 MT5 的相同路径下,否则include 引用会直接报找不到文件。 系列第六部分拆成两章写。第一章先落地四个控件:复选框、文本框、带复选框的编辑框、带复选框的组合框。其中后两个只是前两个的组合,没有未出现过的新机制,所以正文只拆复选框和编辑框的实现。 第二章单独讲滑块和双重滑块。想跟练的话,建议先下第六部分第一章对应的库版本,在 MT5 里建个空 EA 把文件挂好,能编译过再往下看控件代码。外汇与贵金属图表上挂这类自定义界面属于高频复盘场景,但自动化面板不改你的仓位风险,杠杆品种依旧可能快速回撤。
◍ 复选框怎么管开关状态
复选框控件在 MT5 面板里专门管二态参数:开或关。它用带勾和无勾的图标按钮直观显示当前状态,勾上代表参数启用,没勾就是禁用,按钮旁边配一行简短文字说明。 从图形结构看,一个复选框实际由三个对象拼出来:背景块、图标按钮、文字标签。你在对象列表里能看到这三者是分开创建的,改坐标或颜色要分别处理。 这种控件适合做「是否启用某过滤条件」类的开关。实盘里点一下就能切状态,比下拉框更省操作;但注意外汇和贵金属波动大、杠杆高,开关类参数误触可能直接改变下单逻辑,面板做好后建议先开模拟盘验证。
复选框控件的类封装逻辑
复选框和图标按钮在交互上很像,但视觉层更轻:它不改背景色,只切换图标与文字颜色,背景仅作为鼠标命中区域的判定边界。控件可预设的属性也更少——背景、开/关两态图标、标签边距、不同状态的文字色,其中四个图标分活动与屏蔽两组,可直接套用现成资源也可自换。 在库结构里,先在 WndContainer.mqh 用 #include "CheckBox.mqh" 挂入,CheckBox.mqh 再依赖 Element.mqh 与 Window.mqh。CCheckBox 类公开了构造/析构、WindowPointer() 保存父窗指针、OnEvent() 与 OnEventTimer() 两个虚函数,私有侧只留一个 m_wnd 指向所附属窗口。 事件处理上,CHARTEVENT_OBJECT_CLICK 触发后由 OnClickLabel() 接手:背景对象的鼠标左键优先级设为 1,按钮和标签为 0,所以哪怕点到图标也视作点中背景区域,避免事件混淆。随后调用 CheckButtonState() 翻转状态,末尾发自定义事件,携带 ON_CLICK_LABEL 标识、元件 ID 与描述三项数据,供外部窗体监听。 管理状态的两个核心私有方法是 CheckBoxState()(屏蔽/解屏蔽)与 CheckButtonState()(设开/关),公有创建入口只需三个私有加一个公有方法即可跑通。外汇与贵金属 GUI 工具开发属高风险底层改造,参数误用可能导致面板无响应,建议在 MT5 策略测试器外先以独立 EA 验证命中逻辑。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| WndContainer.mqh | class=class="str">"cmt">//| Copyright class="num">2015, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "CheckBox.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| CheckBox.mqh | class=class="str">"cmt">//| Copyright class="num">2015, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "Element.mqh" class="macro">#include "Window.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 用于创建组合框的类 | class=class="str">"cmt">//+------------------------------------------------------------------+ class CCheckBox : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 所附加的表单的指针 CWindow *m_wnd; class=class="str">"cmt">//--- class="kw">public: CCheckBox(class="type">void); ~CCheckBox(class="type">void); class=class="str">"cmt">//--- 保存表单指针 class="type">void WindowPointer(CWindow &object) { m_wnd=::GetPointer(object); } class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 图表事件处理函数 class="kw">virtual 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); class=class="str">"cmt">//--- 计时器函数 class="kw">virtual class="type">void OnEventTimer(class="type">void); class=class="str">"cmt">//--- 移动元件
「复选框类的私有状态与公开设参」
在标准库界面层里,CCheckBox 继承自 CElement,它的私有段把「视觉状态」和「交互层级」全锁在类内部。背景色 m_area_color、四种图标路径(开/关/锁定开/锁定关)、文字与四态文字色,加上 m_label_x_gap / m_label_y_gap 这两个像素级边距,共同决定一个勾选控件在图表上的呈现。 公开方法暴露的只是设参入口:CheckFileOn()、CheckFileOff() 这类内联函数直接把传入的 bmp 路径写进私有成员,例如 CheckFileOn(const string file_path){ m_check_bmp_file_on=file_path; } 一行搞定。想换勾选图标,调它就行,不用碰私有变量。 m_zorder 与 m_area_zorder 控制鼠标左键点击优先级,数值越大越靠前响应;ResetZorders() 会把这套优先级还原。做多控件叠加面板时,外汇与贵金属图表的高波动可能让误触概率上升,建议先在策略测试器里手动改这几个值验证遮挡关系。 下面这段是 CCheckBox 类声明中紧接 CElement 虚函数之后的核心片段,可直接贴进 MT5 的 Include\ChartObjects\CheckBox.mqh 对照看。
class="kw">virtual class="type">void Moving(const class="type">int x,const class="type">int y); class=class="str">"cmt">//--- (class="num">1) 显示, (class="num">2) 隐藏, (class="num">3) 重置, (class="num">4) 删除 class="kw">virtual class="type">void Show(class="type">void); class="kw">virtual class="type">void Hide(class="type">void); class="kw">virtual class="type">void Reset(class="type">void); class="kw">virtual class="type">void Delete(class="type">void); class=class="str">"cmt">//--- (class="num">1) 设置, (class="num">2) 重设鼠标左键点击优先级 class="kw">virtual class="type">void SetZorders(class="type">void); class="kw">virtual class="type">void ResetZorders(class="type">void); class=class="str">"cmt">//--- 重设颜色 class="kw">virtual class="type">void ResetColors(class="type">void); }; class CCheckBox : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 复选框背景色 class="type">class="kw">color m_area_color; class=class="str">"cmt">//--- 活动状态和屏蔽状态下复选框的图标 class="type">class="kw">string m_check_bmp_file_on; class="type">class="kw">string m_check_bmp_file_off; class="type">class="kw">string m_check_bmp_file_on_locked; class="type">class="kw">string m_check_bmp_file_off_locked; class=class="str">"cmt">//--- 复选框的文字 class="type">class="kw">string m_label_text; class=class="str">"cmt">//--- 文字标签的边缘 class="type">int m_label_x_gap; class="type">int m_label_y_gap; class=class="str">"cmt">//--- 不同状态下文字的颜色 class="type">class="kw">color m_label_color; class="type">class="kw">color m_label_color_off; class="type">class="kw">color m_label_color_hover; class="type">class="kw">color m_label_color_locked; class="type">class="kw">color m_label_color_array[]; class=class="str">"cmt">//--- 鼠标左键优先级 class="type">int m_zorder; class="type">int m_area_zorder; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 设置活动与屏蔽状态下的按钮标签 class="type">void CheckFileOn(const class="type">class="kw">string file_path) { m_check_bmp_file_on=file_path; } class="type">void CheckFileOff(const class="type">class="kw">string file_path) { m_check_bmp_file_off=file_path; } class="type">void CheckFileOnLocked(const class="type">class="kw">string file_path) { m_check_bmp_file_on_locked=file_path; } class="type">void CheckFileOffLocked(const class="type">class="kw">string file_path) { m_check_bmp_file_off_locked=file_path; } class=class="str">"cmt">//--- (class="num">1) 背景颜色, (class="num">2) 文字标签的边缘
◍ 复选框控件的配色与构造拆分
上面这组 setter 暴露了 GUI 复选框可调控的全部视觉状态:背景区块颜色由 AreaColor 写入 m_area_color,文字与背景的间距分别由 LabelXGap、LabelYGap 以像素整数控制,默认留白若设成 0 会让标签贴边,MT5 上实测低于 2 像素时点击热区难以辨认。 LabelColor 系列区分了四种状态——常规、禁用(Off)、悬停(Hover)、锁定(Locked),各自对应独立成员变量。做多状态开关面板时,把 Hover 和 Locked 设成对比色,能直接降低误触概率,这是实盘参数面板常忽略的细节。 CCheckBox 类私有成员包含 CRectLabel m_area(底框)、CBmpLabel m_check(勾选位图)、CLabel m_label(文本),公开方法 CreateCheckBox 接收 chart_id、subwin、text、x、y 五个参数完成挂载。私有里的 CreateArea / CreateCheck / CreateLabel 才是真正往图表对象池塞资源的步骤,外部不要直接调。 m_check_button_state 这个布尔量藏在另一段类定义私有区,记录当前勾选状态;想读它得自己补一个 getter,标准库没给。外汇与贵金属图表挂这类控件波动时可能因重绘丢状态,属高风险环境下的界面细节。
class="type">void AreaColor(const class="type">class="kw">color clr) { m_area_color=clr; } class="type">void LabelXGap(const class="type">int x_gap) { m_label_x_gap=x_gap; } class="type">void LabelYGap(const class="type">int y_gap) { m_label_y_gap=y_gap; } class=class="str">"cmt">//--- 不同状态的文字颜色 class="type">void LabelColor(const class="type">class="kw">color clr) { m_label_color=clr; } class="type">void LabelColorOff(const class="type">class="kw">color clr) { m_label_color_off=clr; } class="type">void LabelColorHover(const class="type">class="kw">color clr) { m_label_color_hover=clr; } class="type">void LabelColorLocked(const class="type">class="kw">color clr) { m_label_color_locked=clr; } class=class="str">"cmt">//--- 复选框的描述 class="type">class="kw">string LabelText(class="type">void) const { class="kw">return(m_label.Description()); } }; class CCheckBox : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 用于创建复选框的对象 CRectLabel m_area; CBmpLabel m_check; CLabel m_label; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 创建复选框的方法 class="type">bool CreateCheckBox(const class="type">long chart_id,const class="type">int subwin,const class="type">class="kw">string text,const class="type">int x,const class="type">int y); class=class="str">"cmt">//--- class="kw">private: class="type">bool CreateArea(class="type">void); class="type">bool CreateCheck(class="type">void); class="type">bool CreateLabel(class="type">void); }; class CCheckBox : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 复选框按钮的状态 class="type">bool m_check_button_state;