DoEasy 函数库中的图形(第七十六部分):会话窗对象和预定义的颜色主题(基础篇)
📘

DoEasy 函数库中的图形(第七十六部分):会话窗对象和预定义的颜色主题(基础篇)

第 1/3 篇

「给 DoEasy 加上会话窗与配色主题」

DoEasy 函数库在 2021-08-06 的更新里把会话窗(Session Window)对象和预定义颜色主题纳进了图形层,原文示例贴出时显示阅读量 1663、评论 0,说明这套封装当时还偏底层、少人踩坑。 对做多品种盯盘的交易者来说,会话窗本质是把「某品种可交易时段」画成可视矩形,配合颜色主题能一眼区分亚/欧/美盘活跃区,省掉自己算服务器时区偏移的麻烦。 在 MT5 里接这套库,重点不是背 API,而是先确认你加载的 DoEasy 版本带 Lib\Graph\CSessionWindow 与 ColorTheme 枚举;缺了这两个,后面画框代码直接编译报错。 外汇与贵金属保证金交易杠杆高、滑点随机,任何图形辅助都只是概率参考,别把时段框当成进出场信号本身。

从图形基元到会话窗的过渡设计

上一篇文章里已经把图形元素对象类打好了底,能画基础图元和文本。今天要做的,是把它当父类,派生出“会话窗对象”——这东西能独立承载控件和可视化呈现,不再只是零散的图元。 动手写会话窗之前,得先定 GUI 的设计路数:做一组起始颜色主题,以及图形对象的表现类型。很多带图形引擎的程序都允许用户热切换外观,我们也用主题机制来快速换肤,主题参数塞在独立库文件里,交易者或开发者改几行就能调色。 本文先落地两个主题,后续新对象和功能会不断往里加参数。你不强制用库里这套主题去建自定义对象,但它们是现成的参照样板,能看清后续对象该怎么搭。

◍ 给图形库对象加上可见性与阴影底座

做会话窗之前,先给 DoEasy 图形库打底:在 Data.mqh 里补了 3 条新消息索引(对象已在列表、取图形资源失败、加对象进列表失败),对应俄/英双语文本也一并写进数组,方便后续调试时直接打印。 会话窗打算在自身周围留 5 像素空白画阴影,所以 Defines.mqh 里加了一个宏表示单侧偏移量;同时把图形元素整数型属性枚举中两个用不到的搜索/排序属性踢掉,整数属性总数从 23 改成 21,基于画布的可能排序枚举也同步删掉两个常量。 可见性靠 OBJPROP_TIMEFRAMES 控制:传 OBJ_ALL_PERIODS 显示、传 0 隐藏,先隐后显就能把对象顶到前景。GBaseObj.mqh 的受保护段加了 m_visible 变量,公开段提供 SetVisible() 和 IsVisible(),构造函数里默认初始化为 false。 GCnvElement.mqh 里把删掉的属性挪到类私有变量存背景色和不透明度,并新增受保护参数构造函数(只收类型等基础参数)。亮暗调节走 ARGB→HSL 改 L 分量→回 RGB 的私有方法,change_value 范围 -1.0 到 1.0,传 0 原样返回。 阴影标志和图表背景色在默认构造函数初始化,移动前景复用父类的隐藏+显示。开 MT5 进 Include\DoEasy 对照改这几个文件,编译无报错即说明底座生效。

MQL5 / C++
  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
  MSG_LIB_SYS_OBJ_ALREADY_IN_LIST,                    class=class="str">"cmt">// Such an object is already present in the list
  MSG_LIB_SYS_FAILED_GET_DATA_GRAPH_RES,              class=class="str">"cmt">// Failed to receive graphical resource data
  MSG_LIB_SYS_FAILED_ADD_BUFFER,                      class=class="str">"cmt">// Failed to add buffer object to the list
  MSG_LIB_SYS_FAILED_CREATE_BUFFER_OBJ,               class=class="str">"cmt">// Failed to create "Indicator buffer" object
  MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST,                 class=class="str">"cmt">// Could not add object to the list
  {"Не удалось добавить символ ","Failed to add "},
  {"Не удалось создать объект-графический элемент ","Failed to create graphic element object "},
  {"Такой объект уже есть в списке","Such an object is already in the list"},
  {"Не удалось получить данные графического ресурса","Failed to get graphic resource data"},
  {"Не удалось добавить объект-буфер в список","Failed to add buffer object to list"},
  {"Не удалось создать объект \"Индикаторный буфер\"","Failed to create object \"Indicator buffer\""},
  {"Не удалось добавить объект в список","Failed to add object to the list"},
class=class="str">"cmt">//--- Parameters of the DOM snapshot series

「盘口快照与画布元素的底层常量」

做深度盘口(DOM)序列分析时,先得定死两个容量边界:默认只抓 1 天的盘口快照入库,单品种历史快照上限锁在 200000 帧。超出这个数老数据就会被循环覆盖,回测长周期密度前要先确认自己要的交易日数会不会撞这个天花板。 画布刷新率给了 16 毫秒一帧的节奏,基本贴着 MT5 主线程空闲 slot 走;外圈留白写死 5 像素,是为了鼠标命中区域不误触工作区。背景透明色用 0x00FFFFFF,Alpha 通道为零,叠在报价图上不会糊掉 K 线。 元素属性枚举里,除了 ID、类型、坐标、宽高这些常规整型字段,还单独开了 OPACITY 和 COLOR_BG 两个整型槽。意思很直接:透明度与背景色不走字符串配置,而是塞进同一套整数属性表,循环遍历元素时少一次类型判断。 开 MT5 把下面这段贴进头文件,改 OUTER_AREA_SIZE 到 8 看看面板边缘热区是不是更跟手,比读文档快。

MQL5 / C++
class="macro">#define MBOOKSERIES_DEFAULT_DAYS_COUNT(class="num">1)              class=class="str">"cmt">// The class="kw">default required number of days for DOM snapshots in the series
class="macro">#define MBOOKSERIES_MAX_DATA_TOTAL(class="num">200000)           class=class="str">"cmt">// Maximum number of stored DOM snapshots of a single symbol
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 NULL_COLOR(0x00FFFFFF)       class=class="str">"cmt">// Zero for the canvas with the alpha channel
class="macro">#define OUTER_AREA_SIZE(class="num">5)                class=class="str">"cmt">// Size of one side of the outer area around the workspace
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Enumerations                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
   CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,                     class=class="str">"cmt">// Active area offset from the bottom edge of the element
   CANV_ELEMENT_PROP_OPACITY,                              class=class="str">"cmt">// Element opacity
   CANV_ELEMENT_PROP_COLOR_BG,                             class=class="str">"cmt">// Element background class="type">class="kw">color
   CANV_ELEMENT_PROP_MOVABLE,                              class=class="str">"cmt">// Element moveability flag
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
  {
   CANV_ELEMENT_PROP_ID = class="num">0,                               class=class="str">"cmt">// Element 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">// Element width

画布元素的整数属性与排序枚举

在 MT5 自定义画布(Canvas)体系里,每个图形元素都有一组整数属性用来描述几何与交互边界。从 CANV_ELEMENT_PROP_HEIGHT 到 CANV_ELEMENT_PROP_ACTIVE,覆盖了元素高、右边界、底边界、活跃区四向偏移、是否可拖动、是否激活,以及活跃区坐标与右/下边界共 14 个字段。 代码里用宏固化了计数:CANV_ELEMENT_PROP_INTEGER_TOTAL 定义为 21,CANV_ELEMENT_PROP_INTEGER_SKIP 为 0,说明整数属性总量 21 个且全部参与排序索引,没有预留跳过位。 排序方式由 ENUM_SORT_CANV_ELEMENT_MODE 枚举承载,起点 SORT_BY_CANV_ELEMENT_ID = 0,向后延伸出按活跃区底偏移、不透明度、背景色、可拖动标志等排序模式。注意 SORT_BY_CANV_ELEMENT_OPACITY 与 SORT_BY_CANV_ELEMENT_COLOR_BG 虽归在整数属性段,实际指向的是元素的渲染层参数。 首个位移宏 FIRST_CANV_ELEMENT_DBL_PROP 与 FIRST_CANV_ELEMENT_STR_PROP 用整数总数减跳过数推算,当你要扩展双击属性或字符串属性时,直接改 CANV_ELEMENT_PROP_INTEGER_TOTAL 的值就能重排偏移基址,不用手动数行。

MQL5 / C++
  CANV_ELEMENT_PROP_HEIGHT,                                                                       class=class="str">"cmt">// Element height
  CANV_ELEMENT_PROP_RIGHT,                                                                       class=class="str">"cmt">// Element right border
  CANV_ELEMENT_PROP_BOTTOM,                                                                      class=class="str">"cmt">// Element bottom border
  CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,                                                              class=class="str">"cmt">// Active area offset from the left edge of the element
  CANV_ELEMENT_PROP_ACT_SHIFT_TOP,                                                               class=class="str">"cmt">// Active area offset from the upper edge of the element
  CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,                                                             class=class="str">"cmt">// Active area offset from the right edge of the element
  CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,                                                            class=class="str">"cmt">// Active area offset from the bottom edge of the element
  CANV_ELEMENT_PROP_MOVABLE,                                                                     class=class="str">"cmt">// Element moveability flag
  CANV_ELEMENT_PROP_ACTIVE,                                                                      class=class="str">"cmt">// Element activity flag
  CANV_ELEMENT_PROP_COORD_ACT_X,                                                                 class=class="str">"cmt">// X coordinate of the element active area
  CANV_ELEMENT_PROP_COORD_ACT_Y,                                                                 class=class="str">"cmt">// Y coordinate of the element active area
  CANV_ELEMENT_PROP_ACT_RIGHT,                                                                   class=class="str">"cmt">// Right border of the element active area
  CANV_ELEMENT_PROP_ACT_BOTTOM,                                                                  class=class="str">"cmt">// Bottom border of the element active area
  };
class="macro">#define CANV_ELEMENT_PROP_INTEGER_TOTAL(class="num">21)                                                     class=class="str">"cmt">// Total number of integer properties
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">//+------------------------------------------------------------------+
  SORT_BY_CANV_ELEMENT_ACT_SHIFT_BOTTOM,                                                         class=class="str">"cmt">// Sort by the active area offset from the bottom edge of the element
  SORT_BY_CANV_ELEMENT_OPACITY,                                                                  class=class="str">"cmt">// Sort by the element opacity
  SORT_BY_CANV_ELEMENT_COLOR_BG,                                                                 class=class="str">"cmt">// Sort by the element background class="type">class="kw">color
  SORT_BY_CANV_ELEMENT_MOVABLE,                                                                  class=class="str">"cmt">// Sort by the element moveability flag
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 element ID

◍ 画布元素排序枚举的字段全景

在 MT5 的图形库底层,画布元素(Canvas Element)有一组专门的排序枚举,用来决定遍历或命中检测时元素的前后顺序。上面这段枚举定义了从类型、列表序号到坐标、尺寸、激活区偏移等 22 个整型排序键,外加 2 个字符串属性排序键。 具体看,SORT_BY_CANV_ELEMENT_TYPE 到 SORT_BY_CANV_ELEMENT_ACTIVE 覆盖了元素的静态与状态属性:比如按图表 ID(SORT_BY_CANV_ELEMENT_CHART_ID)区分多图表实例,按 X/Y 坐标(SORT_BY_CANV_ELEMENT_COORD_X/Y)做空间排序,按 movable/active 标志过滤可交互对象。 字符串类排序从 SORT_BY_CANV_ELEMENT_NAME_OBJ = FIRST_CANV_ELEMENT_STR_PROP 开始,说明库把字符串属性排在整型属性之后,NAME_OBJ 对应元素对象名,NAME_RES 对应图形资源名。开 MT5 在 MetaEditor 里全局搜 SORT_BY_CANV_ELEMENT 就能看到完整定义,改排序键会直接影响鼠标拾取和重绘层级。 CGBaseObj 类继承自 CObject,private/protected 区为空壳,意味着具体元素类要在派生层补属性和方法。外汇与贵金属图表上叠加自绘画布时,排序键选错可能让点击热点落在隐藏层,这类界面 bug 在高频盯盘时尤其烦人。

MQL5 / C++
   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 element X coordinate on the chart
   SORT_BY_CANV_ELEMENT_COORD_Y,                                                 class=class="str">"cmt">// Sort by the element Y coordinate on the chart
   SORT_BY_CANV_ELEMENT_WIDTH,                                                   class=class="str">"cmt">// Sort by the element width
   SORT_BY_CANV_ELEMENT_HEIGHT,                                                  class=class="str">"cmt">// Sort by the element height
   SORT_BY_CANV_ELEMENT_RIGHT,                                                   class=class="str">"cmt">// Sort by the element right border
   SORT_BY_CANV_ELEMENT_BOTTOM,                                                  class=class="str">"cmt">// Sort by the element 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 element
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_TOP,                                           class=class="str">"cmt">// Sort by the active area offset from the top edge of the element
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_RIGHT,                                         class=class="str">"cmt">// Sort by the active area offset from the right edge of the element
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_BOTTOM,                                        class=class="str">"cmt">// Sort by the active area offset from the bottom edge of the element
   SORT_BY_CANV_ELEMENT_MOVABLE,                                                 class=class="str">"cmt">// Sort by the element moveability flag
   SORT_BY_CANV_ELEMENT_ACTIVE,                                                  class=class="str">"cmt">// Sort by the element activity flag
   SORT_BY_CANV_ELEMENT_COORD_ACT_X,                                             class=class="str">"cmt">// Sort by X coordinate of the element active area
   SORT_BY_CANV_ELEMENT_COORD_ACT_Y,                                             class=class="str">"cmt">// Sort by Y coordinate of the element active area
   SORT_BY_CANV_ELEMENT_ACT_RIGHT,                                               class=class="str">"cmt">// Sort by the right border of the element active area
   SORT_BY_CANV_ELEMENT_ACT_BOTTOM,                                              class=class="str">"cmt">// Sort by the bottom border of the element 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 an element 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">//| Class of the base object of the library graphical objects        |
class=class="str">"cmt">//+------------------------------------------------------------------+
class CGBaseObj : class="kw">public CObject
  {
class="kw">private:
class="kw">protected:

常见问题

在图形基元过渡到会话窗时,给对象基类补上可见性开关与底部阴影绘制方法,渲染前先判可见性再画阴影底座。
按元素类型、坐标基准、层级标记分别定义整数常量,集中放在头文件便于画布统一调用。
可以,小布能读取你的配色主题与排序枚举,提示重复层级或不可见元素被置顶这类问题。
至少包含元素ID、Z序值、所属会话窗编号、是否锁定,字段全景建议在枚举里一次列清。
常漏掉预定义颜色主题与可见性状态的绑定,导致切换主题时旧窗体残留或点不中。