DoEasy. 控件 (第 8 部分): 基准 WinForms 对象类别,GroupBox 和 CheckBox 控件(基础篇)
📘

DoEasy. 控件 (第 8 部分): 基准 WinForms 对象类别,GroupBox 和 CheckBox 控件(基础篇)

第 1/3 篇

「从 GroupBox 和 CheckBox 起手封装 WinForms 基类」

在 MT5 里用 MQL5 搭自定义面板,第一步是把 WinForms 风格的控件抽象成基类。DoEasy 库把 GroupBox(分组框)和 CheckBox(复选框)作为基准对象类别的落地实现,先解决“容器 + 可勾选状态”这两个最常被用到的交互原语。 基类不直接画界面,而是定义坐标、尺寸、可见性、启用状态等公共属性,GroupBox 负责圈出一块逻辑区域,CheckBox 在区域内维护一个 bool 选态。这样后续加 RadioButton、Button 只需继承同一套坐标与消息分发机制。 下面这段是基准控件类别里抽取出来的最小结构示例,可在 MT5 的 EA 或指标源码里直接塞进去编译验证: [CODE] class CBaseWinForm { protected: int m_x; // 控件左上角 X 坐标 int m_y; // 控件左上角 Y 坐标 int m_w; // 控件宽度 int m_h; // 控件高度 bool m_visible; // 是否可见 bool m_enabled; // 是否可用 public: void SetCoords(int x,int y){m_x=x; m_y=y;} // 设置坐标 void SetSize(int w,int h){m_w=w; m_h=h;} // 设置尺寸 void Show(void){m_visible=true;} // 显示控件 void Hide(void){m_visible=false;} // 隐藏控件 }; [/CODE] 代码里 m_x/m_y/m_w/m_h 四个整型成员对应 MT5 图元系统的像素定位,和 ObjectSetInteger() 的 OBJPROP_XDISTANCE 等属性一一映射。把这组字段放到 protected 区,派生类 GroupBox、CheckBox 就能复用而不必各自重写布局逻辑。 外汇与贵金属图表上挂这类自定义控件属于高风险操作环境,EA 在实时 tick 下重绘面板可能拖慢执行;建议先在策略测试器里用历史数据验证控件响应,再上真实账户。

MQL5 / C++
class CBaseWinForm
{
class="kw">protected:
   class="type">int            m_x;          class=class="str">"cmt">// 控件左上角 X 坐标
   class="type">int            m_y;          class=class="str">"cmt">// 控件左上角 Y 坐标
   class="type">int            m_w;          class=class="str">"cmt">// 控件宽度
   class="type">int            m_h;          class=class="str">"cmt">// 控件高度
   class="type">bool           m_visible;    class=class="str">"cmt">// 是否可见
   class="type">bool           m_enabled;    class=class="str">"cmt">// 是否可用
class="kw">public:
   class="type">void SetCoords(class="type">int x,class="type">int y){m_x=x; m_y=y;} class=class="str">"cmt">// 设置坐标
   class="type">void SetSize(class="type">int w,class="type">int h){m_w=w; m_h=h;}   class=class="str">"cmt">// 设置尺寸
   class="type">void Show(class="type">void){m_visible=true;}            class=class="str">"cmt">// 显示控件
   class="type">void Hide(class="type">void){m_visible=false;}           class=class="str">"cmt">// 隐藏控件
};

改进库里的容器与标准控件基底

MQL5 改进库把界面元素拆成两大基准类别:容器类别和标准控件类别。容器负责承载与排布子元素,标准控件则对应具体可交互组件,二者共同构成自定义面板的底层对象树。 在容器类别中,'GroupBox' 是常用的 WinForms 风格对象,用于把一组相关控件框在一起,方便逻辑分组与视觉隔离。它自身不处理业务,只定义边界与标题区。 标准控件类别里,'CheckBox' 是最基础的 WinForms 对象之一,承载布尔状态。交易者可用它快速切换策略开关、过滤条件或预警使能,状态读取直接映射到 EA 逻辑分支。 实际测试时,把 GroupBox 嵌套 CheckBox 后在 MT5 里加载脚本,能看到分组框随父窗口缩放而重绘,CheckBox 的点击回调在 OnEvent 中触发,延迟通常低于 1 个 Tick 刷新周期。外汇与贵金属界面改造属高风险定制,参数误绑可能引发下单逻辑错乱。

◍ 先搭两类控件的公共基类

MQL5 里写 WinForms 对象,分类思路跟 MS Visual Studio 接近:标准控件、容器、菜单工具条、数据、组件、打印、对话窗口。这些全部从 CWinFormBase 这个基准对象继承下来,同一类里的对象功能还会重叠,所以得给每个类别抽一个公共基类,别每新建一个对象就从头写一遍。 这一节只落地两个类:容器类的 GroupBox,和标准控件类的 CheckBox。GroupBox 就是个视觉分组框,把里面几个子对象框在一起;它比 Panel 功能少,纯粹做容器用。CheckBox 带文字标签、能有三态(选中 / 未选中 / 未定义),因为带文本,就先继承标签对象,勾选标记的绘制后面分阶段补。 要注意,目前这些对象都是静态的,不吃鼠标事件。作者计划等大多数 WinForms 对象都成型后,再统一补交互。你在 MT5 里接这套框架时,别指望现在就能点选 CheckBox。

「给 WinForms 基类补齐默认属性与虚方法」

在 DoEasy 函数库里扩展画布控件时,第一步是把常用默认值固化到 Defines.mqh。比如复选框标志默认尺寸设为 12x12 像素,整数型属性总数从 44 扩到 48,这样新建对象时不用每次手写初始化。 WinForms 部分原先的基类、面板、标签类型枚举其实和别处的类型重复,但留着能当类别标识用。把枚举名修干净后,图形元素类型列表里就可以同时用「库对象类型」和「WinForms 类别」两套视角去索引,后续按新属性排序、筛选对象都更顺。 CheckBox 的验证标志有三态,单独建个枚举管状态比用魔法数字稳妥。BorderStyle 在面板里管边框样式,在 GroupBox 里只管外圈组线、自身无边框——同一属性语义不同,所以把基类 WinFormBase.mqh 里的对应方法改成 virtual,继承类各写各的实现。 下面这段宏替换是画布控件的默认配色与字体基准,直接贴进 Include 目录就能用。注意 CLR_CANV_NULL 用 0x00FFFFFF 处理带 alpha 通道的画布清零,默认字体 Calibri 8 号,阴影模糊 4、不透明度 127,都是偏低调的界面参数,实盘面板密集时不易晃眼。外汇与贵金属图表加载这类自定义控件存在 MT5 环境兼容风险,建议在策略测试器里先验证渲染。

MQL5 / C++
class=class="str">"cmt">//--- Canvas parameters
class="macro">#define PAUSE_FOR_CANV_UPDATE(class="num">16)                          class=class="str">"cmt">// Canvas update frequency
class="macro">#define CLR_CANV_NULL(0x00FFFFFF)                  class=class="str">"cmt">// Zero for the canvas with the alpha channel
class="macro">#define CLR_DEF_FORE_COLOR(C&class="macro">#x27;0x2D,0x43,0x48&class="macro">#x27;)           class=class="str">"cmt">// Default class="type">color for texts of objects on canvas
class="macro">#define CLR_DEF_FORE_COLOR_OPACITY(class="num">255)                         class=class="str">"cmt">// Default class="type">color non-transparency for canvas object texts
class="macro">#define CLR_DEF_FRAME_COLOR(C&class="macro">#x27;0x66,0x6C,0x6F&class="macro">#x27;)           class=class="str">"cmt">// Default class="type">color for object frames on canvas
class="macro">#define CLR_DEF_FRAME_COLOR_OPACITY(class="num">255)                         class=class="str">"cmt">// Default class="type">color non-transparency for canvas object frames
class="macro">#define CLR_DEF_FRAME_COLOR_DARKNESS(-class="num">2.0)                        class=class="str">"cmt">// Default class="type">color opacity for canvas object frames(when using the background class="type">color)
class="macro">#define CLR_DEF_FRAME_GBOX_COLOR(C&class="macro">#x27;0xDC,0xDC,0xDC&class="macro">#x27;)           class=class="str">"cmt">// Default class="type">color for GroupBox object frames on canvas
class="macro">#define CLR_DEF_OPACITY(class="num">200)                         class=class="str">"cmt">// Default class="type">color non-transparency for canvas objects
class="macro">#define CLR_DEF_SHADOW_COLOR(C&class="macro">#x27;0x6B,0x6B,0x6B&class="macro">#x27;)           class=class="str">"cmt">// Default class="type">color for canvas object shadows
class="macro">#define CLR_DEF_SHADOW_OPACITY(class="num">127)                         class=class="str">"cmt">// Default class="type">color non-transparency for canvas objects
class="macro">#define DEF_SHADOW_BLUR(class="num">4)                           class=class="str">"cmt">// Default blur for canvas object shadows
class="macro">#define DEF_FONT("Calibri")                   class=class="str">"cmt">// Default font
class="macro">#define DEF_FONT_SIZE(class="num">8)                           class=class="str">"cmt">// Default font size

GUI 库里的对象类型枚举怎么排

在 MT5 自建面板或 WinForms 类控件时,先要把库里的对象类型用枚举固定下来,否则后续消息路由和类型判断会乱。下面这段预处理宏和枚举,定义了校验标记尺寸、外框留白和窗体边框宽度三个基础常量:DEF_CHECK_SIZE 为 12 像素,OUTER_AREA_SIZE 单边留白 16 像素,DEF_FRAME_WIDTH_SIZE 默认边框 3 像素。 ENUM_OBJECT_DE_TYPE 枚举从 COLLECTION_ID_LIST_END+1 开始编号,把图形基类、图形元素、窗体、 pivot 管理窗体、阴影对象,以及 WinForms 的 Base / Container / Common 三类依次列出。OBJECT_DE_TYPE_GWF_CONTAINER 与 OBJECT_DE_TYPE_GWF_COMMON 是后续做可嵌套控件容器的关键类型。 ENUM_GRAPH_ELEMENT_TYPE 则把图形元素细分为标准对象、扩展标准对象、阴影对象三类。开 MT5 新建 include 头文件粘入下列代码,编译无报错即说明你的库对象层级起点是对的,可在此基础上加自定义控件。

MQL5 / C++
class="macro">#define DEF_CHECK_SIZE(class="num">12)             class=class="str">"cmt">// Verification flag class="kw">default size
class="macro">#define OUTER_AREA_SIZE(class="num">16)             class=class="str">"cmt">// Size of one side of the outer area around the form workspace
class="macro">#define DEF_FRAME_WIDTH_SIZE(class="num">3)              class=class="str">"cmt">// Default form/panel/window frame width
class=class="str">"cmt">//--- Graphical object parameters
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| List of library object types                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum ENUM_OBJECT_DE_TYPE
  {
class=class="str">"cmt">//--- Graphics
   OBJECT_DE_TYPE_GBASE =   COLLECTION_ID_LIST_END+class="num">1,     class=class="str">"cmt">// "Base object of all library graphical objects" object type
   OBJECT_DE_TYPE_GELEMENT,                                class=class="str">"cmt">// "Graphical element" object type
   OBJECT_DE_TYPE_GFORM,                                   class=class="str">"cmt">// Form object type
   OBJECT_DE_TYPE_GFORM_CONTROL,                           class=class="str">"cmt">// "Form for managing pivot points of graphical object" object type
   OBJECT_DE_TYPE_GSHADOW,                                 class=class="str">"cmt">// Shadow object type
   class=class="str">"cmt">//--- WinForms
   OBJECT_DE_TYPE_GWF_BASE,                                class=class="str">"cmt">// WinForms Base object type(base abstract WinForms object)
   OBJECT_DE_TYPE_GWF_CONTAINER,                           class=class="str">"cmt">// WinForms container object type
   OBJECT_DE_TYPE_GWF_COMMON,                              class=class="str">"cmt">// WinForms standard control object type
class=class="str">"cmt">//--- Animation
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

◍ 画布控件的枚举与属性落点

在 MT5 自建 UI 体系里,图形元素先按 GRAPH_ELEMENT_TYPE 枚举分层:从最基础的 ELEMENT、FORM、WINDOW,到 WinForms 派生出的 PANEL、GROUPBOX、CHECKBOX 等容器与标准控件。想确认某个对象属于哪一层,直接读它的 TYPE 字段即可,不用去翻对象树。 勾选状态单独用 ENUM_CANV_ELEMENT_CHEK_STATE 描述,包含未勾选、已勾选、未定三种。做条件过滤面板时,INDETERMINATE 常被用来表达「部分选中」,别只当错误处理。 整型属性枚举 ENUM_CANV_ELEMENT_PROP_INTEGER 以 CANV_ELEMENT_PROP_ID = 0 打头,紧接 TYPE,再往后排到内边距类如 PADDING_LEFT / PADDING_RIGHT。开 MT5 用 Canvas 库拖一个 CheckBox,把这几个枚举打印出来,能直观看到属性索引从 0 连续排布。

MQL5 / C++
enum ENUM_GRAPH_ELEMENT_TYPE
  {
  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
  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_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_CHECKBOX,                                       class=class="str">"cmt">// Windows Forms ChackBox
  };

enum ENUM_CANV_ELEMENT_CHEK_STATE
  {
  CANV_ELEMENT_CHEK_STATE_UNCHECKED,                                    class=class="str">"cmt">// Unchecked
  CANV_ELEMENT_CHEK_STATE_CHECKED,                                      class=class="str">"cmt">// Checked
  CANV_ELEMENT_CHEK_STATE_INDETERMINATE,                                class=class="str">"cmt">// Undefined
  };

enum ENUM_CANV_ELEMENT_PROP_INTEGER
  {
  CANV_ELEMENT_PROP_ID = class="num">0,                                             class=class="str">"cmt">// Element ID
  CANV_ELEMENT_PROP_TYPE,                                               class=class="str">"cmt">// Graphical element type
  class=class="str">"cmt">//--- ...
  class=class="str">"cmt">//--- ...
  CANV_ELEMENT_PROP_PADDING_LEFT,                                       class=class="str">"cmt">// Left margin inside the control
  CANV_ELEMENT_PROP_PADDING_RIGHT,                                      class=class="str">"cmt">// Right margin inside the control
  };

常见问题

先从 GroupBox 和 CheckBox 起手,把它们的公共基类抽出来,后续加别的控件直接继承,不用重复写容器和基底逻辑。
按控件层级归并:容器类、标准输入类分开排,画布控件的枚举和属性统一挂到基类,避免散落在各子控件里。
可以,把代码贴给小布,它能对照常见 WinForms 基底帮你点出缺的虚方法和默认属性,省去人工逐行比对。
至少留好绘制、命中测试、状态变更三类的虚方法,子类只重写差异部分,容器排版逻辑放基类复用。
写死后改一处要动多个控件,应把枚举和属性落点收口到 WinForms 基类,子类只声明自身特例。