DoEasy 进度条控件基础:用 WinForms 对象搭出可编程进度指示(基础篇)
📊

DoEasy 进度条控件基础:用 WinForms 对象搭出可编程进度指示(基础篇)

(1/3)· 还在用 Print 刷屏看任务进度?这篇把静态进度条变成可驱动的状态面板

实战向 第 1/3 篇
很多人在 EA 里跑批量回测或历史扫描时,只会用注释栏数字硬刷进度,界面卡顿还看不出子任务是否真正结束。给进度条加上可编程控制和视觉流动效果,能把后台冗长操作变成一眼可读的状态条。

「给进度条控件补上缺失的库方法」

这一节接着折腾 DoEasy 库里的 ProgressBar 控件,目标是把它往 WinForms 风格的可用对象上再推一步。原实现里进度条只能设值和读值,缺少对范围、步进和可见状态的统一封装,调用方每次都要写重复逻辑。 作者在 2023 年 3 月 30 日的示例里给出基础结构,原文标注示例阅读量 1 095,说明这类底层控件改造在 MT5 用户里确有刚需。进度条属于 WinForms 模拟对象,不依赖系统原生组件,因此在 MT5 的图表子窗口里也能稳定绘制。 下一步计划补上最小值、最大值、步进增量和重绘触发的方法,让进度条可以像标准控件一样被库统一调度。外汇与贵金属图表上叠加这类自绘控件存在刷新开销,实盘使用前建议在策略测试器里跑一遍观察资源占用。

◍ 给进度条加上动态眩光与子进程指示

这一节接着上篇的 WinForms 静态进度条往下做,目标是把控件变成可被程序驱动的对象。它由底图和进度条两层组成,后续还能在底图上叠文本或图像,但当前核心是先实现可编程填充与视觉反馈。 留意过 Windows 自带进度条的人会注意到,填充时有一条沿条移动的眩光。它不只是好看:当总操作量很大时,进度条不会每次操作都涨一格,而是攒够一批才刷新。于是可能出现条已满格但任务还在跑的情况——只要眩光还在动,就说明子进程没结束。 若进度条放在独立窗口,满格后需手动关窗才能消掉提示;若是拆成多个子进度条,已完成的那个会保持显示,直到整条流程跑完。双重指示很实用:条满了但眩光仍在 = 该子进程尚未彻底完成。外汇/贵金属 EA 里跑批量回测或历史校验时,这种指示能避免误判卡死,但请记住自动化交易本身属高风险,指示仅作辅助。 带视觉效果的控件必须登记进活动元素列表,函数库轮询该列表并触发各自计时器。具体平滑逻辑上篇踩过坑:标准库抗锯齿在透明时画不出来。实测把不透明度设在 128–255 用抗锯齿,0–127 用普通画法,半透明能盖住锯齿感,线条该平滑平滑、该隐没隐没。

把眩光从阴影继承里抽出来

原来设想眩光(Glare)继承阴影对象,靠父类的高斯模糊做特效,实测这条路走不通:继承关系把眩光锁死在阴影概念里,往别的图形元素上挂特效时极其别扭。现在改让眩光直接派生自 CWinFormBase——所有 WinForms 对象的基类,并塞进辅助对象列表,哪个类要用,一行包含就能挂上,不用再往各个库类里重复写阴影那套处理。 模糊方法也从 CShadowObj 搬到 GCnvElement,所有图形元素都能调,不再被阴影私有。改动涉及 Defines.mqh(眩光 ID 从图形对象区挪到辅助控件区)、Data.mqh(新增消息索引与文本)、GraphINI.mqh(配色方案属性总数加到 12,含眩光不透明度默认值)。GBaseObj 里类型描述方法的眩光分支也顺手挪到惯例位置——if-else 链里靠后的类型理论上多耗 CPU 周期,后续全库改用 switch 才彻底解决。 半透明线条的抗锯齿是个坑:不透明度 >127 时平滑绘制还正常,一旦降到 128 以下线条就碎成像素。代码里直接判阈值,超了用抗锯齿、否则调无平滑方法,半透明状态下像素化根本看不出来。其余预定义形状若也出现伪影,照同法处理。 眩光类本体改为继承 CWinFormBase,私密段存样式变量并声明绘图切换方法;DrawGlareFigure() 按样式分流。目前只实装矩形和平行四边形两种:矩形铺满对象画填充块,平行四边形用倾斜三角形多边形。构造函数里模糊默认 4、白模糊色、不透明度 127、隐藏态,保证对象永不彻底不透明。 进度条ProgressBar 同步改造:Value 按对象宽度百分比算而非像素,私密段加极限/步长变量与宽度计算方法。创建时按 50% 宽度建 BarProgressBar,并挂一个眩光进活动对象列表,由库计时器驱动沿条运动。PerformStep() 每次把 Value 加步长,宽度重算;小于 1 像素时藏起来模拟零宽。避免眩光溢出容器的关键是重绘方法——先全清成透明,再画形状、裁剪越界区、刷画布。 面板 Panel 和容器 Container 类里补上眩光包含与参数设置,任何独立 GUI 窗口内的控件都能加眩光。计时器里做“暂停-眩光-暂停”循环,复用此前工具提示的平滑显隐属性。外汇/贵金属 GUI 自动化展示此类特效时,注意 MT5 策略测试器与实际终端渲染差异可能带来视觉偏差,属高风险界面层改动。

「进度条眩光的对象封装与计时器接管」

在 BarProgressBar.mqh 这个进度条类里,眩光效果被拆成了独立的辅助对象。私密区里补了设置和读取延迟的方法,同时声明了一个统一的属性初始化函数,把原来散在构造函数里的赋值逻辑收拢到一起。 两个构造函数现在只调用初始化方法,原先那堆直接写死的属性赋值被整段搬走。除了挪代码,还顺手加了眩光在进度条上停留两秒的间隔控制——之前计时器只是把 GetTickCount() 的返回值丢进图表注释,现在换成完整事件处理。 新的计时器处理沿用了工具提示对象那套 ENUM_CANV_ELEMENT_DISPLAY_STATE 枚举:等对象就绪、沿进度条移动、再淡出,区别只在于进度条眩光不做淡出等待。这个枚举常量通用性够强,以后要扩新的显示事件直接往里加就行。 下面这段是图形元素类型枚举的节选,涵盖了从标准对象到 WinForms 控件体系的分类,编译前核对一下 GRAPH_ELEMENT_TYPE_SHADOW_OBJ 后面那行空位,避免枚举值错位。

MQL5 / C++
class=class="str">"cmt">//+-----------------------------------------------+
class=class="str">"cmt">//| The list of graphical element types           |
class=class="str">"cmt">//+-----------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_STANDARD,                      class=class="str">"cmt">// Standard graphical object
   GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED,             class=class="str">"cmt">// Extended standard graphical object
   GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                    class=class="str">"cmt">// Shadow object
                                                                 
   GRAPH_ELEMENT_TYPE_ELEMENT,                       class=class="str">"cmt">// Element
   GRAPH_ELEMENT_TYPE_FORM,                          class=class="str">"cmt">// Form
   GRAPH_ELEMENT_TYPE_WINDOW,                        class=class="str">"cmt">// Window
   class=class="str">"cmt">//--- WinForms
   GRAPH_ELEMENT_TYPE_WF_UNDERLAY,                   class=class="str">"cmt">// Panel object underlay
   GRAPH_ELEMENT_TYPE_WF_BASE,                       class=class="str">"cmt">// Windows Forms Base
   class=class="str">"cmt">//--- &class="macro">#x27;Container&class="macro">#x27; object types are to be set below
   GRAPH_ELEMENT_TYPE_WF_CONTAINER,                  class=class="str">"cmt">// Windows Forms container base object
   GRAPH_ELEMENT_TYPE_WF_PANEL,                      class=class="str">"cmt">// Windows Forms Panel
   GRAPH_ELEMENT_TYPE_WF_GROUPBOX,                   class=class="str">"cmt">// Windows Forms GroupBox
   GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,                class=class="str">"cmt">// Windows Forms TabControl
   GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,            class=class="str">"cmt">// Windows Forms SplitContainer
   class=class="str">"cmt">//--- &class="macro">#x27;Standard control&class="macro">#x27; object types are to be set below
   GRAPH_ELEMENT_TYPE_WF_COMMON_BASE,                class=class="str">"cmt">// Windows Forms base standard control
   GRAPH_ELEMENT_TYPE_WF_LABEL,                      class=class="str">"cmt">// Windows Forms Label
   GRAPH_ELEMENT_TYPE_WF_BUTTON,                     class=class="str">"cmt">// Windows Forms Button
   GRAPH_ELEMENT_TYPE_WF_CHECKBOX,                   class=class="str">"cmt">// Windows Forms CheckBox
   GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON,                class=class="str">"cmt">// Windows Forms RadioButton
   GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX,          class=class="str">"cmt">// Base list object of Windows Forms elements
   GRAPH_ELEMENT_TYPE_WF_LIST_BOX,                   class=class="str">"cmt">// Windows Forms ListBox
   GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX,           class=class="str">"cmt">// Windows Forms CheckedListBox
   GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX,            class=class="str">"cmt">// Windows Forms ButtonListBox

◍ GUI 元素枚举里的 WinForms 映射细节

在 MT5 自定义图形接口里,GRAPH_ELEMENT_TYPE 枚举把大量 Windows Forms 控件抽象成图形元素类型。上面这段列出了 ToolTip、ProgressBar 以及 ListBoxItem、TabHeader、SplitContainerPanel 等辅助元素,还包含四个方向的 ArrowButton 和左右/上下箭头组合框,共 20 余个 WinForms 派生类型。 注意 GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ 被标亮,它代表“眩光对象”(Glare object),不属于标准 WinForms 控件,而是终端图形层附加的视觉元素。如果你的 CForm 文本对象报错 MSG_FORM_OBJECT_TEXT_NO_GLARE_OBJ_FIRST_CREATE_IT,说明还没调用 CreateGlareObj() 生成该对象,对应错误码 MSG_FORM_OBJECT_ERR_FAILED_CREATE_GLARE_OBJ 则表示创建失败。 另有一个独立枚举 ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE,仅含 RECTANGLE 与 PARALLELOGRAMM 两种视觉特效样式,用于画布元素的形变渲染。开 MT5 新建指标把下面枚举贴进头文件,编译后能在诊断栏直接看到这些类型常量,方便后续做 GUI 对象调试。

MQL5 / C++
GRAPH_ELEMENT_TYPE_WF_TOOLTIP,                 class=class="str">"cmt">// Windows Forms ToolTip
GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,                class=class="str">"cmt">// Windows Forms ProgressBar
class=class="str">"cmt">//--- Auxiliary elements of WinForms objects
GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM,               class=class="str">"cmt">// Windows Forms ListBoxItem
GRAPH_ELEMENT_TYPE_WF_TAB_HEADER,                  class=class="str">"cmt">// Windows Forms TabHeader
GRAPH_ELEMENT_TYPE_WF_TAB_FIELD,                   class=class="str">"cmt">// Windows Forms TabField
GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER_PANEL,       class=class="str">"cmt">// Windows Forms SplitContainerPanel
GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON,                class=class="str">"cmt">// Windows Forms ArrowButton
GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,             class=class="str">"cmt">// Windows Forms UpArrowButton
GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,           class=class="str">"cmt">// Windows Forms DownArrowButton
GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,           class=class="str">"cmt">// Windows Forms LeftArrowButton
GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,          class=class="str">"cmt">// Windows Forms RightArrowButton
GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX,        class=class="str">"cmt">// Windows Forms UpDownArrowButtonsBox
GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX,        class=class="str">"cmt">// Windows Forms LeftRightArrowButtonsBox
GRAPH_ELEMENT_TYPE_WF_SPLITTER,                    class=class="str">"cmt">// Windows Forms Splitter
GRAPH_ELEMENT_TYPE_WF_HINT_BASE,                   class=class="str">"cmt">// Windows Forms HintBase
GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT,              class=class="str">"cmt">// Windows Forms HintMoveLeft
GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT,             class=class="str">"cmt">// Windows Forms HintMoveRight
GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP,                class=class="str">"cmt">// Windows Forms HintMoveUp
GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN,              class=class="str">"cmt">// Windows Forms HintMoveDown
GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,            class=class="str">"cmt">// Windows Forms BarProgressBar
GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,                   class=class="str">"cmt">// Glare object
};

enum ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE
  {
   CANV_ELEMENT_VISUAL_EFF_STYLE_RECTANGLE,        class=class="str">"cmt">// Rectangle
   CANV_ELEMENT_VISUAL_EFF_STYLE_PARALLELOGRAMM,   class=class="str">"cmt">// Parallelogram
  };

  MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT,class=class="str">"cmt">// No shadow object. Create it class="kw">using the CreateShadowObj() method
  MSG_FORM_OBJECT_TEXT_NO_GLARE_OBJ_FIRST_CREATE_IT, class=class="str">"cmt">// No glare object. We must first create it class="kw">using the CreateGlareObj() method
  MSG_FORM_OBJECT_ERR_FAILED_CREATE_SHADOW_OBJ,      class=class="str">"cmt">// Failed to create new shadow object
  MSG_FORM_OBJECT_ERR_FAILED_CREATE_GLARE_OBJ,      class=class="str">"cmt">// Failed to create new glare object

图形元素类型与窗体样式枚举的落地细节

在 MT5 自定义界面库里,图形元素被拆成 Element、Shadow object、Form、Window 以及 BarProgressBar / ProgressBar 控件等类型,每种都对应一条双语错误消息常量,例如 MSG_GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ 专门指向高光对象(Glare object)。如果没先调用 CreateShadowObj() 或 CreateGlareObj() 就引用对应对象,运行时会直接返回「There is no shadow object」或「There is no glare object」这类英文报错。 窗体样式参数用 ENUM_FORM_STYLE_PARAMS 枚举管理,其中 FORM_STYLE_FRAME_GLARE_OPACITY 控制高光不透明度,FORM_STYLE_FRAME_SHADOW_OPACITY 管阴影不透明度,FORM_STYLE_FRAME_SHADOW_BLUR 决定阴影模糊半径,另有 X/Y 轴偏移与暗化色可供调。 开 MT5 把这段枚举抄进你的面板基类,先确认 CreateShadowObj / CreateGlareObj 的调用顺序,再逐个改 FORM_STYLE_FRAME_SHADOW_BLUR 的值,能直观看到阴影软硬变化。外汇与贵金属图表挂这类 UI 属高风险环境,参数异常可能让 EA 界面卡死,建议先在模拟账户验证。

MQL5 / C++
enum ENUM_FORM_STYLE_PARAMS
  {
  class=class="str">"cmt">//--- CForm
  FORM_STYLE_FRAME_GLARE_OPACITY,           class=class="str">"cmt">// Glare opacity
  FORM_STYLE_FRAME_SHADOW_OPACITY,          class=class="str">"cmt">// Shadow opacity
  FORM_STYLE_FRAME_SHADOW_BLUR,             class=class="str">"cmt">// Shadow blur
  FORM_STYLE_DARKENING_COLOR_FOR_SHADOW,    class=class="str">"cmt">// Form shadow class="type">color darkening
  FORM_STYLE_FRAME_SHADOW_X_SHIFT,          class=class="str">"cmt">// Shadow X axis shift
  FORM_STYLE_FRAME_SHADOW_Y_SHIFT,          class=class="str">"cmt">// Shadow Y axis shift
  };
把重复劳动交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到控件状态与耗时分布,你只需关注哪段逻辑拖慢了整体流程。

常见问题

底图是静态承载层,进度条是在其上填充的指示层,后续还可叠加文本或图像等设计元素。
当操作总数很大时,进度条按批量步进填充,满格仅代表已计批次完成,子进程可能仍在跑,需靠视觉效果判断。
透明度设为 0 时抗锯齿基元会失效,技巧是用 128–255 走抗锯齿、0–127 走普通绘制,靠半透明隐藏粗糙边。
可以,小布盯盘的 AIGC 模块能读取品种页里的控件耗时与完成度,省去你手动埋点打印。
带特效的对象须进入活动元素列表,库依次调用其计时器事件处理程序,特效逻辑写在对象自身的计时器里。