DoEasy. C控件(第 7 部分):文本标签控件(基础篇)
「给库加一个可复用的文本标签控件」
在 DoEasy 控件系列里,文本标签是最轻量但也最常被低估的基础件。它不画线、不托管指标,只负责把一串字符稳定钉在图表指定坐标上,供后续复合控件调用。 原文示例发布于 2022 年 8 月 29 日,截至统计时点该篇在站内的查看数为 1043、评论数为 0,说明这类底层控件文章读者窄但刚需明确。 本节的落点是先把“文本标签”控件类从原有库结构里单独抽出来做封装,让后续按钮、面板能直接继承它的坐标与绘制逻辑,而不是每次重写 OBJ_LABEL 的创建代码。外汇与贵金属图表高频刷新,这类封装能降低重绘闪烁概率,但 MT5 脚本出错仍可能引发滑点外的显示异常,属高风险环境下的底层改造。
为什么要在 MT5 里造一个独立文本标签控件
MT5 自带的 Text label 图形对象能写文字,但所有 GUI 元素共用画布显示文本,复杂界面里摆放和排版都很别扭。原文作者因此单独做了一个“文本标签”控件,容器可任意定位,功能对齐 MS Visual Studio 的 Label。 这个控件支持设置字体参数,文字被约束在对象边界内;尺寸既能手动指定宽高,也能按字体大小自动适配。边框可平面可立体,给 GUI 内部排版留了较大余地。 为了让新控件的属性可被检索和排序,作者把所有文本标签相关的整型、实型、字符串属性都塞进了函数库图形元素的枚举里。这套做法贯穿其整个函数库,好处是用统一接口就能快速筛选和操纵对象。 想验证的话,打开 MT5 的 MQL5 文件,翻图形元素枚举定义,看是否出现文本标签专属属性项即可。
◍ 给 DoEasy 库补上 Label 控件与属性通道
要在 MT5 里让画布上的文本标签能平滑淡入淡出,得先给函数库打通不透明度和文本属性这两个数据通道。原文在 Data.mqh 与 Defines.mqh 里新增了 MSG_GRAPH_ELEMENT_TYPE_WF_LABEL 消息索引,以及 CLR_DEF_FORE_COLOR_OPACITY 宏(默认值 255),把文本标签类型正式挂进对象类型列表。 图形元素的整数型属性总数从 38 扩到 44,字符串型属性从 2 扩到 3(新增“图形元素文本”)。这意味着排序和筛选图形元素时,可以按文本和不透明度跑了——回测或面板调试里能直接用这些字段做条件过滤。 基类 CWinFormBase 原本私有的变量被移进 protected 段,部分方法虚化以便继承重写。WinFormBase.mqh 里删掉了冗余的成员变量,所有读写改为走 SetProperty()/GetProperty() 枚举通道,构造函数把文本置空串、颜色与不透明度取 Defines.mqh 默认值。 别把正态当圣经 这套改法本质是“去成员变量、走属性枚举”,若你自己的 EA 也堆了私有变量存 GUI 状态,照这个思路重构后,图形元素排序会更统一,但编译前务必核对枚举总数改动,漏一项就会在运行时报属性越界。
MSG_GRAPH_ELEMENT_TYPE_WF_PANEL, class=class="str">"cmt">// Panel control MSG_GRAPH_ELEMENT_TYPE_WF_LABEL, class=class="str">"cmt">// Label control MSG_GRAPH_OBJ_BELONG_PROGRAM, class=class="str">"cmt">// Graphical object belongs to a program class=class="str">"cmt">//--- CPanel MSG_PANEL_OBJECT_ERR_FAILED_CREATE_UNDERLAY_OBJ, class=class="str">"cmt">// Failed to create the underlay object MSG_PANEL_OBJECT_ERR_OBJ_MUST_BE_WFBASE, class=class="str">"cmt">// Error. The created object should be of WinForms Base type or be derived from it }; class=class="str">"cmt">//+------------------------------------------------------------------+ {"Элемент управления \"Panel\"","Control element \"Panel\""}, {"Элемент управления \"Label\"","Control element \"Label\""}, {"Графический объект принадлежит программе","The graphic object belongs to the program"}, class=class="str">"cmt">//--- CPanel {"Не удалось создать объект-подложку","Failed to create underlay object"}, {"Ошибка. Создаваемый объект должен иметь тип WinForms Base или быть его наследником","Error. The object being created must be of type WinForms Base or be derived from it"}, }; class=class="str">"cmt">//+---------------------------------------------------------------------+ 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">class="kw">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">class="kw">color non-transparency for canvas object texts class="macro">#define CLR_DEF_OPACITY(class="num">200) class=class="str">"cmt">// Default class="type">class="kw">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">class="kw">color for canvas object shadows
「画布对象与控件类型的底层宏与枚举」
在 MT5 自定义图形库里,画布类对象的默认观感由一组预处理宏锁定。阴影不透明度给到 127(0~255 区间,约半透明),阴影模糊半径 4 像素,默认字体 Calibri、字号 8,外边距 16、边框宽 3——这些数值直接决定你拖出来的面板是否“挤”。 对象类型用枚举 ENUM_OBJECT_DE_TYPE 做归类,起点接在 COLLECTION_ID_LIST_END+1,也就是 OBJECT_DE_TYPE_GBASE 作为所有图形对象的基类。往下拆出 GELEMENT(图元)、GFORM(窗体)、GFORM_CONTROL(拖拽锚点管理窗体)、GSHADOW(阴影层)。 WinForms 分支从 GWF_BASE 抽象基类起,派生出 GWF_PANEL 容器与 GWF_LABEL 文本标签。做界面时若想加个静态文字,认准 OBJECT_DE_TYPE_GWF_LABEL 这个类型枚举值即可,避免手写字符串比对。 开 MT5 新建 include 把下面代码贴进去,编译后搜 GWF_LABEL 就能看到库已支持标签控件;外汇与贵金属图表叠加自绘 UI 属高风险操作,参数误用可能导致图表卡顿。
class="macro">#define CLR_DEF_SHADOW_OPACITY(class="num">127) class=class="str">"cmt">// Default class="type">class="kw">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 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_PANEL, class=class="str">"cmt">// WinForms Panel object type OBJECT_DE_TYPE_GWF_LABEL, class=class="str">"cmt">// WinForms Label object type class=class="str">"cmt">//--- Animation class=class="str">"cmt">//+------------------------------------------------------------------+
画布控件枚举与整数属性拆解
在 MT5 自定义界面开发里,图形元素先按类型归类,再套用画布属性。下面这段枚举把元素分成标准对象、扩展标准对象、影子对象、基础元素、表单、窗口,以及一套 WinForms 风格子类(面板衬底、基类、面板、标签等)。 [CODE]enum ENUM_GRAPH_ELEMENT_TYPE { GRAPH_ELEMENT_TYPE_STANDARD, // 标准图形对象 GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED, // 扩展标准图形对象 GRAPH_ELEMENT_TYPE_SHADOW_OBJ, // 影子对象 GRAPH_ELEMENT_TYPE_ELEMENT, // 元素 GRAPH_ELEMENT_TYPE_FORM, // 表单 GRAPH_ELEMENT_TYPE_WINDOW, // 窗口 //--- WinForms GRAPH_ELEMENT_TYPE_WF_UNDERLAY, // 面板对象衬底 GRAPH_ELEMENT_TYPE_WF_BASE, // Windows Forms 基类 GRAPH_ELEMENT_TYPE_WF_PANEL, // Windows Forms 面板 GRAPH_ELEMENT_TYPE_WF_LABEL, // Windows Forms 标签 };[/CODE] 上面代码逐行看:enum 定义元素类型集合;前六个是通用层级,从标准对象到窗口;注释 //--- WinForms 之后四个是仿窗体控件,其中 GRAPH_ELEMENT_TYPE_WF_LABEL 常用于在画布上贴静态文字。 整数属性枚举控制具体外观与行为。CANV_ELEMENT_PROP_FORE_COLOR 设所有控件默认文字色,CANV_ELEMENT_PROP_FORE_COLOR_OPACITY 管文字透明度,CANV_ELEMENT_PROP_BOLD_TYPE 定字体粗细,CANV_ELEMENT_PROP_BORDER_STYLE 定边框样式。 [CODE]enum ENUM_CANV_ELEMENT_PROP_INTEGER { CANV_ELEMENT_PROP_FORE_COLOR, // 所有控件对象默认文字颜色 CANV_ELEMENT_PROP_FORE_COLOR_OPACITY, // 所有控件对象默认文字颜色透明度 CANV_ELEMENT_PROP_BOLD_TYPE, // 字体宽度类型 CANV_ELEMENT_PROP_BORDER_STYLE, // 控件边框样式 CANV_ELEMENT_PROP_AUTOSIZE, // 按内容自动调整元素尺寸标志 CANV_ELEMENT_PROP_AUTOSIZE_MODE, // 按内容自动调整尺寸的模式 CANV_ELEMENT_PROP_AUTOSCROLL, // 自动滚动条标志 CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W, // 自动滚动时元素内部区域宽度 CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H, // 自动滚动时元素内部区域高度 CANV_ELEMENT_PROP_DOCK_MODE, // 控件边界绑定到容器的模式 };[/CODE] AUTOSIZE 与 AUTOSCROLL 系列值得在 MT5 里实测:开个面板塞入超长文本,把 CANV_ELEMENT_PROP_AUTOSIZE 设为 true 看是否撑开,再开 CANV_ELEMENT_PROP_AUTOSCROLL 观察边距参数对滚动区的影响。外汇与贵金属图表上挂这类自定义控件,需注意平台卡顿风险,复杂界面可能拖慢报价刷新。
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 GRAPH_ELEMENT_TYPE_WF_PANEL, class=class="str">"cmt">// Windows Forms Panel GRAPH_ELEMENT_TYPE_WF_LABEL, class=class="str">"cmt">// Windows Forms Label }; enum ENUM_CANV_ELEMENT_PROP_INTEGER { CANV_ELEMENT_PROP_FORE_COLOR, class=class="str">"cmt">// Default text class="type">class="kw">color for all control objects CANV_ELEMENT_PROP_FORE_COLOR_OPACITY, class=class="str">"cmt">// Default text class="type">class="kw">color opacity for all control objects CANV_ELEMENT_PROP_BOLD_TYPE, class=class="str">"cmt">// Font width type CANV_ELEMENT_PROP_BORDER_STYLE, class=class="str">"cmt">// Control frame style CANV_ELEMENT_PROP_AUTOSIZE, class=class="str">"cmt">// Flag of the element auto resizing depending on the content CANV_ELEMENT_PROP_AUTOSIZE_MODE, class=class="str">"cmt">// Mode of the element auto resizing depending on the content CANV_ELEMENT_PROP_AUTOSCROLL, class=class="str">"cmt">// Auto scrollbar flag CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W, class=class="str">"cmt">// Width of the field inside the element during auto scrolling CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H, class=class="str">"cmt">// Height of the field inside the element during auto scrolling CANV_ELEMENT_PROP_DOCK_MODE, class=class="str">"cmt">// Mode of binding control borders to the container };
◍ 画布控件属性枚举与排序基址
在 MT5 自定义画布控件库里,图形元素的属性被拆成整数、双精度、字符串三组枚举。整数属性总数由宏定为 44 个,其中不参与排序的跳过量为 0,这意味着全部整型字段都可作为排序键的偏移基准。 字符串属性枚举从整型与双精度属性计数之后接续:ENUM_CANV_ELEMENT_PROP_STRING 里只定义了 3 项——对象名、资源名与元素文本,宏 CANV_ELEMENT_PROP_STRING_TOTAL 即硬编码为 3。若你改了前面整型或双精度的总数,这里起始偏移会自动顺延,不用手改。 排序模式的基址用两个宏算出:FIRST_CANV_ELEMENT_DBL_PROP 等于整型总数减跳过数(44-0),字符串排序基址再叠加上双精度总数。实际写排序函数时,直接拿 SORT_BY_CANV_ELEMENT_FORE_COLOR_OPACITY 这类枚举值当数组下标,就能按前景色透明度、边框样式或自动滚动标志给控件阵列重排。 开 MT5 新建一个 canvas 面板 EA,把上面枚举原样贴进头文件,编译后打印 CANV_ELEMENT_PROP_STRING_TOTAL 的值,应当得到 3;若你前置插入了自定义整型属性,该数不变但字符串起始 ID 会往后挪。
enum ENUM_CANV_ELEMENT_PROP_STRING { CANV_ELEMENT_PROP_NAME_OBJ = (CANV_ELEMENT_PROP_INTEGER_TOTAL+CANV_ELEMENT_PROP_DOUBLE_TOTAL), class=class="str">"cmt">// Graphical element object name CANV_ELEMENT_PROP_NAME_RES, class=class="str">"cmt">// Graphical resource name CANV_ELEMENT_PROP_TEXT, class=class="str">"cmt">// Graphical element text }; class="macro">#define CANV_ELEMENT_PROP_STRING_TOTAL(class="num">3) class=class="str">"cmt">// Total number of class="type">class="kw">string properties class="macro">#define FIRST_CANV_ELEMENT_DBL_PROP(CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP) class="macro">#define FIRST_CANV_ELEMENT_STR_PROP(CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP+CANV_ELEMENT_PROP_DOUBLE_TOTAL-CANV_ELEMENT_PROP_DOUBLE_SKIP) enum ENUM_SORT_CANV_ELEMENT_MODE { SORT_BY_CANV_ELEMENT_ID = class="num">0, class=class="str">"cmt">// Sort by element ID SORT_BY_CANV_ELEMENT_FORE_COLOR, class=class="str">"cmt">// Sort by class="kw">default text class="type">class="kw">color SORT_BY_CANV_ELEMENT_FORE_COLOR_OPACITY, class=class="str">"cmt">// Sort by class="kw">default text class="type">class="kw">color opacity SORT_BY_CANV_ELEMENT_BOLD_TYPE, class=class="str">"cmt">// Sort by font width type SORT_BY_CANV_ELEMENT_BORDER_STYLE, class=class="str">"cmt">// Sort by control frame style SORT_BY_CANV_ELEMENT_AUTOSIZE, class=class="str">"cmt">// Sort by auto resizing flag SORT_BY_CANV_ELEMENT_AUTOSIZE_MODE, class=class="str">"cmt">// Sort by auto resizing mode SORT_BY_CANV_ELEMENT_AUTOSCROLL, class=class="str">"cmt">// Sort by auto scrollbar flag };