
DoEasy 函数库中的图形(第八十九部分):标准图形对象编程。 基本功能
内容
概述
目前,该函数库能够跟踪客户端终端图表上的标准图形对象,包括删除和修改其某些参数。 有时,直接从程序中了解如何在图表上新设置、修改或删除自定义图形对象非常有用。 然而,目前,我们还缺乏从自定义程序创建标准图形对象的能力。 拥有了针对图形对象和跟踪其属性变化的编程能力,我们就能够创建任意复杂度、嵌套程度、以及可控轴点数量的复合图形对象。 在本文中,我将创建标准图形对象的基本编程功能。 在接下来的文章中,我将完善这些功能,同时考虑基于标准图形对象创建自定义复合图形对象的能力。
此外,我还会逐步完成让函数库对象使用动态数组存储其属性的能力。 事实上,我在上一篇文章中已经开始做这些工作了。 在此,我会修复前一篇文章中的一个逻辑错误;该错误导致无法跟踪拥有两个以上轴心点的对象属性变化。 此外,我将修复并改进多维动态数组类,从而令它可以用作函数库的单独单元,并将其转移到单独的文件之中。
改进库类
抽象图形对象的衍生类需要一些由基准对象支持的属性,从而能够实现属性的搜索、排序,并在终端日志里显示。 在 GStdFiboArcObj.mqh 和 GStdGannFanObj.mqh 文件里,为对象加入支持 "Level value" 实数型属性的代码:
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdFiboArcObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property) { switch((int)property) { //--- Supported properties case GRAPH_OBJ_PROP_SCALE : case GRAPH_OBJ_PROP_PRICE : case GRAPH_OBJ_PROP_LEVELVALUE : return true; //--- Other properties are not supported //--- Default is 'false' default: break; } return false; } //+------------------------------------------------------------------+
在 GStdExpansionObj.mqh, GStdFiboChannelObj.mqh, GStdFiboFanObj.mqh, GStdFiboObj.mqh, GStdFiboTimesObj.mqh 和 GStdPitchforkObj.mqh 文件里,按照相同的方法进行以下修改,以便支持相同的属性:
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdPitchforkObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property) { switch((int)property) { //--- Supported properties case GRAPH_OBJ_PROP_PRICE : case GRAPH_OBJ_PROP_LEVELVALUE : return true; //--- Other properties are not supported //--- Default is 'false' default: break; } return false; } //+------------------------------------------------------------------+
在含有 "Horizontal line" 对象类的 GStdHLineObj.mqh 文件里,从返回对象支持该整数型属性的标志的方法中删除 “Pivot point time” 属性,因为该对象在构造时仅用到价格:
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdHLineObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property) { switch((int)property) { //--- Supported properties case GRAPH_OBJ_PROP_ID : case GRAPH_OBJ_PROP_TYPE : case GRAPH_OBJ_PROP_ELEMENT_TYPE : case GRAPH_OBJ_PROP_GROUP : case GRAPH_OBJ_PROP_BELONG : case GRAPH_OBJ_PROP_CHART_ID : case GRAPH_OBJ_PROP_WND_NUM : case GRAPH_OBJ_PROP_NUM : case GRAPH_OBJ_PROP_CREATETIME : case GRAPH_OBJ_PROP_TIMEFRAMES : case GRAPH_OBJ_PROP_BACK : case GRAPH_OBJ_PROP_ZORDER : case GRAPH_OBJ_PROP_HIDDEN : case GRAPH_OBJ_PROP_SELECTED : case GRAPH_OBJ_PROP_SELECTABLE : case GRAPH_OBJ_PROP_TIME : case GRAPH_OBJ_PROP_COLOR : case GRAPH_OBJ_PROP_STYLE : case GRAPH_OBJ_PROP_WIDTH : return true; //--- Other properties are not supported //--- Default is 'false' default: break; } return false; } //+------------------------------------------------------------------+
在 GStdVLineObj.mqh 文件里的 "Vertical line" 对象在构造时仅用到时间。 故此,我从返回对象支持实数型属性的标志的方法中删除了所有内容 — 该对象不再支持实数型属性:
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdVLineObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property) { return false; } //+------------------------------------------------------------------+
在上一篇文章中,我忽略了一个逻辑错误,当用两个轴点构建对象,或对象提供的级别超过两个时,该错误会阻止我们修改对象轴点和级别的属性。 它主要是关于将指定数量的单元添加到数组末尾的方法。 该方法接收指向外部创建的对象的指针,而数组接收指定数量的这些指针:
//--- Add the specified number of cells with objects to the end of the array bool AddQuantity(const string source,const int total,CObject *object) { //--- Declare the variable for storing the result of adding objects to the list bool res=true; //--- in the list by the number of added objects passed to the method for(int i=0;i<total;i++) { //--- if failed to add the object to the list if(!this.Add(object)) { //--- display the appropriate message, add 'false' to the variable value //--- and move on to the loop next iteration CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); res &=false; continue; } } //--- Return the total result of adding the specified number of objects to the list return res; }
然而,这是同一个对象! 我们只需简单地在循环中将指向方法外部创建的对象指针传递给它。 因此,更改对象本身的属性会影响所有指针 — 它们引用的也是同一个对象。 因此,我们在数组中填充的是相同对象属性的实例,而非不同实例的属性。 如果对象具有多个参考点,我们将轴点乘以指定的数量。 取代管理第二、第三、第四和第五个点的实数型数值,我们在数组添加第二个枢轴点的属性。 这会阻止我们去获取、跟踪和更改实数型参考点的数值。 更改第二个轴心点会将这些变化复制到第三、第四和第五个对象点。
我们再添加一个创建新数据对象的方法。 此方法将创建一个新的属性对象。 我们将在 AddQuantity() 方法中把这个新属性(而不是指针)添加到数组中,在该方法中,我们简单地按照指定数量把从外部创建的指针加入数组。
鉴于我们在 \MQL5\Include\DoEasy\Services\XDimArray.mqh 中有三组相同的类 — 创建整数型、实数型和字符串型动态多维数组的类,我们以创建整数型多维动态数组的类作为例子来研究如何运用它们。
在一个 long 型数组维度的类中,编写创建新数据对象的方法:
//+------------------------------------------------------------------+ //| Class of a single long array dimension | //+------------------------------------------------------------------+ class CDimLong : public CArrayObj { private: //--- Create a new data object CDataUnitLong *CreateData(const string source,const long value=0) { //--- Create a new long data object CDataUnitLong *data=new CDataUnitLong(); //--- If failed to create an object, inform of that in the journal if(data==NULL) ::Print(source,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_LONG_DATA_OBJ)); //--- Otherwise, set the value passed to the method for the object else data.Value=value; //--- Return the pointer to the object or NULL return data; } //--- Get long data object from the array
这里的一切都很简单:我们创建一个新的 long 型数据对象,并把要传递给方法的数值赋值给它。 如果无法创建对象,则在日志中通报。 该方法返回指向所创建对象的指针,或者在出现错误时返回 NULL。
将修改添加到 AddQuantity() 方法之中:
//--- Add the specified number of cells with data to the end of the array bool AddQuantity(const string source,const int total,const long value=0) { //--- Declare the variable for storing the result of adding objects to the list bool res=true; //--- in the list by the number of added objects passed to the method for(int i=0;i<total;i++) { //--- Create a new long data object CDataUnitLong *data=this.CreateData(DFUN,value); //--- If failed to create an object, inform of that and move on to the next iteration if(data==NULL) { res &=false; continue; } data.Value=value; //--- if failed to add the object to the list if(!this.Add(data)) { //--- display the appropriate message, remove the object and add 'false' to the variable value //--- and move on to the loop next iteration CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); delete data; res &=false; continue; } } //--- Return the total result of adding the specified number of objects to the list return res; }
现在,该方法接收要分配给新创建属性的值,取代指向该对象的指针。 在循环中,创建一个新对象,并将其添加到列表当中。
在 Increase() 方法中,我之前曾创建了一个新对象,并将指向它的指针传递给 AddQuantity() 方法,然后简单地调用 AddQuantity() 方法,因为新对象现在已于循环中创建,并添加到 AddQuantity() 方法内的数组之中,而不是如前在 crease() 方法中创建的单个指向对象的指针。
我们从方法中删除以下代码块:
//--- Increase the number of data cells by the specified value, return the number of added elements int Increase(const int total,const long value=0) { //--- Save the current array size int size_prev=this.Total(); //--- Create a new long data object CDataUnitLong *data=new CDataUnitLong(); //--- If failed to create an object, inform of that and return zero if(data==NULL) { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_LONG_DATA_OBJ)); return 0; } //--- Set the specified value to a newly created object data.Value=value; //--- Add the specified number of object instances to the list //--- and return the difference between the obtained and previous array size this.AddQuantity(DFUN,total,data); return this.Total()-size_prev; }
被调用的 AddQuantity() 方法现在接收新添加到数组中的数据对象的初始值,而不是指针:
//--- Increase the number of data cells by the specified value, return the number of added elements int Increase(const int total,const long value=0) { //--- Save the current array size int size_prev=this.Total(); //--- Add the specified number of object instances to the list //--- and return the difference between the obtained and previous array size this.AddQuantity(DFUN,total,value); return this.Total()-size_prev; }
针对文件的其余类进行相同的修改。 我不打算在这里重复它们,因为它们雷同。
您可以查看文后附件中的所有修改。
在 \MQL5\Include\DoEasy\Data.mqh 里,加入新的消息索引:
//--- CGraphElementsCollection MSG_GRAPH_ELM_COLLECTION_ERR_OBJ_ALREADY_EXISTS, // Error. A chart control object already exists with chart id MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_CREATE_CTRL_OBJ,// Failed to create chart control object with chart ID MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_GET_CTRL_OBJ, // Failed to get chart control object with chart ID MSG_GRAPH_ELM_COLLECTION_ERR_GR_OBJ_ALREADY_EXISTS,// Such graphical object already exists: //--- GStdGraphObj MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ, // Failed to create the class object for a graphical object MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_STD_GRAPH_OBJ, // Failed to create a graphical object MSG_GRAPH_STD_OBJ_ERR_NOT_FIND_SUBWINDOW, // Failed to find the chart subwindow
...
MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_ON, // On state MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_OFF, // Off state //--- CDataPropObj MSG_DATA_PROP_OBJ_OUT_OF_PROP_RANGE, // Passed property is out of object property range //--- 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_CLOSED_CHARTS, // Chart windows closed: MSG_GRAPH_OBJ_OBJECTS_ON_CLOSED_CHARTS, // Objects removed together with charts: }; //+------------------------------------------------------------------+
及与新添加的索引相对应的消息文本:
//--- CGraphElementsCollection {"Ошибка. Уже существует объект управления чартами с идентификатором чарта ","Error. A chart control object already exists with chart id "}, {"Не удалось создать объект управления чартами с идентификатором чарта ","Failed to create chart control object with chart id "}, {"Не удалось получить объект управления чартами с идентификатором чарта ","Failed to get chart control object with chart id "}, {"Такой графический объект уже существует: ","Such a graphic object already exists: "}, //--- GStdGraphObj {"Не удалось создать объект класса для графического объекта ","Failed to create class object for graphic object"}, {"Не удалось создать графический объект ","Failed to create graphic object "}, {"Не удалось найти подокно графика","Could not find chart subwindow"},
...
{"Состояние \"On\"","State \"On\""}, {"Состояние \"Off\"","State \"Off\""}, //--- CDataPropObj {"Переданное свойство находится за пределами диапазона свойств объекта","The passed property is outside the range of the object's properties"}, //--- 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"}, {"Закрыто окон графиков: ","Closed chart windows: "}, {"С ними удалено объектов: ","Objects removed with them: "}, }; //+---------------------------------------------------------------------+
我们对函数库图形对象的基准对象类进行一些小的改进。
图形对象拥有的 bool 属性能返回某些对象属性的标志。 抽象图形对象类拥有返回和设置此类标志的方法。 方法名则表明该方法是为了设置标志,例如:
SetFlagDrawLines (显示埃洛特波浪标记指示线). 在函数库图形对象的基准对象类中,相应的方法称为 SetDrawLines()。 故此,如果我们尝试为一个对象设置标志,我们将看到两条选择方法的提示。 这有点令人莫名其妙。 此外,如果我们选择基准图形对象的方法,而不是抽象对象的方法,那么对象数组中的属性不会被更改。 代之,我们简单地发出一条命令来修改图形对象本身的属性。 类对象中的相应属性将保持不变。 这意味着我们需要重命名所有这些方法,从而避免在选择两种方法之一时出错。 我相信,以后还需要统一这些方法的返回类型,以便编译器能够明确无误地选择所需的方法。
我们在 \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh 中引入必要的修复。:
//--- Set the "Background object" flag bool SetFlagBack(const bool flag) { ::ResetLastError(); if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_BACK,flag)) { this.m_back=flag; return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Set the "Object selection" flag bool SetFlagSelected(const bool flag) { ::ResetLastError(); if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTED,flag)) { this.m_selected=flag; return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Set the "Object selection" flag bool SetFlagSelectable(const bool flag) { ::ResetLastError(); if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag)) { 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) { ::ResetLastError(); if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag)) { this.m_hidden=flag; return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; }
我们将创建多维动态数组的类移至一个单独的文件当中。 我会对改进它们,令它们成为一种工具,可为函数库中的任何现有或计划中的对象创建属性,并应用数组存储其属性(整数型、实数型和字符串型)。
在服务类和函数的 \MQL5\Include\DoEasy\Services\文件夹中,创建一个新的文件 Properties.mqh。 这是为了获得所有用于创建对象属性的二维数组的类,以及在前一篇文章中直接在 CGStdGraphObj 抽象标准图形对象的类主体中设置的属性对象(包括以前的和当前的):
//+------------------------------------------------------------------+ //| The class of the abstract standard graphical object | //+------------------------------------------------------------------+ class CGStdGraphObj : public CGBaseObj { private: //--- Object property class class CDataPropObj { private: CArrayObj m_list; // list of property objects int m_total_int; // Number of integer parameters int m_total_dbl; // Number of real parameters int m_total_str; // Number of string parameters //--- Return the index of the array the (1) double and (2) string properties are actually located at int IndexProp(ENUM_GRAPH_OBJ_PROP_DOUBLE property) const { return(int)property-this.m_total_int; } int IndexProp(ENUM_GRAPH_OBJ_PROP_STRING property) const { return(int)property-this.m_total_int-this.m_total_dbl; } public: //--- Return the pointer to (1) the list of property objects, as well as to the object of (2) integer, (3) real and (4) string properties CArrayObj *GetList(void) { return &this.m_list; } CXDimArrayLong *Long() const { return this.m_list.At(0); } CXDimArrayDouble *Double() const { return this.m_list.At(1); } CXDimArrayString *String() const { return this.m_list.At(2); } //--- Set object's (1) integer, (2) real and (3) string properties void Set(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Long().Set(property,index,value); } void Set(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value) { this.Double().Set(this.IndexProp(property),index,value); } void Set(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value) { this.String().Set(this.IndexProp(property),index,value); } //--- Return object’s (1) integer, (2) real and (3) string property from the properties array long Get(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index) const { return this.Long().Get(property,index); } double Get(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index) const { return this.Double().Get(this.IndexProp(property),index); } string Get(ENUM_GRAPH_OBJ_PROP_STRING property,int index) const { return this.String().Get(this.IndexProp(property),index); } //--- Return the size of the specified first dimension data array int Size(const int range) const { if(range<this.m_total_int) return this.Long().Size(range); else if(range<this.m_total_int+this.m_total_dbl) return this.Double().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range)); else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str) return this.String().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range)); return 0; } //--- Set the array size in the specified dimensionality bool SetSizeRange(const int range,const int size) { if(range<this.m_total_int) return this.Long().SetSizeRange(range,size); else if(range<this.m_total_int+this.m_total_dbl) return this.Double().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range),size); else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str) return this.String().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range),size); return false; } //--- Constructor CDataPropObj(const int prop_total_integer,const int prop_total_double,const int prop_total_string) { this.m_total_int=prop_total_integer; this.m_total_dbl=prop_total_double; this.m_total_str=prop_total_string; this.m_list.Add(new CXDimArrayLong(this.m_total_int, 1)); this.m_list.Add(new CXDimArrayDouble(this.m_total_dbl,1)); this.m_list.Add(new CXDimArrayString(this.m_total_str,1)); } //--- Destructor ~CDataPropObj() { m_list.Clear(); m_list.Shutdown(); } }; //--- Data class of the current and previous properties class CProperty { public: CDataPropObj *Curr; // Pointer to the current properties object CDataPropObj *Prev; // Pointer to the previous properties object //--- Set the array size ('size') in the specified dimension ('range') bool SetSizeRange(const int range,const int size) { return(this.Curr.SetSizeRange(range,size) && this.Prev.SetSizeRange(range,size) ? true : false); } //--- Return the size of the specified array of the (1) current and (2) previous first dimension data int CurrSize(const int range) const { return Curr.Size(range); } int PrevSize(const int range) const { return Prev.Size(range); } //--- Copy the current data to the previous one void CurrentToPrevious(void) { //--- Copy all integer properties for(int i=0;i<this.Curr.Long().Total();i++) for(int r=0;r<this.Curr.Long().Size(i);r++) this.Prev.Long().Set(i,r,this.Curr.Long().Get(i,r)); //--- Copy all real properties for(int i=0;i<this.Curr.Double().Total();i++) for(int r=0;r<this.Curr.Double().Size(i);r++) this.Prev.Double().Set(i,r,this.Curr.Double().Get(i,r)); //--- Copy all string properties for(int i=0;i<this.Curr.String().Total();i++) for(int r=0;r<this.Curr.String().Size(i);r++) this.Prev.String().Set(i,r,this.Curr.String().Get(i,r)); } //--- Constructor CProperty(const int prop_int_total,const int prop_double_total,const int prop_string_total) { this.Curr=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); this.Prev=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); } };
我们需要去掉任何属于特定类对象的枚举引用,从而令类更具通用性。
为了实现这一点,在选择返回实数型属性索引的方法时,用更普通的 int 变量替换所有枚举。 为了计算属性索引,将实数型和字符串型属性的最大属性传递给类构造函数(整数型属性不会有偏移,并且与属性索引完全对应)。 接下来,简单地根据属性值和属性的最大值计算实值。 与往常一样,当展示出代码时,这个思路看起来更清晰。
在新添加的文件 \MQL5\Include\DoEasy\Services\Properties.mqh 中添加以下类:
//+------------------------------------------------------------------+ //| Properties.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 "XDimArray.mqh" //+------------------------------------------------------------------+ //| Object property class | //+------------------------------------------------------------------+ //--- Object property class class CDataPropObj : public CObject { private: CArrayObj m_list; // list of property objects int m_total_int; // Number of integer parameters int m_total_dbl; // Number of real parameters int m_total_str; // Number of string parameters int m_prop_max_dbl; // Maximum possible real property value int m_prop_max_str; // Maximum possible string property value //--- Return the index of the array the int, double or string property is actually located at int IndexProp(int property) const { //--- If the passed value is less than the number of integer parameters, //--- this is an integer property. Return the value passed to the method if(property<this.m_total_int) return property; //--- Otherwise if the passed value is less than the maximum possible real property value, //--- then this is a real property - return the calculated index in the array of real properties else if(property<this.m_prop_max_dbl) return property-this.m_total_int; //--- Otherwise if the passed value is less than the maximum possible string property value, //--- then this is a string property - return the calculated index in the array of string properties else if(property<this.m_prop_max_str) return property-this.m_total_int-this.m_total_dbl; //--- Otherwise, if the passed value exceeds the maximum range of all values of all properties, //--- inform of this in the journal and return INT_MAX causing the error //--- accessing the array in XDimArray file classes which send the appropriate warning to the journal CMessage::ToLog(DFUN,MSG_DATA_PROP_OBJ_OUT_OF_PROP_RANGE); return INT_MAX; } public: //--- Return the pointer to (1) the list of property objects, as well as to the object of (2) integer, (3) real and (4) string properties CArrayObj *GetList(void) { return &this.m_list; } CXDimArrayLong *Long() const { return this.m_list.At(0); } CXDimArrayDouble *Double() const { return this.m_list.At(1); } CXDimArrayString *String() const { return this.m_list.At(2); } //--- Set (1) integer, (2) real and (3) string properties in the appropriate property object void SetLong(int property,int index,long value) { this.Long().Set(property,index,value); } void SetDouble(int property,int index,double value) { this.Double().Set(this.IndexProp(property),index,value); } void SetString(int property,int index,string value) { this.String().Set(this.IndexProp(property),index,value); } //--- Return (1) integer, (2) real and (3) string property from the appropriate object long GetLong(int property,int index) const { return this.Long().Get(property,index); } double GetDouble(int property,int index) const { return this.Double().Get(this.IndexProp(property),index); } string GetString(int property,int index) const { return this.String().Get(this.IndexProp(property),index); } //--- Return the size of the specified first dimension data array int Size(const int range) const { if(range<this.m_total_int) return this.Long().Size(range); else if(range<this.m_prop_max_dbl) return this.Double().Size(this.IndexProp(range)); else if(range<this.m_prop_max_str) return this.String().Size(this.IndexProp(range)); return 0; } //--- Set the array size in the specified dimensionality bool SetSizeRange(const int range,const int size) { if(range<this.m_total_int) return this.Long().SetSizeRange(range,size); else if(range<this.m_prop_max_dbl) return this.Double().SetSizeRange(this.IndexProp(range),size); else if(range<this.m_prop_max_str) return this.String().SetSizeRange(this.IndexProp(range),size); return false; } //--- Constructor CDataPropObj(const int prop_total_integer,const int prop_total_double,const int prop_total_string) { //--- Set the passed amounts of integer, real and string properties in the variables this.m_total_int=prop_total_integer; this.m_total_dbl=prop_total_double; this.m_total_str=prop_total_string; //--- Calculate and set the maximum values of real and string properties to the variables this.m_prop_max_dbl=this.m_total_int+this.m_total_dbl; this.m_prop_max_str=this.m_total_int+this.m_total_dbl+this.m_total_str; //--- Add newly created objects of integer, real and string properties to the list this.m_list.Add(new CXDimArrayLong(this.m_total_int, 1)); this.m_list.Add(new CXDimArrayDouble(this.m_total_dbl,1)); this.m_list.Add(new CXDimArrayString(this.m_total_str,1)); } //--- Destructor ~CDataPropObj() { m_list.Clear(); m_list.Shutdown(); } }; //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Data class of the current and previous properties | //+------------------------------------------------------------------+ class CProperties : public CObject { private: CArrayObj m_list; // List for storing the pointers to property objects public: CDataPropObj *Curr; // Pointer to the current properties object CDataPropObj *Prev; // Pointer to the previous properties object //--- Set the array size ('size') in the specified dimension ('range') bool SetSizeRange(const int range,const int size) { return(this.Curr.SetSizeRange(range,size) && this.Prev.SetSizeRange(range,size) ? true : false); } //--- Return the size of the specified array of the (1) current and (2) previous first dimension data int CurrSize(const int range) const { return Curr.Size(range); } int PrevSize(const int range) const { return Prev.Size(range); } //--- Copy the current data to the previous one void CurrentToPrevious(void) { //--- Copy all integer properties for(int i=0;i<this.Curr.Long().Total();i++) for(int r=0;r<this.Curr.Long().Size(i);r++) this.Prev.Long().Set(i,r,this.Curr.Long().Get(i,r)); //--- Copy all real properties for(int i=0;i<this.Curr.Double().Total();i++) for(int r=0;r<this.Curr.Double().Size(i);r++) this.Prev.Double().Set(i,r,this.Curr.Double().Get(i,r)); //--- Copy all string properties for(int i=0;i<this.Curr.String().Total();i++) for(int r=0;r<this.Curr.String().Size(i);r++) this.Prev.String().Set(i,r,this.Curr.String().Get(i,r)); } //--- Constructor CProperties(const int prop_int_total,const int prop_double_total,const int prop_string_total) { //--- Create new objects of the current and previous properties this.Curr=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); this.Prev=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); //--- Add newly created objects to the list this.m_list.Add(this.Curr); this.m_list.Add(this.Prev); } //--- Destructor ~CProperties() { this.m_list.Clear(); this.m_list.Shutdown(); } }; //+------------------------------------------------------------------+
所有主要解释都在代码注释中设置。 将这些类与我在 \MQL5\Include\DoEasy\Objects\Graph\Standard\gstdgraphhobj.mqh 中创建的类进行比较。
现在,我们来改进 \MQL5\Include\DoEasy\Objects\Graph\standard\gstdgraphhobj.mqh 中的抽象标准图形对象类。
首先,包含新创建的对象属性类文件:
//+------------------------------------------------------------------+ //| GStdGraphObj.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 "..\GBaseObj.mqh" #include "..\..\..\Services\Properties.mqh" //+------------------------------------------------------------------+ //| The class of the abstract standard graphical object | //+------------------------------------------------------------------+ class CGStdGraphObj : public CGBaseObj {
属性对象类已经从类的私密部分删除。 指向属性对象的指针的声明也在其中。 访问属性对象的相应方法,位于类公开部分的每个 Get 和 Set 方法:
//+------------------------------------------------------------------+ //| The class of the abstract standard graphical object | //+------------------------------------------------------------------+ class CGStdGraphObj : public CGBaseObj { private: CProperties *Prop; // Pointer to the properties object int m_pivots; // Number of object reference points //--- Read and set (1) the time and (2) the price of the specified object pivot point void SetTimePivot(const int index); void SetPricePivot(const int index); //--- Read and set (1) color, (2) style, (3) width, (4) value, (5) text of the specified object level void SetLevelColor(const int index); void SetLevelStyle(const int index); void SetLevelWidth(const int index); void SetLevelValue(const int index); void SetLevelText(const int index); //--- Read and set the BMP file name for the "Bitmap Level" object. Index: 0 - ON, 1 - OFF void SetBMPFile(const int index); public: //--- Set object's (1) integer, (2) real and (3) string properties void SetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Prop.Curr.SetLong(property,index,value); } void SetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value) { this.Prop.Curr.SetDouble(property,index,value); } void SetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value) { this.Prop.Curr.SetString(property,index,value); } //--- Return object’s (1) integer, (2) real and (3) string property from the properties array long GetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index) const { return this.Prop.Curr.GetLong(property,index); } double GetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index) const { return this.Prop.Curr.GetDouble(property,index); } string GetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index) const { return this.Prop.Curr.GetString(property,index); } //--- Set object's previous (1) integer, (2) real and (3) string properties void SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Prop.Prev.SetLong(property,index,value); } void SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value){ this.Prop.Prev.SetDouble(property,index,value); } void SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value){ this.Prop.Prev.SetString(property,index,value); } //--- Return object’s (1) integer, (2) real and (3) string property from the previous properties array long GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index) const { return this.Prop.Prev.GetLong(property,index); } double GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index) const { return this.Prop.Prev.GetDouble(property,index); } string GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index) const { return this.Prop.Prev.GetString(property,index); } //--- Return itself CGStdGraphObj *GetObject(void) { return &this;}
在公开部分,添加类的析构函数,完成属性对象的删除:
//--- Default constructor CGStdGraphObj(){ this.m_type=OBJECT_DE_TYPE_GSTD_OBJ; m_group=WRONG_VALUE; } //--- Destructor ~CGStdGraphObj() { if(this.Prop!=NULL) delete this.Prop; } protected: //--- Protected parametric constructor CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type, const ENUM_GRAPH_OBJ_BELONG belong, const ENUM_GRAPH_OBJ_GROUP group, const long chart_id, const int pivots, const string name);
在简化访问和设置图形对象属性的方法部分,改进了设置标志属性的方法:
//--- Background object bool Back(void) const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_BACK,0); } void SetFlagBack(const bool flag) { if(CGBaseObj::SetFlagBack(flag)) this.SetProperty(GRAPH_OBJ_PROP_BACK,0,flag); } //--- 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); } void SetZorder(const long value) { if(CGBaseObj::SetZorder(value)) this.SetProperty(GRAPH_OBJ_PROP_ZORDER,0,value); } //--- 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); } void SetFlagHidden(const bool flag) { if(CGBaseObj::SetFlagHidden(flag)) this.SetProperty(GRAPH_OBJ_PROP_HIDDEN,0,flag); } //--- Object selection bool Selected(void) const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTED,0); } void SetFlagSelected(const bool flag) { if(CGBaseObj::SetFlagSelected(flag)) this.SetProperty(GRAPH_OBJ_PROP_SELECTED,0,flag); } //--- Object availability bool Selectable(void) const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTABLE,0); } void SetFlagSelectable(const bool flag) { if(CGBaseObj::SetFlagSelectable(flag)) this.SetProperty(GRAPH_OBJ_PROP_SELECTABLE,0,flag); } //--- Time coordinate
把复制当前属性到之前属性的方法从私密部分移动到公开部分:
//--- Return the description of the object visibility on timeframes string VisibleOnTimeframeDescription(void); //--- Re-write all graphical object properties void PropertiesRefresh(void); //--- Check object property changes void PropertiesCheckChanged(void); //--- Copy the current data to the previous one void PropertiesCopyToPrevData(void); private: //--- Get and save (1) integer, (2) real and (3) string properties void GetAndSaveINT(void); void GetAndSaveDBL(void); void GetAndSaveSTR(void); }; //+------------------------------------------------------------------+
在受保护的参数化构造函数中,创建图形对象属性的新对象:
//+------------------------------------------------------------------+ //| Protected parametric constructor | //+------------------------------------------------------------------+ CGStdGraphObj::CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type, const ENUM_GRAPH_OBJ_BELONG belong, const ENUM_GRAPH_OBJ_GROUP group, const long chart_id,const int pivots, const string name) { //--- Create the property object with the default values this.Prop=new CProperties(GRAPH_OBJ_PROP_INTEGER_TOTAL,GRAPH_OBJ_PROP_DOUBLE_TOTAL,GRAPH_OBJ_PROP_STRING_TOTAL); //--- Set the number of pivot points and object levels
将整数型、实数型和字符串型图形对象属性的数量传递给类构造函数。
在返回图形整数型属性,并将其保存在类对象属性中的方法中,检查对象级别的数量是否已更改,如果是,则修改所有属性的数组大小,从而确保能够存储级别值。
否则,在设置级别属性时,我们可能会收到数组超界错误:
//--- 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)
简化检查对象属性变化的方法:
//+------------------------------------------------------------------+ //| Check object property changes | //+------------------------------------------------------------------+ void CGStdGraphObj::PropertiesCheckChanged(void) { 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; ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop)); } } } 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; ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop)); } } } 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)) { changed=true; ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop)); } } } if(changed) PropertiesCopyToPrevData(); } //+------------------------------------------------------------------+
在过去的方法实现中,我采用 if-else 构造来确保属性拥有多个值(例如锚定点时间),并在单独的代码模块中逐一处理每个属性。 由于我们能知道每个属性的属性数组大小,故只需依据数组第二维度的大小循环遍历单个属性的值就足够了。 对于单个属性,第二个维度的大小为 1,而对于多个属性,它等于多属性值的数量。 因此,在单循环中即可完成每个对象属性的访问。 这就是我在上面所做的。
我还在同一个文件中实现了一些小的改进(例如更改方法名)。 举例来说,LevelColorsDescription() 已重命名为 LevelsColorDescription(),这更符合方法的原意。 我不会在此讨论如何重新命名。 您可以在附件中找到它们。
在其它属性之外,每个函数库对象都有一个自定义对象 ID。 图形元素集合类提供了两个集合 — 图形元素集合,在图形对象集合(以手动创建的标准图形对象为特征)完成之前,我暂停了它的开发;我现在正忙于可编程创建标准图形对象。 在此,我启动开发可编程标准图形对象的功能。
以编程方式创建的图形对象的 ID 将处于 1 到 10000(含)之间。 手动创建的图形对象的 ID 从 10001 开始。
我们在 \MQL5\Include\DoEasy\Defines.mqh 文件里设置这个阈值 :
//--- Pending request type IDs #define PENDING_REQUEST_ID_TYPE_ERR (1) // Type of a pending request created based on the server return code #define PENDING_REQUEST_ID_TYPE_REQ (2) // Type of a pending request created by request //--- Timeseries parameters #define SERIES_DEFAULT_BARS_COUNT (1000) // Required default amount of timeseries data #define PAUSE_FOR_SYNC_ATTEMPTS (16) // Amount of pause milliseconds between synchronization attempts #define ATTEMPTS_FOR_SYNC (5) // Number of attempts to receive synchronization with the server //--- Tick series parameters #define TICKSERIES_DEFAULT_DAYS_COUNT (1) // Required number of days for tick data in default series #define TICKSERIES_MAX_DATA_TOTAL (200000) // Maximum number of stored tick data of a single symbol //--- Parameters of the DOM snapshot series #define MBOOKSERIES_DEFAULT_DAYS_COUNT (1) // The default required number of days for DOM snapshots in the series #define MBOOKSERIES_MAX_DATA_TOTAL (200000) // Maximum number of stored DOM snapshots of a single symbol //--- Canvas parameters #define PAUSE_FOR_CANV_UPDATE (16) // Canvas update frequency #define NULL_COLOR (0x00FFFFFF) // Zero for the canvas with the alpha channel #define OUTER_AREA_SIZE (16) // Size of one side of the outer area around the workspace //--- Graphical object parameters #define PROGRAM_OBJ_MAX_ID (10000) // Maximum value of an ID of a graphical object belonging to a program //+------------------------------------------------------------------+ //| Enumerations | //+------------------------------------------------------------------+
标准图形对象的编程方法
我们已拥有跟踪图表上手动创建图形对象、创建相应类对象并将它们添加到集合列表当中的方法。 当然,最好在当前的任务中使用它们,但有一些原因迫使我放弃使用部分现成的方法。 我们简单地跟踪计时器中图形对象的外观。 当以编程方式创建对象时,我不想等待计时器的下一次跳动,并定义新创建的对象,及其创建方法(编程和手动)。
取而代之,我将在图形元素集合类中创建构建标准图形对象的方法。 在构建对象之后,我将立即创建相应的类对象,并将其放置在集合当中。 搜索对象属性中的变化改由已创建的功能执行。 因此,我们将能够创建对象,并将其添加到集合当中,同时无需考虑对象创建方法,即可保留搜索其变化的能力。 将来,这将简化复合图形对象的创建和属性管理。
在以编程方式创建的图形对象时,其名称将包含源自创建对象程序的名称。 这将令我们能够区分“自我”图形对象,和手动创建的图形对象。
为了实现这一点,在图形元素集合类 \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh 文件中的图表对象管理类的私密部分中添加存储程序名的新变量:
//+------------------------------------------------------------------+ //| Chart object management class | //+------------------------------------------------------------------+ class CChartObjectsControl : public CObject { private: CArrayObj m_list_new_graph_obj; // List of added graphical objects ENUM_TIMEFRAMES m_chart_timeframe; // Chart timeframe long m_chart_id; // Chart ID long m_chart_id_main; // Control program chart ID string m_chart_symbol; // Chart symbol bool m_is_graph_obj_event; // Event flag in the list of graphical objects int m_total_objects; // Number of graphical objects int m_last_objects; // Number of graphical objects during the previous check int m_delta_graph_obj; // Difference in the number of graphical objects compared to the previous check int m_handle_ind; // Event controller indicator handle string m_name_ind; // Short name of the event controller indicator string m_name_program; // Program name //--- Return the name of the last graphical object added to the chart string LastAddedGraphObjName(void); //--- Set the permission to track mouse events and graphical objects void SetMouseEvent(void); public:
在类的公开部分,从 CreateNewGraphObj() 方法中删除指定图表 ID 的操作,因为该 ID 是图表对象的主要属性之一,其可直接从该对象获得,无需传递。
将程序名称赋值给类构造函数中的相应变量:
public: //--- Return the variable values ENUM_TIMEFRAMES Timeframe(void) const { return this.m_chart_timeframe; } long ChartID(void) const { return this.m_chart_id; } string Symbol(void) const { return this.m_chart_symbol; } bool IsEvent(void) const { return this.m_is_graph_obj_event; } int TotalObjects(void) const { return this.m_total_objects; } int Delta(void) const { return this.m_delta_graph_obj; } //--- Create a new standard graphical object CGStdGraphObj *CreateNewGraphObj(const ENUM_OBJECT obj_type,const string name); //--- Return the list of newly added objects CArrayObj *GetListNewAddedObj(void) { return &this.m_list_new_graph_obj;} //--- Create the event control indicator bool CreateEventControlInd(const long chart_id_main); //--- Add the event control indicator to the chart bool AddEventControlInd(void); //--- Check the chart objects void Refresh(void); //--- Constructors CChartObjectsControl(void) { this.m_name_program=::MQLInfoString(MQL_PROGRAM_NAME); this.m_chart_id=::ChartID(); this.m_chart_timeframe=(ENUM_TIMEFRAMES)::ChartPeriod(this.m_chart_id); this.m_chart_symbol=::ChartSymbol(this.m_chart_id); this.m_chart_id_main=::ChartID(); this.m_list_new_graph_obj.Clear(); this.m_list_new_graph_obj.Sort(); this.m_is_graph_obj_event=false; this.m_total_objects=0; this.m_last_objects=0; this.m_delta_graph_obj=0; this.m_name_ind=""; this.m_handle_ind=INVALID_HANDLE; this.SetMouseEvent(); } CChartObjectsControl(const long chart_id) { this.m_name_program=::MQLInfoString(MQL_PROGRAM_NAME); this.m_chart_timeframe=(ENUM_TIMEFRAMES)::ChartPeriod(this.m_chart_id); this.m_chart_symbol=::ChartSymbol(this.m_chart_id); this.m_chart_id_main=::ChartID(); this.m_list_new_graph_obj.Clear(); this.m_list_new_graph_obj.Sort(); this.m_chart_id=chart_id; this.m_is_graph_obj_event=false; this.m_total_objects=0; this.m_last_objects=0; this.m_delta_graph_obj=0; this.m_name_ind=""; this.m_handle_ind=INVALID_HANDLE; this.SetMouseEvent(); }
除了检查空名称之外,确保对象不是在检查图表对象的方法中以编程方式创建的:
//+------------------------------------------------------------------+ //| 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 the number of objects has changed if(this.m_delta_graph_obj!=0) { //--- Create the string and display it in the journal with the chart ID, its symbol and timeframe string txt=", "+(m_delta_graph_obj>0 ? "Added: " : "Deleted: ")+(string)fabs(m_delta_graph_obj)+" obj"; Print(DFUN,"ChartID=",this.ChartID(),", ",this.Symbol(),", ",TimeframeDescription(this.Timeframe()),txt); } //--- 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(); 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) 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) { this.m_list_new_graph_obj.Add(obj); } } } //--- 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; } //+------------------------------------------------------------------+
换句话说,如果一个对象名没有包含程序名称的子字符串,那么该对象应由该方法处理,否则这是一个通过编程创建的图形对象,其应由另一个方法添加到集合列表当中。
在创建新标准图形对象的方法中,以前需传递给方法的所有 chart_id,现在可由对象自身所含的 id 替换:
//+------------------------------------------------------------------+ //| CChartObjectsControl: | //| Create a new standard graphical object | //+------------------------------------------------------------------+ CGStdGraphObj *CChartObjectsControl::CreateNewGraphObj(const ENUM_OBJECT obj_type,const string name) { CGStdGraphObj *obj=NULL; switch((int)obj_type) { //--- Lines case OBJ_VLINE : return new CGStdVLineObj(this.ChartID(),name); case OBJ_HLINE : return new CGStdHLineObj(this.ChartID(),name); case OBJ_TREND : return new CGStdTrendObj(this.ChartID(),name); case OBJ_TRENDBYANGLE : return new CGStdTrendByAngleObj(this.ChartID(),name); case OBJ_CYCLES : return new CGStdCyclesObj(this.ChartID(),name); case OBJ_ARROWED_LINE : return new CGStdArrowedLineObj(this.ChartID(),name); //--- Channels case OBJ_CHANNEL : return new CGStdChannelObj(this.ChartID(),name); case OBJ_STDDEVCHANNEL : return new CGStdStdDevChannelObj(this.ChartID(),name); case OBJ_REGRESSION : return new CGStdRegressionObj(this.ChartID(),name); case OBJ_PITCHFORK : return new CGStdPitchforkObj(this.ChartID(),name); //--- Gann case OBJ_GANNLINE : return new CGStdGannLineObj(this.ChartID(),name); case OBJ_GANNFAN : return new CGStdGannFanObj(this.ChartID(),name); case OBJ_GANNGRID : return new CGStdGannGridObj(this.ChartID(),name); //--- Fibo case OBJ_FIBO : return new CGStdFiboObj(this.ChartID(),name); case OBJ_FIBOTIMES : return new CGStdFiboTimesObj(this.ChartID(),name); case OBJ_FIBOFAN : return new CGStdFiboFanObj(this.ChartID(),name); case OBJ_FIBOARC : return new CGStdFiboArcObj(this.ChartID(),name); case OBJ_FIBOCHANNEL : return new CGStdFiboChannelObj(this.ChartID(),name); case OBJ_EXPANSION : return new CGStdExpansionObj(this.ChartID(),name); //--- Elliott case OBJ_ELLIOTWAVE5 : return new CGStdElliotWave5Obj(this.ChartID(),name); case OBJ_ELLIOTWAVE3 : return new CGStdElliotWave3Obj(this.ChartID(),name); //--- Shapes case OBJ_RECTANGLE : return new CGStdRectangleObj(this.ChartID(),name); case OBJ_TRIANGLE : return new CGStdTriangleObj(this.ChartID(),name); case OBJ_ELLIPSE : return new CGStdEllipseObj(this.ChartID(),name); //--- Arrows case OBJ_ARROW_THUMB_UP : return new CGStdArrowThumbUpObj(this.ChartID(),name); case OBJ_ARROW_THUMB_DOWN : return new CGStdArrowThumbDownObj(this.ChartID(),name); case OBJ_ARROW_UP : return new CGStdArrowUpObj(this.ChartID(),name); case OBJ_ARROW_DOWN : return new CGStdArrowDownObj(this.ChartID(),name); case OBJ_ARROW_STOP : return new CGStdArrowStopObj(this.ChartID(),name); case OBJ_ARROW_CHECK : return new CGStdArrowCheckObj(this.ChartID(),name); case OBJ_ARROW_LEFT_PRICE : return new CGStdArrowLeftPriceObj(this.ChartID(),name); case OBJ_ARROW_RIGHT_PRICE : return new CGStdArrowRightPriceObj(this.ChartID(),name); case OBJ_ARROW_BUY : return new CGStdArrowBuyObj(this.ChartID(),name); case OBJ_ARROW_SELL : return new CGStdArrowSellObj(this.ChartID(),name); case OBJ_ARROW : return new CGStdArrowObj(this.ChartID(),name); //--- Graphical objects case OBJ_TEXT : return new CGStdTextObj(this.ChartID(),name); case OBJ_LABEL : return new CGStdLabelObj(this.ChartID(),name); case OBJ_BUTTON : return new CGStdButtonObj(this.ChartID(),name); case OBJ_CHART : return new CGStdChartObj(this.ChartID(),name); case OBJ_BITMAP : return new CGStdBitmapObj(this.ChartID(),name); case OBJ_BITMAP_LABEL : return new CGStdBitmapLabelObj(this.ChartID(),name); case OBJ_EDIT : return new CGStdEditObj(this.ChartID(),name); case OBJ_EVENT : return new CGStdEventObj(this.ChartID(),name); case OBJ_RECTANGLE_LABEL : return new CGStdRectangleLabelObj(this.ChartID(),name); default : return NULL; } } //+------------------------------------------------------------------+
在图形对象的 CGraphElementsCollection 集合类中,即,在返回第一个可用图形对象 ID 的方法中,添加标志,指定所需对象 ID:false — 对于手动创建的对象;true — 对于编程创建的对象:
//--- Return the first free ID of the graphical (1) object and (2) element on canvas long GetFreeGraphObjID(bool program_object); long GetFreeCanvElmID(void); //--- Add a graphical object to the collection
声明创建新标准图形对象的私密方法:
//--- Remove the object of managing charts from the list bool DeleteGraphObjCtrlObjFromList(CChartObjectsControl *obj); //--- Create a new standard graphical object, return an object name bool CreateNewStdGraphObject(const long chart_id, const string name, const ENUM_OBJECT type, const int subwindow, 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); public:
在类的私密部分,编写创建新图形对象,并返回指向图表管理对象指针的方法:
//--- 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; } public:
方法逻辑已在代码注释中描述。 该方法将在类的公开部分创建指定类型的标准图形对象时被调用。
创建“垂直线”图形对象的方法:
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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); //--- If failed to add an object to the collection list, if(!this.m_list_all_graph_obj.Add(obj)) { //--- inform of that, remove the graphical and class object, and return 'false' CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } //--- Redraw the chart and display all object properties in the journal (temporarily, for test purposes only) ::ChartRedraw(chart_id); obj.Print(); return true; }
该方法的代码注释中已有详细描述。 每个特定对象中固有的属性,以及参数中传递的属性,将在每个此类对象中进行设置。 首先在指定的图表上创建一个物理图形对象,形成指向图表管理对象的指针。 其 CreateNewGraphObj() 方法创建与指定类型相对应的类对象。 如果将对象添加到列表中失败,则物理图形对象本身和类对象将被删除,并向日志发送错误消息。 如果创建成功,图表将被更新,方法将返回 true。
其余创建图形对象的方法与上述方法雷同,仅在为每个特定图形对象定义的参数集上有所区别。
我们来看看添加的其它所有方法的清单:
//--- Create the "Horizontal line" graphical object bool CreateLineHorizontal(const long chart_id,const string name,const int subwindow,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_HLINE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,price); if(ctrl==NULL) return false; CGStdHLineObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_TREND; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdTrendObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_TRENDBYANGLE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdTrendByAngleObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetAngle(angle); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Cyclic lines" graphical object bool CreateLineCycle(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_CYCLES; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdCyclesObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Arrowed line" graphical object bool CreateLineArrowed(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROWED_LINE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdArrowedLineObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Equidistant channel" graphical object bool CreateChannel(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2, double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_CHANNEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdChannelObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Standard deviation channel" graphical object bool CreateChannelStdDeviation(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const double deviation=1.5) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_STDDEVCHANNEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdStdDevChannelObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDeviation(deviation); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Linear regression channel" graphical object bool CreateChannelRegression(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_REGRESSION; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdRegressionObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Andrews' Pitchfork" graphical object bool CreatePitchforkAndrews(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_PITCHFORK; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdPitchforkObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Gann line" graphical object bool CreateGannLine(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,double angle) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_GANNLINE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdGannLineObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetAngle(angle); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Gann fan" graphical object bool CreateGannFan(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2, const ENUM_GANN_DIRECTION direction,const double scale) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_GANNFAN; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdGannFanObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDirection(direction); obj.SetScale(scale); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Gann grid" graphical object bool CreateGannGrid(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2, const ENUM_GANN_DIRECTION direction,const double scale) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_GANNGRID; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2); if(ctrl==NULL) return false; CGStdGannGridObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDirection(direction); obj.SetScale(scale); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo levels" graphical object bool CreateFiboLevels(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBO; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdFiboObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo Time Zones" graphical object bool CreateFiboTimeZones(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBOTIMES; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdFiboTimesObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo fan" graphical object bool CreateFiboFan(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBOFAN; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdFiboFanObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo arc" graphical object bool CreateFiboArc(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2, const double scale,const bool ellipse) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBOARC; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdFiboArcObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetScale(scale); obj.SetFlagEllipse(ellipse); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo channel" graphical object bool CreateFiboChannel(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBOCHANNEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdFiboChannelObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo extension" graphical object bool CreateFiboExpansion(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_EXPANSION; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdExpansionObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Elliott 5 waves" graphical object bool CreateElliothWave5(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2, const datetime time3,double price3,const datetime time4,double price4, const datetime time5,double price5,const ENUM_ELLIOT_WAVE_DEGREE degree, const bool draw_lines) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ELLIOTWAVE5; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5); if(ctrl==NULL) return false; CGStdElliotWave5Obj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDegree(degree); obj.SetFlagDrawLines(draw_lines); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Elliott 3 waves" graphical object bool CreateElliothWave3(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2, double price2,const datetime time3,double price3, const ENUM_ELLIOT_WAVE_DEGREE degree,const bool draw_lines) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ELLIOTWAVE3; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdElliotWave3Obj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDegree(degree); obj.SetFlagDrawLines(draw_lines); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Rectangle graphical object bool CreateRectangle(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_RECTANGLE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdRectangleObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Triangle graphical object bool CreateTriangle(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_TRIANGLE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdTriangleObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Ellipse graphical object bool CreateEllipse(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ELLIPSE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdEllipseObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Thumb up" graphical object bool CreateThumbUp(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_THUMB_UP; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowThumbUpObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Thumb down" graphical object bool CreateThumbDown(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_THUMB_DOWN; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowThumbDownObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Arrow up" graphical object bool CreateArrowUp(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_UP; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowUpObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Arrow down" graphical object bool CreateArrowDown(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_DOWN; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowDownObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Stop graphical object bool CreateSignalStop(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_STOP; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowStopObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Check mark" graphical object bool CreateSignalCheck(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_CHECK; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowCheckObj *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.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_LEFT_PRICE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowLeftPriceObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_RIGHT_PRICE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowRightPriceObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Buy graphical object bool CreateSignalBuy(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_BUY; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowBuyObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Sell graphical object bool CreateSignalSell(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_SELL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowSellObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetArrowCode(arrow_code); obj.SetAnchor(anchor); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_TEXT; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdTextObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetText(text); obj.SetFontSize(size); obj.SetAnchor(anchor_point); obj.SetAngle(angle); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_LABEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdLabelObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetText(text); obj.SetFontSize(size); obj.SetCorner(corner); obj.SetAnchor(anchor_point); obj.SetAngle(angle); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_BUTTON; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdButtonObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetCorner(corner); obj.SetFontSize(font_size); obj.SetFlagState(button_state); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_CHART; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdChartObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetCorner(corner); obj.SetChartObjChartScale(scale); obj.SetChartObjSymbol(symbol); obj.SetChartObjPeriod(timeframe); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_BITMAP; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdBitmapObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetAnchor(anchor); obj.SetBMPFile(image1,0); obj.SetBMPFile(image2,1); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_BITMAP_LABEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdBitmapLabelObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetCorner(corner); obj.SetAnchor(anchor); obj.SetBMPFile(image1,0); obj.SetBMPFile(image2,1); obj.SetFlagState(state); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_EDIT; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdEditObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetFontSize(font_size); obj.SetCorner(corner); obj.SetAlign(align); obj.SetFlagReadOnly(readonly); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Economic calendar event" graphical object bool CreateCalendarEvent(const long chart_id,const string name,const int subwindow,const datetime time) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_EVENT; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,0); if(ctrl==NULL) return false; CGStdEventObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- 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) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_RECTANGLE_LABEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdRectangleLabelObj *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); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetCorner(corner); obj.SetBorderType(border); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } }; //+------------------------------------------------------------------+
所有方法都有自己的输入集合。 这些参数设置的最小对象属性,足以创建一个对象。 创建图形对象后,所有其余的属性可以随时更改。
返回第一个可用图形对象 ID 的方法:
//+------------------------------------------------------------------+ //| Return the first free graphical object ID | //+------------------------------------------------------------------+ long CGraphElementsCollection::GetFreeGraphObjID(bool program_object) { CArrayObj *list=NULL; int index=WRONG_VALUE; if(program_object) list=CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_ID,0,PROGRAM_OBJ_MAX_ID,EQUAL_OR_LESS); else list=CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_ID,0,PROGRAM_OBJ_MAX_ID,MORE); index=CSelect::FindGraphicStdObjectMax(list,GRAPH_OBJ_PROP_ID,0); CGStdGraphObj *obj=list.At(index); int first_id=(program_object ? 1 : PROGRAM_OBJ_MAX_ID+1); return(obj!=NULL ? obj.ObjectID()+1 : first_id); } //+------------------------------------------------------------------+
现在,该方法要考虑接收所需的 ID。
如果它用于编程创建图形对象,则获取 ID 小于或等于 PROGRAM_OBJ_MAX_ID (10000) 常量值的所有对象的列表。
如果它用于手动创建图形对象,则获取 ID 大于 PROGRAM_OBJ_MAX_ID 的所有对象的列表。
接下来,从获得的列表中提取最大 ID 的对象索引,并依据其索引获取所列对象。
接着,计算第一个 ID 的值(对于编程对象 — 1,对于手动创建对象 — 10000+1)。
如果接收到 ID 最大的对象,则取其 ID+1 的值。 否则,对象不在列表中,并返回第一个计算 ID 值(1 或 10001)。
在添加图形对象到集合的方法中,找出一个对象是通过编程还是手动创建的(依据对象名)来搜索 ID,并将其值传递给 GetFreeGraphBobjid() 方法:
//+------------------------------------------------------------------+ //| Add a graphical object to the collection | //+------------------------------------------------------------------+ bool CGraphElementsCollection::AddGraphObjToCollection(const string source,CChartObjectsControl *obj_control) { //--- Get the list of the last added graphical objects from the class for managing graphical objects CArrayObj *list=obj_control.GetListNewAddedObj(); //--- If failed to obtain the list, inform of that and return 'false' if(list==NULL) { CMessage::ToLog(DFUN_ERR_LINE,MSG_GRAPH_OBJ_FAILED_GET_ADDED_OBJ_LIST); return false; } //--- If the list is empty, return 'false' if(list.Total()==0) return false; //--- Declare the variable for storing the result bool res=true; //--- In the loop by the list of newly added standard graphical objects, for(int i=0;i<list.Total();i++) { //--- retrieve the next object from the list and CGStdGraphObj *obj=list.Detach(i); //--- if failed to retrieve the object, inform of that, add 'false' to the resulting variable and move on to the next one if(obj==NULL) { CMessage::ToLog(source,MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST); res &=false; continue; } //--- if failed to add the object to the collection list, inform of that, //--- remove the object, add 'false' to the resulting variable and move on to the next one if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); delete obj; res &=false; continue; } //--- The object has been successfully retrieved from the list of newly added graphical objects and introduced into the collection - //--- find the next free object ID, write it to the property and display the short object description in the journal else { bool program_object=(::StringFind(obj.Name(),this.m_name_program)==0); obj.SetObjectID(this.GetFreeGraphObjID(program_object)); obj.Print(); } } //--- Return the result of adding the object to the collection return res; } //+------------------------------------------------------------------+
我们去掉 if-else,并添加对象单击跟踪来简化事件处理程序逻辑,从而判断用鼠标选择对象(尚未实现):
//+------------------------------------------------------------------+ //| 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 || idx==CHARTEVENT_OBJECT_CHANGE || idx==CHARTEVENT_OBJECT_DRAG || id==CHARTEVENT_OBJECT_CLICK || idx==CHARTEVENT_OBJECT_CLICK) { //--- Get the chart ID. If lparam is zero, //--- the event is from the current chart, //--- otherwise, this is a custom event from an indicator long chart_id=(lparam==0 ? ::ChartID() : lparam); //--- 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); //--- Set a new name for the collection list object, which does not correspond to any graphical object on the chart obj.SetName(name_new); } //--- Update the properties of the obtained object //--- and check their change obj.PropertiesRefresh(); obj.PropertiesCheckChanged(); } } //+------------------------------------------------------------------+
创建新标准图形对象的方法:
//+------------------------------------------------------------------+ //| Create a new standard graphical object | //+------------------------------------------------------------------+ bool CGraphElementsCollection::CreateNewStdGraphObject(const long chart_id, const string name, const ENUM_OBJECT type, const int subwindow, 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) { ::ResetLastError(); switch(type) { //--- Lines case OBJ_VLINE : return ::ObjectCreate(chart_id,name,OBJ_VLINE,subwindow,time1,0); case OBJ_HLINE : return ::ObjectCreate(chart_id,name,OBJ_HLINE,subwindow,0,price1); case OBJ_TREND : return ::ObjectCreate(chart_id,name,OBJ_TREND,subwindow,time1,price1,time2,price2); case OBJ_TRENDBYANGLE : return ::ObjectCreate(chart_id,name,OBJ_TRENDBYANGLE,subwindow,time1,price1,time2,price2); case OBJ_CYCLES : return ::ObjectCreate(chart_id,name,OBJ_CYCLES,subwindow,time1,price1,time2,price2); case OBJ_ARROWED_LINE : return ::ObjectCreate(chart_id,name,OBJ_ARROWED_LINE,subwindow,time1,price1,time2,price2); //--- Channels case OBJ_CHANNEL : return ::ObjectCreate(chart_id,name,OBJ_CHANNEL,subwindow,time1,price1,time2,price2,time3,price3); case OBJ_STDDEVCHANNEL : return ::ObjectCreate(chart_id,name,OBJ_STDDEVCHANNEL,subwindow,time1,price1,time2,price2); case OBJ_REGRESSION : return ::ObjectCreate(chart_id,name,OBJ_REGRESSION,subwindow,time1,price1,time2,price2); case OBJ_PITCHFORK : return ::ObjectCreate(chart_id,name,OBJ_PITCHFORK,subwindow,time1,price1,time2,price2,time3,price3); //--- Gann case OBJ_GANNLINE : return ::ObjectCreate(chart_id,name,OBJ_GANNLINE,subwindow,time1,price1,time2,price2); case OBJ_GANNFAN : return ::ObjectCreate(chart_id,name,OBJ_GANNFAN,subwindow,time1,price1,time2,price2); case OBJ_GANNGRID : return ::ObjectCreate(chart_id,name,OBJ_GANNGRID,subwindow,time1,price1,time2,price2); //--- Fibo case OBJ_FIBO : return ::ObjectCreate(chart_id,name,OBJ_FIBO,subwindow,time1,price1,time2,price2); case OBJ_FIBOTIMES : return ::ObjectCreate(chart_id,name,OBJ_FIBOTIMES,subwindow,time1,price1,time2,price2); case OBJ_FIBOFAN : return ::ObjectCreate(chart_id,name,OBJ_FIBOFAN,subwindow,time1,price1,time2,price2); case OBJ_FIBOARC : return ::ObjectCreate(chart_id,name,OBJ_FIBOARC,subwindow,time1,price1,time2,price2); case OBJ_FIBOCHANNEL : return ::ObjectCreate(chart_id,name,OBJ_FIBOCHANNEL,subwindow,time1,price1,time2,price2,time3,price3); case OBJ_EXPANSION : return ::ObjectCreate(chart_id,name,OBJ_EXPANSION,subwindow,time1,price1,time2,price2,time3,price3); //--- Elliott case OBJ_ELLIOTWAVE5 : return ::ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE5,subwindow,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5); case OBJ_ELLIOTWAVE3 : return ::ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE3,subwindow,time1,price1,time2,price2,time3,price3); //--- Shapes case OBJ_RECTANGLE : return ::ObjectCreate(chart_id,name,OBJ_RECTANGLE,subwindow,time1,price1,time2,price2); case OBJ_TRIANGLE : return ::ObjectCreate(chart_id,name,OBJ_TRIANGLE,subwindow,time1,price1,time2,price2,time3,price3); case OBJ_ELLIPSE : return ::ObjectCreate(chart_id,name,OBJ_ELLIPSE,subwindow,time1,price1,time2,price2,time3,price3); //--- Arrows case OBJ_ARROW_THUMB_UP : return ::ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_UP,subwindow,time1,price1); case OBJ_ARROW_THUMB_DOWN : return ::ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_DOWN,subwindow,time1,price1); case OBJ_ARROW_UP : return ::ObjectCreate(chart_id,name,OBJ_ARROW_UP,subwindow,time1,price1); case OBJ_ARROW_DOWN : return ::ObjectCreate(chart_id,name,OBJ_ARROW_DOWN,subwindow,time1,price1); case OBJ_ARROW_STOP : return ::ObjectCreate(chart_id,name,OBJ_ARROW_STOP,subwindow,time1,price1); case OBJ_ARROW_CHECK : return ::ObjectCreate(chart_id,name,OBJ_ARROW_CHECK,subwindow,time1,price1); case OBJ_ARROW_LEFT_PRICE : return ::ObjectCreate(chart_id,name,OBJ_ARROW_LEFT_PRICE,subwindow,time1,price1); case OBJ_ARROW_RIGHT_PRICE : return ::ObjectCreate(chart_id,name,OBJ_ARROW_RIGHT_PRICE,subwindow,time1,price1); case OBJ_ARROW_BUY : return ::ObjectCreate(chart_id,name,OBJ_ARROW_BUY,subwindow,time1,price1); case OBJ_ARROW_SELL : return ::ObjectCreate(chart_id,name,OBJ_ARROW_SELL,subwindow,time1,price1); case OBJ_ARROW : return ::ObjectCreate(chart_id,name,OBJ_ARROW,subwindow,time1,price1); //--- Graphical objects case OBJ_TEXT : return ::ObjectCreate(chart_id,name,OBJ_TEXT,subwindow,time1,price1); case OBJ_LABEL : return ::ObjectCreate(chart_id,name,OBJ_LABEL,subwindow,0,0); case OBJ_BUTTON : return ::ObjectCreate(chart_id,name,OBJ_BUTTON,subwindow,0,0); case OBJ_CHART : return ::ObjectCreate(chart_id,name,OBJ_CHART,subwindow,0,0); case OBJ_BITMAP : return ::ObjectCreate(chart_id,name,OBJ_BITMAP,subwindow,time1,price1); case OBJ_BITMAP_LABEL : return ::ObjectCreate(chart_id,name,OBJ_BITMAP_LABEL,subwindow,0,0); case OBJ_EDIT : return ::ObjectCreate(chart_id,name,OBJ_EDIT,subwindow,0,0); case OBJ_EVENT : return ::ObjectCreate(chart_id,name,OBJ_EVENT,subwindow,time1,0); case OBJ_RECTANGLE_LABEL : return ::ObjectCreate(chart_id,name,OBJ_RECTANGLE_LABEL,subwindow,0,0); //--- default: return false; } } //+------------------------------------------------------------------+
该方法接收对象所处的图表 ID、其名称、类型、图表子窗口,和五个轴心点坐标。 第一个坐标(时间和价格)是必需的,而其它坐标都有预定义的默认值,允许用户构建任何标准图形对象。 在该方法中,重置最后一个错误代码,并根据对象类型返回 ObjectCreate() 函数执行的结果。 在对象创建错误的情况下,上面研究的 CreateNewStdGraphObjectAndGetCtrlObj() 方法和调用方法,都会向日志发送含有错误代码及其描述的消息。
现在,一切就绪,可以测试改进实现的类,以及可编程标准图形对象。
测试
我不会创建所有图形对象,而是将限定为一条垂直线。 在图表上按住 Ctrl 键的同时单击鼠标左键,将创建该垂线。 我们检查一下对象的创建,在尝试创建同名对象时处理错误,处理时间坐标的更改,以及跟踪含有两个以上轴点的对象更改其轴点坐标。
为了执行测试,我借助来自上一篇文章中的 EA,并将其保存在 \MQL5\Experts\TestDoEasy\Part89\ 中,命名为 TestDoEasyPart89.mq5。
在 EA 的 OnChartEvent() 应答程序中,禁用按住 Ctrl 键创建窗体对象的代码块,添加代码块,在图表上按住 Ctrl 键的同时用鼠标单击坐标,创建含有指定名称的垂直线:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- If working in the tester, exit if(MQLInfoInteger(MQL_TESTER)) return; //--- If the mouse is moved /* if(id==CHARTEVENT_MOUSE_MOVE) { CForm *form=NULL; datetime time=0; double price=0; int wnd=0; //--- If Ctrl is not pressed, if(!IsCtrlKeyPressed()) { //--- clear the list of created form objects, allow scrolling a chart with the mouse and show the context menu list_forms.Clear(); ChartSetInteger(ChartID(),CHART_MOUSE_SCROLL,true); ChartSetInteger(ChartID(),CHART_CONTEXT_MENU,true); return; } //--- If X and Y chart coordinates are successfully converted into time and price, if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- get the bar index the cursor is hovered over int index=iBarShift(Symbol(),PERIOD_CURRENT,time); if(index==WRONG_VALUE) return; //--- Get the bar index by index CBar *bar=engine.SeriesGetBar(Symbol(),Period(),index); if(bar==NULL) return; //--- Convert the coordinates of a chart from the time/price representation of the bar object to the X and Y coordinates int x=(int)lparam,y=(int)dparam; if(!ChartTimePriceToXY(ChartID(),0,bar.Time(),(bar.Open()+bar.Close())/2.0,x,y)) return; //--- Disable moving a chart with the mouse and showing the context menu ChartSetInteger(ChartID(),CHART_MOUSE_SCROLL,false); ChartSetInteger(ChartID(),CHART_CONTEXT_MENU,false); //--- Create the form object name and hide all objects except one having such a name string name="FormBar_"+(string)index; HideFormAllExceptOne(name); //--- If the form object with such a name does not exist yet, if(!IsPresentForm(name)) { //--- create a new form object form=bar.CreateForm(index,name,x,y,114,16); if(form==NULL) return; //--- Set activity and unmoveability flags for the form form.SetActive(true); form.SetMovable(false); //--- Set the opacity of 200 form.SetOpacity(200); //--- The form background color is set as the first color from the color array form.SetColorBackground(array_clr[0]); //--- Form outlining frame color form.SetColorFrame(C'47,70,59'); //--- Draw the shadow drawing flag form.SetShadow(true); //--- Calculate the shadow color as the chart background color converted to the monochrome one color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100); //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units //--- Otherwise, use the color specified in the settings for drawing the shadow color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3); //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes //--- Set the shadow opacity to 200, while the blur radius is equal to 4 form.DrawShadow(2,2,clr,200,3); //--- Fill the form background with a vertical gradient form.Erase(array_clr,form.Opacity()); //--- Draw an outlining rectangle at the edges of the form form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity()); //--- If failed to add the form object to the list, remove the form and exit the handler if(!list_forms.Add(form)) { delete form; return; } //--- Capture the form appearance form.Done(); } //--- If the form object exists, if(form!=NULL) { //--- draw a text with the bar type description on it and show the form. The description corresponds to the mouse cursor position form.TextOnBG(0,bar.BodyTypeDescription(),form.Width()/2,form.Height()/2-1,FRAME_ANCHOR_CENTER,C'7,28,21'); form.Show(); } //--- Re-draw the chart ChartRedraw(); } } */ 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)) engine.GetGraphicObjCollection().CreateLineVertical(ChartID(),"LineVertical",0,time); } engine.GetGraphicObjCollection().OnChartEvent(id,lparam,dparam,sparam); } //+------------------------------------------------------------------+
编译 EA,并在图表上启动它。
首先,在图表上按住 Ctrl 键的同时单击鼠标,创建一条垂直线,查看垂线 ID,以及当它沿图表移动线时对象属性的变化。 如果我们重新创建同一条垂线,我们在日志中会收到错误消息
接下来,创建一个等距通道,查看其 ID 值,并检查如何跟踪其三个轴点属性的变化:
下一步是什么?
在下一篇文章中,我将继续研究可编程图形对象的功能。
在评论中留下您的问题、意见和建议。
*该系列的前几篇文章:
- DoEasy 函数库中的图形(第八十三部分):抽象标准图形对象类
- DoEasy 函数库中的图形(第八十四部分):抽象标准图形对象的衍生后代类
- DoEasy 函数库中的图形(第八十五部分):图形对象集合 - 添加新创建的对象
- DoEasy 函数库中的图形(第八十六部分):图形对象集合 - 管理属性修改
- DoEasy 函数库中的图形(第八十七部分):图形对象集合 - 在所有打开的图表上管理对象属性修改
- DoEasy 函数库中的图形(第八十八部分):图形对象集合 — 存储对象动态变化属性的二维动态数组
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/10119


