图形界面 X: 文本编辑框, 图片滑块和简单控件 (构建 5)(基础篇)
在 MT5 里搭一个能用的文本编辑框
想在 MT5 的 EA 或指标面板上放一个可输入参数的文本框,核心是用 Windows API 的 CreateWindowExW 配合 EDIT 类。官方示例里这一套控件被归在「图形界面 X」构建 5,发布于 2017-01-19,累计查看 4826 次,说明老交易者早就在折腾自定义面板了。 外汇和贵金属杠杆高、滑点猛,面板只是辅助,别指望控件能替你管风险。文本编辑框适合让人工临时改手数或偏离阈值,比每次重编译省事。 下面这段是示例里创建编辑框的关键调用,逐行拆一下你就知道改哪几个参数能挪位置、限定长度。
m_editHandle = CreateWindowExW(class="num">0, L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, class="num">10, class="num">10, class="num">120, class="num">20, m_parentHandle, NULL, m_instanceHandle, NULL);
「标准控件类的封装与字体处理」
MQL5 标准库把文本编辑框、图片滑块、文本标签和图片控件都做成了独立类,交易者开 MT5 后可在 Include/Controls 路径下直接翻到这些封装,省去从零写窗口消息循环的麻烦。 文本编辑框类负责接收键盘输入与光标管理,图片滑块类则把位图资源映射到可拖拽轨道,二者都依赖底层 OnEvent 回调把鼠标坐标转成控件状态。 字体渲染由专门的 CFonts 类接管,它能按字号、粗细、字符集动态创建 GDI 资源;外汇与贵金属图表挂自定义面板时,若中文标签发虚,多半是 CFonts 没指定 ANSI 字符集,这属于高风险界面调试点,改错可能让 EA 面板在实盘崩绘。 其余更新清单里还列了若干控件事件常量与绘制函数重载,建议直接把测试用 mq5 拖进策略测试器跑一遍,验证控件在可视化模式下是否响应点击。
◍ 这版控件库到底加了什么
这一节先把本轮函数库更新的范围说清楚:新增了文本编辑框、图片滑块,以及文本标签和图片这类基础控件,老控件也做了改进。 对已经用上这套库的用户来说,最直接的反馈渠道是各章末尾的文章清单链接,完整开发版可以从那里按原目录结构下载,目录层级不能乱,否则 MT5 加载会找不到依赖。 官方提到从用户侧收到了大量评论和建议,其中大部分已经落进新版;另外一些算法做了优化,方向是降低 CPU 负载,具体省了多少会在后面章节展开。外汇与贵金属 EA 界面若跑在低端 VPS 上,这类负载优化值得实测验证。
给函数库补一个能输任意文本的编辑框
之前函数库里的 CSpinEdit 只能塞数值,碰到要输字符串的场景就歇菜。现在补一个文本编辑框控件,字段里能写任意文本,用处很实际:比如在终端沙盒的文件里做字符串搜索,或者让最终用户直接贴一组交易品种名进去跑逻辑。 控件拆开看由四块组成:背景、图标、描述、编辑框本体。布局上图标和描述做提示,中间留编辑区域,和之前数值框的骨架类似但放开了输入类型。 外汇和贵金属这类高波动品种,用文本编辑框批量喂 Symbol 时容易手滑写错格式,建议在回测里先验证字符串解析是否容错。
「自己写一个 MT5 文本输入框类」
想在 MT5 面板里塞一个能输入参数的文本框,得从 CElement 派生一个 CTextEdit 类,把背景色、图标、边距、文本色这些属性全收进私有成员,再暴露一堆 setter 给外部调。标准方法已经挂在WndContainer引擎里,你新建 TextEdit.mqh 后直接 include 就能用。 类里可自定义的属性很多:控件背景色、激活/阻塞两套图标、图标与标签的 x/y 边距、描述文本、各状态文字色、编辑框宽高、编辑框边距、选中高亮色、边框色、重置模式、文本对齐(左/中/右)等。下面这段是类声明的核心骨架,逐行看私有字段就能知道 MT5 控件到底管了哪些视觉状态。
class CTextEdit : class="kw">public CElement { class="kw">private: class="type">color m_area_color; class=class="str">"cmt">// 控件背景色 class="type">class="kw">string m_icon_file_on; class=class="str">"cmt">// 激活状态图标路径 class="type">class="kw">string m_icon_file_off; class=class="str">"cmt">// 阻塞状态图标路径 class="type">int m_icon_x_gap; class=class="str">"cmt">// 图标X轴边距 class="type">int m_icon_y_gap; class=class="str">"cmt">// 图标Y轴边距 class="type">class="kw">string m_label_text; class=class="str">"cmt">// 描述文本 class="type">int m_label_x_gap; class=class="str">"cmt">// 标签X边距 class="type">int m_label_y_gap; class=class="str">"cmt">// 标签Y边距 class="type">color m_label_color; class=class="str">"cmt">// 普通标签色 class="type">color m_label_color_hover; class=class="str">"cmt">// 悬停标签色 class="type">color m_label_color_locked; class=class="str">"cmt">// 锁定标签色 class="type">color m_label_color_array[]; class=class="str">"cmt">// 标签色数组 class="type">class="kw">string m_edit_value; class=class="str">"cmt">// 编辑框当前值 class="type">int m_edit_x_size; class=class="str">"cmt">// 编辑框宽 class="type">int m_edit_y_size; class=class="str">"cmt">// 编辑框高 class="type">int m_edit_x_gap; class=class="str">"cmt">// 编辑框X边距 class="type">int m_edit_y_gap; class=class="str">"cmt">// 编辑框Y边距 class="type">color m_edit_color; class=class="str">"cmt">// 编辑框背景色 class="type">color m_edit_color_locked; class=class="str">"cmt">// 锁定背景色 class="type">color m_edit_text_color; class=class="str">"cmt">// 文本色 class="type">color m_edit_text_color_locked;class=class="str">"cmt">// 锁定文本色 class="type">color m_edit_text_color_highlight;class=class="str">"cmt">// 选中高亮文本色 class="type">color m_edit_border_color; class=class="str">"cmt">// 边框色 class="type">color m_edit_border_color_hover;class=class="str">"cmt">// 悬停边框色 class="type">color m_edit_border_color_locked;class=class="str">"cmt">// 锁定边框色 class="type">color m_edit_border_color_array[];class=class="str">"cmt">// 边框色数组 class="type">bool m_reset_mode; class=class="str">"cmt">// 空串重置模式 class="type">bool m_show_text_pointer_mode;class=class="str">"cmt">// 文本指针显示开关 ENUM_ALIGN_MODE m_align_mode; class=class="str">"cmt">// 对齐模式 class="kw">public: class="type">void IconXGap(class="kw">const class="type">int x_gap){ m_icon_x_gap=x_gap; } class="type">void IconYGap(class="kw">const class="type">int y_gap){ m_icon_y_gap=y_gap; } class="type">void AreaColor(class="kw">const class="type">color clr){ m_area_color=clr; } class="type">class="kw">string LabelText(class="type">void) class="kw">const { class="kw">return(m_label.Description()); } class="type">void LabelText(class="kw">const class="type">class="kw">string text){ m_label.Description(text); } class="type">void LabelXGap(class="kw">const class="type">int x_gap){ m_label_x_gap=x_gap; } class="type">void LabelYGap(class="kw">const class="type">int y_gap){ m_label_y_gap=y_gap; } class="type">void LabelColor(class="kw">const class="type">color clr){ m_label_color=clr; } class="type">void LabelColorHover(class="kw">const class="type">color clr){ m_label_color_hover=clr; } class="type">void LabelColorLocked(class="kw">const class="type">color clr){ m_label_color_locked=clr; } class="type">void EditXSize(class="kw">const class="type">int x_size){ m_edit_x_size=x_size; } class="type">void EditYSize(class="kw">const class="type">int y_size){ m_edit_y_size=y_size; } class="type">void EditXGap(class="kw">const class="type">int x_gap){ m_edit_x_gap=x_gap; } class="type">void EditYGap(class="kw">const class="type">int y_gap){ m_edit_y_gap=y_gap; } class="type">void EditColor(class="kw">const class="type">color clr){ m_edit_color=clr; } class="type">void EditColorLocked(class="kw">const class="type">color clr){ m_edit_color_locked=clr; } class="type">void EditTextColor(class="kw">const class="type">color clr){ m_edit_text_color=clr; } class="type">void EditTextColorLocked(class="kw">const class="type">color clr){ m_edit_text_color_locked=clr; } class="type">void EditTextColorHighlight(class="kw">const class="type">color clr){ m_edit_text_color_highlight=clr; } class="type">void EditBorderColor(class="kw">const class="type">color clr){ m_edit_border_color=clr; } class="type">void EditBorderColorHover(class="kw">const class="type">color clr){ m_edit_border_color_hover=clr; } class="type">void EditBorderColorLocked(class="kw">const class="type">color clr){ m_edit_border_color_locked=clr; } class="type">bool ResetMode(class="type">void){ class="kw">return(m_reset_mode); } class="type">void ResetMode(class="kw">const class="type">bool mode){ m_reset_mode=mode; } class="type">void ShowTextPointerMode(class="kw">const class="type">bool mode){ m_show_text_pointer_mode=mode; } class="type">void AlignMode(ENUM_ALIGN_MODE mode){ m_align_mode=mode; } class="type">void IconFileOn(class="kw">const class="type">class="kw">string file_path); class="type">void IconFileOff(class="kw">const class="type">class="kw">string file_path); };
enum ENUM_MOUSE_POINTER { MP_CUSTOM = class="num">0, class=class="str">"cmt">// 自定义 MP_X_RESIZE = class="num">1, class=class="str">"cmt">// 横向缩放 MP_Y_RESIZE = class="num">2, class=class="str">"cmt">// 纵向缩放 MP_XY1_RESIZE = class="num">3, class=class="str">"cmt">// 斜向1缩放 MP_XY2_RESIZE = class="num">4, class=class="str">"cmt">// 斜向2缩放 MP_X_SCROLL = class="num">5, class=class="str">"cmt">// 横滚 MP_Y_SCROLL = class="num">6, class=class="str">"cmt">// 纵滚 MP_TEXT_SELECT = class="num">7 class=class="str">"cmt">// 文本选择 };
class CTextEdit : class="kw">public CElement { class="kw">private: class="type">color m_area_color; class="type">class="kw">string m_icon_file_on; class="type">class="kw">string m_icon_file_off; class="type">int m_icon_x_gap; class="type">int m_icon_y_gap; class="type">class="kw">string m_label_text; class="type">int m_label_x_gap; class="type">int m_label_y_gap; class="type">color m_label_color; class="type">color m_label_color_hover; class="type">color m_label_color_locked; class="type">color m_label_color_array[]; class="type">class="kw">string m_edit_value; class="type">int m_edit_x_size; class="type">int m_edit_y_size; class="type">int m_edit_x_gap; class="type">int m_edit_y_gap; class="type">color m_edit_color; class="type">color m_edit_color_locked; class="type">color m_edit_text_color; class="type">color m_edit_text_color_locked; class="type">color m_edit_text_color_highlight; class="type">color m_edit_border_color; class="type">color m_edit_border_color_hover; class="type">color m_edit_border_color_locked; class="type">color m_edit_border_color_array[]; class="type">bool m_reset_mode; class="type">bool m_show_text_pointer_mode; ENUM_ALIGN_MODE m_align_mode; class="kw">public: class="type">void IconXGap(class="kw">const class="type">int x_gap){ m_icon_x_gap=x_gap; } class="type">void IconYGap(class="kw">const class="type">int y_gap){ m_icon_y_gap=y_gap; } class="type">void AreaColor(class="kw">const class="type">color clr){ m_area_color=clr; } class="type">class="kw">string LabelText(class="type">void) class="kw">const { class="kw">return(m_label.Description()); } class="type">void LabelText(class="kw">const class="type">class="kw">string text){ m_label.Description(text); } class="type">void LabelXGap(class="kw">const class="type">int x_gap){ m_label_x_gap=x_gap; } class="type">void LabelYGap(class="kw">const class="type">int y_gap){ m_label_y_gap=y_gap; } class="type">void LabelColor(class="kw">const class="type">color clr){ m_label_color=clr; } class="type">void LabelColorHover(class="kw">const class="type">color clr){ m_label_color_hover=clr; } class="type">void LabelColorLocked(class="kw">const class="type">color clr){ m_label_color_locked=clr; } class="type">void EditXSize(class="kw">const class="type">int x_size){ m_edit_x_size=x_size; } class="type">void EditYSize(class="kw">const class="type">int y_size){ m_edit_y_size=y_size; } class="type">void EditXGap(class="kw">const class="type">int x_gap){ m_edit_x_gap=x_gap; } class="type">void EditYGap(class="kw">const class="type">int y_gap){ m_edit_y_gap=y_gap; } class="type">void EditColor(class="kw">const class="type">color clr){ m_edit_color=clr; } class="type">void EditColorLocked(class="kw">const class="type">color clr){ m_edit_color_locked=clr; } class="type">void EditTextColor(class="kw">const class="type">color clr){ m_edit_text_color=clr; } class="type">void EditTextColorLocked(class="kw">const class="type">color clr){ m_edit_text_color_locked=clr; } class="type">void EditTextColorHighlight(class="kw">const class="type">color clr){ m_edit_text_color_highlight=clr; } class="type">void EditBorderColor(class="kw">const class="type">color clr){ m_edit_border_color=clr; } class="type">void EditBorderColorHover(class="kw">const class="type">color clr){ m_edit_border_color_hover=clr; } class="type">void EditBorderColorLocked(class="kw">const class="type">color clr){ m_edit_border_color_locked=clr; } class="type">bool ResetMode(class="type">void){ class="kw">return(m_reset_mode); } class="type">void ResetMode(class="kw">const class="type">bool mode){ m_reset_mode=mode; } class="type">void ShowTextPointerMode(class="kw">const class="type">bool mode){ m_show_text_pointer_mode=mode; } class="type">void AlignMode(ENUM_ALIGN_MODE mode){ m_align_mode=mode; } class="type">void IconFileOn(class="kw">const class="type">class="kw">string file_path); class="type">void IconFileOff(class="kw">const class="type">class="kw">string file_path); }; enum ENUM_MOUSE_POINTER { MP_CUSTOM = class="num">0, MP_X_RESIZE = class="num">1, MP_Y_RESIZE = class="num">2, MP_XY1_RESIZE = class="num">3, MP_XY2_RESIZE = class="num">4, MP_X_SCROLL = class="num">5, MP_Y_SCROLL = class="num">6, MP_TEXT_SELECT = class="num">7 };
◍ 文本编辑框的光标与字符上限
上面这段 CPointer::SetPointerBmp 按光标类型给控件换图标:横向缩放、纵向缩放、斜向缩放、滚动、文本选择各自对应一组 on/off 位图,文本选择态下 on 和 off 共用同一张 pointer_text_select.bmp。若 m_type 被设为 MP_CUSTOM 却没填 m_file_on 或 m_file_off,会直接 Print 提示必须给光标设两个图标——在 MT5 里跑自定义控件时,这个报错能帮你快速定位资源漏配。 文本编辑框 CTextEdit 继承自 CElement,私有成员里塞了五个对象:区域底框 m_area、图标 m_icon、静态标签 m_label、输入行 m_edit、以及文本选择光标 m_text_select;对外只暴露一个 CreateTextEdit 负责在指定 chart_id、子窗口和坐标处拼装控件,其余五个 Create* 方法都在内部跑。 类里没讲的部分和前面几篇同构,可以自己改参数试。当前这版文本编辑框硬上限是 63 个字符,做贵金属报价备注或短指令输入够用,想存长文本得改底层缓冲逻辑。外汇与贵金属杠杆交易高风险,这类 GUI 增强只解决交互效率,不暗示任何胜率改善。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Pointer.mqh | class=class="str">"cmt">//| 版权所有 class="num">2015, MetaQuotes 软件公司| class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "Element.mqh" class=class="str">"cmt">//--- 资源 ... class="macro">#resource "\\Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 基于光标类型设置光标图标 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CPointer::SetPointerBmp(class="type">void) { class="kw">switch(m_type) { case MP_X_RESIZE: m_file_on = "Images\\EasyAndFastGUI\\Controls\\pointer_x_rs_blue.bmp"; m_file_off = "Images\\EasyAndFastGUI\\Controls\\pointer_x_rs.bmp"; class="kw">break; case MP_Y_RESIZE: m_file_on = "Images\\EasyAndFastGUI\\Controls\\pointer_y_rs_blue.bmp"; m_file_off = "Images\\EasyAndFastGUI\\Controls\\pointer_y_rs.bmp"; class="kw">break; case MP_XY1_RESIZE: m_file_on = "Images\\EasyAndFastGUI\\Controls\\pointer_xy1_rs_blue.bmp"; m_file_off = "Images\\EasyAndFastGUI\\Controls\\pointer_xy1_rs.bmp"; class="kw">break; case MP_XY2_RESIZE: m_file_on = "Images\\EasyAndFastGUI\\Controls\\pointer_xy2_rs_blue.bmp"; m_file_off = "Images\\EasyAndFastGUI\\Controls\\pointer_xy2_rs.bmp"; class="kw">break; case MP_X_SCROLL: m_file_on = "Images\\EasyAndFastGUI\\Controls\\pointer_x_scroll_blue.bmp"; m_file_off = "Images\\EasyAndFastGUI\\Controls\\pointer_x_scroll.bmp"; class="kw">break; case MP_Y_SCROLL: m_file_on = "Images\\EasyAndFastGUI\\Controls\\pointer_y_scroll_blue.bmp"; m_file_off = "Images\\EasyAndFastGUI\\Controls\\pointer_y_scroll.bmp"; class="kw">break; case MP_TEXT_SELECT: m_file_on = "Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp"; m_file_off = "Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp"; class="kw">break; } class=class="str">"cmt">//--- 如果已指定光标类型 (MP_CUSTOM) if(m_file_on=="" || m_file_off=="") ::Print(__FUNCTION__," > 必须为光标设置两个图标!"); } class CTextEdit : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 创建编辑框的对象 CRectLabel m_area; CBmpLabel m_icon; CLabel m_label; CEdit m_edit; CPointer m_text_select; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 创建文本编辑框的方法 class="type">bool CreateTextEdit(class="kw">const class="type">long chart_id,class="kw">const class="type">int subwin,class="kw">const class="type">class="kw">string label_text,class="kw">const class="type">int x,class="kw">const class="type">int y); class=class="str">"cmt">//--- class="kw">private: class="type">bool CreateArea(class="type">void); class="type">bool CreateIcon(class="type">void); class="type">bool CreateLabel(class="type">void); class="type">bool CreateEdit(class="type">void); class="type">bool CreateTextSelectPointer(class="type">void); };