
DoEasy 函数库中的图形(第九十部分):标准图形对象事件。 基本功能
内容
概述
当操控客户端提供的图形对象时,我们可能需要以编程方式定义这些对象的一些属性值。 该程序可以跟踪图形对象轨迹线的值,并执行嵌入式算法,例如当该轨迹线与价格交叉时。 当终端用户移动图形对象时,轨迹线也许会移位。 相应地,该程序应针对此事件做出响应。 但是程序应该知道被跟踪的轨迹线数值已有变化,或者不断地测量图形对象属性的数值,这是一项资源密集型操作。 这一事实在帮助中得到了明确的说明。
它的功能能更便利地显示任何图形对象的任何变化。 这种功能在终端中的存在形式,是作为 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 的图表会创建垂直线 — 每个图表一条线。 现在更改它们的属性,并查看获取的相关事件消息如何在日志当中显示:
正如我们所见,有关对象事件的消息显示在日志当中。 当以编程方式创建对象时,不会产生对象创建事件,因为程序员已经知道创建图形对象的时间点。 因此,不需要发送事件来重复事实
当然,在日志中简单地显示泛泛的消息不足以处理该事件。 但这些只是关于基本事件的消息,其参数已包含了稍后需定义的有关事件的所有数据。
下一步是什么?
在下一篇文章中,我将继续研究图形对象事件,并实现处理每个所获事件。
*该系列的前几篇文章:
DoEasy 函数库中的图形(第八十六部分):图形对象集合 - 管理属性修改
DoEasy 函数库中的图形(第八十七部分):图形对象集合 - 在所有打开的图表上管理对象属性修改
DoEasy 函数库中的图形(第八十八部分):图形对象集合 — 存储对象动态变化属性的二维动态数组
DoEasy 函数库中的图形(第八十九部分):标准图形对象编程。 基本功能
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/10139


