DoEasy 函数库中的图形(第七十四部分):由 CCanvas 类提供强力支持的基本图形元素(基础篇)
◍ 正文
DoEasy 函数库中的图形(第七十四部分):由 CCanvas 类提供强力支持的基本图形元素 MetaTrader 5 — 示例 | 26 七月 2021, 09:41
- 724
3 Artyom Trishkin 概述 改进库类 基于画布的所有函数库图形对象的基准对象 测试 下一步是什么?
把图形对象拆成「元素」再搭基类
上一节里基于 CCanvas 做的交互窗对象,细看下来比函数库基准对象复杂太多,概念也对不上。于是这里换思路:在画布上引入“元素(Element)”作为最底层的图形构件,后面所有图形对象都从它长出来。 具体层次是这样:基准图形对象派生自 CObject,带终端图形对象的固有属性;Element 对象属性全建立在画布对象之上;Form 对象给元素加外观属性与功能;Window 则是元素加交互窗的复合体。 按这个新概念,CGBaseObj 这个图形基类要重做,同时新建一个“图形元素”对象,把基准对象的整套构建逻辑完整复刻一遍。后面就能直接按对象类型快速检索、排序、管行为和渲染,MT5 里打开类视图对照这套继承链就能验证。
「给图形元素对象打地基」
要在 MT5 里用函数库统一管理画布类图形,第一步是扩展 DoEasy 的底层枚举与消息。Data.mqh 中新增了 MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ 这条索引,对应俄英双语文本 "Failed to create graphic element object",专门捕获图形元素对象创建失败的运行期错误。 Defines.mqh 里补了 ENUM_GRAPH_ELEMENT_TYPE 枚举,目前含 GRAPH_ELEMENT_TYPE_ELEMENT、FORM、WINDOW 三个成员,把“图形元素”从普通 OBJ_LABEL 之类剥离成独立类型族。由于基于画布的对象在标准库中没有实数型属性,而构造函数库对象需要统一属性接口,作者塞了一个 stub 实数属性进去占位——这点在回看 CCanvas 派生结构时会发现它目前只是空壳。 GBaseObj.mqh 被整体重写而非修补:删空后只留图表 ID、子窗口索引、名称前缀、Y 偏移这几个公共字段,所有具体图形对象后续都从它继承。m_name_prefix 默认拼上程序名加下划线,完整对象名 = 前缀 + 用户给的唯一名,这样多 EA 同图运行时不会互相误删对方的图形。 类构造函数初始化列表里把 m_type 默认置 0,并重写标准库 CObject::Type() 虚函数返回 m_type 而非写死值。想验证的话,开 MT5 在 Include\DoEasy 路径下比对上述枚举与文本是否就位,缺一条编译图形元素模块就会报未定义标识符。外汇与贵金属图表加载此类 EA 属高风险操作,图形对象泄漏可能拖慢终端响应。
MSG_LIB_SYS_FAILED_CREATE_STORAGE_FOLDER, class=class="str">"cmt">// Failed to create folder for storing files. Error: MSG_LIB_SYS_FAILED_ADD_ACC_OBJ_TO_LIST, class=class="str">"cmt">// Error. Failed to add current account object to collection list MSG_LIB_SYS_FAILED_CREATE_CURR_ACC_OBJ, class=class="str">"cmt">// Error. Failed to create account object with current account data MSG_LIB_SYS_FAILED_OPEN_FILE_FOR_WRITE, class=class="str">"cmt">// Could not open file for writing MSG_LIB_SYS_INPUT_ERROR_NO_SYMBOL, class=class="str">"cmt">// Input error: no symbol MSG_LIB_SYS_FAILED_CREATE_SYM_OBJ, class=class="str">"cmt">// Failed to create symbol object MSG_LIB_SYS_FAILED_ADD_SYM_OBJ, class=class="str">"cmt">// Failed to add symbol MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ, class=class="str">"cmt">// Failed to create the graphical element object {"Не удалось создать папку хранения файлов. Ошибка: ","Could not create file storage folder. Error: "}, {"Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию","Error. Failed to add current account object to collection list"}, {"Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта","Error. Failed to create account object with current account data"}, {"Не удалось открыть для записи файл ","Could not open file for writing: "}, {"Ошибка входных данных: нет символа ","Input error: no "}, {"Не удалось создать объект-символ ","Failed to create symbol object "}, {"Не удалось добавить символ ","Failed to add "}, {"Не удалось создать объект-графический элемент ","Failed to create graphic element object "}, 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_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">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Integer properties of the graphical element on the canvas | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_CANV_ELEMENT_PROP_INTEGER {
◍ 画布表单的整数属性枚举
在 MT5 的 Canvas 界面框架里,一个表单(Form)被拆成 23 个整数属性来管理,从 ID、类型、所属图表子窗口到坐标宽高全在其中。 下面这段枚举定义了每个属性的语义,开 MT5 把代码贴进 MQ5 头文件就能直接引用,不用自己重排顺序。 注意 CANV_ELEMENT_PROP_INTEGER_TOTAL 被宏定义为 23,和枚举里实际列出的属性条数一致;若你往后增删属性,这个宏必须同步改,否则遍历属性数组会越界。 外汇与贵金属图表上挂这类自定义画布属于高风险操作,属性算错可能导致面板漂移到不可见区域,建议在策略测试器里先验证坐标逻辑。
CANV_ELEMENT_PROP_ID = class="num">0, class=class="str">"cmt">// Form ID CANV_ELEMENT_PROP_TYPE, class=class="str">"cmt">// Graphical element type CANV_ELEMENT_PROP_NUM, class=class="str">"cmt">// Element index in the list CANV_ELEMENT_PROP_CHART_ID, class=class="str">"cmt">// Chart ID CANV_ELEMENT_PROP_WND_NUM, class=class="str">"cmt">// Chart subwindow index CANV_ELEMENT_PROP_COORD_X, class=class="str">"cmt">// Form&class="macro">#x27;s X coordinate on the chart CANV_ELEMENT_PROP_COORD_Y, class=class="str">"cmt">// Form&class="macro">#x27;s Y coordinate on the chart CANV_ELEMENT_PROP_WIDTH, class=class="str">"cmt">// Form width CANV_ELEMENT_PROP_HEIGHT, class=class="str">"cmt">// Form height CANV_ELEMENT_PROP_RIGHT, class=class="str">"cmt">// Form right border CANV_ELEMENT_PROP_BOTTOM, class=class="str">"cmt">// Form bottom border CANV_ELEMENT_PROP_ACT_SHIFT_LEFT, class=class="str">"cmt">// Active area offset from the left edge of the form CANV_ELEMENT_PROP_ACT_SHIFT_TOP, class=class="str">"cmt">// Active area offset from the top edge of the form CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT, class=class="str">"cmt">// Active area offset from the right edge of the form CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM, class=class="str">"cmt">// Active area offset from the bottom edge of the form CANV_ELEMENT_PROP_OPACITY, class=class="str">"cmt">// Form opacity CANV_ELEMENT_PROP_COLOR_BG, class=class="str">"cmt">// Form background class="type">color CANV_ELEMENT_PROP_MOVABLE, class=class="str">"cmt">// Form moveability flag CANV_ELEMENT_PROP_ACTIVE, class=class="str">"cmt">// Form activity flag CANV_ELEMENT_PROP_COORD_ACT_X, class=class="str">"cmt">// X coordinate of the form&class="macro">#x27;s active area CANV_ELEMENT_PROP_COORD_ACT_Y, class=class="str">"cmt">// Y coordinate of the form&class="macro">#x27;s active area CANV_ELEMENT_PROP_ACT_RIGHT, class=class="str">"cmt">// Right border of the form&class="macro">#x27;s active area CANV_ELEMENT_PROP_ACT_BOTTOM, class=class="str">"cmt">// Bottom border of the form&class="macro">#x27;s active area }; class="macro">#define CANV_ELEMENT_PROP_INTEGER_TOTAL(class="num">23) class=class="str">"cmt">// Total number of integer properties
画布元素属性与排序枚举的底层定义
在 MT5 自定义图形界面开发里,画布元素被拆成整数、实数、字符串三类属性分别管理。整数类跳过了 0 个不参与排序的字段,实数类只定义了 1 个占位属性(CANV_ELEMENT_PROP_DUMMY)且全部跳过排序,字符串类则有对象名与资源名共 2 个属性。 排序起始偏移由宏算出:整数可用排序起点 = 总数减跳过数;字符串起点还要再叠加上实数部分。代码里 FIRST_CANV_ELEMENT_STR_PROP 正是用 INTEGER_TOTAL 减 INTEGER_SKIP 再加 DOUBLE_TOTAL 减 DOUBLE_SKIP 推出来的,改这两个 SKIP 宏会直接挪动字符串排序号。 ENUM_SORT_CANV_ELEMENT_MODE 从 0 开始枚举,SORT_BY_CANV_ELEMENT_ID 到 SORT_BY_CANV_ELEMENT_RIGHT 覆盖了 ID、类型、列表序号、图表 ID、窗口序号、X/Y 坐标、宽高及右边框等 10 种整数排序依据。实盘写面板重绘逻辑时,按坐标或宽度排序可能显著改变图层叠放顺序,外汇与贵金属图表多窗口场景下误排会导致点击命中错位,属高风险操作,建议开 MT5 用这两段宏现场改 SKIP 值验证偏移。
class="macro">#define CANV_ELEMENT_PROP_INTEGER_SKIP(class="num">0) class=class="str">"cmt">// Number of integer properties not used in sorting class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Real properties of the graphical element on the canvas | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_CANV_ELEMENT_PROP_DOUBLE { CANV_ELEMENT_PROP_DUMMY = CANV_ELEMENT_PROP_INTEGER_TOTAL, class=class="str">"cmt">// DBL stub }; class="macro">#define CANV_ELEMENT_PROP_DOUBLE_TOTAL(class="num">1) class=class="str">"cmt">// Total number of real properties class="macro">#define CANV_ELEMENT_PROP_DOUBLE_SKIP(class="num">1) class=class="str">"cmt">// Number of real properties not used in sorting class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| String properties of the graphical element on the canvas | class=class="str">"cmt">//+------------------------------------------------------------------+ 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">// Form object name CANV_ELEMENT_PROP_NAME_RES, class=class="str">"cmt">// Graphical resource name }; class="macro">#define CANV_ELEMENT_PROP_STRING_TOTAL(class="num">2) class=class="str">"cmt">// Total number of class="type">class="kw">string properties class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Possible sorting criteria of graphical elements on the canvas | class=class="str">"cmt">//+------------------------------------------------------------------+ 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 { class=class="str">"cmt">//--- Sort by integer properties SORT_BY_CANV_ELEMENT_ID = class="num">0, class=class="str">"cmt">// Sort by form ID SORT_BY_CANV_ELEMENT_TYPE, class=class="str">"cmt">// Sort by graphical element type SORT_BY_CANV_ELEMENT_NUM, class=class="str">"cmt">// Sort by form index in the list SORT_BY_CANV_ELEMENT_CHART_ID, class=class="str">"cmt">// Sort by chart ID SORT_BY_CANV_ELEMENT_WND_NUM, class=class="str">"cmt">// Sort by chart window index SORT_BY_CANV_ELEMENT_COORD_X, class=class="str">"cmt">// Sort by the form X coordinate on the chart SORT_BY_CANV_ELEMENT_COORD_Y, class=class="str">"cmt">// Sort by the form Y coordinate on the chart SORT_BY_CANV_ELEMENT_WIDTH, class=class="str">"cmt">// Sort by the form width SORT_BY_CANV_ELEMENT_HEIGHT, class=class="str">"cmt">// Sort by the form height SORT_BY_CANV_ELEMENT_RIGHT, class=class="str">"cmt">// Sort by the form right border };
「画布元素排序枚举的收尾定义」
上面这组枚举值把画布表单对象能拿来排序的维度列干净了:从外框底边 SORT_BY_CANV_ELEMENT_BOTTOM,到活动区相对四边的偏移、透明度、背景色、是否可拖动、是否激活,再到活动区坐标与右/下边界,一共 14 个整型枚举项。 字符串类排序单独从 FIRST_CANV_ELEMENT_STR_PROP 起算,目前挂了表单对象名 SORT_BY_CANV_ELEMENT_NAME_OBJ 和图形资源名 SORT_BY_CANV_ELEMENT_NAME_RES 两项;注释里留了『按真实属性』『按字符串属性』的分组空行,说明后续可能继续扩。 下方 GBaseObj.mqh 头文件标注 2021 年 MetaQuotes 版权、version 1.00 与 strict 模式(兼顾 mql4 编译)。在 MT5 里新建 EA 引用该枚举时,可直接用 SORT_BY_CANV_ELEMENT_ACT_SHIFT_LEFT 这类常量给自定义面板做 z-order 或命中测试排序,省去手写比较函数。
SORT_BY_CANV_ELEMENT_BOTTOM, class=class="str">"cmt">// Sort by the form bottom border SORT_BY_CANV_ELEMENT_ACT_SHIFT_LEFT, class=class="str">"cmt">// Sort by the active area offset from the left edge of the form SORT_BY_CANV_ELEMENT_ACT_SHIFT_TOP, class=class="str">"cmt">// Sort by the active area offset from the top edge of the form SORT_BY_CANV_ELEMENT_ACT_SHIFT_RIGHT, class=class="str">"cmt">// Sort by the active area offset from the right edge of the form SORT_BY_CANV_ELEMENT_ACT_SHIFT_BOTTOM, class=class="str">"cmt">// Sort by the active area offset from the bottom edge of the form SORT_BY_CANV_ELEMENT_OPACITY, class=class="str">"cmt">// Sort by the form opacity SORT_BY_CANV_ELEMENT_COLOR_BG, class=class="str">"cmt">// Sort by the form background class="type">color SORT_BY_CANV_ELEMENT_MOVABLE, class=class="str">"cmt">// Sort by the form moveability flag SORT_BY_CANV_ELEMENT_ACTIVE, class=class="str">"cmt">// Sort by the form activity flag SORT_BY_CANV_ELEMENT_COORD_ACT_X, class=class="str">"cmt">// Sort by X coordinate of the form active area SORT_BY_CANV_ELEMENT_COORD_ACT_Y, class=class="str">"cmt">// Sort by Y coordinate of the form active area SORT_BY_CANV_ELEMENT_ACT_RIGHT, class=class="str">"cmt">// Sort by the right border of the form active area SORT_BY_CANV_ELEMENT_ACT_BOTTOM, class=class="str">"cmt">// Sort by the bottom border of the form active area class=class="str">"cmt">//--- Sort by real properties class=class="str">"cmt">//--- Sort by class="type">class="kw">string properties SORT_BY_CANV_ELEMENT_NAME_OBJ = FIRST_CANV_ELEMENT_STR_PROP, class=class="str">"cmt">// Sort by the form object name SORT_BY_CANV_ELEMENT_NAME_RES, class=class="str">"cmt">// Sort by the graphical resource name }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| GBaseObj.mqh | class=class="str">"cmt">//| Copyright class="num">2021, MetaQuotes Ltd. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2021, MetaQuotes Ltd." class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#class="kw">property strict class=class="str">"cmt">// Necessary for mql4 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Include files | class=class="str">"cmt">//+------------------------------------------------------------------+