English Русский Español Deutsch 日本語 Português
DoEasy 函数库中的图形(第九十部分):标准图形对象事件。 基本功能

DoEasy 函数库中的图形(第九十部分):标准图形对象事件。 基本功能

MetaTrader 5示例 | 28 二月 2022, 11:20
1 151 0
Artyom Trishkin
Artyom Trishkin

内容


概述

当操控客户端提供的图形对象时,我们可能需要以编程方式定义这些对象的一些属性值。 该程序可以跟踪图形对象轨迹线的值,并执行嵌入式算法,例如当该轨迹线与价格交叉时。 当终端用户移动图形对象时,轨迹线也许会移位。 相应地,该程序应针对此事件做出响应。 但是程序应该知道被跟踪的轨迹线数值已有变化,或者不断地测量图形对象属性的数值,这是一项资源密集型操作。 这一事实在帮助中得到了明确的说明。

它的功能能更便利地显示任何图形对象的任何变化。 这种功能在终端中的存在形式,是作为 OnChartEvent() 事件响应程序。 我们用若干个事件来补充它的工具箱,这些事件在我们的函数库中会厘清图形对象到底发生了什么。 由函数库控制的程序能够准确地知道图形对象发生了什么,以及哪些属性已被更改。

我们将需开发的功能分为两个阶段 — 首先,创建可能发生在图形对象上的一般事件。 接下来,添加厘清对象到底发生了什么的功能,并允许用户以编程方式快速搜索。 为创建这样的功能,几乎所有的东西都已准备就绪了。 我们所要做的就是稍微改进库类,并在事件处理程序中创建一个位置,在其中处理图形对象发生的事件。

基本图形对象事件定义如下:

  • 创建一个新的图形对象,
  • 更改图形对象属性,
  • 重命名一个图形对象,
  • 删除一个图形对象,
  • 将图形对象与图表窗口一起删除。

这些就是我将在本文中实现的事件。 它们将被发送到 OnChartEvent() 响应程序。 在下一篇文章中,我将实现针对每个事件的处理,从而我们能够确切地知道图形对象上哪些属性已经更改。

请注意,重命名图形对象,按说涉及到更改 Name 属性。 但我决定将其放在一个单独的事件中,以便简化处理,因为更改名称会导致一行中出现若干个事件 — 删除一个图形对象,创建一个新对象,并更改其属性。 所有这些状态都已在函数库中处理。 重命名事件计算正确。 故此,我们将它推送给以后处理该事件的程序来。

因此,删除图形对象当前允许我们准确地找出删除了哪个对象,并报告其名称。 不过,当删除包含图形对象的图表窗口时,我们仍然只能知道位于已删除图表上的图形对象数量。 目前,这两个事件只会通知我们已把图形对象删除。 也许,在将来,我会考虑记录已删除对象属性的必要。 目前,我还没见到实现这一功能的迫切需要性。


改进库类

为了跟踪图形对象的分配,我们需要为单击图形对象事件添加一个响应程序。 双击未选中的图形对象是选其进行编辑,而双击选定对象是取消已选中的对象。 为了在当前图表上处理这样一个对象事件,我们需要为事件响应程序添加一个新的事件 ID。 为了在其它图表上处理此类事件,我们需要改进事件控制指标,在每次新打开的图表窗口时自动设置。

打开指标文件 \MQL5\Indicators\DoEasy\EventControl.mq5,并添加要发送给图表上控制程序的新事件 ID

//+------------------------------------------------------------------+
//|                                                 EventControl.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property indicator_chart_window
#property indicator_plots 0
//--- input parameters
input long     InpChartSRC = 0;
input long     InpChartDST = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator shortname
   IndicatorSetString(INDICATOR_SHORTNAME,"EventSend_From#"+(string)InpChartSRC+"_To#"+(string)InpChartDST);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   return rates_total;
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id==CHARTEVENT_OBJECT_CHANGE || id==CHARTEVENT_OBJECT_DRAG || id==CHARTEVENT_OBJECT_CLICK)
     {
      EventChartCustom(InpChartDST,(ushort)id,InpChartSRC,dparam,sparam);
     }
  }
//+------------------------------------------------------------------+


在 \MQL5\Include\DoEasy\Data.mqh 里,添加新的消息索引:

//--- CGraphElementsCollection
   MSG_GRAPH_OBJ_FAILED_GET_ADDED_OBJ_LIST,           // Failed to get the list of newly added objects
   MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST,         // Failed to remove a graphical object from the list
   
   MSG_GRAPH_OBJ_CREATE_EVN_CTRL_INDICATOR,           // Indicator for controlling and sending events created
   MSG_GRAPH_OBJ_FAILED_CREATE_EVN_CTRL_INDICATOR,    // Failed to create the indicator for controlling and sending events
   MSG_GRAPH_OBJ_ADDED_EVN_CTRL_INDICATOR,            // Indicator for controlling and sending events successfully added to the chart
   MSG_GRAPH_OBJ_FAILED_ADD_EVN_CTRL_INDICATOR,       // Failed to add the indicator for controlling and sending events
   MSG_GRAPH_OBJ_CLOSED_CHARTS,                       // Chart windows closed:
   MSG_GRAPH_OBJ_OBJECTS_ON_CLOSED_CHARTS,            // Objects removed together with charts:
   MSG_GRAPH_OBJ_FAILED_CREATE_EVN_OBJ,               // Failed to create the event object for a graphical object
   MSG_GRAPH_OBJ_FAILED_ADD_EVN_OBJ,                  // Failed to add the event object to the list
   
   MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_CREATE,                // New graphical object created
   MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_CHANGE,                // Changed the graphical object property
   MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_RENAME,                // Graphical object renamed
   MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_DELETE,                // Graphical object removed
   MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_DEL_CHART,             // Graphical object removed together with the chart
   
  };
//+------------------------------------------------------------------+

以及与新添加的索引对应的消息文本

//--- CGraphElementsCollection
   {"Не удалось получить список вновь добавленных объектов","Failed to get the list of newly added objects"},
   {"Не удалось изъять графический объект из списка","Failed to detach graphic object from the list"},
   
   {"Создан индикатор контроля и отправки событий","An indicator for monitoring and sending events has been created"},
   {"Не удалось создать индикатор контроля и отправки событий","Failed to create indicator for monitoring and sending events"},
   {"Индикатор контроля и отправки событий успешно добавлен на график ","The indicator for monitoring and sending events has been successfully added to the chart"},
   {"Не удалось добавить индикатор контроля и отправки событий на график ","Failed to add the indicator of monitoring and sending events to the chart "},
   {"Закрыто окон графиков: ","Closed chart windows: "},
   {"С ними удалено объектов: ","Objects removed with them: "},
   {"Не удалось создать объект-событие для графического объекта","Failed to create event object for graphic object"},
   {"Не удалось добавить объект-событие в список","Failed to add event object to list"},
   
   {"Создан новый графический объект","New graphic object created"},
   {"Изменено свойство графического объекта","Changed graphic object property"},
   {"Графический объект переименован","Graphic object renamed"},
   {"Графический объект удалён","Graphic object deleted"},
   {"Графический объект удалён вместе с графиком","The graphic object has been removed along with the chart"},
   
  };
//+---------------------------------------------------------------------+


我们在 \MQL5\Include\DoEasy\Defines.mqh 中进行进行相应修改。

从可能的图形对象事件列表中删除对象重新定位事件,因为图形对象事件的枚举中已存在属性更改项:

//+------------------------------------------------------------------+
//| List of possible graphical object events                         |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_EVENT
  {
   GRAPH_OBJ_EVENT_NO_EVENT = CHART_OBJ_EVENTS_NEXT_CODE,// No event
   GRAPH_OBJ_EVENT_CREATE,                            // "Creating a new graphical object" event
   GRAPH_OBJ_EVENT_CHANGE,                            // "Changing graphical object properties" event
   GRAPH_OBJ_EVENT_MOVE,                              // "Moving graphical object" event
   GRAPH_OBJ_EVENT_RENAME,                            // "Renaming graphical object" event
   GRAPH_OBJ_EVENT_DELETE,                            // "Removing graphical object" event
  };

将一个新常数添加到列表中,这是删除图形对象和图表的事件:

//+------------------------------------------------------------------+
//| Data for handling graphical elements                             |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of possible graphical object events                         |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_EVENT
  {
   GRAPH_OBJ_EVENT_NO_EVENT = CHART_OBJ_EVENTS_NEXT_CODE,// No event
   GRAPH_OBJ_EVENT_CREATE,                            // "Creating a new graphical object" event
   GRAPH_OBJ_EVENT_CHANGE,                            // "Changing graphical object properties" event
   GRAPH_OBJ_EVENT_RENAME,                            // "Renaming graphical object" event
   GRAPH_OBJ_EVENT_DELETE,                            // "Removing graphical object" event
   GRAPH_OBJ_EVENT_DEL_CHART,                         // "Removing a graphical object together with the chart window" event
  };
#define GRAPH_OBJ_EVENTS_NEXT_CODE  (GRAPH_OBJ_EVENT_DEL_CHART+1) // The code of the next event after the last graphical object event code
//+------------------------------------------------------------------+

图形对象事件代码之后的下一个事件代码,现在会依据添加到枚举的最后一个值进行计算


在创建任何标准图形对象时,在其构造函数中,我们从图表上的物理对象读取数据,并将其写入类对象的相应属性。 一些图形对象属性被设置为所有图形对象的通用属性。 它们可以在每个对象中找到,并在所有函数库图形对象的基类中设置。

其算法如下:首先使用标准 ObjectGetXXX 函数(Integer, Double and String)从图形对象读取参数。 如果成功收到数据,这些参数将首先设置在 CGBaseObj 基准图形对象类的属性当中。 然后,在其衍生类的属性中设置它们。 对于标准图形对象,这是 CGStdGraphObj 类。

此处,我们面临着某种冲突。 我们已有设置图形对象参数的方法。 这些方法将传递给它们的属性值设置到图形对象本身和相应的类对象属性当中 — 使用 ObjectSetXXX(Integer, Double and String) 函数成功为图形对象设置参数的情况下。 但有时我们只需要将图形对象参数的已知值设置到类属性当中。 为了实现这一点,我们不需要再次读取该数值,也不需要将其指定给图形对象。 取而代之,我们应该简单地将其值赋予类变量。 函数库的基本图形对象的 Set 方法首先设置图形对象参数的值,然后将其写入类变量。 为了避免设置已知的图形对象属性,取代将其设置到类变量,而是在此类方法中添加 bool 变量 only_prop。 该变量表示该值仅需作为变量值设置,或设置为图形对象参数,或设置为类对象属性。 如果输入为 true,则参数首先作为类属性进行设置。 否则,该值将首先作为设置给图形对象。 类变量排在第二位。

在所有函数库图形对象的基准对象类 \MQL5\Include\DoEasy\objects\Graph\GBaseObj.mqh 中,将变量添加到类方法之中,并修改方法逻辑:

//--- Set the "Background object" flag
   bool              SetFlagBack(const bool flag,const bool only_prop)
                       {
                        ::ResetLastError();
                        if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_BACK,flag)) || only_prop)
                          {
                           this.m_back=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }

此处,如果变量为 false ,且属性已设置为图形对象或如果变量为 true则把传递给方法的值写入类变量当中

所有的类方法都以这种方式修改:

//--- Set the "Background object" flag
   bool              SetFlagBack(const bool flag,const bool only_prop)
                       {
                        ::ResetLastError();
                        if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_BACK,flag)) || only_prop)
                          {
                           this.m_back=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the "Object selection" flag
   bool              SetFlagSelected(const bool flag,const bool only_prop)
                       {
                        ::ResetLastError();
                        if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTED,flag)) || only_prop)
                          {
                           this.m_selected=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the "Object selection" flag
   bool              SetFlagSelectable(const bool flag,const bool only_prop)
                       {
                        ::ResetLastError();
                        if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag)) || only_prop)
                          {
                           this.m_selectable=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the "Disable displaying the name of a graphical object in the terminal object list" flag
   bool              SetFlagHidden(const bool flag,const bool only_prop)
                       {
                        ::ResetLastError();
                        if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag)) || only_prop)
                          {
                           this.m_hidden=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the priority of a graphical object for receiving the event of clicking on a chart 
   bool              SetZorder(const long value,const bool only_prop)
                       {
                        ::ResetLastError();
                        if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_ZORDER,value)) || only_prop)
                          {
                           this.m_zorder=value;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set object visibility on all timeframes
   bool              SetVisible(const bool flag,const bool only_prop)   
                       {
                        long value=(flag ? OBJ_ALL_PERIODS : OBJ_NO_PERIODS);
                        ::ResetLastError();
                        if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_TIMEFRAMES,value)) || only_prop)
                          {
                           this.m_visible=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set visibility flags on timeframes specified as flags
   bool              SetVisibleOnTimeframes(const int flags,const bool only_prop)
                       {
                        ::ResetLastError();
                        if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_TIMEFRAMES,flags)) || only_prop)
                          {
                           this.m_timeframes_visible=flags;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Add the visibility flag on a specified timeframe
   bool              SetVisibleOnTimeframe(const ENUM_TIMEFRAMES timeframe,const bool only_prop)
                       {
                        int flags=this.m_timeframes_visible;
                        switch(timeframe)
                          {
                           case PERIOD_M1    : flags |= OBJ_PERIOD_M1;  break;
                           case PERIOD_M2    : flags |= OBJ_PERIOD_M2;  break;
                           case PERIOD_M3    : flags |= OBJ_PERIOD_M3;  break;
                           case PERIOD_M4    : flags |= OBJ_PERIOD_M4;  break;
                           case PERIOD_M5    : flags |= OBJ_PERIOD_M5;  break;
                           case PERIOD_M6    : flags |= OBJ_PERIOD_M6;  break;
                           case PERIOD_M10   : flags |= OBJ_PERIOD_M10; break;
                           case PERIOD_M12   : flags |= OBJ_PERIOD_M12; break;
                           case PERIOD_M15   : flags |= OBJ_PERIOD_M15; break;
                           case PERIOD_M20   : flags |= OBJ_PERIOD_M20; break;
                           case PERIOD_M30   : flags |= OBJ_PERIOD_M30; break;
                           case PERIOD_H1    : flags |= OBJ_PERIOD_H1;  break;
                           case PERIOD_H2    : flags |= OBJ_PERIOD_H2;  break;
                           case PERIOD_H3    : flags |= OBJ_PERIOD_H3;  break;
                           case PERIOD_H4    : flags |= OBJ_PERIOD_H4;  break;
                           case PERIOD_H6    : flags |= OBJ_PERIOD_H6;  break;
                           case PERIOD_H8    : flags |= OBJ_PERIOD_H8;  break;
                           case PERIOD_H12   : flags |= OBJ_PERIOD_H12; break;
                           case PERIOD_D1    : flags |= OBJ_PERIOD_D1;  break;
                           case PERIOD_W1    : flags |= OBJ_PERIOD_W1;  break;
                           case PERIOD_MN1   : flags |= OBJ_PERIOD_MN1; break;
                           default           : return true;
                          }
                        ::ResetLastError();
                        if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_TIMEFRAMES,flags)) || only_prop)
                          {
                           this.m_timeframes_visible=flags;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }

现在我们能够选择如何填写属性了 — 要么作为图形对象和类变量的一个新属性(使其对应于一个新设置的值);要么作为类变量为其设置已知的图形对象参数值(就像创建新图形对象时在类构造函数中所做的那样)。 如此我们能够避免过度访问速度较慢的函数,因其处理图形对象时需保持同步。

在 \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh 里,修复改进后方法的调用:

//--- Return (1) the element ID, (2) element index in the list, (3) flag of the form shadow presence and (4) the chart background color
   int               ID(void)                            const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ID);                   }
   int               Number(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_NUM);                  }
   bool              IsShadow(void)                      const { return this.m_shadow;                                                 }
   color             ChartColorBackground(void)          const { return this.m_chart_color_bg;                                         }
//--- Set the object above all
   void              BringToTop(void)                          { CGBaseObj::SetVisible(false,false); CGBaseObj::SetVisible(true,false);}
//--- (1) Show and (2) hide the element
   virtual void      Show(void)                                { CGBaseObj::SetVisible(true,false);                                    }
   virtual void      Hide(void)                                { CGBaseObj::SetVisible(false,false);                                   }
   
//+------------------------------------------------------------------+
//| The methods of receiving raster data                             |
//+------------------------------------------------------------------+

在 \MQL5\Include\DoEasy\Objects\Graph\Form.mqh 里,修复两个方法:

//+------------------------------------------------------------------+
//| Create the shadow object                                         |
//+------------------------------------------------------------------+
void CForm::CreateShadowObj(const color colour,const uchar opacity)
  {
//--- If the shadow flag is disabled or the shadow object already exists, exit
   if(!this.m_shadow || this.m_shadow_obj!=NULL)
      return;

//--- Calculate the shadow object coordinates according to the offset from the top and left
   int x=this.CoordX()-OUTER_AREA_SIZE;
   int y=this.CoordY()-OUTER_AREA_SIZE;
//--- Calculate the width and height in accordance with the top, bottom, left and right offsets
   int w=this.Width()+OUTER_AREA_SIZE*2;
   int h=this.Height()+OUTER_AREA_SIZE*2;
//--- Create a new shadow object and set the pointer to it in the variable
   this.m_shadow_obj=new CShadowObj(this.ChartID(),this.SubWindow(),this.CreateNameDependentObject("Shadow"),x,y,w,h);
   if(this.m_shadow_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_SHADOW_OBJ));
      return;
     }
//--- Set the properties for the created shadow object
   this.m_shadow_obj.SetID(this.ID());
   this.m_shadow_obj.SetNumber(-1);
   this.m_shadow_obj.SetOpacityShadow(opacity);
   this.m_shadow_obj.SetColorShadow(colour);
   this.m_shadow_obj.SetMovable(true);
   this.m_shadow_obj.SetActive(false);
   this.m_shadow_obj.SetVisible(false,false);
//--- Move the form object to the foreground
   this.BringToTop();
  }
//+------------------------------------------------------------------+
//| Draw the shadow                                                  |
//+------------------------------------------------------------------+
void CForm::DrawShadow(const int shift_x,const int shift_y,const color colour,const uchar opacity=127,const uchar blur=4)
  {
//--- If the shadow flag is disabled, exit
   if(!this.m_shadow)
      return;
//--- If there is no shadow object, create it
   if(this.m_shadow_obj==NULL)
      this.CreateShadowObj(colour,opacity);
//--- If the shadow object exists, draw the shadow on it,
//--- set the shadow object visibility flag and
//--- move the form object to the foreground
   if(this.m_shadow_obj!=NULL)
     {
      this.m_shadow_obj.DrawShadow(shift_x,shift_y,blur);
      this.m_shadow_obj.SetVisible(true,false);
      this.BringToTop();
     }
  }
//+------------------------------------------------------------------+


在标准图形对象类中,令所有设置图形对象属性的方法都返回布尔类型值(当前,这些方法不返回任何值,且为 void 类型)。 这是必要的,如此相应父类方法在子类中可重载同样 bool 返回类型的方法。 在这种情况下,我们在编写代码时可以避免混淆,因为提示不包含来自基准对象的 bool 类型,和来自其衍生后代的 void 类型两种方法。

我们以设置子窗口索引的方法为例进行研究:

//--- Chart subwindow index
   int               SubWindow(void)               const { return (int)this.GetProperty(GRAPH_OBJ_PROP_WND_NUM,0);                        }
   bool              SetSubWindow(void)
                       {
                        if(!CGBaseObj::SetSubwindow(CGBaseObj::ChartID(),CGBaseObj::Name()))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_WND_NUM,0,CGBaseObj::SubWindow());
                        return true;
                       }

由于子窗口索引是通过图表 ID 和对象名称来搜索的,基准对象中已经设置的图表 ID 和图形对象名称被简单地传递给设置子窗口索引的基类方法如果基准对象中设置数值失败,则返回 false否则在对象属性里设置基准对象中设置的新值,并返回 true

我们以在所有时间帧中设置对象可见性的方法为例进行研究

//--- Object visibility on timeframes
   bool              Visible(void)                 const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0);                    }
   bool              SetFlagVisible(const bool flag,const bool only_prop)
                       {
                        if(!CGBaseObj::SetVisible(flag,only_prop))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0,flag);
                        return true;
                       }

此处,该方法接收一个新参数,我之前添加这个参数是为了指定某参数应设置的类型 — 仅对象属性,或图形对象参数和类属性。 接下来,将这些属性设置为基准对象如果失败,则返回 false
否则,在类对象属性里填写数值,并返回 true

所有其它方法的修改与上述方法雷同:

//--- Background object
   bool              Back(void)                    const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_BACK,0);                          }
   bool              SetFlagBack(const bool flag,const bool only_prop)
                       {
                        if(!CGBaseObj::SetFlagBack(flag,only_prop))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_BACK,0,flag);
                        return true;
                       }
//--- Priority of a graphical object for receiving the event of clicking on a chart
   long              Zorder(void)                  const { return this.GetProperty(GRAPH_OBJ_PROP_ZORDER,0);                              }
   bool              SetZorder(const long value,const bool only_prop)
                       {
                        if(!CGBaseObj::SetZorder(value,only_prop))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_ZORDER,0,value);
                        return true;
                       }
//--- Disable displaying the name of a graphical object in the terminal object list
   bool              Hidden(void)                  const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_HIDDEN,0);                        }
   bool              SetFlagHidden(const bool flag,const bool only_prop)
                       {
                        if(!CGBaseObj::SetFlagHidden(flag,only_prop))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_HIDDEN,0,flag);
                        return true;
                       }
//--- Object selection
   bool              Selected(void)                const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTED,0);                      }
   bool              SetFlagSelected(const bool flag,const bool only_prop)
                       {
                        if(!CGBaseObj::SetFlagSelected(flag,only_prop))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_SELECTED,0,flag);
                        return true;
                       }
//--- Object availability
   bool              Selectable(void)              const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTABLE,0);                    }
   bool              SetFlagSelectable(const bool flag,const bool only_prop)
                       {
                        if(!CGBaseObj::SetFlagSelectable(flag,only_prop))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_SELECTABLE,0,flag);
                        return true;
                       }
//--- Time coordinate
   datetime          Time(const int modifier)      const { return (datetime)this.GetProperty(GRAPH_OBJ_PROP_TIME,modifier);               }
   bool              SetTime(const datetime time,const int modifier)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_TIME,modifier,time))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_TIME,modifier,time);
                        return true;
                       }
//--- Color
   color             Color(void)                   const { return (color)this.GetProperty(GRAPH_OBJ_PROP_COLOR,0);                        }
   bool              SetColor(const color colour)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_COLOR,colour))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_COLOR,0,colour);
                        return true;
                       }
//--- Style
   ENUM_LINE_STYLE   Style(void)                   const { return (ENUM_LINE_STYLE)this.GetProperty(GRAPH_OBJ_PROP_STYLE,0);              }
   bool              SetStyle(const ENUM_LINE_STYLE style)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_STYLE,style))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_STYLE,0,style);
                        return true;
                       }
//--- Line width
   int               Width(void)                   const { return (int)this.GetProperty(GRAPH_OBJ_PROP_WIDTH,0);                          }
   bool              SetWidth(const int width)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_WIDTH,width))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_WIDTH,0,width);
                        return true;
                       }
//--- Object color filling
   bool              Fill(void)                    const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_FILL,0);                          }
   bool              SetFlagFill(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_FILL,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_FILL,0,flag);
                        return true;
                       }
//--- Ability to edit text in the Edit object
   bool              ReadOnly(void)                const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_READONLY,0);                      }
   bool              SetFlagReadOnly(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_READONLY,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_READONLY,0,flag);
                        return true;
                       }
//--- Number of levels
   int               Levels(void)                  const { return (int)this.GetProperty(GRAPH_OBJ_PROP_LEVELS,0);                         }
   bool              SetLevels(const int levels)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELS,levels))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_LEVELS,0,levels);
                        return true;
                       }
//--- Line level color
   color             LevelColor(const int modifier)   const { return (color)this.GetProperty(GRAPH_OBJ_PROP_LEVELCOLOR,modifier);         }
   bool              SetLevelColor(const color colour,const int modifier)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELCOLOR,modifier,colour))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_LEVELCOLOR,modifier,colour);
                        return true;
                       }
//--- Level line style
   ENUM_LINE_STYLE   LevelStyle(const int modifier)const { return (ENUM_LINE_STYLE)this.GetProperty(GRAPH_OBJ_PROP_LEVELSTYLE,modifier);  }
   bool              SetLevelStyle(const ENUM_LINE_STYLE style,const int modifier)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELSTYLE,modifier,style))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_LEVELSTYLE,modifier,style);
                        return true;
                       }
///--- Level line width
   int               LevelWidth(const int modifier)const { return (int)this.GetProperty(GRAPH_OBJ_PROP_LEVELWIDTH,modifier);              }
   bool              SetLevelWidth(const int width,const int modifier)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELWIDTH,modifier,width))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_LEVELWIDTH,modifier,width);
                        return true;
                       }
//--- Horizontal text alignment in the Edit object (OBJ_EDIT)
   ENUM_ALIGN_MODE   Align(void)                   const { return (ENUM_ALIGN_MODE)this.GetProperty(GRAPH_OBJ_PROP_ALIGN,0);              }
   bool              SetAlign(const ENUM_ALIGN_MODE align)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ALIGN,align))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_ALIGN,0,align);
                        return true;
                       }
//--- Font size
   int               FontSize(void)                const { return (int)this.GetProperty(GRAPH_OBJ_PROP_FONTSIZE,0);                       }
   bool              SetFontSize(const int size)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_FONTSIZE,size))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_FONTSIZE,0,size);
                        return true;
                       }
//--- Ray goes to the left
   bool              RayLeft(void)                 const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_RAY_LEFT,0);                      }
   bool              SetFlagRayLeft(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_RAY_LEFT,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_RAY_LEFT,0,flag);
                        return true;
                       }
//--- Ray goes to the right
   bool              RayRight(void)                const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_RAY_RIGHT,0);                     }
   bool              SetFlagRayRight(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_RAY_RIGHT,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_RAY_RIGHT,0,flag);
                        return true;
                       }
//--- Vertical line goes through all windows of a chart
   bool              Ray(void)                     const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_RAY,0);                           }
   bool              SetFlagRay(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_RAY,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_RAY,0,flag);
                        return true;
                       }
//--- Display the full ellipse of the Fibonacci Arc object
   bool              Ellipse(void)                 const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_ELLIPSE,0);                       }
   bool              SetFlagEllipse(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ELLIPSE,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_ELLIPSE,0,flag);
                        return true;
                       }
//--- Arrow code for the "Arrow" object
   uchar             ArrowCode(void)               const { return (uchar)this.GetProperty(GRAPH_OBJ_PROP_ARROWCODE,0);                    }
   bool              SetArrowCode(const uchar code)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ARROWCODE,code))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_ARROWCODE,0,code);
                        return true;
                       }
//--- Position of the graphical object anchor point
   int               Anchor(void)                  const { return (int)this.GetProperty(GRAPH_OBJ_PROP_ANCHOR,0);                         }
   bool              SetAnchor(const int anchor)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ANCHOR,anchor))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_ANCHOR,0,anchor);
                        return true;
                       }
//--- Distance from the base corner along the X axis in pixels
   int               XDistance(void)               const { return (int)this.GetProperty(GRAPH_OBJ_PROP_XDISTANCE,0);                      }
   bool              SetXDistance(const int distance)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_XDISTANCE,distance))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_XDISTANCE,0,distance);
                        return true;
                       }
//--- Distance from the base corner along the Y axis in pixels
   int               YDistance(void)               const { return (int)this.GetProperty(GRAPH_OBJ_PROP_YDISTANCE,0);                      }
   bool              SetYDistance(const int distance)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_YDISTANCE,distance))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_YDISTANCE,0,distance);
                        return true;
                       }
//--- Gann object trend
   ENUM_GANN_DIRECTION Direction(void)             const { return (ENUM_GANN_DIRECTION)this.GetProperty(GRAPH_OBJ_PROP_DIRECTION,0);      }
   bool              SetDirection(const ENUM_GANN_DIRECTION direction)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DIRECTION,direction))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_DIRECTION,0,direction);
                        return true;
                       }
//--- Elliott wave marking level
   ENUM_ELLIOT_WAVE_DEGREE Degree(void)            const { return (ENUM_ELLIOT_WAVE_DEGREE)this.GetProperty(GRAPH_OBJ_PROP_DEGREE,0);     }
   bool              SetDegree(const ENUM_ELLIOT_WAVE_DEGREE degree)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DEGREE,degree))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_DEGREE,0,degree);
                        return true;
                       }
//--- Display lines for Elliott wave marking
   bool              DrawLines(void)               const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_DRAWLINES,0);                     }
   bool              SetFlagDrawLines(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DRAWLINES,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_DRAWLINES,0,flag);
                        return true;
                       }
//--- Button state (pressed/released)
   bool              State(void)                   const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_STATE,0);                         }
   bool              SetFlagState(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_STATE,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_STATE,0,flag);
                        return true;
                       }
//--- Chart object ID (OBJ_CHART)
   long              ChartObjChartID(void)         const { return this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_ID,0);                  }
   bool              SetChartObjChartID(const long chart_id)
                       {
                        this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_ID,0,chart_id);
                        return true;
                       }
//--- Chart object period
   ENUM_TIMEFRAMES   ChartObjPeriod(void)          const { return (ENUM_TIMEFRAMES)this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PERIOD,0);   }
   bool              SetChartObjPeriod(const ENUM_TIMEFRAMES timeframe)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_PERIOD,timeframe))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PERIOD,0,timeframe);
                        return true;
                       }
//--- Time scale display flag for the Chart object
   bool              ChartObjDateScale(void)       const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE,0);          }
   bool              SetFlagChartObjDateScale(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DATE_SCALE,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE,0,flag);
                        return true;
                       }
//--- Price scale display flag for the Chart object
   bool              ChartObjPriceScale(void)      const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE,0);         }
   bool              SetFlagPriceScale(const bool flag)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_PRICE_SCALE,flag))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE,0,flag);
                        return true;
                       }
//--- Chart object scale
   int               ChartObjChartScale(void)      const { return (int)this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE,0);          }
   bool              SetChartObjChartScale(const int scale)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_CHART_SCALE,scale))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE,0,scale);
                        return true;
                       }
//--- Object width along the X axis in pixels
   int               XSize(void)                   const { return (int)this.GetProperty(GRAPH_OBJ_PROP_XSIZE,0);                          }
   bool              SetXSize(const int size)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_XSIZE,size))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_XSIZE,0,size);
                        return true;
                       }
//--- Object height along the Y axis in pixels
   int               YSize(void)                   const { return (int)this.GetProperty(GRAPH_OBJ_PROP_YSIZE,0);                          }
   bool              SetYSize(const int size)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_YSIZE,size))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_YSIZE,0,size);
                        return true;
                       }
//--- X coordinate of the upper-left corner of the visibility area
   int               XOffset(void)                 const { return (int)this.GetProperty(GRAPH_OBJ_PROP_XOFFSET,0);                        }
   bool              SetXOffset(const int offset)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_XOFFSET,offset))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_XOFFSET,0,offset);
                        return true;
                       }
//--- Y coordinate of the upper-left corner of the visibility area
   int               YOffset(void)                 const { return (int)this.GetProperty(GRAPH_OBJ_PROP_YOFFSET,0);                        }
   bool              SetYOffset(const int offset)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_YOFFSET,offset))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_YOFFSET,0,offset);
                        return true;
                       }
//--- Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
   color             BGColor(void)                 const { return (color)this.GetProperty(GRAPH_OBJ_PROP_BGCOLOR,0);                      }
   bool              SetBGColor(const color colour)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_BGCOLOR,colour))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_BGCOLOR,0,colour);
                        return true;
                       }
//--- Chart corner for attaching a graphical object
   ENUM_BASE_CORNER  Corner(void)                  const { return (ENUM_BASE_CORNER)this.GetProperty(GRAPH_OBJ_PROP_CORNER,0);            }
   bool              SetCorner(const ENUM_BASE_CORNER corner)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_CORNER,corner))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_CORNER,0,corner);
                        return true;
                       }
//--- Border type for the Rectangle label object
   ENUM_BORDER_TYPE  BorderType(void)              const { return (ENUM_BORDER_TYPE)this.GetProperty(GRAPH_OBJ_PROP_BORDER_TYPE,0);       }
   bool              SetBorderType(const ENUM_BORDER_TYPE type)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_BORDER_TYPE,type))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_BORDER_TYPE,0,type);
                        return true;
                       }
//--- Border color for OBJ_EDIT and OBJ_BUTTON
   color             BorderColor(void)             const { return (color)this.GetProperty(GRAPH_OBJ_PROP_BORDER_COLOR,0);                 }
   bool              SetBorderColor(const color colour)
                       {
                        if(!::ObjectSetInteger(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_BORDER_COLOR,colour))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_BORDER_COLOR,0,colour);
                        return true;
                       }

//--- Price coordinate
   double            Price(const int modifier)     const { return this.GetProperty(GRAPH_OBJ_PROP_PRICE,modifier);                        }
   bool              SetPrice(const double price,const int modifier)
                       {
                        if(!::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_PRICE,modifier,price))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_PRICE,modifier,price);
                        return true;
                       }
//--- Level value
   double            LevelValue(const int modifier)const { return this.GetProperty(GRAPH_OBJ_PROP_LEVELVALUE,modifier);                   }
   bool              SetLevelValue(const double value,const int modifier)
                       {
                        if(!::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELVALUE,modifier,value))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_LEVELVALUE,modifier,value);
                        return true;
                       }
//--- Scale
   double            Scale(void)                   const { return this.GetProperty(GRAPH_OBJ_PROP_SCALE,0);                               }
   bool              SetScale(const double scale)
                       {
                        if(!::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_SCALE,scale))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_SCALE,0,scale);
                        return true;
                       }
//--- Angle
   double            Angle(void)                   const { return this.GetProperty(GRAPH_OBJ_PROP_ANGLE,0);                               }
   bool              SetAngle(const double angle)
                       {
                        if(!::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_ANGLE,angle))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_ANGLE,0,angle);
                        return true;
                       }
//--- Deviation of the standard deviation channel
   double            Deviation(void)               const { return this.GetProperty(GRAPH_OBJ_PROP_DEVIATION,0);                           }
   bool              SetDeviation(const double deviation)
                       {
                        if(!::ObjectSetDouble(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_DEVIATION,deviation))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_DEVIATION,0,deviation);
                        return true;
                       }

//--- Object name
   string            Name(void)                    const { return this.GetProperty(GRAPH_OBJ_PROP_NAME,0);                                }
   bool              SetName(const string name)
                       {
                        if(CGBaseObj::Name()==name)
                           return true;
                        if(CGBaseObj::Name()=="")
                          {
                           CGBaseObj::SetName(name);
                           this.SetProperty(GRAPH_OBJ_PROP_NAME,0,name);
                           return true;
                          }
                        else
                          {
                           if(!::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_NAME,name))
                              return false;
                           CGBaseObj::SetName(name);
                           this.SetProperty(GRAPH_OBJ_PROP_NAME,0,name);
                           return true;
                          }
                       }
//--- Object description (text contained in the object)
   string            Text(void)                    const { return this.GetProperty(GRAPH_OBJ_PROP_TEXT,0);                                }
   bool              SetText(const string text)
                       {
                        if(!::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_TEXT,text))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_TEXT,0,text);
                        return true;
                       }
//--- Tooltip text
   string            Tooltip(void)                 const { return this.GetProperty(GRAPH_OBJ_PROP_TOOLTIP,0);                             }
   bool              SetTooltip(const string tooltip)
                       {
                        if(!::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_TOOLTIP,tooltip))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_TOOLTIP,0,tooltip);
                        return true;
                       }
//--- Level description
   string            LevelText(const int modifier) const { return this.GetProperty(GRAPH_OBJ_PROP_LEVELTEXT,modifier);                    }
   bool              SetLevelText(const string text,const int modifier)
                       {
                        if(!::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_LEVELTEXT,modifier,text))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_LEVELTEXT,modifier,text);
                        return true;
                       }
//--- Font
   string            Font(void)                    const { return this.GetProperty(GRAPH_OBJ_PROP_FONT,0);                                }
   bool              SetFont(const string font)
                       {
                        if(!::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_FONT,font))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_FONT,0,font);
                        return true;
                       }
//--- BMP file name for the "Bitmap Level" object
   string            BMPFile(const int modifier)   const { return this.GetProperty(GRAPH_OBJ_PROP_BMPFILE,modifier);                      }
   bool              SetBMPFile(const string bmp_file,const int modifier)
                       {
                        if(!::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_BMPFILE,bmp_file))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_BMPFILE,modifier,bmp_file);
                        return true;
                       }
//--- Symbol for the Chart object 
   string            ChartObjSymbol(void)          const { return this.GetProperty(GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL,0);                    }
   bool              SetChartObjSymbol(const string symbol)
                       {
                        if(!::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_SYMBOL,symbol))
                           return false;
                        this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL,0,symbol);
                        return true;
                       }

在接收和保存整数型属性的方法中,首先在基准对象中把数据写入基本对象属性。 接下来,将该对象的值填写到图形对象类属性当中:

//+------------------------------------------------------------------+
//| Get and save the integer properties                              |
//+------------------------------------------------------------------+
void CGStdGraphObj::GetAndSaveINT(void)
  {
   //--- Properties inherent in all graphical objects and present in a graphical object
   CGBaseObj::SetVisibleOnTimeframes((int)::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_TIMEFRAMES),true);   // Write Object visibility on timeframes to the base object
   CGBaseObj::SetFlagBack(::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_BACK),true);                         // Write Background object flag to the base object
   CGBaseObj::SetZorder(::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ZORDER),true);                         // Write Priority of a graphical object for receiving the event of clicking on a chart to the base object
   CGBaseObj::SetFlagHidden(::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_HIDDEN),true);                     // Write Disable displaying the name of a graphical object in the terminal object list to the base object
   CGBaseObj::SetFlagSelectable(::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_SELECTABLE),true);             // Write Object availability to the base object
   CGBaseObj::SetFlagSelected(::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_SELECTED),true);                 // Write Object selection to the base object
   
   this.SetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0,CGBaseObj::VisibleOnTimeframes());                                   // Object visibility on timeframes
   this.SetProperty(GRAPH_OBJ_PROP_BACK,0,CGBaseObj::IsBack());                                                      // Background object
   this.SetProperty(GRAPH_OBJ_PROP_ZORDER,0,CGBaseObj::Zorder());                                                    // Priority of a graphical object for receiving the event of clicking on a chart
   this.SetProperty(GRAPH_OBJ_PROP_HIDDEN,0,CGBaseObj::IsHidden());                                                  // Disable displaying the name of a graphical object in the terminal object list
   this.SetProperty(GRAPH_OBJ_PROP_SELECTABLE,0,CGBaseObj::IsSelectable());                                          // Object availability
   this.SetProperty(GRAPH_OBJ_PROP_SELECTED,0,CGBaseObj::IsSelected());                                              // Object selection
   
   this.SetProperty(GRAPH_OBJ_PROP_CREATETIME,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_CREATETIME));  // Object creation time
   for(int i=0;i<this.m_pivots;i++)                                                                                  // Point time coordinates
      this.SetTimePivot(i);
   this.SetProperty(GRAPH_OBJ_PROP_COLOR,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_COLOR));            // Color
   this.SetProperty(GRAPH_OBJ_PROP_STYLE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_STYLE));            // Style
   this.SetProperty(GRAPH_OBJ_PROP_WIDTH,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_WIDTH));            // Line width
   //--- Properties belonging to different graphical objects
   this.SetProperty(GRAPH_OBJ_PROP_FILL,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_FILL));              // Fill an object with color
   this.SetProperty(GRAPH_OBJ_PROP_READONLY,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_READONLY));      // Ability to edit text in the Edit object
   this.SetProperty(GRAPH_OBJ_PROP_LEVELS,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_LEVELS));          // Number of levels
   
   if(this.GetProperty(GRAPH_OBJ_PROP_LEVELS,0)!=this.GetPropertyPrev(GRAPH_OBJ_PROP_LEVELS,0))                      // Check if the number of levels has changed
     {
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELCOLOR,this.Levels());
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELSTYLE,this.Levels());
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELWIDTH,this.Levels());
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELVALUE,this.Levels());
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELTEXT,this.Levels());
     }
   for(int i=0;i<this.Levels();i++)                                                                                  // Level data
     {
      this.SetLevelColor(i);
      this.SetLevelStyle(i);
      this.SetLevelWidth(i);
     }
   this.SetProperty(GRAPH_OBJ_PROP_ALIGN,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ALIGN));            // Horizontal text alignment in the Edit object (OBJ_EDIT)
   this.SetProperty(GRAPH_OBJ_PROP_FONTSIZE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_FONTSIZE));      // Font size
   this.SetProperty(GRAPH_OBJ_PROP_RAY_LEFT,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_RAY_LEFT));      // Ray goes to the left
   this.SetProperty(GRAPH_OBJ_PROP_RAY_RIGHT,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_RAY_RIGHT));    // Ray goes to the right
   this.SetProperty(GRAPH_OBJ_PROP_RAY,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_RAY));                // Vertical line goes through all windows of a chart
   this.SetProperty(GRAPH_OBJ_PROP_ELLIPSE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ELLIPSE));        // Display the full ellipse of the Fibonacci Arc object
   this.SetProperty(GRAPH_OBJ_PROP_ARROWCODE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ARROWCODE));    // Arrow code for the "Arrow" object
   this.SetProperty(GRAPH_OBJ_PROP_ANCHOR,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ANCHOR));          // Position of the binding point of the graphical object
   this.SetProperty(GRAPH_OBJ_PROP_XDISTANCE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_XDISTANCE));    // Distance from the base corner along the X axis in pixels
   this.SetProperty(GRAPH_OBJ_PROP_YDISTANCE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_YDISTANCE));    // Distance from the base corner along the Y axis in pixels
   this.SetProperty(GRAPH_OBJ_PROP_DIRECTION,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_DIRECTION));    // Gann object trend
   this.SetProperty(GRAPH_OBJ_PROP_DEGREE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_DEGREE));          // Elliott wave marking level
   this.SetProperty(GRAPH_OBJ_PROP_DRAWLINES,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_DRAWLINES));    // Display lines for Elliott wave marking
   this.SetProperty(GRAPH_OBJ_PROP_STATE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_STATE));            // Button state (pressed/released)
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_ID,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_CHART_ID));// Chart object ID (OBJ_CHART).
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PERIOD,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_PERIOD));    // Chart object period
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_DATE_SCALE));  // Time scale display flag for the Chart object
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_PRICE_SCALE));// Price scale display flag for the Chart object
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_CHART_SCALE));// Chart object scale
   this.SetProperty(GRAPH_OBJ_PROP_XSIZE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_XSIZE));            // Object width along the X axis in pixels.
   this.SetProperty(GRAPH_OBJ_PROP_YSIZE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_YSIZE));            // Object height along the Y axis in pixels.
   this.SetProperty(GRAPH_OBJ_PROP_XOFFSET,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_XOFFSET));        // X coordinate of the upper-left corner of the visibility area.
   this.SetProperty(GRAPH_OBJ_PROP_YOFFSET,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_YOFFSET));        // Y coordinate of the upper-left corner of the visibility area.
   this.SetProperty(GRAPH_OBJ_PROP_BGCOLOR,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_BGCOLOR));        // Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
   this.SetProperty(GRAPH_OBJ_PROP_CORNER,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_CORNER));          // Chart corner for binding a graphical object
   this.SetProperty(GRAPH_OBJ_PROP_BORDER_TYPE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_BORDER_TYPE));// Border type for "Rectangle border"
   this.SetProperty(GRAPH_OBJ_PROP_BORDER_COLOR,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_BORDER_COLOR));// Border color for OBJ_EDIT and OBJ_BUTTON
  }
//+------------------------------------------------------------------+

因此,我们填充基类及其衍生子类中复制的所有属性。 否则,在接收对象属性时,我们应采用基准对象方法。 它们当中不会填写图形对象数据。

在创建用于跟踪标准图形对象事件的功能时,我将留下一些改进供考虑。


标准图形对象事件

处理图形对象事件的逻辑基于以下概念:我们能够定义对象属性发生的任何事件。 我们来创建一个小型图形对象基事件类。 当定义任何图形对象事件时,将创建一个新的事件对象,该对象将接收:

  • 事件 ID,
  • 包含发生图形对象事件的图表 ID,
  • 发生事件的对象名称。

发送自定义事件至指定图表的函数 EventChartCustom() 有五个参数:

//+------------------------------------------------------------------+
bool  EventChartCustom(
   long    chart_id,            // event receiving chart ID
   ushort  custom_event_id,     // event ID
   long    lparam,              // long parameter
   double  dparam,              // double parameter
   string  sparam               // event string parameter
   );
//+------------------------------------------------------------------+

对于图形对象事件 id,要填写 custom_event_id;对于包含发生图形对象事件的图表 id 是 lparam;对于图形对象名称则是 sparam。 我们还有一个自由参数 dparam。 我们将用其来指定更改后的属性常量值,或者在关闭图表窗口时同时删除的图形对象数量。

将为每个对象事件创建一个事件对象(并在事件列表中设置)。 在检查对象属性的变化之后,我们将获得图形对象发生的所有事件的完整列表。 在完成所有对象属性的验证后,我们将沿着新创建的事件列表移动,将每个事件发送到控制程序图表,在该图表中,图形元素集合类的 OnChartEvent() 事件响应程序方法将依次被调用。 响应程序能够处理发送自所创建图形对象事件列表中的每个事件。 相应地,每个这样的事件都包含事件 ID、修改的图形对象所在图表的 ID、及其名称。 这样就可精确地定义图形对象,而将准确地指向需更改的属性,如此我们就能够获得集合中对象的指针,并读取已更改属性的新值。 所有这些都允许我们准确地指向图形对象本身和其已更改属性,从而依据其固有逻辑进一步在程序中处理事件。

在本文中,我只实现创建事件,并将它们发送给图形对象集合事件的响应程序。 这些事件将在下一篇文章中把它们分解为组件。

在基准图形对象文件 \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh 的最开始处,添加图形库对象的基准事件新类:

//+------------------------------------------------------------------+
//|                                                     GBaseObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\DELib.mqh"
#include <Graphics\Graphic.mqh>
//+------------------------------------------------------------------+
//| Graphical object event class                                     |
//+------------------------------------------------------------------+
class CGBaseEvent : public CObject
  {
private:
   ushort            m_id;
   long              m_lparam;
   double            m_dparam;
   string            m_sparam;
public:
   void              ID(ushort id)                          { this.m_id=id;         }
   ushort            ID(void)                         const { return this.m_id;     }
   void              LParam(const long value)               { this.m_lparam=value;  }
   long              Lparam(void)                     const { return this.m_lparam; }
   void              DParam(const double value)             { this.m_dparam=value;  }
   double            Dparam(void)                     const { return this.m_dparam; }
   void              SParam(const string value)             { this.m_sparam=value;  }
   string            Sparam(void)                     const { return this.m_sparam; }
   bool              Send(const long chart_id)
                       {
                        ::ResetLastError();
                        return ::EventChartCustom(chart_id,m_id,m_lparam,m_dparam,m_sparam);
                       }
                     CGBaseEvent (const ushort event_id,const long lparam,const double dparam,const string sparam) : 
                        m_id(event_id),m_lparam(lparam),m_dparam(dparam),m_sparam(sparam){}
                    ~CGBaseEvent (void){}
  };
//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CGBaseObj : public CObject

存储上述所有事件对象属性的类成员变量在类的私密部分中声明,而公开部分包含设置和返回变量值的方法,以及将自定义事件发送到指定图表的方法
类的构造函数接收赋值给类变量的所有值。 这些值会被立即赋值给构造函数初始化列表中的变量

在基准图形对象类的受保护部分,声明存储对象事件的列表,并编写处理列表和图形对象事件的方法

//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CGBaseObj : public CObject
  {
protected:
   CArrayObj         m_list_events;                      // Object event list
   ENUM_OBJECT       m_type_graph_obj;                   // Graphical object type
   ENUM_GRAPH_ELEMENT_TYPE m_type_element;               // Graphical element type
   ENUM_GRAPH_OBJ_BELONG m_belong;                       // Program affiliation
   ENUM_GRAPH_OBJ_GROUP m_group;                         // Graphical object group
   string            m_name_prefix;                      // Object name prefix
   string            m_name;                             // Object name
   long              m_chart_id;                         // Object chart ID
   long              m_object_id;                        // Object ID
   long              m_zorder;                           // Priority of a graphical object for receiving the mouse click event
   int               m_subwindow;                        // Subwindow index
   int               m_shift_y;                          // Subwindow Y coordinate shift
   int               m_type;                             // Object type
   int               m_timeframes_visible;               // Visibility of an object on timeframes (a set of flags)
   int               m_digits;                           // Number of decimal places in a quote
   bool              m_visible;                          // Object visibility
   bool              m_back;                             // "Background object" flag
   bool              m_selected;                         // "Object selection" flag
   bool              m_selectable;                       // "Object availability" flag
   bool              m_hidden;                           // "Disable displaying the name of a graphical object in the terminal object list" flag
   datetime          m_create_time;                      // Object creation time
   
//--- Create (1) the object structure and (2) the object from the structure
   virtual bool      ObjectToStruct(void)                      { return true; }
   virtual void      StructToObject(void){;}

//--- Return the list of object events
   CArrayObj        *GetListEvents(void)                       { return &this.m_list_events;          }
//--- Create a new object event
   CGBaseEvent      *CreateNewEvent(const ushort event_id,const long lparam,const double dparam,const string sparam)
                       {
                        CGBaseEvent *event=new CGBaseEvent(event_id,lparam,dparam,sparam);
                        return event;
                       }
//--- Create a new object event and add it to the event list
   bool              CreateAndAddNewEvent(const ushort event_id,const long lparam,const double dparam,const string sparam)
                       {
                        return this.AddEvent(new CGBaseEvent(event_id,lparam,dparam,sparam));
                       }
//--- Add an event object to the event list
   bool              AddEvent(CGBaseEvent *event)              { return this.m_list_events.Add(event);}
//--- Clear the event list
   void              ClearEventsList(void)                     { this.m_list_events.Clear();          }
//--- Return the number of events in the list
   int               EventsTotal(void)                         { return this.m_list_events.Total();   }

public:

所有提供的方法都非常简单,易于理解。 如果您有任何疑问,请随时在下面的评论中提问。

在类构造函数中,清除对象事件列表,并设置已排序列表标志

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CGBaseObj::CGBaseObj() : m_shift_y(0),m_visible(false), m_name_prefix(::MQLInfoString(MQL_PROGRAM_NAME)+"_"),m_belong(GRAPH_OBJ_BELONG_PROGRAM)
  {
   this.m_list_events.Clear();                  // Clear the event list
   this.m_list_events.Sort();                   // Sorted list flag
   this.m_type=OBJECT_DE_TYPE_GBASE;            // Object type
   this.m_type_graph_obj=WRONG_VALUE;           // Graphical object type
   this.m_type_element=WRONG_VALUE;             // Graphical object type
   this.m_belong=WRONG_VALUE;                   // Program/terminal affiliation
   this.m_name_prefix="";                       // Object name prefix
   this.m_name="";                              // Object name
   this.m_chart_id=0;                           // Object chart ID
   this.m_object_id=0;                          // Object ID
   this.m_zorder=0;                             // Priority of a graphical object for receiving the mouse click event
   this.m_subwindow=0;                          // Subwindow index
   this.m_shift_y=0;                            // Subwindow Y coordinate shift
   this.m_timeframes_visible=OBJ_ALL_PERIODS;   // Visibility of an object on timeframes (a set of flags)
   this.m_visible=true;                         // Object visibility
   this.m_back=false;                           // "Background object" flag
   this.m_selected=false;                       // "Object selection" flag
   this.m_selectable=false;                     // "Object availability" flag
   this.m_hidden=true;                          // "Disable displaying the name of a graphical object in the terminal object list" flag
   this.m_create_time=0;                        // Object creation time
   
  }
//+------------------------------------------------------------------+


在标准图形对象类 \MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqh 里,即在检查对象属性变化的方法中,清除事件列表在列表里设置正在创建和添加的事件对象并将它们发送到已创建列表中图形对象集合事件的响应程序

//+------------------------------------------------------------------+
//| Check object property changes                                    |
//+------------------------------------------------------------------+
void CGStdGraphObj::PropertiesCheckChanged(void)
  {
   CGBaseObj::ClearEventsList();
   bool changed=false;
   int begin=0, end=GRAPH_OBJ_PROP_INTEGER_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_INTEGER prop=(ENUM_GRAPH_OBJ_PROP_INTEGER)i;
      if(!this.SupportProperty(prop)) continue;
      for(int j=0;j<Prop.CurrSize(prop);j++)
        {
         if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j))
           {
            changed=true;
            this.CreateAndAddNewEvent(GRAPH_OBJ_EVENT_CHANGE,this.ChartID(),prop,this.Name());
           }
        }
     }

   begin=end; end+=GRAPH_OBJ_PROP_DOUBLE_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_DOUBLE prop=(ENUM_GRAPH_OBJ_PROP_DOUBLE)i;
      if(!this.SupportProperty(prop)) continue;
      for(int j=0;j<Prop.CurrSize(prop);j++)
        {
         if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j))
           {
            changed=true;
            this.CreateAndAddNewEvent(GRAPH_OBJ_EVENT_CHANGE,this.ChartID(),prop,this.Name());
           }
        }
     }

   begin=end; end+=GRAPH_OBJ_PROP_STRING_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_STRING prop=(ENUM_GRAPH_OBJ_PROP_STRING)i;
      if(!this.SupportProperty(prop)) continue;
      for(int j=0;j<Prop.CurrSize(prop);j++)
        {
         if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j) && prop!=GRAPH_OBJ_PROP_NAME)
           {
            changed=true;
            this.CreateAndAddNewEvent(GRAPH_OBJ_EVENT_CHANGE,this.ChartID(),prop,this.Name());
           }
        }
     }
   if(changed)
     {
      for(int i=0;i<this.m_list_events.Total();i++)
        {
         CGBaseEvent *event=this.m_list_events.At(i);
         if(event==NULL)
            continue;
         ::EventChartCustom(::ChartID(),event.ID(),event.Lparam(),event.Dparam(),event.Sparam());
        }
      PropertiesCopyToPrevData();
     }
  }
//+------------------------------------------------------------------+

此处,我们循环遍历所有对象属性,检查每个对象属性是否有变化。 如果检测到变化,则创建事件对象,并将其添加到对象事件列表当中。 如果至少有一个变化,则获取每个事件对象,并循环遍历已创建列表,将其发送给控制程序图表。 接下来,在图形元素集合类的 OnChartEvent() 响应程序中发送和处理这些事件。

打开图形元素集合类文件 \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh。 我们稍微改进一下检查图表对象的图形对象管理类方法:

//+------------------------------------------------------------------+
//| CChartObjectsControl: Check objects on a chart                   |
//+------------------------------------------------------------------+
void CChartObjectsControl::Refresh(void)
  {
//--- Graphical objects on the chart
   this.m_total_objects=::ObjectsTotal(this.ChartID());
   this.m_delta_graph_obj=this.m_total_objects-this.m_last_objects;

   //--- If an object is added to the chart
   if(this.m_delta_graph_obj>0)
     {
      //--- find the last added graphical object, select it and write its name
      string name=this.LastAddedGraphObjName();
      //--- Handle only non-programmatically created objects
      if(name!="" && ::StringFind(name,m_name_program)==WRONG_VALUE)
        {
         //--- Create the object of the graphical object class corresponding to the added graphical object type
         ENUM_OBJECT type=(ENUM_OBJECT)::ObjectGetInteger(this.ChartID(),name,OBJPROP_TYPE);
         ENUM_OBJECT_DE_TYPE obj_type=ENUM_OBJECT_DE_TYPE(type+OBJECT_DE_TYPE_GSTD_OBJ+1);
         CGStdGraphObj *obj=this.CreateNewGraphObj(type,name);
         if(obj==NULL)
           {
            CMessage::ToLog(DFUN,MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ);
            return;
           }
         //--- Set the object affiliation and add the created object to the list of new objects
         obj.SetBelong(GRAPH_OBJ_BELONG_NO_PROGRAM); 
         if(this.m_list_new_graph_obj.Search(obj)==WRONG_VALUE)
           {
            //--- If failed to add the object to the list, inform of that, delete the object and leave
            if(!this.m_list_new_graph_obj.Add(obj))
              {
               CMessage::ToLog(DFUN_ERR_LINE,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
               delete obj;
               return;
              }
            //--- Send an event to the control program chart
            ::EventChartCustom(this.m_chart_id_main,GRAPH_OBJ_EVENT_CREATE,this.ChartID(),0,obj.Name());
           }
        }
     }

//--- save the index of the last added graphical object and the difference with the last check
   this.m_last_objects=this.m_total_objects;
   this.m_is_graph_obj_event=(bool)this.m_delta_graph_obj;
  }
//+------------------------------------------------------------------+

在此,我加入在日志里显示错误消息并向控制程序图表发送对象创建事件

在图形元素集合类的公开部分,添加返回图表管理对象列表的方法

//--- Return the number of new graphical objects, (3) the flag of the occurred change in the list of graphical objects
   int               NewObjects(void)   const                                                            { return this.m_delta_graph_obj;       }
   bool              IsEvent(void) const                                                                 { return this.m_is_graph_obj_event;    }
//--- Return a graphical object by chart name and ID
   CGStdGraphObj    *GetStdGraphObject(const string name,const long chart_id);
//--- Return the chart management object list
   CArrayObj        *GetListChartsControl(void)                                                          { return &this.m_list_charts_control;  }
//--- Constructor
                     CGraphElementsCollection();


在前一篇文章中创建标准图形对象的方法有一大段重复的代码。 我们把它移到一个单独的私密方法中 :

//--- Event handler
   void              OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);

private:
//--- Create a new graphical object, return the pointer to the chart management object
   CChartObjectsControl *CreateNewStdGraphObjectAndGetCtrlObj(const long chart_id,
                                                              const string name,
                                                              int subwindow,
                                                              const ENUM_OBJECT type_object,
                                                              const datetime time1,
                                                              const double price1,
                                                              const datetime time2=0,
                                                              const double price2=0,
                                                              const datetime time3=0,
                                                              const double price3=0,
                                                              const datetime time4=0,
                                                              const double price4=0,
                                                              const datetime time5=0,
                                                              const double price5=0)
                       {
                        //--- If an object with a chart ID and name is already present in the collection, inform of that and return NULL
                        if(this.IsPresentGraphObjInList(chart_id,name))
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELM_COLLECTION_ERR_GR_OBJ_ALREADY_EXISTS)," ChartID ",(string)chart_id,", ",name);
                           return NULL;
                          }
                        //--- If failed to create a new standard graphical object, inform of that and return NULL
                        if(!this.CreateNewStdGraphObject(chart_id,name,type_object,subwindow,time1,0))
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_STD_GRAPH_OBJ),StdGraphObjectTypeDescription(type_object));
                           CMessage::ToLog(::GetLastError(),true);
                           return NULL;
                          }
                        //--- If failed to get a chart management object, inform of that
                        CChartObjectsControl *ctrl=this.GetChartObjectCtrlObj(chart_id);
                        if(ctrl==NULL)
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_GET_CTRL_OBJ),(string)chart_id);
                        //--- Return the pointer to a chart management object or NULL in case of a failed attempt to get it
                        return ctrl;
                       }
//--- Add a newly created object to the list
   bool              AddCreatedObjToList(const string source,const long chart_id,const string name,CGStdGraphObj *obj)
                       {
                        bool res=true;
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,name);
                           delete obj;
                           res=false;
                          }
                        ::ChartRedraw(chart_id);
                        return res;
                       }
public:
//--- Create the "Vertical line" graphical object

在所有创建标准图形对象的方法中,返回该方法的操作结果

public:
//--- Create the "Vertical line" graphical object
   bool              CreateLineVertical(const long chart_id,const string name,const int subwindow,const datetime time)
                       {
                        //--- Set the name and type of a created object
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_VLINE;
                        //--- Create a new graphical object and get the pointer to the chart management object
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,0);
                        if(ctrl==NULL)
                           return false;
                        //--- Create a new class object corresponding to the newly created graphical object
                        CGStdVLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true,false);
                        obj.SetFlagSelected(true,false);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        //--- Return the result of adding the object to the list
                        return this.AddCreatedObjToList(DFUN,chart_id,nm,obj);
                       }

另外,针对新变化设置所需的标志,从而进行正确操作,为图形对象属性设置新值。

创建标准图形对象的所有其它方法,都以相同的方式修改。 在此研究它们没有意义。 您可在文后的附件中找到它们。

在创建管理指定图表的图形对象,并将其添加到列表的新对象方法中在将事件控制指示器添加到图表时,实现将消息添加到日志

//+------------------------------------------------------------------+
//| Create a new graphical object management object                  |
//| for a specified and add it to the list                           |
//+------------------------------------------------------------------+
CChartObjectsControl *CGraphElementsCollection::CreateChartObjectCtrlObj(const long chart_id)
  {
//--- Create a new object for managing chart objects by ID
   CChartObjectsControl *obj=new CChartObjectsControl(chart_id);
//--- If the object is not created, inform of the error and return NULL
   if(obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_CREATE_CTRL_OBJ),(string)chart_id);
      return NULL;
     }
//--- If failed to add the object to the list, inform of the error, remove the object and return NULL
   if(!this.m_list_charts_control.Add(obj))
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
      delete obj;
      return NULL;
     }
   if(obj.ChartID()!=CBaseObj::GetMainChartID() && obj.CreateEventControlInd(CBaseObj::GetMainChartID()))
      if(!obj.AddEventControlInd())
        {
         CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_ADD_EVN_CTRL_INDICATOR);
         CMessage::ToLog(DFUN,::GetLastError(),true);
        }
      else
         ::Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_ADDED_EVN_CTRL_INDICATOR),obj.Symbol()," #",obj.ChartID());
//--- Return the pointer to the object that was created and added to the list
   return obj;
  }
//+------------------------------------------------------------------+


在更新所有图形对象列表的方法中发送图形对象删除事件,替代在日志中简单地显示检测到集合列表对象已被删除:

//+------------------------------------------------------------------+
//| Update the list of all graphical objects                         |
//+------------------------------------------------------------------+
void CGraphElementsCollection::Refresh(void)
  {
   this.RefreshForExtraObjects();
//--- Declare variables to search for charts
   long chart_id=0;
   int i=0;
//--- In the loop by all open charts in the terminal (no more than 100)
   while(i<CHARTS_MAX)
     {
      //--- Get the chart ID
      chart_id=::ChartNext(chart_id);
      if(chart_id<0)
         break;
      //--- Get the pointer to the object for managing graphical objects
      //--- and update the list of graphical objects by chart ID
      CChartObjectsControl *obj_ctrl=this.RefreshByChartID(chart_id);
      //--- If failed to get the pointer, move on to the next chart
      if(obj_ctrl==NULL)
         continue;
      //--- If the number of objects on the chart changes
      if(obj_ctrl.IsEvent())
        {
         //--- If a graphical object is added to the chart
         if(obj_ctrl.Delta()>0)
           {
            //--- Get the list of added graphical objects and move them to the collection list
            //--- (if failed to move the object to the collection, move on to the next object)
            if(!this.AddGraphObjToCollection(DFUN_ERR_LINE,obj_ctrl))
               continue;
           }
         //--- If the graphical object has been removed
         else if(obj_ctrl.Delta()<0)
           {
            // Find an extra object in the list
            CGStdGraphObj *obj=this.FindMissingObj(chart_id);
            if(obj!=NULL)
              {
               //--- Send an event to the control program chart
               ::EventChartCustom(this.m_chart_id_main,GRAPH_OBJ_EVENT_DELETE,obj.ChartID(),0,obj.Name());
               //--- Remove the class object of a removed graphical object from the collection list
               if(!this.DeleteGraphObjFromList(obj))
                  CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST);
              }
           }
        }
      //--- Increase the loop index
      i++;
     }
  }
//+------------------------------------------------------------------+

在事件的字符串参数中,传递已删除对象的名称。 也许,我将实现把已删除对象保存到一个单独的列表中,如此当接收到删除事件时,我们就能够定义一个已删除对象及其属性,以及能够以编程方式恢复它。

在处理删除图表窗口的方法中也向控制程序图表发送事件,替代简单的日志消息:

//+------------------------------------------------------------------+
//| Handle removing the chart window                                 |
//+------------------------------------------------------------------+
void CGraphElementsCollection::RefreshForExtraObjects(void)
  {
   for(int i=this.m_list_charts_control.Total()-1;i>WRONG_VALUE;i--)
     {
      CChartObjectsControl *obj_ctrl=this.m_list_charts_control.At(i);
      if(obj_ctrl==NULL)
         continue;
      if(!this.IsPresentChartWindow(obj_ctrl.ChartID()))
        {
         long chart_id=obj_ctrl.ChartID();
         string chart_symb=obj_ctrl.Symbol();
         int total_ctrl=this.m_list_charts_control.Total();
         this.DeleteGraphObjCtrlObjFromList(obj_ctrl);
         int total_obj=this.m_list_all_graph_obj.Total();
         this.DeleteGraphObjectsFromList(chart_id);
         int del_ctrl=total_ctrl-this.m_list_charts_control.Total();
         int del_obj=total_obj-this.m_list_all_graph_obj.Total();
         ::EventChartCustom(this.m_chart_id_main,GRAPH_OBJ_EVENT_DEL_CHART,chart_id,del_obj,chart_symb);
        }
     }
  }
//+------------------------------------------------------------------+

在此,我们以参数的形式传递已关闭图表 ID与该图表一起删除的图形对象数量、以及已关闭图表品种符号

在图形元素集合类事件的响应程序中,添加图形对象的基准事件响应程序:

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CGraphElementsCollection::OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   CGStdGraphObj *obj=NULL;
   ushort idx=ushort(id-CHARTEVENT_CUSTOM);
   if(id==CHARTEVENT_OBJECT_CHANGE  || id==CHARTEVENT_OBJECT_DRAG    || id==CHARTEVENT_OBJECT_CLICK   ||
      idx==CHARTEVENT_OBJECT_CHANGE || idx==CHARTEVENT_OBJECT_DRAG   || idx==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Calculate the chart ID
      //--- If the event ID corresponds to an event from the current chart, the chart ID is received from ChartID
      //--- If the event ID corresponds to a user event, the chart ID is received from lparam
      //--- Otherwise, the chart ID is assigned to -1
      long param=(id==CHARTEVENT_OBJECT_CLICK ? ::ChartID() : idx==CHARTEVENT_OBJECT_CLICK ? lparam : WRONG_VALUE);
      long chart_id=(param==WRONG_VALUE ? (lparam==0 ? ::ChartID() : lparam) : param);
      //--- Get the object, whose properties were changed or which was relocated,
      //--- from the collection list by its name set in sparam
      obj=this.GetStdGraphObject(sparam,chart_id);

      //--- If failed to get the object by its name, it is not on the list,
      //--- which means its name has been changed
      if(obj==NULL)
        {
         //--- Let's search the list for the object that is not on the chart
         obj=this.FindMissingObj(chart_id);
         //--- If failed to find the object here as well, exit
         if(obj==NULL)
            return;
         //--- Get the name of the renamed graphical object on the chart, which is not in the collection list
         string name_new=this.FindExtraObj(chart_id);
         //--- Send an event with the old name of an object to the control program chart and
         //--- set a new name for the collection list object, which does not correspond to any graphical object on the chart
         ::EventChartCustom(this.m_chart_id_main,GRAPH_OBJ_EVENT_RENAME,obj.ChartID(),0,obj.Name());
         obj.SetName(name_new);
        }
      //--- Update the properties of the obtained object
      //--- and check their change
      obj.PropertiesRefresh();
      obj.PropertiesCheckChanged();
     }
//--- Handle standard graphical object events
   if(idx>GRAPH_OBJ_EVENT_NO_EVENT && idx<GRAPH_OBJ_EVENTS_NEXT_CODE)
     {
      //--- Depending on the event type, display an appropriate message in the journal
      switch(idx)
        {
         case GRAPH_OBJ_EVENT_CREATE   :
           ::Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_CREATE));
           obj=this.GetStdGraphObject(sparam,lparam);
           if(obj!=NULL)
              obj.PrintShort();
           break;
         case GRAPH_OBJ_EVENT_CHANGE   :
           ::Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_CHANGE));
           obj=this.GetStdGraphObject(sparam,lparam);
           if(obj!=NULL)
              obj.PrintShort();
           break;
         case GRAPH_OBJ_EVENT_RENAME   :
           ::Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_RENAME));
           obj=this.GetStdGraphObject(sparam,lparam);
           if(obj!=NULL)
              obj.PrintShort();
           break;
         case GRAPH_OBJ_EVENT_DELETE   :
           ::Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_DELETE));
           break;
         case GRAPH_OBJ_EVENT_DEL_CHART:
           ::Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_DEL_CHART),": ChartID: ",lparam,", ChartSymbol: ",sparam);
           break;
         default:
           break;
        }
     }
  }
//+------------------------------------------------------------------+

方法逻辑已在代码注释中描述。 在此,我添加了一个点击图表的响应。 当双击发生,对象会更改其选择状态,进而引发对象参数更改事件。 由此,我们能够处理对象选择/取消选择事件。
最终,已经处理的图形对象事件(已为其创建了基准事件)会被送达至相同的方法。 这些基准事件会在新代码模块中处理。 目前,我们在此只是向日志发送消息。 在后续文章中,我将创建一个更成熟的处理对每个事件程序,程序能由此知道、并快速访问已更改对象及其属性。


为了简化图形对象的处理,在 \MQL5\Include\DoEasy\Engine.mqh 中的 CEngine 函数库主类中创建处理图形对象的方法。

为了定义使用标准图形对象类的打开图表,我们可以查看图表管理对象列表。 该列表允许我们从对象中提取所有打开图表的 ID,从而获得访问它们的能力。 为了简化程序接收 ID,创建方法,把打开图表 ID 上创建的控制对象填充到传递给它的 long 型数组当中:

//--- Launch the new pause countdown
   void                 Pause(const ulong pause_msc,const datetime time_start=0)
                          {
                           this.PauseSetWaitingMSC(pause_msc);
                           this.PauseSetTimeBegin(time_start*1000);
                           while(!this.PauseIsCompleted() && !::IsStopped()){}
                          }

//--- Return the graphical object collection
   CGraphElementsCollection *GetGraphicObjCollection(void)              { return &this.m_graph_objects; }
   
//--- Fill in the array with IDs of the charts opened in the terminal
   void              GraphGetArrayChartsID(long &array_charts_id[])
                       {
                        CArrayObj *list=this.m_graph_objects.GetListChartsControl();
                        if(list==NULL)
                           return;
                        ::ArrayResize(array_charts_id,list.Total());
                        ::ArrayInitialize(array_charts_id,WRONG_VALUE);
                        for(int i=0;i<list.Total();i++)
                          {
                           CChartObjectsControl *obj=list.At(i);
                           if(obj==NULL)
                              continue;
                           array_charts_id[i]=obj.ChartID();
                          }
                       }

//--- Create the "Vertical line" graphical object

在此,我们立即依据所传递数组的大小来设置图表管理对象列表的大小,并用数值 -1 值初始化数组。 如果在循环中接收图表管理对象时出错,则需在对应的图表管理对象索引数组单元格中设置 -1,这是必需的,代表我们获取该索引失败。 若获取对象时出错,则它用作错误信号。
当然,只有在成功接收对象的情况下,我才能增加循环中的数组大小,但在循环中调用 ArrayResize() 会降低性能。 因此,会立即根据列表大小增加数组尺寸。 如果出现错误,相应的数组单元格将包含 -1。
接下来,在循环遍历所获列表时,提取下一个图表管理对象,并将图表 ID(包含在图表管理对象中)写入与循环索引相对应的数组单元。

为了简化创建标准图形对象的方法,编写创建它们的方法 — 每个对象两个方法。 第一个方法调用同名图形元素集合类来创建标准图形对象,而第二个方法调用第一个方法来指定当前图表 ID

//--- Create the "Vertical line" graphical object
   bool              CreateLineVertical(const long chart_id,const string name,const int subwindow,const datetime time)
                       { return this.m_graph_objects.CreateLineVertical(chart_id,name,subwindow,time); }
   bool              CreateLineVertical(const string name,const int subwindow,const datetime time)
                       { return this.CreateLineVertical(::ChartID(),name,subwindow,time); }

//--- Create the "Horizontal line" graphical object
   bool              CreateLineHorizontal(const long chart_id,const string name,const int subwindow,const double price)
                       { return this.m_graph_objects.CreateLineHorizontal(chart_id,name,subwindow,price); }
   bool              CreateLineHorizontal(const string name,const int subwindow,const double price)
                       { return this.CreateLineHorizontal(::ChartID(),name,subwindow,price); }
 
//--- Create the "Trend line" graphical object
   bool              CreateLineTrend(const long chart_id,const string name,const int subwindow,
                                     const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.m_graph_objects.CreateLineTrend(chart_id,name,subwindow,time1,price1,time2,price2); }
   bool              CreateLineTrend(const string name,const int subwindow,
                                     const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.CreateLineTrend(::ChartID(),name,subwindow,time1,price1,time2,price2); }

//--- Create the "Trend line by angle" graphical object
   bool              CreateLineTrendByAngle(const long chart_id,const string name,const int subwindow,
                                            const datetime time1,const double price1,const datetime time2,const double price2,
                                            const double angle)
                       { return this.m_graph_objects.CreateLineTrendByAngle(chart_id,name,subwindow,time1,price1,time2,price2,angle); }
   bool              CreateLineTrendByAngle(const string name,const int subwindow,
                                            const datetime time1,const double price1,const datetime time2,const double price2,
                                            const double angle)
                       { return this.CreateLineTrendByAngle(::ChartID(),name,subwindow,time1,price1,time2,price2,angle); }

//--- Create the "Cyclic lines" graphical object
   bool              CreateLineCycle(const long chart_id,const string name,const int subwindow,
                                     const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.m_graph_objects.CreateLineCycle(chart_id,name,subwindow,time1,price1,time2,price2); }
   bool              CreateLineCycle(const string name,const int subwindow,
                                     const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.CreateLineCycle(::ChartID(),name,subwindow,time1,price1,time2,price2); }

//--- Create the "Arrowed line" graphical object
   bool              CreateLineArrowed(const long chart_id,const string name,const int subwindow,
                                       const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.m_graph_objects.CreateLineArrowed(chart_id,name,subwindow,time1,price1,time2,price2); }
   bool              CreateLineArrowed(const string name,const int subwindow,
                                       const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.CreateLineArrowed(::ChartID(),name,subwindow,time1,price1,time2,price2); }

//--- Create the "Equidistant channel" graphical object
   bool              CreateChannel(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2,
                                   const datetime time3,const double price3)
                       { return this.m_graph_objects.CreateChannel(chart_id,name,subwindow,time1,price1,time2,price2,time3,price3); }
   bool              CreateChannel(const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2,
                                   const datetime time3,const double price3)
                       { return this.CreateChannel(::ChartID(),name,subwindow,time1,price1,time2,price2,time3,price3); }

//--- Create the "Standard deviation channel" graphical object
   bool              CreateChannelStdDeviation(const long chart_id,const string name,const int subwindow,
                                               const datetime time1,const double price1,const datetime time2,const double price2,
                                               const double deviation=1.5)
                       { return this.m_graph_objects.CreateChannelStdDeviation(chart_id,name,subwindow,time1,price1,time2,price2,deviation); }
   bool              CreateChannelStdDeviation(const string name,const int subwindow,
                                               const datetime time1,const double price1,const datetime time2,const double price2,
                                               const double deviation=1.5)
                       { return this.CreateChannelStdDeviation(::ChartID(),name,subwindow,time1,price1,time2,price2,deviation); }

//--- Create the "Linear regression channel" graphical object
   bool              CreateChannelRegression(const long chart_id,const string name,const int subwindow,
                                             const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.m_graph_objects.CreateChannelRegression(chart_id,name,subwindow,time1,price1,time2,price2); }
   bool              CreateChannelRegression(const string name,const int subwindow,
                                             const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.CreateChannelRegression(::ChartID(),name,subwindow,time1,price1,time2,price2); }

//--- Create the "Andrews' Pitchfork" graphical object
   bool              CreatePitchforkAndrews(const long chart_id,const string name,const int subwindow,
                                            const datetime time1,const double price1,const datetime time2,const double price2,
                                            const datetime time3,const double price3)
                       { return this.m_graph_objects.CreatePitchforkAndrews(chart_id,name,subwindow,time1,price1,time2,price2,time3,price3); }
   bool              CreatePitchforkAndrews(const string name,const int subwindow,
                                            const datetime time1,const double price1,const datetime time2,const double price2,
                                            const datetime time3,const double price3)
                       { return this.CreatePitchforkAndrews(::ChartID(),name,subwindow,time1,price1,time2,price2,time3,price3); }

//--- Create the "Gann line" graphical object
   bool              CreateGannLine(const long chart_id,const string name,const int subwindow,
                                    const datetime time1,const double price1,const datetime time2,const double price2,const double angle)
                       { return this.m_graph_objects.CreateGannLine(chart_id,name,subwindow,time1,price1,time2,price2,angle); }
   bool              CreateGannLine(const string name,const int subwindow,
                                    const datetime time1,const double price1,const datetime time2,const double price2,const double angle)
                       { return this.CreateGannLine(::ChartID(),name,subwindow,time1,price1,time2,price2,angle); }

//--- Create the "Gann fan" graphical object
   bool              CreateGannFan(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2,
                                   const ENUM_GANN_DIRECTION direction,const double scale)
                       { return this.m_graph_objects.CreateGannFan(chart_id,name,subwindow,time1,price1,time2,price2,direction,scale); }
   bool              CreateGannFan(const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2,
                                   const ENUM_GANN_DIRECTION direction,const double scale)
                       { return this.CreateGannFan(::ChartID(),name,subwindow,time1,price1,time2,price2,direction,scale); }

//--- Create the "Gann grid" graphical object
   bool              CreateGannGrid(const long chart_id,const string name,const int subwindow,
                                    const datetime time1,const double price1,const datetime time2,
                                    const ENUM_GANN_DIRECTION direction,const double scale)
                       { return this.m_graph_objects.CreateGannGrid(chart_id,name,subwindow,time1,price1,time2,direction,scale); }
   bool              CreateGannGrid(const string name,const int subwindow,
                                    const datetime time1,const double price1,const datetime time2,
                                    const ENUM_GANN_DIRECTION direction,const double scale)
                       { return this.CreateGannGrid(::ChartID(),name,subwindow,time1,price1,time2,direction,scale); }

//--- Create the "Fibo levels" graphical object
   bool              CreateFiboLevels(const long chart_id,const string name,const int subwindow,
                                      const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.m_graph_objects.CreateFiboLevels(chart_id,name,subwindow,time1,price1,time2,price2); }
   bool              CreateFiboLevels(const string name,const int subwindow,
                                      const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.CreateFiboLevels(::ChartID(),name,subwindow,time1,price1,time2,price2); }

//--- Create the "Fibo Time Zones" graphical object
   bool              CreateFiboTimeZones(const long chart_id,const string name,const int subwindow,
                                         const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.m_graph_objects.CreateFiboTimeZones(chart_id,name,subwindow,time1,price1,time2,price2); }
   bool              CreateFiboTimeZones(const string name,const int subwindow,
                                         const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.CreateFiboTimeZones(::ChartID(),name,subwindow,time1,price1,time2,price2); }

//--- Create the "Fibo fan" graphical object
   bool              CreateFiboFan(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.m_graph_objects.CreateFiboFan(chart_id,name,subwindow,time1,price1,time2,price2); }
   bool              CreateFiboFan(const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.CreateFiboFan(::ChartID(),name,subwindow,time1,price1,time2,price2); }

//--- Create the "Fibo arc" graphical object
   bool              CreateFiboArc(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2,
                                   const double scale,const bool ellipse)
                       { return this.m_graph_objects.CreateFiboArc(chart_id,name,subwindow,time1,price1,time2,price2,scale,ellipse); }
   bool              CreateFiboArc(const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2,
                                   const double scale,const bool ellipse)
                       { return this.CreateFiboArc(::ChartID(),name,subwindow,time1,price1,time2,price2,scale,ellipse); }

//--- Create the "Fibo channel" graphical object
   bool              CreateFiboChannel(const long chart_id,const string name,const int subwindow,
                                       const datetime time1,const double price1,const datetime time2,const double price2,const datetime time3,const double price3)
                       { return this.m_graph_objects.CreateFiboChannel(chart_id,name,subwindow,time1,price1,time2,price2,time3,price3); }
   bool              CreateFiboChannel(const string name,const int subwindow,
                                       const datetime time1,const double price1,const datetime time2,const double price2,const datetime time3,const double price3)
                       { return this.CreateFiboChannel(::ChartID(),name,subwindow,time1,price1,time2,price2,time3,price3); }

//--- Create the "Fibo extension" graphical object
   bool              CreateFiboExpansion(const long chart_id,const string name,const int subwindow,
                                         const datetime time1,const double price1,const datetime time2,const double price2,const datetime time3,const double price3)
                       { return this.m_graph_objects.CreateFiboExpansion(chart_id,name,subwindow,time1,price1,time2,price2,time3,price3); }
   bool              CreateFiboExpansion(const string name,const int subwindow,
                                         const datetime time1,const double price1,const datetime time2,const double price2,const datetime time3,const double price3)
                       { return this.CreateFiboExpansion(::ChartID(),name,subwindow,time1,price1,time2,price2,time3,price3); }

//--- Create the "Elliott 5 waves" graphical object
   bool              CreateElliothWave5(const long chart_id,const string name,const int subwindow,
                                        const datetime time1,const double price1,const datetime time2,const double price2,
                                        const datetime time3,const double price3,const datetime time4,const double price4,
                                        const datetime time5,const double price5,const ENUM_ELLIOT_WAVE_DEGREE degree,
                                        const bool draw_lines)
                       { return this.m_graph_objects.CreateElliothWave5(chart_id,name,subwindow,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5,degree,draw_lines); }
   bool              CreateElliothWave5(const string name,const int subwindow,
                                        const datetime time1,const double price1,const datetime time2,const double price2,
                                        const datetime time3,const double price3,const datetime time4,const double price4,
                                        const datetime time5,const double price5,const ENUM_ELLIOT_WAVE_DEGREE degree,
                                        const bool draw_lines)
                       { return this.CreateElliothWave5(::ChartID(),name,subwindow,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5,degree,draw_lines); }

//--- Create the "Elliott 3 waves" graphical object
   bool              CreateElliothWave3(const long chart_id,const string name,const int subwindow,
                                        const datetime time1,const double price1,const datetime time2,
                                        const double price2,const datetime time3,const double price3,
                                        const ENUM_ELLIOT_WAVE_DEGREE degree,const bool draw_lines)
                       { return this.m_graph_objects.CreateElliothWave3(chart_id,name,subwindow,time1,price1,time2,price2,time3,price3,degree,draw_lines); }
   bool              CreateElliothWave3(const string name,const int subwindow,
                                        const datetime time1,const double price1,const datetime time2,
                                        const double price2,const datetime time3,const double price3,
                                        const ENUM_ELLIOT_WAVE_DEGREE degree,const bool draw_lines)
                       { return this.CreateElliothWave3(::ChartID(),name,subwindow,time1,price1,time2,price2,time3,price3,degree,draw_lines); }

//--- Create the Rectangle graphical object
   bool              CreateRectangle(const long chart_id,const string name,const int subwindow,
                                     const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.m_graph_objects.CreateRectangle(chart_id,name,subwindow,time1,price1,time2,price2); }
   bool              CreateRectangle(const string name,const int subwindow,
                                     const datetime time1,const double price1,const datetime time2,const double price2)
                       { return this.CreateRectangle(::ChartID(),name,subwindow,time1,price1,time2,price2); }

//--- Create the Triangle graphical object
   bool              CreateTriangle(const long chart_id,const string name,const int subwindow,
                                    const datetime time1,const double price1,const datetime time2,const double price2,const datetime time3,const double price3)
                       { return this.m_graph_objects.CreateTriangle(chart_id,name,subwindow,time1,price1,time2,price2,time3,price3); }
   bool              CreateTriangle(const string name,const int subwindow,
                                    const datetime time1,const double price1,const datetime time2,const double price2,const datetime time3,const double price3)
                       { return this.CreateTriangle(::ChartID(),name,subwindow,time1,price1,time2,price2,time3,price3); }

//--- Create the Ellipse graphical object
   bool              CreateEllipse(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2,const datetime time3,const double price3)
                       { return this.m_graph_objects.CreateEllipse(chart_id,name,subwindow,time1,price1,time2,price2,time3,price3); }
   bool              CreateEllipse(const string name,const int subwindow,
                                   const datetime time1,const double price1,const datetime time2,const double price2,const datetime time3,const double price3)
                       { return this.CreateEllipse(::ChartID(),name,subwindow,time1,price1,time2,price2,time3,price3); }

//--- Create the "Thumb up" graphical object
   bool              CreateThumbUp(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreateThumbUp(chart_id,name,subwindow,time,price); }
   bool              CreateThumbUp(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreateThumbUp(::ChartID(),name,subwindow,time,price); }

//--- Create the "Thumb down" graphical object
   bool              CreateThumbDown(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreateThumbDown(chart_id,name,subwindow,time,price); }
   bool              CreateThumbDown(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreateThumbDown(::ChartID(),name,subwindow,time,price); }

//--- Create the "Arrow up" graphical object
   bool              CreateArrowUp(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreateArrowUp(chart_id,name,subwindow,time,price); }
   bool              CreateArrowUp(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreateArrowUp(::ChartID(),name,subwindow,time,price); }

//--- Create the "Arrow down" graphical object
   bool              CreateArrowDown(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreateArrowDown(chart_id,name,subwindow,time,price); }
   bool              CreateArrowDown(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreateArrowDown(::ChartID(),name,subwindow,time,price); }

//--- Create the Stop graphical object
   bool              CreateSignalStop(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreateSignalStop(chart_id,name,subwindow,time,price); }
   bool              CreateSignalStop(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreateSignalStop(::ChartID(),name,subwindow,time,price); }

//--- Create the "Check mark" graphical object
   bool              CreateSignalCheck(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreateSignalCheck(chart_id,name,subwindow,time,price); }
   bool              CreateSignalCheck(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreateSignalCheck(::ChartID(),name,subwindow,time,price); }

//--- Create the "Left price label" graphical object
   bool              CreatePriceLabelLeft(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreatePriceLabelLeft(chart_id,name,subwindow,time,price); }
   bool              CreatePriceLabelLeft(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreatePriceLabelLeft(::ChartID(),name,subwindow,time,price); }

//--- Create the "Right price label" graphical object
   bool              CreatePriceLabelRight(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreatePriceLabelRight(chart_id,name,subwindow,time,price); }
   bool              CreatePriceLabelRight(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreatePriceLabelRight(::ChartID(),name,subwindow,time,price); }

//--- Create the Buy graphical object
   bool              CreateSignalBuy(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreateSignalBuy(chart_id,name,subwindow,time,price); }
   bool              CreateSignalBuy(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreateSignalBuy(::ChartID(),name,subwindow,time,price); }

//--- Create the Sell graphical object
   bool              CreateSignalSell(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       { return this.m_graph_objects.CreateSignalSell(chart_id,name,subwindow,time,price); }
   bool              CreateSignalSell(const string name,const int subwindow,const datetime time,const double price)
                       { return this.CreateSignalSell(::ChartID(),name,subwindow,time,price); }

//--- Create the Arrow graphical object
   bool              CreateArrow(const long chart_id,const string name,const int subwindow,const datetime time,const double price,
                                 const uchar arrow_code,const ENUM_ARROW_ANCHOR anchor)
                       { return this.m_graph_objects.CreateArrow(chart_id,name,subwindow,time,price,arrow_code,anchor); }
   bool              CreateArrow(const string name,const int subwindow,const datetime time,const double price,
                                 const uchar arrow_code,const ENUM_ARROW_ANCHOR anchor)
                       { return this.CreateArrow(::ChartID(),name,subwindow,time,price,arrow_code,anchor); }

//--- Create the Text graphical object
   bool              CreateText(const long chart_id,const string name,const int subwindow,const datetime time,const double price,
                                const string text,const int size,const ENUM_ANCHOR_POINT anchor_point,const double angle)
                       { return this.m_graph_objects.CreateText(chart_id,name,subwindow,time,price,text,size,anchor_point,angle); }
   bool              CreateText(const string name,const int subwindow,const datetime time,const double price,
                                const string text,const int size,const ENUM_ANCHOR_POINT anchor_point,const double angle)
                       { return this.CreateText(::ChartID(),name,subwindow,time,price,text,size,anchor_point,angle); }

//--- Create the "Text label" graphical object
   bool              CreateTextLabel(const long chart_id,const string name,const int subwindow,const int x,const int y,
                                     const string text,const int size,const ENUM_BASE_CORNER corner,
                                     const ENUM_ANCHOR_POINT anchor_point,const double angle)
                       { return this.m_graph_objects.CreateTextLabel(chart_id,name,subwindow,x,y,text,size,corner,anchor_point,angle); }
   bool              CreateTextLabel(const string name,const int subwindow,const int x,const int y,
                                     const string text,const int size,const ENUM_BASE_CORNER corner,
                                     const ENUM_ANCHOR_POINT anchor_point,const double angle)
                       { return this.CreateTextLabel(::ChartID(),name,subwindow,x,y,text,size,corner,anchor_point,angle); }

//--- Create the Button graphical object
   bool              CreateButton(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                  const ENUM_BASE_CORNER corner,const int font_size,const bool button_state)
                       { return this.m_graph_objects.CreateButton(chart_id,name,subwindow,x,y,w,h,corner,font_size,button_state); }
   bool              CreateButton(const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                  const ENUM_BASE_CORNER corner,const int font_size,const bool button_state)
                       { return this.CreateButton(::ChartID(),name,subwindow,x,y,w,h,corner,font_size,button_state); }

//--- Create the Chart graphical object
   bool              CreateChart(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                 const ENUM_BASE_CORNER corner,const int scale,const string symbol,const ENUM_TIMEFRAMES timeframe)
                       { return this.m_graph_objects.CreateChart(chart_id,name,subwindow,x,y,w,h,corner,scale,symbol,timeframe); }
   bool              CreateChart(const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                 const ENUM_BASE_CORNER corner,const int scale,const string symbol,const ENUM_TIMEFRAMES timeframe)
                       { return this.CreateChart(::ChartID(),name,subwindow,x,y,w,h,corner,scale,symbol,timeframe); }

//--- Create the Bitmap graphical object
   bool              CreateBitmap(const long chart_id,const string name,const int subwindow,const datetime time,const double price,
                                  const string image1,const string image2,const ENUM_ANCHOR_POINT anchor)
                       { return this.m_graph_objects.CreateBitmap(chart_id,name,subwindow,time,price,image1,image2,anchor); }
   bool              CreateBitmap(const string name,const int subwindow,const datetime time,const double price,
                                  const string image1,const string image2,const ENUM_ANCHOR_POINT anchor)
                       { return this.CreateBitmap(::ChartID(),name,subwindow,time,price,image1,image2,anchor); }

//--- Create the "Bitmap label" graphical object
   bool              CreateBitmapLabel(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                       const string image1,const string image2,const ENUM_BASE_CORNER corner,const ENUM_ANCHOR_POINT anchor,
                                       const bool state)
                       { return this.m_graph_objects.CreateBitmapLabel(chart_id,name,subwindow,x,y,w,h,image1,image2,corner,anchor,state); }
   bool              CreateBitmapLabel(const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                       const string image1,const string image2,const ENUM_BASE_CORNER corner,const ENUM_ANCHOR_POINT anchor,
                                       const bool state)
                       { return this.CreateBitmapLabel(::ChartID(),name,subwindow,x,y,w,h,image1,image2,corner,anchor,state); }

//--- Create the "Input field" graphical object
   bool              CreateEditField(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                     const int font_size,const ENUM_BASE_CORNER corner,const ENUM_ALIGN_MODE align,const bool readonly)
                       { return this.m_graph_objects.CreateEditField(chart_id,name,subwindow,x,y,w,h,font_size,corner,align,readonly); }
   bool              CreateEditField(const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                     const int font_size,const ENUM_BASE_CORNER corner,const ENUM_ALIGN_MODE align,const bool readonly)
                       { return this.CreateEditField(::ChartID(),name,subwindow,x,y,w,h,font_size,corner,align,readonly); }

//--- Create the "Economic calendar event" graphical object
   bool              CreateCalendarEvent(const long chart_id,const string name,const int subwindow,const datetime time)
                       { return this.m_graph_objects.CreateCalendarEvent(chart_id,name,subwindow,time); }
   bool              CreateCalendarEvent(const string name,const int subwindow,const datetime time)
                       { return this.CreateCalendarEvent(::ChartID(),name,subwindow,time); }

//--- Create the "Rectangular label" graphical object
   bool              CreateRectangleLabel(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                          const ENUM_BASE_CORNER corner,const ENUM_BORDER_TYPE border)
                       { return this.m_graph_objects.CreateRectangleLabel(chart_id,name,subwindow,x,y,w,h,corner,border); }
   bool              CreateRectangleLabel(const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                          const ENUM_BASE_CORNER corner,const ENUM_BORDER_TYPE border)
                       { return this.CreateRectangleLabel(::ChartID(),name,subwindow,x,y,w,h,corner,border); }
   
//--- Constructor/destructor
                        CEngine();
                       ~CEngine();

目前,这些改进都是创建旨在跟踪图形对象事件的基本功能所必需的。


测试

为了执行测试,我将借用前一篇文章中的 EA,将其保存在 \MQL5\Experts\TestDoEasy\Part90\ 中,命名为 TestDoEasyPart90.mq5

在前一篇文章中,我们在按住 Ctrl 键的同时单击图表会创建一条垂直线。 现在我们将在终端中所有打开的图表上创建它。

在处理图表单击的 OnChartEvent() 代码模块中,添加代码,在数组里填写所有打开的图表 ID在循环遍历所获数组时在每个图表上创建一条垂直线

   if(id==CHARTEVENT_CLICK)
     {
      if(!IsCtrlKeyPressed())
         return;
      datetime time=0;
      double price=0;
      int sw=0;
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,sw,time,price))
        {
         long array[];
         engine.GraphGetArrayChartsID(array);
         for(int i=0;i<ArraySize(array);i++)
            engine.CreateLineVertical(array[i],"LineVertical",0,time);
        }
     }
   engine.GetGraphicObjCollection().OnChartEvent(id,lparam,dparam,sparam);
   
  }
//+------------------------------------------------------------------+

编译 EA,并在图表上启动它,在打开另一个图表后,会把两个图表水平排列。 点击含有 EA 的图表会创建垂直线 — 每个图表一条线。 现在更改它们的属性,并查看获取的相关事件消息如何在日志当中显示:


正如我们所见,有关对象事件的消息显示在日志当中。 当以编程方式创建对象时,不会产生对象创建事件,因为程序员已经知道创建图形对象的时间点。 因此,不需要发送事件来重复事实
当然,在日志中简单地显示泛泛的消息不足以处理该事件。 但这些只是关于基本事件的消息,其参数已包含了稍后需定义的有关事件的所有数据。


下一步是什么?

在下一篇文章中,我将继续研究图形对象事件,并实现处理每个所获事件。

以下是 MQL5 的当前函数库版本、测试 EA,和图表事件控制指标的所有文件,供您测试和下载。 在评论中留下您的问题、意见和建议。

返回内容目录

*该系列的前几篇文章:

DoEasy 函数库中的图形(第八十六部分):图形对象集合 - 管理属性修改
DoEasy 函数库中的图形(第八十七部分):图形对象集合 - 在所有打开的图表上管理对象属性修改
DoEasy 函数库中的图形(第八十八部分):图形对象集合 — 存储对象动态变化属性的二维动态数组
DoEasy 函数库中的图形(第八十九部分):标准图形对象编程。 基本功能

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/10139

附加的文件 |
MQL5.zip (4178.92 KB)
MQL5 中的矩阵和向量 MQL5 中的矩阵和向量
运用特殊的数据类型“矩阵”和“向量”,可以创建非常贴合数学符号本意的代码。 运用这些方法,您可以避免创建嵌套循环,或在计算中分心记忆正确的数组索引。 因此,矩阵和向量方法的运用能为开发复杂程序提高可靠性和速度。
以 Doji(十字星)为例阐述改进的烛条形态识别 以 Doji(十字星)为例阐述改进的烛条形态识别
如何找到比平常更多的烛条形态? 简单的烛条形态背后,还有一个严重的瑕疵,可经由现代自动交易化工具所提供的强大能力来抵消。
DoEasy 函数库中的图形(第九十一部分):标准图形对象事件。 对象名称更改历史记录 DoEasy 函数库中的图形(第九十一部分):标准图形对象事件。 对象名称更改历史记录
在本文中,我将改进基本功能,从而能够基于函数库程序来控制图形对象事件。 我一开始将以“对象名称”属性为例,实现存储图形对象更改历史的功能。
在 MQL5 中使用 AutoIt 在 MQL5 中使用 AutoIt
简述。 在本文中,我们将探索采用 MetraTrader 5 终端里以集成的 MQL5 编写 AutoIt 脚本。 在其中,我们将覆盖如何操纵终端的用户界面来自动完成各种任务,并介绍一个采用 AutoItX 库的类。