图形界面进度条与线形图控件:从零搭出可复用 MQL5 界面基类(基础篇)
(1/3)· 还在用 Print 看程序跑到哪一步?这一章把进度条和线形图控件的类结构一次讲清
给 MT5 面板加进度条和线形图
在 MT5 自定义图形界面里,进度条(ProgressBar)和线形图表(LineChart)属于轻量但高频的反馈控件:前者用来显示某段任务完成度,后者适合把一系列数值画成折线段做直观对比。 原文示例发布于 2016 年 10 月 18 日,在 MetaTrader 5 环境下实现,截至统计显示该示例获得 4275 次查看与 32 条互动,说明这类基础控件在实盘面板里需求稳定。 想在 MT5 里验证,可直接新建 EA 的对话框资源,拖入 ProgressBar 控件并绑定一个 0–100 的整型变量;线形图则多用 CopyBuffer 取指标缓冲后按点重绘,贵金属与外汇波动快,此类控件仅作状态展示,不构成任何方向判断。
◍ 这份控件的章节地图
这一节先把后续要落地的控件与代码模块列清楚,方便你开 MT5 照着逐块验证。 整套内容围绕两类自定义控件展开:进度条与线形图表。进度条部分会先从标准库的 CProgressBar 类讲起,再写测试程序看实际渲染;线形图表则会动手增强标准库已有类,封装成 CLineGraph,最后用一段独立 EA 把图打出来。 全文共 6 节,本篇是第 1 篇的第 2 节,后续每节都附带可直接编译的 MQL5 代码,建议你每看完一节就丢进 MT5 的 indicators 或 scripts 目录测一次。
「从哪接上这套界面库」
这套 MQL5 图形界面开发库不是从零讲起的,第一篇《图形界面 I: 库结构的准备工作 (第一章)》已经把目录结构和编译前置条件铺好了,没读过的直接去翻,否则后面控件挂不上。 每章文末都带了章节链接和最新完整库压缩包,下载后必须按归档里的相对路径原样落盘到 MT5 的 MQL5 目录下,错一个文件夹 EA 就找不到资源。 上一篇已经把颜色选择器和颜色按钮这对联动控件拆完了,这一章接着做进度条和线形图表。实例还是老规矩,给的是能直接塞进自定义指标或 EA 的调用代码,不是伪代码。
进度条的长耗时反馈怎么做
跑回测或批量下载 tick 数据时,MT5 用户最怕界面没反应。给长时间过程加一个进度条,本质是两层矩形:底层画总时长,上层画已完成部分,二者宽度比就是当前阶段。 很多实现会在控件里直接标百分比,其实还能塞更多上下文,比如当前处理的品种名或已用秒数。图 1 里把一个标准进度条拆成了背景、指针滚动条、指针背景和百分比四块,开发库就是按这几个组件拼的。 做控件类时,先算总任务量再映射像素宽度,误差通常能压到 1% 以内;若任务量未知,就改用未知时长模式,只滚指针不画百分比。
◍ 在 MT5 里搓一个可配置的进度条控件
做图形面板时,原生 MT5 没有现成的进度条对象可用。自己写个 CProgressBar 类塞进 ProgressBar.mqh,再被 WndContainer.mqh 的库引擎引用,就能在 EA 或脚本的界面里拖出带百分比的加载条。 这个类对外开放的配置项很细:背景色、描述文字及其颜色、双轴偏移、指示区尺寸与边框色宽、滚动条颜色、百分比标签偏移,以及小数位数。内部用 5 个私有方法管绘制,1 个公有 Update() 负责跟外部交互。 Update() 吃两个参数——当前迭代索引 index 和总步数 total。先调私有的 StepsTotal() 和 CurrentIndex() 把数值钳在有效范围内,再算指示条新宽度、拼百分比字符串、写回标签。外汇与贵金属 GUI 工具开发属高风险周边,参数越界可能让面板重绘卡死。 下面这段是类头与部分 setter 的节选,注意 m_digits 用 fabs 兜负值,其余 setter 都是直接赋值。开 MT5 建个 mqh 把这段补完,挂到自己的容器类里就能看到控件跑起来。
class CProgressBar : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 控件的范围颜色 class="type">color m_area_color; class=class="str">"cmt">//--- 显示过程的颜色 class="type">class="kw">string m_label_text; class=class="str">"cmt">//--- 文字颜色 class="type">color m_label_color; class=class="str">"cmt">//--- 两个轴上文字标签的偏移 class="type">int m_label_x_offset; class="type">int m_label_y_offset; class=class="str">"cmt">//--- 进度条的颜色和区域边框的颜色 class="type">color m_bar_area_color; class="type">color m_bar_border_color; class=class="str">"cmt">//--- 进度条的大小 class="type">int m_bar_x_size; class="type">int m_bar_y_size; class=class="str">"cmt">//--- 进度条在两个轴上的偏移 class="type">int m_bar_x_offset; class="type">int m_bar_y_offset; class=class="str">"cmt">//--- 进度条的边框宽度 class="type">int m_bar_border_width; class=class="str">"cmt">//--- 指针颜色 class="type">color m_indicator_color; class=class="str">"cmt">//--- 百分比标签的偏移 class="type">int m_percent_x_offset; class="type">int m_percent_y_offset; class=class="str">"cmt">//--- 小数点位数 class="type">int m_digits; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 小数点位数 class="type">void SetDigits(class="kw">const class="type">int digits) { m_digits=::fabs(digits); } class=class="str">"cmt">//--- (class="num">1) 区域的颜色, (class="num">2) 标签的文字 以及(class="num">3)标签的颜色 class="type">void AreaColor(class="kw">const class="type">color clr) { m_area_color=clr; } class="type">void LabelText(class="kw">const class="type">class="kw">string text) { m_label_text=text; } class="type">void LabelColor(class="kw">const class="type">color clr) { m_label_color=clr; } class=class="str">"cmt">//--- 文字标签的偏移 class="type">void LabelXOffset(class="kw">const class="type">int x_offset){ m_label_x_offset=x_offset; }
「进度条控件的样式与创建接口」
在 MT5 自定义指标或 EA 面板里画进度条,外观全靠一组 setter 控制。下面这段接口把标签纵向偏移、区域/边框/指针三色、边框宽度、进度条与百分比文字的 XY 偏移都暴露出来了,改一个 int 或 color 参数就能实时换肤。 void LabelYOffset(const int y_offset) { m_label_y_offset=y_offset; } //--- (1) 区域的颜色 (2) 进度条边框的颜色, (3) 指针的颜色 void BarAreaColor(const color clr) { m_bar_area_color=clr; } void BarBorderColor(const color clr) { m_bar_border_color=clr; } void IndicatorColor(const color clr) { m_indicator_color=clr; } //--- (1) 边框宽度, (2) 指针区域的大小 void BarBorderWidth(const int width) { m_bar_border_width=width; } void BarXSize(const int x_size) { m_bar_x_size=x_size; } void BarYSize(const int y_size) { m_bar_y_size=y_size; } //--- (1) 进度条在两个轴上的偏移, (2) 百分比标签的偏移 void BarXOffset(const int x_offset) { m_bar_x_offset=x_offset; } void BarYOffset(const int y_offset) { m_bar_y_offset=y_offset; } //--- 文字标签的偏移 (过程的百分比) void PercentXOffset(const int x_offset) { m_percent_x_offset=x_offset; } void PercentYOffset(const int y_offset) { m_percent_y_offset=y_offset; } CProgressBar 类私有成员挂了五个图形对象:m_area(底层矩形)、m_label(标题)、m_bar_bg(进度槽)、m_indicator(填充条)、m_percent(百分比文字)。CreateProgressBar() 是公开入口,接收 chart_id、子窗口号 subwin 以及 x、y 坐标,内部再分别调 CreateArea / CreateLabel / CreateBarArea / CreateIndicator 拼装。 实盘加载这类面板注意:外汇与贵金属杠杆高、滑点跳变频繁,进度条若绑定订单扫描循环,刷新频率建议控制在每秒 1~2 次,避免主图卡顿造成信号延迟。
class="type">void LabelYOffset(class="kw">const class="type">int y_offset) { m_label_y_offset=y_offset; } class=class="str">"cmt">//--- (class="num">1) 区域的颜色 (class="num">2) 进度条边框的颜色, (class="num">3) 指针的颜色 class="type">void BarAreaColor(class="kw">const class="type">color clr) { m_bar_area_color=clr; } class="type">void BarBorderColor(class="kw">const class="type">color clr) { m_bar_border_color=clr; } class="type">void IndicatorColor(class="kw">const class="type">color clr) { m_indicator_color=clr; } class=class="str">"cmt">//--- (class="num">1) 边框宽度, (class="num">2) 指针区域的大小 class="type">void BarBorderWidth(class="kw">const class="type">int width) { m_bar_border_width=width; } class="type">void BarXSize(class="kw">const class="type">int x_size) { m_bar_x_size=x_size; } class="type">void BarYSize(class="kw">const class="type">int y_size) { m_bar_y_size=y_size; } class=class="str">"cmt">//--- (class="num">1) 进度条在两个轴上的偏移, (class="num">2) 百分比标签的偏移 class="type">void BarXOffset(class="kw">const class="type">int x_offset) { m_bar_x_offset=x_offset; } class="type">void BarYOffset(class="kw">const class="type">int y_offset) { m_bar_y_offset=y_offset; } class=class="str">"cmt">//--- 文字标签的偏移 (过程的百分比) class="type">void PercentXOffset(class="kw">const class="type">int x_offset) { m_percent_x_offset=x_offset; } class="type">void PercentYOffset(class="kw">const class="type">int y_offset) { m_percent_y_offset=y_offset; } }; class CProgressBar : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 用于创建控件的对象 CRectLabel m_area; CLabel m_label; CRectLabel m_bar_bg; CRectLabel m_indicator; CLabel m_percent; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 用于创建控件的方法 class="type">bool CreateProgressBar(class="kw">const class="type">long chart_id,class="kw">const class="type">int subwin,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 CreateLabel(class="type">void); class="type">bool CreateBarArea(class="type">void); class="type">bool CreateIndicator(class="type">void);