Grafiken in der Bibliothek DoEasy (Teil 89): Programmieren von grafischen Standardobjekten, grundlegende Funktionsweise
Inhalt
- Konzept
- Verbesserung der Klassenbibliothek
- Methoden zur Programmierung grafischer Standardobjekte
- Test
- Was kommt als Nächstes?
Konzept
Derzeit ist die Bibliothek in der Lage, Standard-Grafikobjekte auf dem Client-Terminal-Chart zu kontrollieren, einschließlich ihrer Entfernung und Änderung einiger ihrer Parameter. Manchmal ist es nützlich, über neu eingestellte, geänderte oder entfernte nutzerdefinierte grafische Objekte in einem Charts direkt aus Ihrem Programm zu wissen. Im Moment fehlt uns jedoch die Möglichkeit, Standard-Grafikobjekte aus nutzerdefinierten Programmen zu erstellen. Mit der Möglichkeit, grafische Objekte zu programmieren und Änderungen ihrer Eigenschaften zu verfolgen, können wir zusammengesetzte grafische Objekte beliebiger Komplexität, Verschachtelungstiefe und Anzahl kontrollierter Pivotpunkte erstellen. In diesem Artikel werde ich die grundlegenden Funktionen für die Programmierung grafischer Standardobjekte erstellen. Ich werde die Funktionalität in den kommenden Artikeln verfeinern und dabei die Möglichkeit berücksichtigen, nutzerdefinierte zusammengesetzte grafische Objekte auf der Grundlage der Standardobjekte zu erstellen.
Außerdem werde ich nach und nach dafür sorgen, dass Bibliotheksobjekte dynamische Arrays zur Speicherung ihrer Eigenschaften verwenden. In der Tat habe ich damit bereits im vorherigen Artikel begonnen. Hier werde ich einen logischen Fehler beheben, der im vorigen Artikel gemacht wurde und dazu führte, dass Eigenschaftsänderungen von Objekten mit mehr als zwei Pivot-Punkten nicht verfolgt werden konnten. Außerdem werde ich die Klasse eines mehrdimensionalen dynamischen Arrays korrigieren und verbessern, so dass sie als separate Einheit der Bibliothek verwendet werden kann, und sie in eine separate Datei verschieben.
Verbesserung der Klassenbibliothek
Die abgeleiteten Klassen eines abstrakten grafischen Objekts benötigen einige Eigenschaften, die von dem Objekt unterstützt werden, damit diese Eigenschaften bei der Suche, Sortierung und Anzeige der Eigenschaften im Terminaljournal berücksichtigt werden können. In den Dateien GStdFiboArcObj.mqh und GStdGannFanObj.mqh fügen wir die Zeichenkette zur Unterstützung der realen Eigenschaft "Pegelwert" durch das Objekt hinzu:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
In den Dateien GStdExpansionObj.mqh, GStdFiboChannelObj.mqh, GStdFiboFanObj.mqh, GStdFiboObj.mqh, GStdFiboTimesObj.mqh und GStdPitchforkObj.mqh wurden die folgenden Änderungen in der gleichen Methode vorgenommen, um die gleiche Eigenschaft zu unterstützen:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
In der Datei GStdHLineObj.mqh der Objektklasse "Horizontal line", entfernen wir die Eigenschaft "Pivot point time" aus der Methode, die das Flag des Objekts zurückgibt, das die Integer-Eigenschaft unterstützt, da das Objekt nur den Preis zur Konstruktion verwendet:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Das Objekt "Vertikale Linie" in der Datei GStdVLineObj.mqh verwendet nur Zeit für seine Konstruktion. Daher werde ich alles aus der Methode entfernen, das das Flag des Objekts zurückgibt, das eine echte Eigenschaft unterstützt — das Objekt unterstützt keine echten Eigenschaften:
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdVLineObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property) { return false; } //+------------------------------------------------------------------+
Im vorigen Artikel habe ich einen logischen Fehler übersehen, der uns daran hindert, die Änderungen der Eigenschaften von Objekt-Drehpunkten und -Ebenen zu kontrollieren, wenn zwei Drehpunkte für die Objektkonstruktion verwendet werden oder das Objekt mehr als zwei Ebenen aufweist. Es handelte sich hauptsächlich um die Methode, die die angegebene Anzahl von Zellen am Ende des Arrays hinzufügt. Die Methode erhielt den Zeiger auf ein außerhalb erstelltes Objekt, während das Array die angegebene Anzahl dieser Zeiger erhielt:
//--- 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; }
Es handelt sich jedoch um das gleiche Objekt! Wir übergeben einfach den Zeiger auf ein außerhalb der Methode erzeugtes Objekt und multiplizieren die Zeiger darauf in einer Schleife. Daher wirkt sich eine Änderung der Eigenschaften des Objekts selbst auf alle Zeiger aus — auch sie verweisen auf dasselbe Objekt. Daher haben wir das Array mit Instanzen derselben Objekteigenschaft und nicht mit unterschiedlichen Eigenschaften gefüllt. Wenn das Objekt mehrere Bezugspunkte aufwies, haben wir den Drehpunkt mit der angegebenen Anzahl multipliziert. Anstatt die realen Werte des zweiten, dritten, vierten und fünften Punktes zu verwalten, fügten wir dem Array die Eigenschaft des zweiten Drehpunktes hinzu. Dies verhinderte, dass wir die Werte des realen Referenzpunktes abrufen, verfolgen und ändern konnten. Die Änderung des zweiten Pivotpunkts führte dazu, dass diese Änderungen auf den dritten, vierten und fünften Objektpunkt kopiert wurden.
Fügen wir eine weitere Methode zum Erstellen eines neuen Datenobjekts hinzu. Mit dieser Methode wird ein neues Eigenschaftsobjekt erstellt. Diese neue Eigenschaft (und nicht den Zeiger) fügen wir dem Array in der Methode AddQuantity() hinzu, in der wir einfach den von außen erstellten Zeiger in der angegebenen Menge dem Array hinzugefügt haben.
Da wir in \MQL5\Include\DoEasy\Services\XDimArray.mqh drei Sätze identischer Klassen haben — die Klassen zur Erstellung dynamischer mehrdimensionaler Integer-, Real- und String-Arrays -, wollen wir dies am Beispiel der Klassen zur Erstellung eines mehrdimensionalen dynamischen Integer-Arrays betrachten.
In der Klasse eines Array vom Typ long schreiben wir die Methode zur Erstellung eines neuen Datenobjekts:
//+------------------------------------------------------------------+ //| 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
Hier ist alles ganz einfach: wir erstellen ein neues Objekt mit datem dey Typs long und setzen den Wert, der der Methode übergeben wurde, für dieses Objekt. Wenn es nicht gelingt, ein Objekt zu erstellen, wird das im Journal mitgeteilt. Die Methode gibt den Zeiger auf das erstellte Objekt zurück oder NULL im Falle eines Fehlers.
Fügen Sie die Änderungen in der Methode AddQuantity() hinzu:
//--- 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; }
Anstelle des Zeigers auf das Objekt erhält die Methode nun den Wert, der einer neu erstellten Eigenschaft zugewiesen werden soll. In der Schleife wird ein neues Objekt erstellt und der Liste hinzugefügt.
In der Methode Increase(), in der ich zuvor ein neues Objekt erstellt und den Zeiger darauf an die Methode AddQuantity() übergeben habe, rufe ich einfach die Methode AddQuantity() auf, da nun neue Objekte in der Schleife erstellt und dem Array innerhalb der Methode AddQuantity() hinzugefügt werden und nicht mehr ein Zeiger auf ein einzelnes Objekt, das zuvor in der Methode Increase() erstellt wurde.
Entfernen wir den folgenden Codeblock aus der Methode:
//--- 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; }
Die aufgerufene Methode AddQuantity() erhält nun einen Anfangswert für ein neu zum Array hinzugefügtes Datenobjekt anstelle eines Zeigers:
//--- 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; }
Die gleichen Änderungen wurden an den übrigen Klassen der Datei vorgenommen. Ich werde sie hier nicht wiederholen, da sie identisch sind.
Sie können alle Änderungen in den unten angehängten Dateien sehen.
In \MQL5\Include\DoEasy\Data.mqh fügen wir die neue Nachrichtenindizes hinzu:
//--- 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: }; //+------------------------------------------------------------------+
und die Nachrichtentexte, die den neu hinzugefügten Indizes entsprechen:
//--- 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: "}, }; //+---------------------------------------------------------------------+
Machen wir noch kleinere Verbesserungen in der Klasse des Basisobjekts der grafischen Objekte der Bibliothek.
Die grafischen Objekte verfügen über Eigenschaften vom Typ bool, die die Flags einiger Objekteigenschaften zurückgeben. Die abstrakte Klasse der grafischen Objekte hat Methoden, die solche Flags zurückgeben und setzen. Die Methodennamen zeigen an, dass die Methode das Flag setzt, zum Beispiel:
SetFlagDrawLines (Linien für die Elliott-Wellenmarkierung anzeigen). In der Klasse des Basisobjekts der grafischen Objekte der Bibliothek gibt es eine entsprechende Methode namens SetDrawLines(). Wenn wir also versuchen, das Flag für ein Objekt zu setzen, sehen wir zwei Hinweise zur Auswahl einer Methode. Das ist verwirrend. Wenn wir außerdem die Methode des grafischen Basisobjekts und nicht des abstrakten Objekts auswählen, wird in den Eigenschaften keine Änderung vorgenommen, die in den Objektarrays festgelegt wurde. Stattdessen geben wir einfach einen Befehl zur Änderung einer Eigenschaft im grafischen Objekt selbst. Die entsprechende Eigenschaft im Klassenobjekt bleibt unverändert. Das bedeutet, dass wir alle diese Methoden umbenennen müssen, um Fehler bei der Auswahl von zwei Methoden zu vermeiden. Ich glaube, dass es später auch notwendig sein wird, die Rückgabetypen dieser Methoden zu vereinheitlichen, damit der Compiler in der Lage ist, die erforderliche Methode eindeutig auszuwählen.
Lassen Sie uns die notwendigen Korrekturen in \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh einführen:
//--- 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; }
Verschieben wir die Klassen zur Erstellung eines multidimensionalen dynamischen Arrays in eine separate Datei. Ich werde sie so verbessern, dass sie zu einem Werkzeug für die Erstellung von Eigenschaftsobjekten für jedes bestehende oder geplante Objekt der Bibliothek werden, das Arrays für die Speicherung seiner Eigenschaften (Integer, Real und String) verwendet.
Im Ordner \MQL5\Include\DoEasy\Services\ der Serviceklassen und -funktionen erstellen wir die neue Datei Properties.mqh. Sie soll alle Klassen für die Erstellung eines zweidimensionalen Arrays von Objekteigenschaften und eines Eigenschaftsobjekts (sowohl die vorherigen als auch die aktuellen), die im vorherigen Artikel festgelegt wurden, direkt in den Klassenkörper des abstrakten grafischen Standardobjekts CGStdGraphObj bringen:
//+------------------------------------------------------------------+ //| 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); } };
Um die Klasse universell zu machen, müssen wir die Verweise auf alle Aufzählungen, die zu einem bestimmten Klassenobjekt gehören, entfernen.
Um dies zu erreichen, ersetzen wir alle Enumerationen, die zur Auswahl der Methoden verwendet werden, die einen realen Eigenschaftsindex zurückgeben, durch gewöhnliche int-Variablen. Um die Eigenschaftsindizes zu berechnen, übergeben wir den Klassenkonstruktoren die maximale Eigenschaft für Real- und String-Eigenschaften (eine Integer-Eigenschaft verschiebt ihren Wert nicht und entspricht vollständig dem Eigenschaftsindex). Berechnen wir dann einfach die reellen Werte auf der Grundlage des Eigenschaftswerts und des Maximalwerts der Eigenschaften. Wie üblich wird die Idee deutlicher, wenn sie als Code dargestellt wird.
Die folgenden Klassen fügen wir der neu hinzugefügte Datei \MQL5\Include\DoEasy\Services\Properties.mqh hinzu:
//+------------------------------------------------------------------+ //| 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(); } }; //+------------------------------------------------------------------+
Alle wichtigen Erklärungen sind in den Codekommentaren enthalten. Vergleichen wir diese Klassen mit denen, die im vorherigen Artikel in \MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqh erstellt wurden.
Nun wollen wir die abstrakte grafische Standardobjektklasse in \MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqh verbessern.
Zunächst fügen wir die neu erstellte Datei der Objekteigenschaftsklassen hinzu:
//+------------------------------------------------------------------+ //| 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 {
Die Klassen der Eigenschaftsobjekte sind bereits aus dem privaten Abschnitt der Klasse entfernt. Der Zeiger auf das Eigenschaftsobjekt wird ebenfalls darin deklariert. Die entsprechende Methode des properties-Objekts wird in jeder der Get- und Set-Methoden im öffentlichen Abschnitt der Klasse aufgerufen:
//+------------------------------------------------------------------+ //| 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;}
Im öffentlichen Abschnitt tragen wir den Destruktor der Klasse ein, in der das Eigenschaftsobjekt entfernt werden soll:
//--- 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);
Im Abschnitt der Methoden für den vereinfachten Zugriff und das Setzen von grafischen Objekteigenschaften, verbessern wir die Methoden zum Setzen der Eigenschaften der Flags:
//--- 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
Die Methode, die die aktuellen Eigenschaften zu den vorherigen kopiert, wird aus dem privaten Bereich in den öffentlichen verschoben:
//--- 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); }; //+------------------------------------------------------------------+
In dem geschützten parametrischen Konstruktor erzeugen wir ein neues Objekt mit den Eigenschaften des grafischen Objekts:
//+------------------------------------------------------------------+ //| 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
Die Anzahl der grafischen Objekteigenschaften der Typen ganzzahlig, reellen und Text wird dem Klassenkonstruktor übergeben.
In der Methode, die die ganzzahligen Eigenschaften eines grafischen Objekts zurückgibt und sie in den Objekteigenschaften der Klasse speichert, wird geprüft, ob sich die Anzahl der Objektebenen geändert hat. Wenn ja, dann wird die Größe der Arrays aller Eigenschaften, die die Ebenenwerte speichern, geändert.
Andernfalls wird beim Setzen der Ebeneneigenschaften der Fehler "Array out of range" angezeigt:
//--- 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)
Vereinfachung der Methode zur Überprüfung der Änderungen von Objekteigenschaften:
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
In der bisherigen Methodenimplementierung habe ich die if-else-Konstruktion verwendet, um sicherzustellen, dass die Eigenschaft mehrere Werte hat (z. B. die Ankerpunktzeit), und jede solche Eigenschaft in einem eigenen Codeblock behandelt. Da wir in der Lage sind, die Größe des Eigenschaftsarrays für jede der Eigenschaften zu kennen, ist es ausreichend, die Werte einer einzelnen Eigenschaft in der Schleife einfach nach der Größe der zweiten Dimension des Arrays durchzugehen. Für eine einzelne Eigenschaft ist die Größe der zweiten Dimension 1, während sie für eine mehrfache gleich der Anzahl der Werte der Eigenschaft multi-properties ist. Somit kann alles in einer einzigen Schleife für jede der Objekteigenschaften durchgeführt werden. Genau das habe ich oben getan.
Ich habe auch einige kleinere Verbesserungen (z. B. Änderung der Methodennamen) in derselben Datei vorgenommen. Zum Beispiel wurde LevelColorsDescription() in LevelsColorDescription() umbenannt, was mehr dem Zweck der Methode entspricht. Ich werde diese Umbenennung hier nicht weiter besprechen. Sie finden sie in den angehängten Dateien.
Jedes der Bibliotheksobjekte hat neben anderen Eigenschaften auch eine eigene Objekt-ID. Die Kollektionsklasse der grafischen Elemente verfügt über zwei Kollektionen — die Kollektion der grafischen Elemente, deren Entwicklung ich bis zur Fertigstellung der Sammlung der grafischen Objekte (mit manuell erstellten grafischen Standardobjekten), an der ich gerade arbeite, ausgesetzt habe, und die grafischen Standardobjekte, die programmatisch erstellt werden. Hier werde ich mit der Entwicklung der Funktionalität zur Programmierung von grafischen Standardobjekten beginnen.
Die IDs von programmatisch erstellten grafischen Objekten werden im Bereich von 1 bis einschließlich 10000 liegen. Die IDs von manuell erstellten grafischen Objekten beginnen bei 10001.
Lassen Sie uns diesen Schwellenwert in \MQL5\Include\DoEasy\Defines.mqh einstellen:
//--- 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 | //+------------------------------------------------------------------+
Methoden zur Programmierung grafischer Standardobjekte
Wir verfügen bereits über Methoden, die die manuelle Erstellung von grafischen Objekten auf einem Diagramm, die Erstellung der entsprechenden Klassenobjekte und das Hinzufügen zur Kollektion verfolgen. Natürlich wäre es gut, sie für die aktuellen Aufgaben zu verwenden, aber es gibt einige Gründe, die mich gezwungen haben, die Verwendung von teilweise fertigen Methoden aufzugeben. Wir verfolgen einfach das Erscheinen von grafischen Objekten im Timer. Wenn ich ein Objekt programmatisch erstelle, möchte ich nicht auf den nächsten Timer-Tick warten und das neu erstellte Objekt sowie seine Erstellungsmethode (programmatisch und manuell) definieren.
Stattdessen werde ich die Methode in der Kollektion der grafischen Elemente für die Erstellung von grafischen Standardobjekten erstellen. Unmittelbar nach der Konstruktion des Objekts werde ich das entsprechende Klassenobjekt erstellen und es in die Kollektion aufnehmen. Die Suche nach Änderungen in den Objekteigenschaften wird von der bereits erstellten Funktionalität durchgeführt. Auf diese Weise werden wir in der Lage sein, Objekte zu erstellen und sie der Kollektion hinzuzufügen, während wir die Möglichkeit behalten, nach Änderungen zu suchen, ohne die Methode der Objekterstellung zu berücksichtigen. In Zukunft wird dies die Erstellung von zusammengesetzten grafischen Objekten und die Verwaltung ihrer Eigenschaften vereinfachen.
Der Name eines programmatisch erstellten grafischen Objekts enthält den Namen des Programms, aus dem das Objekt erstellt wurde. Dies wird es uns ermöglichen, unsere "eigenen" grafischen Objekte von manuell erstellten Objekten zu unterscheiden.
Um dies zu erreichen, fügen wir die neue Variable für die Speicherung des Programmnamens in den privaten Abschnitt der Diagrammobjekt-Verwaltungsklasse in der Datei der grafischen Element-Kollektion-Klasse \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh ein:
//+------------------------------------------------------------------+ //| 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:
Im öffentlichen Abschnitt der Klasse entfernen wir die Angabe einer Chart-ID aus der Methode CreateNewGraphObj(), da die ID eine der primären Eigenschaften des Verwaltungsobjekts des Chartobjekt ist und sie direkt vom Objekt und nicht durch Übergabe an die Methode erhalten werden kann.
Setzen des Wertes des Programmnamens auf die entsprechende Variable in den Klassenkonstruktoren:
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(); }
Bei der Prüfung auf einen leeren Namen ist außerdem darauf zu achten, dass das Objekt in der Methode, die Chart-Objekte prüft, nicht programmatisch erstellt wird:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Mit anderen Worten, wenn ein Objektname keine Teilzeichenkette mit einem Programmnamen hat, sollte ein solches Objekt von der Methode behandelt werden, andernfalls handelt es sich um ein programmatisch erzeugtes grafisches Objekt, das durch eine andere Methode der Kollektion hinzugefügt wird.
In der Methode zum Erzeugen eines neuen grafischen Standardobjekts, ersetzen wir alle chart_id, die zuvor an die Methode übergeben wurden, durch die Chart-ID, die für das von ihr kontrollierte Objekt festgelegt wurde:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
In der Kollektion CGraphElementsCollection von grafischen Objekten, nämlich in der Methode, die die ID des ersten freien grafischen Objekts zurückgibt, fügen wir das Flag hinzu, das die ID des benötigten Objekts angibt: false — für ein manuell erstelltes Objekt, true — für ein programmatisch erstelltes Objekt
//--- 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
Deklarieren der privaten Methode, die ein neues grafisches Standardobjekt erstellt:
//--- 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:
Im privaten Abschnitt der Klasse schreiben wir die Methode, die ein neues grafisches Objekt erstellt und den Zeiger auf das Chart-Verwaltungsobjekt zurückgibt:
//--- 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:
Die Logik der Methode wird in den Code-Kommentaren beschrieben. Die Methode wird bei der Erstellung bestimmter grafischer Standardobjekttypen verwendet, die sich weiter im öffentlichen Teil der Klasse befinden.
Die Methode, die das grafische Objekt "Vertikale Linie" erzeugt:
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; }
Die Methode wird in den Codekommentaren hinreichend genau erklärt. Die Eigenschaften, die jedem spezifischen Objekt innewohnen und in den Parametern übergeben werden, werden in jedem dieser Objekte eingestellt. Auf dem angegebenen Chart wird zunächst ein physisches grafisches Objekt erstellt, das einen Zeiger auf das Chart-Verwaltungsobjekt bildet. Dessen Methode CreateNewGraphObj() wird verwendet, um das Klassenobjekt zu erstellen, das dem erstellten Objekttyp entspricht. Wenn das Hinzufügen des Objekts zur Liste fehlschlägt, werden das physische grafische Objekt selbst und das Klassenobjekt entfernt und eine Fehlermeldung an das Journal gesendet. Wenn die Erstellung erfolgreich war, wird das Chart aktualisiert und die Methode gibt true zurück.
Die übrigen Methoden zur Erstellung von grafischen Objekten sind identisch mit der oben betrachteten und unterscheiden sich nur durch den Satz von Parametern, die für jedes spezifische grafische Objekt definiert sind.
Werfen wir einen Blick auf die Auflistung aller anderen hinzugefügten Methoden:
//--- 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; } }; //+------------------------------------------------------------------+
Alle Methoden verfügen über ihre eigenen Eingabeparameter. Diese Parameter werden als minimale Objekteigenschaften festgelegt, die für die Erstellung des Objekts ausreichen. Alle übrigen Eigenschaften können nach der Erstellung eines grafischen Objekts geändert werden.
Die Methode gibt die erste freie grafische Objekt-ID zurück:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Die Methode berücksichtigt nun eine notwendige ID, die übergeben werden muss.
Wenn sie für ein programmatisch erzeugtes grafisches Objekt bestimmt ist, holt sie die Liste aller Objekte, deren ID kleiner oder gleich dem Wert der Konstante PROGRAM_OBJ_MAX_ID (10000) ist.
Wenn es sich um ein manuell erstelltes grafisches Objekt handelt, hole die Liste aller Objekte mit IDs über PROGRAM_OBJ_MAX_ID.
Als Nächstes holen wir den Index eines Objekts mit der maximalen ID aus der erhaltenen Liste, sowie ein aufgelistetes Objekt nach seinem Index.
Danach berechnen wir den Wert der allerersten ID (für ein programmiertes Objekt — 1, für ein manuell erstelltes Objekt — 10000+1).
Wenn das Objekt mit der höchsten ID empfangen wurde, erhalte den Wert seiner ID+1. Andernfalls ist das Objekt nicht in der Liste und es wird der berechnete Wert der ersten ID (1 oder 10001) zurückgegeben.
In der Methode, die das grafische Objekt zur Kollektion hinzufügt, ermitteln wir, ob ein Objekt programmatisch oder manuell erstellt wurde (über den Objektnamen), um nach einer ID zu suchen und übergeben den Wert an die Methode GetFreeGraphObjID():
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Vereinfachen wir die Logik der Ereignisbehandlung, indem wir if-else loswerden und ein Objekt-Klick-Tracking hinzufügen, um die Objektauswahl mit der Maus zu bestimmen (noch nicht implementiert):
//+------------------------------------------------------------------+ //| 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(); } } //+------------------------------------------------------------------+
Die Methode, die ein neues grafisches Standardobjekts erstellt:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
Die Methode erhält die ID des Charts, auf dem ein Objekt dargestellt werden soll, seinen Namen, seinen Typ, das Chart-Unterfenster und fünf Pivotpunkt-Koordinaten. Die erste Koordinate (Zeit und Preis) ist obligatorisch, während die übrigen vordefinierte Standardwerte haben, die es dem Nutzer ermöglichen, jedes beliebige grafische Standardobjekt zu erstellen. In der Methode wird der letzte Fehlercode zurückgesetzt und das Ergebnis der Ausführung der Funktion ObjectCreate() in Abhängigkeit von einem Objekttyp zurückgegeben. Im Falle eines Fehlers bei der Objekterzeugung wird die oben besprochenen Methode CreateNewStdGraphObjectAndGetCtrlObj() und der Aufruf der Methode die Fehlermeldung mit dem Fehlercode und dessen Beschreibung an das Journal gesendet.
Jetzt ist alles bereit, um die Verbesserungen zu testen, die in den Klassen und im Programm für grafische Standardobjekte implementiert wurden.
Test
Anstatt alle grafischen Objekte zu erstellen, beschränke ich mich auf eine vertikale Linie. Sie wird erstellt, wenn Sie mit der linken Maustaste auf ein Chart klicken und dabei die Strg-Taste gedrückt halten. Prüfen wir die Erstellung eines Objekts, die Behandlung eines Fehlers beim Versuch, ein Objekt mit demselben Namen zu erstellen, die Behandlung von Änderungen der Zeitkoordinate sowie die Verfolgung von Änderungen der Pivotpunktkoordinaten von Objekten mit mehr als zwei Pivotpunkten.
Um den Test durchzuführen, verwende ich den EA aus dem vorherigen Artikel und speichere ihn in \MQL5\Experts\TestDoEasy\Part89\ als TestDoEasyPart89.mq5.
In der Ereignisfunktion OnChartEvent() des EAs wird der Codeblock für die Erstellung von Formularobjekten bei gedrückter Strg-Taste deaktiviert und der Codeblock für die Erstellung einer vertikalen Linie mit einem bestimmten Namen hinzugefügt, wenn bei gedrückter Strg-Taste in der Mausklickkoordinate auf einen Chart geklickt wird:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Kompilieren Sie den EA und starten Sie ihn auf dem Chart.
Zunächst wird eine vertikale Linie erstellt, durch einen klick auf einen Chart bei gedrückter Strg-Taste. Sehen Sie sich die Linien-ID an und beobachten Sie, wie sich die Objekteigenschaften beim Verschieben der Linie entlang des Charts ändern. Wenn wir die gleiche Linie erneut erstellen, erhalten wir die Fehlermeldung im Journal.
Als Nächstes erstellen wir einen äquidistanten Kanal, und wir sehen seinen ID-Wert an und können prüfen, wie die Änderungen der Eigenschaften seiner drei Pivotpunkte kontrolliert werden:
Was kommt als Nächstes?
Im nächsten Artikel werde ich weiter an der Funktionalität zur Programmierung grafischer Objekte arbeiten.
Stellen Sie Ihre Fragen, Kommentare und Vorschläge bitte im Kommentarteil.
*Frühere Artikel dieser Serie:
- Grafiken in der Bibliothek DoEasy (Teil 83): Die Klasse des abstrakten grafischen Standardobjekts
- Grafiken in der Bibliothek DoEasy (Teil 84): Abgeleitete Klassen des abstrakten grafischen Standardobjekts
- Grafiken in der Bibliothek DoEasy (Teil 85): Grafische Objektkollektion - Hinzufügen neu erstellter Objekte
- Grafiken in der Bibliothek DoEasy (Teil 86): Grafische Objektkollektion - Verwaltung der Eigenschaftsänderungen
- Grafiken in der Bibliothek DoEasy (Teil 87): Grafische Kollektion - Verwaltung der Änderungen von Eigenschaften von Objekten auf allen offenen Charts
- Grafiken in der Bibliothek DoEasy (Teil 88): Grafische Objektkollektion — zweidimensionales dynamisches Array zur Speicherung der sich dynamisch ändernden Objekteigenschaften
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/10119
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.