DoEasyライブラリのグラフィックス(第89部): 抽象標準グラフィカルオブジェクトのプログラミング基本機能
目次
概念
現在、ライブラリでは、一部のパラメータの削除や変更など、クライアントターミナルのチャート上の標準のグラフィカルオブジェクトを追跡できます。プログラムから直接、チャート上で新しく設定、変更、削除されたカスタムグラフィカルオブジェクトについて知っておくと便利な場合がありますが、現時点では、カスタムプログラムから標準のグラフィカルオブジェクトを作成する機能がありません。グラフィカルオブジェクトをプログラミングしてそれらのプロパティの変更を追跡する機能があれば、複雑さ、ネストの程度、および制御されたピボットポイントの数を問わず、複合グラフィカルオブジェクトを作成できるようになります。本稿では、標準グラフィカルオブジェクトをプログラミングするための基本的な機能を作成します。今後の記事では、標準のオブジェクトに基づいてカスタムの複合グラフィカルオブジェクトを作成する機能を考慮しながら機能を改良していきます。
また、徐々にライブラリオブジェクトがプロパティを格納するために動的配列を使用するようにしていきます。実際、これはすでに前の記事で始めています。ここでは、前の記事で導入された、3つ以上のピボットポイントを持つオブジェクトのプロパティの変更を追跡できない原因となる論理エラーを修正します。また、多次元動的配列のクラスを修正および改良して、ライブラリの別ユニットとして使用できるようにし、別のファイルに移動します。
ライブラリクラスの改善
抽象グラフィカルオブジェクトの子孫クラスには、オブジェクトでサポートされているいくつかのプロパティが必要です。これにより、ターミナルの操作ログでプロパティを検索、並べ替え、表示するときにこれらのプロパティを考慮することができるようになります。GStdFiboArcObj.mqhファイルとGStdGannFanObj.mqhファイルに、オブジェクトによる「レベル値」の実数プロパティをサポートするための文字列を追加します。
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdFiboArcObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property) { switch((int)property) { //--- Supported properties case GRAPH_OBJ_PROP_SCALE : case GRAPH_OBJ_PROP_PRICE : case GRAPH_OBJ_PROP_LEVELVALUE : return true; //--- Other properties are not supported //--- Default is 'false' default: break; } return false; } //+------------------------------------------------------------------+
GStdExpansionObj.mqh、GStdFiboChannelObj.mqh、GStdFiboFanObj.mqh、GStdFiboObj.mqh、GStdFiboTimesObj.mqh、GStdPitchforkObj.mqhファイルでは、同じプロパティをサポートするために、同じメソッドで次の変更を行います。
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdPitchforkObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property) { switch((int)property) { //--- Supported properties case GRAPH_OBJ_PROP_PRICE : case GRAPH_OBJ_PROP_LEVELVALUE : return true; //--- Other properties are not supported //--- Default is 'false' default: break; } return false; } //+------------------------------------------------------------------+
「垂直線」オブジェクトクラスのGStdHLineObj.mqhファイルでは、整数プロパティをサポートするオブジェクトの構築に使用されるのは価格のみであるため、そのようなオブジェクトのフラグを返すメソッドから「ピボットポイント時間」プロパティを削除します。
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdHLineObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property) { switch((int)property) { //--- Supported properties case GRAPH_OBJ_PROP_ID : case GRAPH_OBJ_PROP_TYPE : case GRAPH_OBJ_PROP_ELEMENT_TYPE : case GRAPH_OBJ_PROP_GROUP : case GRAPH_OBJ_PROP_BELONG : case GRAPH_OBJ_PROP_CHART_ID : case GRAPH_OBJ_PROP_WND_NUM : case GRAPH_OBJ_PROP_NUM : case GRAPH_OBJ_PROP_CREATETIME : case GRAPH_OBJ_PROP_TIMEFRAMES : case GRAPH_OBJ_PROP_BACK : case GRAPH_OBJ_PROP_ZORDER : case GRAPH_OBJ_PROP_HIDDEN : case GRAPH_OBJ_PROP_SELECTED : case GRAPH_OBJ_PROP_SELECTABLE : case GRAPH_OBJ_PROP_TIME : case GRAPH_OBJ_PROP_COLOR : case GRAPH_OBJ_PROP_STYLE : case GRAPH_OBJ_PROP_WIDTH : return true; //--- Other properties are not supported //--- Default is 'false' default: break; } return false; } //+------------------------------------------------------------------+
GStdVLineObj.mqhファイルの「垂直線」オブジェクトの構築には、時間のみが使用されるため、すべてをメソッドから削除して、実数プロパティをサポートするオブジェクトのフラグを返します。このオブジェクトは実数プロパティをサポートしていません。
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdVLineObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property) { return false; } //+------------------------------------------------------------------+
前回の記事では、オブジェクトの構築に2つのピボットポイントが使用されている場合、またはオブジェクトが2つ以上のレベルを備えている場合に、オブジェクトのピボットポイントとレベルのプロパティの変更を制御できない1つの論理エラーをスキップしました。これは主に、指定された数のセルを配列の最後に追加するメソッドに関するものでした。このメソッドは外部で作成されたオブジェクトへのポインタを受け取っていましたが、配列はこれらのポインタの指定された数を受け取っていました。
//--- 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; }
ただし、これは同じオブジェクトです。メソッド外で作成されたオブジェクトへのポインタを渡し、ループ内でそのオブジェクトへのポインタを乗算するだけです。したがって、オブジェクト自体のプロパティを変更すると、すべてのポインタに影響します。これらのポインタも同じオブジェクトを参照するためです。そのため、異なるプロパティではなく、同じオブジェクトプロパティのインスタンスで配列を埋めました。オブジェクトに複数の参照ポイントがある場合は、ピボットポイントに指定された数を乗算しました。2番目、3番目、4番目、5番目のポイントの実際の値を管理する代わりに、2番目のピボットポイントのプロパティを配列に追加しました。これにより、実際の参照ポイントの値を取得、追跡、変更することができなくなりました。2番目のピボットポイントを変更すると、これらの変更が3番目、4番目、5番目のオブジェクトポイントにコピーされます。
新しいデータオブジェクトを作成するためのメソッドをもう1つ追加しましょう。このメソッドでは、新しいプロパティオブジェクトを作成します。AddQuantity()メソッドの配列に(ポインタではなく)この新しいプロパティを追加します。このメソッドでは、外部から作成されたポインタを指定された量だけ配列に追加します。
\MQL5\Include\DoEasy\Services\XDimArray.mqhに整数、実数、文字列のための動的多次元配列を作成するための3セットの同一クラスがあるため、例として、整数の多次元動的配列を作成するクラスを使用して検討します。
1つのlong配列次元のクラスで、新しいデータオブジェクトを作成するためのメソッドを記述します。
//+------------------------------------------------------------------+ //| Class of a single long array dimension | //+------------------------------------------------------------------+ class CDimLong : public CArrayObj { private: //--- Create a new data object CDataUnitLong *CreateData(const string source,const long value=0) { //--- Create a new long data object CDataUnitLong *data=new CDataUnitLong(); //--- If failed to create an object, inform of that in the journal if(data==NULL) ::Print(source,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_LONG_DATA_OBJ)); //--- Otherwise, set the value passed to the method for the object else data.Value=value; //--- Return the pointer to the object or NULL return data; } //--- Get long data object from the array
ここではすべて簡単です。longデータで新しいオブジェクトを作成し、そのメソッドに渡される値を設定します。オブジェクトの作成に失敗した場合は、操作ログでそのことを通知します。このメソッドは、作成されたオブジェクトへのポインタを返します。エラーが発生した場合はNULLを返します。
AddQuantity()メソッドに変更を追加します。
//--- Add the specified number of cells with data to the end of the array bool AddQuantity(const string source,const int total,const long value=0) { //--- Declare the variable for storing the result of adding objects to the list bool res=true; //--- in the list by the number of added objects passed to the method for(int i=0;i<total;i++) { //--- Create a new long data object CDataUnitLong *data=this.CreateData(DFUN,value); //--- If failed to create an object, inform of that and move on to the next iteration if(data==NULL) { res &=false; continue; } data.Value=value; //--- if failed to add the object to the list if(!this.Add(data)) { //--- display the appropriate message, remove the object and add 'false' to the variable value //--- and move on to the loop next iteration CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); delete data; res &=false; continue; } } //--- Return the total result of adding the specified number of objects to the list return res; }
これで、オブジェクトへのポインタの代わりに、メソッドは新しく作成されたプロパティに割り当てられる値を受け取ります。ループで新しいオブジェクトを作成して、リストに追加します。
以前に新しいオブジェクトを作成してそのオブジェクトへのポインタをAddQuantity()メソッドに渡すIncrease()メソッドでは、AddQuantity()メソッドを呼び出すだけです。これは、Increase()メソッドで以前に作成された単一のオブジェクトへのポインタではなく、ループで作成された新しいオブジェクトがAddQuantity()メソッド内で配列に追加されるためです。
メソッドから次のコードブロックを削除しましょう。
//--- Increase the number of data cells by the specified value, return the number of added elements int Increase(const int total,const long value=0) { //--- Save the current array size int size_prev=this.Total(); //--- Create a new long data object CDataUnitLong *data=new CDataUnitLong(); //--- If failed to create an object, inform of that and return zero if(data==NULL) { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_LONG_DATA_OBJ)); return 0; } //--- Set the specified value to a newly created object data.Value=value; //--- Add the specified number of object instances to the list //--- and return the difference between the obtained and previous array size this.AddQuantity(DFUN,total,data); return this.Total()-size_prev; }
呼び出されたAddQuantity()メソッドは、ポインタではなく、配列に新しく追加されたデータオブジェクトの初期値を受け取るようになります。
//--- Increase the number of data cells by the specified value, return the number of added elements int Increase(const int total,const long value=0) { //--- Save the current array size int size_prev=this.Total(); //--- Add the specified number of object instances to the list //--- and return the difference between the obtained and previous array size this.AddQuantity(DFUN,total,value); return this.Total()-size_prev; }
ファイルの残りのクラスにも同じ変更が加えられました 。それらは同一であるため、ここでは繰り返しません。
すべての変更は以下に添付されているファイルでご覧になれます。
\MQL5\Include\DoEasy\Data.mqhに、新しいメッセージインデックスを追加します。
//--- CGraphElementsCollection MSG_GRAPH_ELM_COLLECTION_ERR_OBJ_ALREADY_EXISTS, // Error. A chart control object already exists with chart id MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_CREATE_CTRL_OBJ,// Failed to create chart control object with chart ID MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_GET_CTRL_OBJ, // Failed to get chart control object with chart ID MSG_GRAPH_ELM_COLLECTION_ERR_GR_OBJ_ALREADY_EXISTS,// Such graphical object already exists: //--- GStdGraphObj MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ, // Failed to create the class object for a graphical object MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_STD_GRAPH_OBJ, // Failed to create a graphical object MSG_GRAPH_STD_OBJ_ERR_NOT_FIND_SUBWINDOW, // Failed to find the chart subwindow
...
MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_ON, // On state MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_OFF, // Off state //--- CDataPropObj MSG_DATA_PROP_OBJ_OUT_OF_PROP_RANGE, // Passed property is out of object property range //--- CGraphElementsCollection MSG_GRAPH_OBJ_FAILED_GET_ADDED_OBJ_LIST, // Failed to get the list of newly added objects MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST, // Failed to remove a graphical object from the list MSG_GRAPH_OBJ_CREATE_EVN_CTRL_INDICATOR, // Indicator for controlling and sending events created MSG_GRAPH_OBJ_FAILED_CREATE_EVN_CTRL_INDICATOR, // Failed to create the indicator for controlling and sending events MSG_GRAPH_OBJ_CLOSED_CHARTS, // Chart windows closed: MSG_GRAPH_OBJ_OBJECTS_ON_CLOSED_CHARTS, // Objects removed together with charts: }; //+------------------------------------------------------------------+
また、新しく追加したインデックスに対応するメッセージテキストも追加します。
//--- CGraphElementsCollection {"Ошибка. Уже существует объект управления чартами с идентификатором чарта ","Error. A chart control object already exists with chart id "}, {"Не удалось создать объект управления чартами с идентификатором чарта ","Failed to create chart control object with chart id "}, {"Не удалось получить объект управления чартами с идентификатором чарта ","Failed to get chart control object with chart id "}, {"Такой графический объект уже существует: ","Such a graphic object already exists: "}, //--- GStdGraphObj {"Не удалось создать объект класса для графического объекта ","Failed to create class object for graphic object"}, {"Не удалось создать графический объект ","Failed to create graphic object "}, {"Не удалось найти подокно графика","Could not find chart subwindow"},
...
{"Состояние \"On\"","State \"On\""}, {"Состояние \"Off\"","State \"Off\""}, //--- CDataPropObj {"Переданное свойство находится за пределами диапазона свойств объекта","The passed property is outside the range of the object's properties"}, //--- CGraphElementsCollection {"Не удалось получить список вновь добавленных объектов","Failed to get the list of newly added objects"}, {"Не удалось изъять графический объект из списка","Failed to detach graphic object from the list"}, {"Создан индикатор контроля и отправки событий","An indicator for monitoring and sending events has been created"}, {"Не удалось создать индикатор контроля и отправки событий","Failed to create indicator for monitoring and sending events"}, {"Закрыто окон графиков: ","Closed chart windows: "}, {"С ними удалено объектов: ","Objects removed with them: "}, }; //+---------------------------------------------------------------------+
ライブラリのグラフィカルオブジェクトの基本オブジェクトのクラスを少し改善してみましょう。
グラフィカルオブジェクトは、いくつかのオブジェクトプロパティのフラグを返すboolプロパティを備えています。抽象グラフィカルオブジェクトクラスには、そのようなフラグを返したり設定したりするメソッドがあります。メソッド名は、メソッドがフラグを設定することを示します(例:
SetFlagDrawLines(エリオット波動マーキングの線を表示))。ライブラリグラフィカルオブジェクトの基本オブジェクトのクラスでは、対応するメソッドはSetDrawLines()と呼ばれます。したがって、オブジェクトにフラグを設定しようとすると、メソッドを選択するための2つのヒントが表示され、紛らわしくなります。さらに、抽象オブジェクトではなく基本グラフィカルオブジェクトのメソッドを選択した場合、オブジェクト配列に設定された変更はプロパティで行われません。代わりに、グラフィカルオブジェクト自体のプロパティを変更するコマンドを指定するだけです。クラスオブジェクトの適切なプロパティは変更されません。つまり、2つのメソッドから選択する際の間違いを避けるために、そのようなすべてのメソッドの名前を変更する必要があるのです。コンパイラが必要なメソッドを明確に選択できるように、後にこれらのメソッドの戻り型も統一する必要もあると思います。
\MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqhで必要な修正を導入しましょう。
//--- Set the "Background object" flag bool SetFlagBack(const bool flag) { ::ResetLastError(); if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_BACK,flag)) { this.m_back=flag; return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Set the "Object selection" flag bool SetFlagSelected(const bool flag) { ::ResetLastError(); if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTED,flag)) { this.m_selected=flag; return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Set the "Object selection" flag bool SetFlagSelectable(const bool flag) { ::ResetLastError(); if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag)) { this.m_selectable=flag; return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Set the "Disable displaying the name of a graphical object in the terminal object list" flag bool SetFlagHidden(const bool flag) { ::ResetLastError(); if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag)) { this.m_hidden=flag; return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; }
多次元動的配列を作成するためのクラスを別のファイルに移動します。それらを改善して、ライブラリの既存または計画されたオブジェクトのプロパティオブジェクトを作成し、そのプロパティ(整数、実数、文字列)を格納する配列を適用するツールに変えます。
サービスクラスと関数がある\MQL5\Include\DoEasy\Services\フォルダに、新しいProperties.mqhファイルを作成します。オブジェクトプロパティの2次元配列を作成するためのすべてのクラスと、前の記事で設定されたプロパティオブジェクト(以前と現在の両方)をCGStdGraphObj抽象標準グラフィカルオブジェクトのクラス本体に直接取得します。
//+------------------------------------------------------------------+ //| The class of the abstract standard graphical object | //+------------------------------------------------------------------+ class CGStdGraphObj : public CGBaseObj { private: //--- Object property class class CDataPropObj { private: CArrayObj m_list; // list of property objects int m_total_int; // Number of integer parameters int m_total_dbl; // Number of real parameters int m_total_str; // Number of string parameters //--- Return the index of the array the (1) double and (2) string properties are actually located at int IndexProp(ENUM_GRAPH_OBJ_PROP_DOUBLE property) const { return(int)property-this.m_total_int; } int IndexProp(ENUM_GRAPH_OBJ_PROP_STRING property) const { return(int)property-this.m_total_int-this.m_total_dbl; } public: //--- Return the pointer to (1) the list of property objects, as well as to the object of (2) integer, (3) real and (4) string properties CArrayObj *GetList(void) { return &this.m_list; } CXDimArrayLong *Long() const { return this.m_list.At(0); } CXDimArrayDouble *Double() const { return this.m_list.At(1); } CXDimArrayString *String() const { return this.m_list.At(2); } //--- Set object's (1) integer, (2) real and (3) string properties void Set(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Long().Set(property,index,value); } void Set(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value) { this.Double().Set(this.IndexProp(property),index,value); } void Set(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value) { this.String().Set(this.IndexProp(property),index,value); } //--- Return object’s (1) integer, (2) real and (3) string property from the properties array long Get(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index) const { return this.Long().Get(property,index); } double Get(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index) const { return this.Double().Get(this.IndexProp(property),index); } string Get(ENUM_GRAPH_OBJ_PROP_STRING property,int index) const { return this.String().Get(this.IndexProp(property),index); } //--- Return the size of the specified first dimension data array int Size(const int range) const { if(range<this.m_total_int) return this.Long().Size(range); else if(range<this.m_total_int+this.m_total_dbl) return this.Double().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range)); else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str) return this.String().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range)); return 0; } //--- Set the array size in the specified dimensionality bool SetSizeRange(const int range,const int size) { if(range<this.m_total_int) return this.Long().SetSizeRange(range,size); else if(range<this.m_total_int+this.m_total_dbl) return this.Double().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range),size); else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str) return this.String().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range),size); return false; } //--- Constructor CDataPropObj(const int prop_total_integer,const int prop_total_double,const int prop_total_string) { this.m_total_int=prop_total_integer; this.m_total_dbl=prop_total_double; this.m_total_str=prop_total_string; this.m_list.Add(new CXDimArrayLong(this.m_total_int, 1)); this.m_list.Add(new CXDimArrayDouble(this.m_total_dbl,1)); this.m_list.Add(new CXDimArrayString(this.m_total_str,1)); } //--- Destructor ~CDataPropObj() { m_list.Clear(); m_list.Shutdown(); } }; //--- Data class of the current and previous properties class CProperty { public: CDataPropObj *Curr; // Pointer to the current properties object CDataPropObj *Prev; // Pointer to the previous properties object //--- Set the array size ('size') in the specified dimension ('range') bool SetSizeRange(const int range,const int size) { return(this.Curr.SetSizeRange(range,size) && this.Prev.SetSizeRange(range,size) ? true : false); } //--- Return the size of the specified array of the (1) current and (2) previous first dimension data int CurrSize(const int range) const { return Curr.Size(range); } int PrevSize(const int range) const { return Prev.Size(range); } //--- Copy the current data to the previous one void CurrentToPrevious(void) { //--- Copy all integer properties for(int i=0;i<this.Curr.Long().Total();i++) for(int r=0;r<this.Curr.Long().Size(i);r++) this.Prev.Long().Set(i,r,this.Curr.Long().Get(i,r)); //--- Copy all real properties for(int i=0;i<this.Curr.Double().Total();i++) for(int r=0;r<this.Curr.Double().Size(i);r++) this.Prev.Double().Set(i,r,this.Curr.Double().Get(i,r)); //--- Copy all string properties for(int i=0;i<this.Curr.String().Total();i++) for(int r=0;r<this.Curr.String().Size(i);r++) this.Prev.String().Set(i,r,this.Curr.String().Get(i,r)); } //--- Constructor CProperty(const int prop_int_total,const int prop_double_total,const int prop_string_total) { this.Curr=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); this.Prev=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); } };
クラスを汎用にするには、特定のクラスオブジェクトに属する列挙型への参照を削除する必要があります。
これを実現するには、実数プロパティインデックスを返すメソッドを選択するために使用されるすべての列挙型を、通常のint変数に置き換えます。プロパティインデックスを計算するには、実数プロパティと文字列プロパティの最大プロパティをクラスコンストラクタに渡します(整数プロパティはその値をシフトせず、プロパティインデックスに完全に対応します)。次に、プロパティ値とプロパティの最大値に基づいて実際の値を計算するだけです。いつものように、コードとして表示すると、アイデアはより明確に見えます。
新しく追加された\MQL5\Include\DoEasy\Services\Properties.mqhファイルに次のクラスを追加します。
//+------------------------------------------------------------------+ //| Properties.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "XDimArray.mqh" //+------------------------------------------------------------------+ //| Object property class | //+------------------------------------------------------------------+ //--- Object property class class CDataPropObj : public CObject { private: CArrayObj m_list; // list of property objects int m_total_int; // Number of integer parameters int m_total_dbl; // Number of real parameters int m_total_str; // Number of string parameters int m_prop_max_dbl; // Maximum possible real property value int m_prop_max_str; // Maximum possible string property value //--- Return the index of the array the int, double or string property is actually located at int IndexProp(int property) const { //--- If the passed value is less than the number of integer parameters, //--- this is an integer property. Return the value passed to the method if(property<this.m_total_int) return property; //--- Otherwise if the passed value is less than the maximum possible real property value, //--- then this is a real property - return the calculated index in the array of real properties else if(property<this.m_prop_max_dbl) return property-this.m_total_int; //--- Otherwise if the passed value is less than the maximum possible string property value, //--- then this is a string property - return the calculated index in the array of string properties else if(property<this.m_prop_max_str) return property-this.m_total_int-this.m_total_dbl; //--- Otherwise, if the passed value exceeds the maximum range of all values of all properties, //--- inform of this in the journal and return INT_MAX causing the error //--- accessing the array in XDimArray file classes which send the appropriate warning to the journal CMessage::ToLog(DFUN,MSG_DATA_PROP_OBJ_OUT_OF_PROP_RANGE); return INT_MAX; } public: //--- Return the pointer to (1) the list of property objects, as well as to the object of (2) integer, (3) real and (4) string properties CArrayObj *GetList(void) { return &this.m_list; } CXDimArrayLong *Long() const { return this.m_list.At(0); } CXDimArrayDouble *Double() const { return this.m_list.At(1); } CXDimArrayString *String() const { return this.m_list.At(2); } //--- Set (1) integer, (2) real and (3) string properties in the appropriate property object void SetLong(int property,int index,long value) { this.Long().Set(property,index,value); } void SetDouble(int property,int index,double value) { this.Double().Set(this.IndexProp(property),index,value); } void SetString(int property,int index,string value) { this.String().Set(this.IndexProp(property),index,value); } //--- Return (1) integer, (2) real and (3) string property from the appropriate object long GetLong(int property,int index) const { return this.Long().Get(property,index); } double GetDouble(int property,int index) const { return this.Double().Get(this.IndexProp(property),index); } string GetString(int property,int index) const { return this.String().Get(this.IndexProp(property),index); } //--- Return the size of the specified first dimension data array int Size(const int range) const { if(range<this.m_total_int) return this.Long().Size(range); else if(range<this.m_prop_max_dbl) return this.Double().Size(this.IndexProp(range)); else if(range<this.m_prop_max_str) return this.String().Size(this.IndexProp(range)); return 0; } //--- Set the array size in the specified dimensionality bool SetSizeRange(const int range,const int size) { if(range<this.m_total_int) return this.Long().SetSizeRange(range,size); else if(range<this.m_prop_max_dbl) return this.Double().SetSizeRange(this.IndexProp(range),size); else if(range<this.m_prop_max_str) return this.String().SetSizeRange(this.IndexProp(range),size); return false; } //--- Constructor CDataPropObj(const int prop_total_integer,const int prop_total_double,const int prop_total_string) { //--- Set the passed amounts of integer, real and string properties in the variables this.m_total_int=prop_total_integer; this.m_total_dbl=prop_total_double; this.m_total_str=prop_total_string; //--- Calculate and set the maximum values of real and string properties to the variables this.m_prop_max_dbl=this.m_total_int+this.m_total_dbl; this.m_prop_max_str=this.m_total_int+this.m_total_dbl+this.m_total_str; //--- Add newly created objects of integer, real and string properties to the list this.m_list.Add(new CXDimArrayLong(this.m_total_int, 1)); this.m_list.Add(new CXDimArrayDouble(this.m_total_dbl,1)); this.m_list.Add(new CXDimArrayString(this.m_total_str,1)); } //--- Destructor ~CDataPropObj() { m_list.Clear(); m_list.Shutdown(); } }; //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Data class of the current and previous properties | //+------------------------------------------------------------------+ class CProperties : public CObject { private: CArrayObj m_list; // List for storing the pointers to property objects public: CDataPropObj *Curr; // Pointer to the current properties object CDataPropObj *Prev; // Pointer to the previous properties object //--- Set the array size ('size') in the specified dimension ('range') bool SetSizeRange(const int range,const int size) { return(this.Curr.SetSizeRange(range,size) && this.Prev.SetSizeRange(range,size) ? true : false); } //--- Return the size of the specified array of the (1) current and (2) previous first dimension data int CurrSize(const int range) const { return Curr.Size(range); } int PrevSize(const int range) const { return Prev.Size(range); } //--- Copy the current data to the previous one void CurrentToPrevious(void) { //--- Copy all integer properties for(int i=0;i<this.Curr.Long().Total();i++) for(int r=0;r<this.Curr.Long().Size(i);r++) this.Prev.Long().Set(i,r,this.Curr.Long().Get(i,r)); //--- Copy all real properties for(int i=0;i<this.Curr.Double().Total();i++) for(int r=0;r<this.Curr.Double().Size(i);r++) this.Prev.Double().Set(i,r,this.Curr.Double().Get(i,r)); //--- Copy all string properties for(int i=0;i<this.Curr.String().Total();i++) for(int r=0;r<this.Curr.String().Size(i);r++) this.Prev.String().Set(i,r,this.Curr.String().Get(i,r)); } //--- Constructor CProperties(const int prop_int_total,const int prop_double_total,const int prop_string_total) { //--- Create new objects of the current and previous properties this.Curr=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); this.Prev=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); //--- Add newly created objects to the list this.m_list.Add(this.Curr); this.m_list.Add(this.Prev); } //--- Destructor ~CProperties() { this.m_list.Clear(); this.m_list.Shutdown(); } }; //+------------------------------------------------------------------+
主な説明はすべてコードコメントに設定されています。これらのクラスを、前の記事で\MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqhに作成したクラスと比較してください。
次に、\MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqhの抽象標準グラフィカルオブジェクトクラスを改善します。
まず、新しく作成されたオブジェクトプロパティクラスのファイルをインクルードします。
//+------------------------------------------------------------------+ //| GStdGraphObj.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\GBaseObj.mqh" #include "..\..\..\Services\Properties.mqh" //+------------------------------------------------------------------+ //| The class of the abstract standard graphical object | //+------------------------------------------------------------------+ class CGStdGraphObj : public CGBaseObj {
プロパティオブジェクトのクラスは、クラスのprivateセクションからすでに削除されています。プロパティオブジェクトへのポインタも宣言されています。クラスのpublicセクションにあるGetメソッドとSetメソッドのそれぞれでプロパティオブジェクトの適切なメソッドにアクセスします。
//+------------------------------------------------------------------+ //| The class of the abstract standard graphical object | //+------------------------------------------------------------------+ class CGStdGraphObj : public CGBaseObj { private: CProperties *Prop; // Pointer to the properties object int m_pivots; // Number of object reference points //--- Read and set (1) the time and (2) the price of the specified object pivot point void SetTimePivot(const int index); void SetPricePivot(const int index); //--- Read and set (1) color, (2) style, (3) width, (4) value, (5) text of the specified object level void SetLevelColor(const int index); void SetLevelStyle(const int index); void SetLevelWidth(const int index); void SetLevelValue(const int index); void SetLevelText(const int index); //--- Read and set the BMP file name for the "Bitmap Level" object. Index: 0 - ON, 1 - OFF void SetBMPFile(const int index); public: //--- Set object's (1) integer, (2) real and (3) string properties void SetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Prop.Curr.SetLong(property,index,value); } void SetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value) { this.Prop.Curr.SetDouble(property,index,value); } void SetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value) { this.Prop.Curr.SetString(property,index,value); } //--- Return object’s (1) integer, (2) real and (3) string property from the properties array long GetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index) const { return this.Prop.Curr.GetLong(property,index); } double GetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index) const { return this.Prop.Curr.GetDouble(property,index); } string GetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index) const { return this.Prop.Curr.GetString(property,index); } //--- Set object's previous (1) integer, (2) real and (3) string properties void SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Prop.Prev.SetLong(property,index,value); } void SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value){ this.Prop.Prev.SetDouble(property,index,value); } void SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value){ this.Prop.Prev.SetString(property,index,value); } //--- Return object’s (1) integer, (2) real and (3) string property from the previous properties array long GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index) const { return this.Prop.Prev.GetLong(property,index); } double GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index) const { return this.Prop.Prev.GetDouble(property,index); } string GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index) const { return this.Prop.Prev.GetString(property,index); } //--- Return itself CGStdGraphObj *GetObject(void) { return &this;}
publicセクションで、プロパティオブジェクトが削除されるクラスのデストラクタを追加します。
//--- Default constructor CGStdGraphObj(){ this.m_type=OBJECT_DE_TYPE_GSTD_OBJ; m_group=WRONG_VALUE; } //--- Destructor ~CGStdGraphObj() { if(this.Prop!=NULL) delete this.Prop; } protected: //--- Protected parametric constructor CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type, const ENUM_GRAPH_OBJ_BELONG belong, const ENUM_GRAPH_OBJ_GROUP group, const long chart_id, const int pivots, const string name);
メソッドの簡略化されたアクセスとグラフィカルオブジェクトプロパティを設定するセクションで、フラグプロパティの設定方法を改善します。
//--- Background object bool Back(void) const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_BACK,0); } void SetFlagBack(const bool flag) { if(CGBaseObj::SetFlagBack(flag)) this.SetProperty(GRAPH_OBJ_PROP_BACK,0,flag); } //--- Priority of a graphical object for receiving the event of clicking on a chart long Zorder(void) const { return this.GetProperty(GRAPH_OBJ_PROP_ZORDER,0); } void SetZorder(const long value) { if(CGBaseObj::SetZorder(value)) this.SetProperty(GRAPH_OBJ_PROP_ZORDER,0,value); } //--- Disable displaying the name of a graphical object in the terminal object list bool Hidden(void) const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_HIDDEN,0); } void SetFlagHidden(const bool flag) { if(CGBaseObj::SetFlagHidden(flag)) this.SetProperty(GRAPH_OBJ_PROP_HIDDEN,0,flag); } //--- Object selection bool Selected(void) const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTED,0); } void SetFlagSelected(const bool flag) { if(CGBaseObj::SetFlagSelected(flag)) this.SetProperty(GRAPH_OBJ_PROP_SELECTED,0,flag); } //--- Object availability bool Selectable(void) const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTABLE,0); } void SetFlagSelectable(const bool flag) { if(CGBaseObj::SetFlagSelectable(flag)) this.SetProperty(GRAPH_OBJ_PROP_SELECTABLE,0,flag); } //--- Time coordinate
現在のプロパティを前のプロパティにコピーするメソッドをprivateセクションからpublicセクションに移動します。
//--- Return the description of the object visibility on timeframes string VisibleOnTimeframeDescription(void); //--- Re-write all graphical object properties void PropertiesRefresh(void); //--- Check object property changes void PropertiesCheckChanged(void); //--- Copy the current data to the previous one void PropertiesCopyToPrevData(void); private: //--- Get and save (1) integer, (2) real and (3) string properties void GetAndSaveINT(void); void GetAndSaveDBL(void); void GetAndSaveSTR(void); }; //+------------------------------------------------------------------+
protectedパラメトリックコンストラクタで、グラフィカルオブジェクトプロパティの新しいオブジェクトを作成します。
//+------------------------------------------------------------------+ //| Protected parametric constructor | //+------------------------------------------------------------------+ CGStdGraphObj::CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type, const ENUM_GRAPH_OBJ_BELONG belong, const ENUM_GRAPH_OBJ_GROUP group, const long chart_id,const int pivots, const string name) { //--- Create the property object with the default values this.Prop=new CProperties(GRAPH_OBJ_PROP_INTEGER_TOTAL,GRAPH_OBJ_PROP_DOUBLE_TOTAL,GRAPH_OBJ_PROP_STRING_TOTAL); //--- Set the number of pivot points and object levels
整数、実数、文字列グラフィカルオブジェクトプロパティの数をクラスコンストラクタに渡します。
グラフィックから整数プロパティを返し、それらをクラスオブジェクトプロパティに保存するメソッドで、オブジェクトレベルの数が変更されたかどうかを確認します。変更されている場合、すべてのレベル値を保存するプロパティの配列のサイズを変更します。
そうしないと、レベルプロパティを設定するときに、配列に範囲外エラーが発生します。
//--- Properties belonging to different graphical objects this.SetProperty(GRAPH_OBJ_PROP_FILL,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_FILL)); // Fill an object with color this.SetProperty(GRAPH_OBJ_PROP_READONLY,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_READONLY)); // Ability to edit text in the Edit object this.SetProperty(GRAPH_OBJ_PROP_LEVELS,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_LEVELS)); // Number of levels if(this.GetProperty(GRAPH_OBJ_PROP_LEVELS,0)!=this.GetPropertyPrev(GRAPH_OBJ_PROP_LEVELS,0)) // Check if the number of levels has changed { this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELCOLOR,this.Levels()); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELSTYLE,this.Levels()); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELWIDTH,this.Levels()); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELVALUE,this.Levels()); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELTEXT,this.Levels()); } for(int i=0;i<this.Levels();i++) // Level data { this.SetLevelColor(i); this.SetLevelStyle(i); this.SetLevelWidth(i); } this.SetProperty(GRAPH_OBJ_PROP_ALIGN,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ALIGN)); // Horizontal text alignment in the Edit object (OBJ_EDIT)
オブジェクトプロパティの変更を確認するメソッドを簡略化します。
//+------------------------------------------------------------------+ //| Check object property changes | //+------------------------------------------------------------------+ void CGStdGraphObj::PropertiesCheckChanged(void) { bool changed=false; int begin=0, end=GRAPH_OBJ_PROP_INTEGER_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_INTEGER prop=(ENUM_GRAPH_OBJ_PROP_INTEGER)i; if(!this.SupportProperty(prop)) continue; for(int j=0;j<Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j)) { changed=true; ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop)); } } } begin=end; end+=GRAPH_OBJ_PROP_DOUBLE_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_DOUBLE prop=(ENUM_GRAPH_OBJ_PROP_DOUBLE)i; if(!this.SupportProperty(prop)) continue; for(int j=0;j<Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j)) { changed=true; ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop)); } } } begin=end; end+=GRAPH_OBJ_PROP_STRING_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_STRING prop=(ENUM_GRAPH_OBJ_PROP_STRING)i; if(!this.SupportProperty(prop)) continue; for(int j=0;j<Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j)) { changed=true; ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop)); } } } if(changed) PropertiesCopyToPrevData(); } //+------------------------------------------------------------------+
以前のメソッドの実装では、if-else構造を使用して、プロパティに複数の値(アンカーポイント時間など)があることを確認し、そのような各プロパティを個別のコードブロックで処理しました。各プロパティのプロパティ配列サイズを知ることができるので、ループ内の単一のプロパティの値を配列の2番目の次元のサイズで調べるだけで十分です。単一のプロパティの場合、2番目のディメンションのサイズは1ですが、複数のプロパティの場合は、プロパティの複数プロパティの値の数と同じです。したがって、すべてのオブジェクトプロパティごとに1つのループで実行できます。これは私が上でしたことです。
また、同じファイルにいくつかのマイナーな改善(メソッド名の変更など)を実装しました。たとえば、LevelColorsDescription()の名前はLevelsColorDescription()に変更されました。これは、メソッドの目的により沿ったものです。ここでは、そのような名前の変更については考慮しませんが、添付ファイルでご覧になれます。
各ライブラリオブジェクトには、他のプロパティに加えてカスタムオブジェクトIDがあります。グラフィック要素のコレクションクラスには、2つのコレクションがあります。1つ目は、グラフィック要素のコレクションです。これについては現在作業しているグラフィカルオブジェクトのコレクションが完了するまで開発を中断しています(手動で作成した標準のグラフィカルオブジェクトを使用)。2つ目は、プログラムで作成される標準のグラフィカルオブジェクトです。ここでは、標準のグラフィカルオブジェクトをプログラミングするための機能の開発を開始します。
プログラムで作成されたグラフィカルオブジェクトのIDの範囲は1から10000までです。手動で作成されたグラフィカルオブジェクトのIDは10001から始まります。
\MQL5\Include\DoEasy\Defines.mqhにこのしきい値を設定します。
//--- Pending request type IDs #define PENDING_REQUEST_ID_TYPE_ERR (1) // Type of a pending request created based on the server return code #define PENDING_REQUEST_ID_TYPE_REQ (2) // Type of a pending request created by request //--- Timeseries parameters #define SERIES_DEFAULT_BARS_COUNT (1000) // Required default amount of timeseries data #define PAUSE_FOR_SYNC_ATTEMPTS (16) // Amount of pause milliseconds between synchronization attempts #define ATTEMPTS_FOR_SYNC (5) // Number of attempts to receive synchronization with the server //--- Tick series parameters #define TICKSERIES_DEFAULT_DAYS_COUNT (1) // Required number of days for tick data in default series #define TICKSERIES_MAX_DATA_TOTAL (200000) // Maximum number of stored tick data of a single symbol //--- Parameters of the DOM snapshot series #define MBOOKSERIES_DEFAULT_DAYS_COUNT (1) // The default required number of days for DOM snapshots in the series #define MBOOKSERIES_MAX_DATA_TOTAL (200000) // Maximum number of stored DOM snapshots of a single symbol //--- Canvas parameters #define PAUSE_FOR_CANV_UPDATE (16) // Canvas update frequency #define NULL_COLOR (0x00FFFFFF) // Zero for the canvas with the alpha channel #define OUTER_AREA_SIZE (16) // Size of one side of the outer area around the workspace //--- Graphical object parameters #define PROGRAM_OBJ_MAX_ID (10000) // Maximum value of an ID of a graphical object belonging to a program //+------------------------------------------------------------------+ //| Enumerations | //+------------------------------------------------------------------+
標準グラフィカルオブジェクトをプログラミングするメソッド
チャート上でのグラフィカルオブジェクトの手動作成を追跡し、適切なクラスオブジェクトを作成し、それらをコレクションリストに追加するメソッドはすでに存在します。もちろん、現在のタスクにそれらを使用するのは良いことですが、部分的に既成のメソッドの使用を断念せざるを得なかった理由がいくつかあります。タイマーではグラフィカルオブジェクトの出現を追跡するだけです。プログラムでオブジェクトを作成する場合、次のタイマーティックを待って、新しく作成されたオブジェクトとその作成メソッド(プログラムおよび手動)を定義することはしたくありません。
代わりに、標準グラフィカルオブジェクトを構築するためのグラフィカル要素のコレクションクラスにメソッドを作成します。オブジェクトを作成した直後に、対応するクラスオブジェクトを作成し、コレクションに配置します。オブジェクトプロパティの変更の検索は、すでに作成されている機能によって実行されます。したがって、オブジェクト作成メソッドを考慮せずに変更を検索する機能を維持しながら、オブジェクトを作成してコレクションに追加することができます。将来的には、これにより、複合グラフィカルオブジェクトの作成とそのプロパティの管理が簡素化されます。
プログラムで作成されたグラフィカルオブジェクトの名前には、オブジェクトの作成元のプログラムの名前が含まれます。これにより、「独自の」グラフィカルオブジェクトを手動で作成したオブジェクトと区別できるようになります。
これを実現するには、グラフィック要素コレクションクラス(\MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh)のファイルのチャートオブジェクト管理クラスのprivateセクションにプログラム名を格納するための新しい変数を追加します。
//+------------------------------------------------------------------+ //| 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:
クラスのpublicセクションで、CreateNewGraphObj()メソッドからチャートIDの指定を削除します。IDはチャートオブジェクト管理オブジェクトの主要なプロパティの1つであり、メソッドに渡すのではなくオブジェクトから直接取得できるためです。
クラスコンストラクタでプログラム名の値を適切な変数に設定します。
public: //--- Return the variable values ENUM_TIMEFRAMES Timeframe(void) const { return this.m_chart_timeframe; } long ChartID(void) const { return this.m_chart_id; } string Symbol(void) const { return this.m_chart_symbol; } bool IsEvent(void) const { return this.m_is_graph_obj_event; } int TotalObjects(void) const { return this.m_total_objects; } int Delta(void) const { return this.m_delta_graph_obj; } //--- Create a new standard graphical object CGStdGraphObj *CreateNewGraphObj(const ENUM_OBJECT obj_type,const string name); //--- Return the list of newly added objects CArrayObj *GetListNewAddedObj(void) { return &this.m_list_new_graph_obj;} //--- Create the event control indicator bool CreateEventControlInd(const long chart_id_main); //--- Add the event control indicator to the chart bool AddEventControlInd(void); //--- Check the chart objects void Refresh(void); //--- Constructors CChartObjectsControl(void) { this.m_name_program=::MQLInfoString(MQL_PROGRAM_NAME); this.m_chart_id=::ChartID(); this.m_chart_timeframe=(ENUM_TIMEFRAMES)::ChartPeriod(this.m_chart_id); this.m_chart_symbol=::ChartSymbol(this.m_chart_id); this.m_chart_id_main=::ChartID(); this.m_list_new_graph_obj.Clear(); this.m_list_new_graph_obj.Sort(); this.m_is_graph_obj_event=false; this.m_total_objects=0; this.m_last_objects=0; this.m_delta_graph_obj=0; this.m_name_ind=""; this.m_handle_ind=INVALID_HANDLE; this.SetMouseEvent(); } CChartObjectsControl(const long chart_id) { this.m_name_program=::MQLInfoString(MQL_PROGRAM_NAME); this.m_chart_timeframe=(ENUM_TIMEFRAMES)::ChartPeriod(this.m_chart_id); this.m_chart_symbol=::ChartSymbol(this.m_chart_id); this.m_chart_id_main=::ChartID(); this.m_list_new_graph_obj.Clear(); this.m_list_new_graph_obj.Sort(); this.m_chart_id=chart_id; this.m_is_graph_obj_event=false; this.m_total_objects=0; this.m_last_objects=0; this.m_delta_graph_obj=0; this.m_name_ind=""; this.m_handle_ind=INVALID_HANDLE; this.SetMouseEvent(); }
空の名前のチェックに加えて、チャートオブジェクトをチェックするメソッドでオブジェクトがプログラムで作成されていないことを確認します。
//+------------------------------------------------------------------+ //| CChartObjectsControl: Check objects on a chart | //+------------------------------------------------------------------+ void CChartObjectsControl::Refresh(void) { //--- Graphical objects on the chart this.m_total_objects=::ObjectsTotal(this.ChartID()); this.m_delta_graph_obj=this.m_total_objects-this.m_last_objects; //--- If the number of objects has changed if(this.m_delta_graph_obj!=0) { //--- Create the string and display it in the journal with the chart ID, its symbol and timeframe string txt=", "+(m_delta_graph_obj>0 ? "Added: " : "Deleted: ")+(string)fabs(m_delta_graph_obj)+" obj"; Print(DFUN,"ChartID=",this.ChartID(),", ",this.Symbol(),", ",TimeframeDescription(this.Timeframe()),txt); } //--- If an object is added to the chart if(this.m_delta_graph_obj>0) { //--- find the last added graphical object, select it and write its name string name=this.LastAddedGraphObjName(); if(name!="" && ::StringFind(name,m_name_program)==WRONG_VALUE) { //--- Create the object of the graphical object class corresponding to the added graphical object type ENUM_OBJECT type=(ENUM_OBJECT)::ObjectGetInteger(this.ChartID(),name,OBJPROP_TYPE); ENUM_OBJECT_DE_TYPE obj_type=ENUM_OBJECT_DE_TYPE(type+OBJECT_DE_TYPE_GSTD_OBJ+1); CGStdGraphObj *obj=this.CreateNewGraphObj(type,name); if(obj==NULL) return; //--- Set the object affiliation and add the created object to the list of new objects obj.SetBelong(GRAPH_OBJ_BELONG_NO_PROGRAM); if(this.m_list_new_graph_obj.Search(obj)==WRONG_VALUE) { this.m_list_new_graph_obj.Add(obj); } } } //--- save the index of the last added graphical object and the difference with the last check this.m_last_objects=this.m_total_objects; this.m_is_graph_obj_event=(bool)this.m_delta_graph_obj; } //+------------------------------------------------------------------+
つまり、オブジェクト名にプログラム名の部分文字列がない場合、そのようなオブジェクトはメソッドで処理する必要があります。それ以外の場合、これはプログラムで作成されたグラフィカルオブジェクトであり、別のメソッドによってコレクションリストに追加されます。
新しい標準のグラフィカルオブジェクトを作成するメソッドで、以前にメソッドに渡されたすべてのchart_idを、それが制御するオブジェクトに設定されたチャートIDに置き換えます。
//+------------------------------------------------------------------+ //| CChartObjectsControl: | //| Create a new standard graphical object | //+------------------------------------------------------------------+ CGStdGraphObj *CChartObjectsControl::CreateNewGraphObj(const ENUM_OBJECT obj_type,const string name) { CGStdGraphObj *obj=NULL; switch((int)obj_type) { //--- Lines case OBJ_VLINE : return new CGStdVLineObj(this.ChartID(),name); case OBJ_HLINE : return new CGStdHLineObj(this.ChartID(),name); case OBJ_TREND : return new CGStdTrendObj(this.ChartID(),name); case OBJ_TRENDBYANGLE : return new CGStdTrendByAngleObj(this.ChartID(),name); case OBJ_CYCLES : return new CGStdCyclesObj(this.ChartID(),name); case OBJ_ARROWED_LINE : return new CGStdArrowedLineObj(this.ChartID(),name); //--- Channels case OBJ_CHANNEL : return new CGStdChannelObj(this.ChartID(),name); case OBJ_STDDEVCHANNEL : return new CGStdStdDevChannelObj(this.ChartID(),name); case OBJ_REGRESSION : return new CGStdRegressionObj(this.ChartID(),name); case OBJ_PITCHFORK : return new CGStdPitchforkObj(this.ChartID(),name); //--- Gann case OBJ_GANNLINE : return new CGStdGannLineObj(this.ChartID(),name); case OBJ_GANNFAN : return new CGStdGannFanObj(this.ChartID(),name); case OBJ_GANNGRID : return new CGStdGannGridObj(this.ChartID(),name); //--- Fibo case OBJ_FIBO : return new CGStdFiboObj(this.ChartID(),name); case OBJ_FIBOTIMES : return new CGStdFiboTimesObj(this.ChartID(),name); case OBJ_FIBOFAN : return new CGStdFiboFanObj(this.ChartID(),name); case OBJ_FIBOARC : return new CGStdFiboArcObj(this.ChartID(),name); case OBJ_FIBOCHANNEL : return new CGStdFiboChannelObj(this.ChartID(),name); case OBJ_EXPANSION : return new CGStdExpansionObj(this.ChartID(),name); //--- Elliott case OBJ_ELLIOTWAVE5 : return new CGStdElliotWave5Obj(this.ChartID(),name); case OBJ_ELLIOTWAVE3 : return new CGStdElliotWave3Obj(this.ChartID(),name); //--- Shapes case OBJ_RECTANGLE : return new CGStdRectangleObj(this.ChartID(),name); case OBJ_TRIANGLE : return new CGStdTriangleObj(this.ChartID(),name); case OBJ_ELLIPSE : return new CGStdEllipseObj(this.ChartID(),name); //--- Arrows case OBJ_ARROW_THUMB_UP : return new CGStdArrowThumbUpObj(this.ChartID(),name); case OBJ_ARROW_THUMB_DOWN : return new CGStdArrowThumbDownObj(this.ChartID(),name); case OBJ_ARROW_UP : return new CGStdArrowUpObj(this.ChartID(),name); case OBJ_ARROW_DOWN : return new CGStdArrowDownObj(this.ChartID(),name); case OBJ_ARROW_STOP : return new CGStdArrowStopObj(this.ChartID(),name); case OBJ_ARROW_CHECK : return new CGStdArrowCheckObj(this.ChartID(),name); case OBJ_ARROW_LEFT_PRICE : return new CGStdArrowLeftPriceObj(this.ChartID(),name); case OBJ_ARROW_RIGHT_PRICE : return new CGStdArrowRightPriceObj(this.ChartID(),name); case OBJ_ARROW_BUY : return new CGStdArrowBuyObj(this.ChartID(),name); case OBJ_ARROW_SELL : return new CGStdArrowSellObj(this.ChartID(),name); case OBJ_ARROW : return new CGStdArrowObj(this.ChartID(),name); //--- Graphical objects case OBJ_TEXT : return new CGStdTextObj(this.ChartID(),name); case OBJ_LABEL : return new CGStdLabelObj(this.ChartID(),name); case OBJ_BUTTON : return new CGStdButtonObj(this.ChartID(),name); case OBJ_CHART : return new CGStdChartObj(this.ChartID(),name); case OBJ_BITMAP : return new CGStdBitmapObj(this.ChartID(),name); case OBJ_BITMAP_LABEL : return new CGStdBitmapLabelObj(this.ChartID(),name); case OBJ_EDIT : return new CGStdEditObj(this.ChartID(),name); case OBJ_EVENT : return new CGStdEventObj(this.ChartID(),name); case OBJ_RECTANGLE_LABEL : return new CGStdRectangleLabelObj(this.ChartID(),name); default : return NULL; } } //+------------------------------------------------------------------+
グラフィカルオブジェクトのCGraphElementsCollectionコレクションクラスの最初の空きグラフィカルオブジェクトIDを返すメソッドで、必要なオブジェクトのIDを指定するフラグ(手動で作成されたものの場合falseで、プログラムで作成されたものの場合true)を追加します。
//--- Return the first free ID of the graphical (1) object and (2) element on canvas long GetFreeGraphObjID(bool program_object); long GetFreeCanvElmID(void); //--- Add a graphical object to the collection
新しい標準のグラフィカルオブジェクトを作成するprivateメソッドを宣言します。
//--- 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:
クラスのprivateセクションで、新しいグラフィカルオブジェクトを作成し、チャート管理オブジェクトへのポインタを返すメソッドを記述します。
//--- Event handler void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam); private: //--- Create a new graphical object, return the pointer to the chart management object CChartObjectsControl *CreateNewStdGraphObjectAndGetCtrlObj(const long chart_id, const string name, int subwindow, const ENUM_OBJECT type_object, const datetime time1, const double price1, const datetime time2=0, const double price2=0, const datetime time3=0, const double price3=0, const datetime time4=0, const double price4=0, const datetime time5=0, const double price5=0) { //--- If an object with a chart ID and name is already present in the collection, inform of that and return NULL if(this.IsPresentGraphObjInList(chart_id,name)) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELM_COLLECTION_ERR_GR_OBJ_ALREADY_EXISTS)," ChartID ",(string)chart_id,", ",name); return NULL; } //--- If failed to create a new standard graphical object, inform of that and return NULL if(!this.CreateNewStdGraphObject(chart_id,name,type_object,subwindow,time1,0)) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_STD_GRAPH_OBJ),StdGraphObjectTypeDescription(type_object)); CMessage::ToLog(::GetLastError(),true); return NULL; } //--- If failed to get a chart management object, inform of that CChartObjectsControl *ctrl=this.GetChartObjectCtrlObj(chart_id); if(ctrl==NULL) ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_GET_CTRL_OBJ),(string)chart_id); //--- Return the pointer to a chart management object or NULL in case of a failed attempt to get it return ctrl; } public:
メソッドのロジックは、コードのコメントで説明されています。このメソッドは、クラスのpublicセクションの後部にある指定された標準のグラフィカルオブジェクトタイプを作成するときに使用されます。
以下は、「垂直線」グラフィック要素オブジェクトを作成するメソッドです。
public: //--- Create the "Vertical line" graphical object bool CreateLineVertical(const long chart_id,const string name,const int subwindow,const datetime time) { //--- Set the name and type of a created object string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_VLINE; //--- Create a new graphical object and get the pointer to the chart management object CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,0); if(ctrl==NULL) return false; //--- Create a new class object corresponding to the newly created graphical object CGStdVLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); //--- If failed to add an object to the collection list, if(!this.m_list_all_graph_obj.Add(obj)) { //--- inform of that, remove the graphical and class object, and return 'false' CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } //--- Redraw the chart and display all object properties in the journal (temporarily, for test purposes only) ::ChartRedraw(chart_id); obj.Print(); return true; }
メソッドは、コードコメントで十分に詳細に説明されています。それぞれの特定のオブジェクトに固有で、パラメータに渡されるプロパティは、そのような各オブジェクトに設定されます。指定されたチャート上に物理的なグラフィカルオブジェクトが作成され、最初にチャート管理オブジェクトへのポインタが形成されます。そのCreateNewGraphObj()メソッドは、作成されたオブジェクトタイプに対応するクラスオブジェクトを作成するために使用されます。オブジェクトをリストに追加できなかった場合、物理グラフィカルオブジェクト自体とクラスオブジェクトが削除され、エラーメッセージが操作ログに送信されます。正常に作成されると、チャートが更新され、メソッドはtrueを返します。
グラフィカルオブジェクトを作成するための残りのメソッドは、上記で検討したものと同じであり、特定のグラフィカルオブジェクトごとに定義されたパラメータのセットのみが異なります。
他のすべての追加されたメソッドのリストを見てみましょう。
//--- Create the "Horizontal line" graphical object bool CreateLineHorizontal(const long chart_id,const string name,const int subwindow,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_HLINE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,price); if(ctrl==NULL) return false; CGStdHLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Trend line" graphical object bool CreateLineTrend(const long chart_id,const string name,const int subwindow, const datetime time1,const double price1,const datetime time2,const double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_TREND; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdTrendObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Trend line by angle" graphical object bool CreateLineTrendByAngle(const long chart_id,const string name,const int subwindow, const datetime time1,const double price1,const datetime time2,const double price2,const double angle) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_TRENDBYANGLE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdTrendByAngleObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetAngle(angle); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Cyclic lines" graphical object bool CreateLineCycle(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_CYCLES; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdCyclesObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Arrowed line" graphical object bool CreateLineArrowed(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROWED_LINE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdArrowedLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Equidistant channel" graphical object bool CreateChannel(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2, double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_CHANNEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdChannelObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Standard deviation channel" graphical object bool CreateChannelStdDeviation(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const double deviation=1.5) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_STDDEVCHANNEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdStdDevChannelObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDeviation(deviation); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Linear regression channel" graphical object bool CreateChannelRegression(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_REGRESSION; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdRegressionObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Andrews' Pitchfork" graphical object bool CreatePitchforkAndrews(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_PITCHFORK; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdPitchforkObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Gann line" graphical object bool CreateGannLine(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,double angle) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_GANNLINE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdGannLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetAngle(angle); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Gann fan" graphical object bool CreateGannFan(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2, const ENUM_GANN_DIRECTION direction,const double scale) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_GANNFAN; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdGannFanObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDirection(direction); obj.SetScale(scale); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Gann grid" graphical object bool CreateGannGrid(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2, const ENUM_GANN_DIRECTION direction,const double scale) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_GANNGRID; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2); if(ctrl==NULL) return false; CGStdGannGridObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDirection(direction); obj.SetScale(scale); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo levels" graphical object bool CreateFiboLevels(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBO; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdFiboObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo Time Zones" graphical object bool CreateFiboTimeZones(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBOTIMES; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdFiboTimesObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo fan" graphical object bool CreateFiboFan(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBOFAN; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdFiboFanObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo arc" graphical object bool CreateFiboArc(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2, const double scale,const bool ellipse) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBOARC; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdFiboArcObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetScale(scale); obj.SetFlagEllipse(ellipse); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo channel" graphical object bool CreateFiboChannel(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_FIBOCHANNEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdFiboChannelObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Fibo extension" graphical object bool CreateFiboExpansion(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_EXPANSION; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdExpansionObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Elliott 5 waves" graphical object bool CreateElliothWave5(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2, const datetime time3,double price3,const datetime time4,double price4, const datetime time5,double price5,const ENUM_ELLIOT_WAVE_DEGREE degree, const bool draw_lines) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ELLIOTWAVE5; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5); if(ctrl==NULL) return false; CGStdElliotWave5Obj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDegree(degree); obj.SetFlagDrawLines(draw_lines); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Elliott 3 waves" graphical object bool CreateElliothWave3(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2, double price2,const datetime time3,double price3, const ENUM_ELLIOT_WAVE_DEGREE degree,const bool draw_lines) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ELLIOTWAVE3; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdElliotWave3Obj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetDegree(degree); obj.SetFlagDrawLines(draw_lines); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Rectangle graphical object bool CreateRectangle(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_RECTANGLE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2); if(ctrl==NULL) return false; CGStdRectangleObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Triangle graphical object bool CreateTriangle(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_TRIANGLE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdTriangleObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Ellipse graphical object bool CreateEllipse(const long chart_id,const string name,const int subwindow, const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ELLIPSE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3); if(ctrl==NULL) return false; CGStdEllipseObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Thumb up" graphical object bool CreateThumbUp(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_THUMB_UP; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowThumbUpObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Thumb down" graphical object bool CreateThumbDown(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_THUMB_DOWN; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowThumbDownObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Arrow up" graphical object bool CreateArrowUp(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_UP; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowUpObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Arrow down" graphical object bool CreateArrowDown(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_DOWN; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowDownObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Stop graphical object bool CreateSignalStop(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_STOP; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowStopObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Check mark" graphical object bool CreateSignalCheck(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_CHECK; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowCheckObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Left price label" graphical object bool CreatePriceLabelLeft(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_LEFT_PRICE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowLeftPriceObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Right price label" graphical object bool CreatePriceLabelRight(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_RIGHT_PRICE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowRightPriceObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Buy graphical object bool CreateSignalBuy(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_BUY; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowBuyObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Sell graphical object bool CreateSignalSell(const long chart_id,const string name,const int subwindow,const datetime time,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW_SELL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowSellObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Arrow graphical object bool CreateArrow(const long chart_id,const string name,const int subwindow,const datetime time,const double price, const uchar arrow_code,const ENUM_ARROW_ANCHOR anchor) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_ARROW; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdArrowObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetArrowCode(arrow_code); obj.SetAnchor(anchor); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Text graphical object bool CreateText(const long chart_id,const string name,const int subwindow,const datetime time,const double price, const string text,const int size,const ENUM_ANCHOR_POINT anchor_point,const double angle) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_TEXT; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdTextObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetText(text); obj.SetFontSize(size); obj.SetAnchor(anchor_point); obj.SetAngle(angle); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Text label" graphical object bool CreateTextLabel(const long chart_id,const string name,const int subwindow,const int x,const int y, const string text,const int size,const ENUM_BASE_CORNER corner, const ENUM_ANCHOR_POINT anchor_point,const double angle) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_LABEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdLabelObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetText(text); obj.SetFontSize(size); obj.SetCorner(corner); obj.SetAnchor(anchor_point); obj.SetAngle(angle); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Button graphical object bool CreateButton(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h, const ENUM_BASE_CORNER corner,const int font_size,const bool button_state) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_BUTTON; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdButtonObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetCorner(corner); obj.SetFontSize(font_size); obj.SetFlagState(button_state); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Chart graphical object bool CreateChart(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h, const ENUM_BASE_CORNER corner,const int scale,const string symbol,const ENUM_TIMEFRAMES timeframe) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_CHART; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdChartObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetCorner(corner); obj.SetChartObjChartScale(scale); obj.SetChartObjSymbol(symbol); obj.SetChartObjPeriod(timeframe); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the Bitmap graphical object bool CreateBitmap(const long chart_id,const string name,const int subwindow,const datetime time,const double price, const string image1,const string image2,const ENUM_ANCHOR_POINT anchor) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_BITMAP; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price); if(ctrl==NULL) return false; CGStdBitmapObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetAnchor(anchor); obj.SetBMPFile(image1,0); obj.SetBMPFile(image2,1); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Bitmap label" graphical object bool CreateBitmapLabel(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h, const string image1,const string image2,const ENUM_BASE_CORNER corner,const ENUM_ANCHOR_POINT anchor, const bool state) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_BITMAP_LABEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdBitmapLabelObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetCorner(corner); obj.SetAnchor(anchor); obj.SetBMPFile(image1,0); obj.SetBMPFile(image2,1); obj.SetFlagState(state); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Input field" graphical object bool CreateEditField(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h, const int font_size,const ENUM_BASE_CORNER corner,const ENUM_ALIGN_MODE align,const bool readonly) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_EDIT; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdEditObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetFontSize(font_size); obj.SetCorner(corner); obj.SetAlign(align); obj.SetFlagReadOnly(readonly); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Economic calendar event" graphical object bool CreateCalendarEvent(const long chart_id,const string name,const int subwindow,const datetime time) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_EVENT; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,0); if(ctrl==NULL) return false; CGStdEventObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } //--- Create the "Rectangular label" graphical object bool CreateRectangleLabel(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h, const ENUM_BASE_CORNER corner,const ENUM_BORDER_TYPE border) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_RECTANGLE_LABEL; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0); if(ctrl==NULL) return false; CGStdRectangleLabelObj *obj=ctrl.CreateNewGraphObj(type_object,nm); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true); obj.SetFlagSelected(true); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.SetXDistance(x); obj.SetYDistance(y); obj.SetXSize(w); obj.SetYSize(h); obj.SetCorner(corner); obj.SetBorderType(border); obj.PropertiesCopyToPrevData(); if(!this.m_list_all_graph_obj.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); ::ObjectDelete(chart_id,nm); delete obj; return false; } ::ChartRedraw(chart_id); obj.Print(); return true; } }; //+------------------------------------------------------------------+
すべてのメソッドは、独自の入力セットを備えています。これらのパラメータは、作成に十分な最小限のオブジェクトプロパティとして設定されます。残りのすべてのプロパティは、グラフィカルオブジェクトの作成後に変更できます。
以下は、最初の空のグラフィカルオブジェクトIDを返すメソッドです。
//+------------------------------------------------------------------+ //| Return the first free graphical object ID | //+------------------------------------------------------------------+ long CGraphElementsCollection::GetFreeGraphObjID(bool program_object) { CArrayObj *list=NULL; int index=WRONG_VALUE; if(program_object) list=CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_ID,0,PROGRAM_OBJ_MAX_ID,EQUAL_OR_LESS); else list=CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_ID,0,PROGRAM_OBJ_MAX_ID,MORE); index=CSelect::FindGraphicStdObjectMax(list,GRAPH_OBJ_PROP_ID,0); CGStdGraphObj *obj=list.At(index); int first_id=(program_object ? 1 : PROGRAM_OBJ_MAX_ID+1); return(obj!=NULL ? obj.ObjectID()+1 : first_id); } //+------------------------------------------------------------------+
これで、メソッドは必要なIDを受け取ると見なすようになります。
プログラムで作成されたグラフィカルオブジェクトを対象としている場合は、PROGRAM_OBJ_MAX_ID(10000)定数値以下のIDを持つすべてのオブジェクトのリストを取得します 。
手動で作成されたグラフィカルオブジェクトを対象としている場合は、IDがPROGRAM_OBJ_MAX_IDを超えるすべてのオブジェクトのリストを取得します。
次に、取得したリストから最大IDのオブジェクトのインデックスを取得し、そのインデックスでリストされたオブジェクトを取得します。
次に、最初のIDの値を計算します(プログラムされたオブジェクトの場合は1、手動で作成されたオブジェクトの場合は10000 + 1)。
最大IDのオブジェクトを受信した場合は、そのID +1の値を取得します。それ以外の場合、オブジェクトはリストになく、最初のIDの計算値(1または10001)が返されます。
グラフィカルオブジェクトをコレクションに追加するメソッドで、IDを検索するためにオブジェクトがプログラムで作成されたか手動で作成されたか(オブジェクト名で)を確認 し、値を 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; } //+------------------------------------------------------------------+
if-elseを削除してオブジェクトクリックトラッキングを追加して、マウスでオブジェクトの選択を決定することにより、イベントハンドラロジックを簡素化しましょう (まだ実装されていません)。
//+------------------------------------------------------------------+ //| Event handler | //+------------------------------------------------------------------+ void CGraphElementsCollection::OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { CGStdGraphObj *obj=NULL; ushort idx=ushort(id-CHARTEVENT_CUSTOM); if(id==CHARTEVENT_OBJECT_CHANGE || id==CHARTEVENT_OBJECT_DRAG || idx==CHARTEVENT_OBJECT_CHANGE || idx==CHARTEVENT_OBJECT_DRAG || id==CHARTEVENT_OBJECT_CLICK || idx==CHARTEVENT_OBJECT_CLICK) { //--- Get the chart ID. If lparam is zero, //--- the event is from the current chart, //--- otherwise, this is a custom event from an indicator long chart_id=(lparam==0 ? ::ChartID() : lparam); //--- Get the object, whose properties were changed or which was relocated, //--- from the collection list by its name set in sparam obj=this.GetStdGraphObject(sparam,chart_id); //--- If failed to get the object by its name, it is not on the list, //--- which means its name has been changed if(obj==NULL) { //--- Let's search the list for the object that is not on the chart obj=this.FindMissingObj(chart_id); //--- If failed to find the object here as well, exit if(obj==NULL) return; //--- Get the name of the renamed graphical object on the chart, which is not in the collection list string name_new=this.FindExtraObj(chart_id); //--- Set a new name for the collection list object, which does not correspond to any graphical object on the chart obj.SetName(name_new); } //--- Update the properties of the obtained object //--- and check their change obj.PropertiesRefresh(); obj.PropertiesCheckChanged(); } } //+------------------------------------------------------------------+
以下は、新しい標準グラフィカルオブジェクトを作成するメソッドです。
//+------------------------------------------------------------------+ //| Create a new standard graphical object | //+------------------------------------------------------------------+ bool CGraphElementsCollection::CreateNewStdGraphObject(const long chart_id, const string name, const ENUM_OBJECT type, const int subwindow, const datetime time1, const double price1, const datetime time2=0, const double price2=0, const datetime time3=0, const double price3=0, const datetime time4=0, const double price4=0, const datetime time5=0, const double price5=0) { ::ResetLastError(); switch(type) { //--- Lines case OBJ_VLINE : return ::ObjectCreate(chart_id,name,OBJ_VLINE,subwindow,time1,0); case OBJ_HLINE : return ::ObjectCreate(chart_id,name,OBJ_HLINE,subwindow,0,price1); case OBJ_TREND : return ::ObjectCreate(chart_id,name,OBJ_TREND,subwindow,time1,price1,time2,price2); case OBJ_TRENDBYANGLE : return ::ObjectCreate(chart_id,name,OBJ_TRENDBYANGLE,subwindow,time1,price1,time2,price2); case OBJ_CYCLES : return ::ObjectCreate(chart_id,name,OBJ_CYCLES,subwindow,time1,price1,time2,price2); case OBJ_ARROWED_LINE : return ::ObjectCreate(chart_id,name,OBJ_ARROWED_LINE,subwindow,time1,price1,time2,price2); //--- Channels case OBJ_CHANNEL : return ::ObjectCreate(chart_id,name,OBJ_CHANNEL,subwindow,time1,price1,time2,price2,time3,price3); case OBJ_STDDEVCHANNEL : return ::ObjectCreate(chart_id,name,OBJ_STDDEVCHANNEL,subwindow,time1,price1,time2,price2); case OBJ_REGRESSION : return ::ObjectCreate(chart_id,name,OBJ_REGRESSION,subwindow,time1,price1,time2,price2); case OBJ_PITCHFORK : return ::ObjectCreate(chart_id,name,OBJ_PITCHFORK,subwindow,time1,price1,time2,price2,time3,price3); //--- Gann case OBJ_GANNLINE : return ::ObjectCreate(chart_id,name,OBJ_GANNLINE,subwindow,time1,price1,time2,price2); case OBJ_GANNFAN : return ::ObjectCreate(chart_id,name,OBJ_GANNFAN,subwindow,time1,price1,time2,price2); case OBJ_GANNGRID : return ::ObjectCreate(chart_id,name,OBJ_GANNGRID,subwindow,time1,price1,time2,price2); //--- Fibo case OBJ_FIBO : return ::ObjectCreate(chart_id,name,OBJ_FIBO,subwindow,time1,price1,time2,price2); case OBJ_FIBOTIMES : return ::ObjectCreate(chart_id,name,OBJ_FIBOTIMES,subwindow,time1,price1,time2,price2); case OBJ_FIBOFAN : return ::ObjectCreate(chart_id,name,OBJ_FIBOFAN,subwindow,time1,price1,time2,price2); case OBJ_FIBOARC : return ::ObjectCreate(chart_id,name,OBJ_FIBOARC,subwindow,time1,price1,time2,price2); case OBJ_FIBOCHANNEL : return ::ObjectCreate(chart_id,name,OBJ_FIBOCHANNEL,subwindow,time1,price1,time2,price2,time3,price3); case OBJ_EXPANSION : return ::ObjectCreate(chart_id,name,OBJ_EXPANSION,subwindow,time1,price1,time2,price2,time3,price3); //--- Elliott case OBJ_ELLIOTWAVE5 : return ::ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE5,subwindow,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5); case OBJ_ELLIOTWAVE3 : return ::ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE3,subwindow,time1,price1,time2,price2,time3,price3); //--- Shapes case OBJ_RECTANGLE : return ::ObjectCreate(chart_id,name,OBJ_RECTANGLE,subwindow,time1,price1,time2,price2); case OBJ_TRIANGLE : return ::ObjectCreate(chart_id,name,OBJ_TRIANGLE,subwindow,time1,price1,time2,price2,time3,price3); case OBJ_ELLIPSE : return ::ObjectCreate(chart_id,name,OBJ_ELLIPSE,subwindow,time1,price1,time2,price2,time3,price3); //--- Arrows case OBJ_ARROW_THUMB_UP : return ::ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_UP,subwindow,time1,price1); case OBJ_ARROW_THUMB_DOWN : return ::ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_DOWN,subwindow,time1,price1); case OBJ_ARROW_UP : return ::ObjectCreate(chart_id,name,OBJ_ARROW_UP,subwindow,time1,price1); case OBJ_ARROW_DOWN : return ::ObjectCreate(chart_id,name,OBJ_ARROW_DOWN,subwindow,time1,price1); case OBJ_ARROW_STOP : return ::ObjectCreate(chart_id,name,OBJ_ARROW_STOP,subwindow,time1,price1); case OBJ_ARROW_CHECK : return ::ObjectCreate(chart_id,name,OBJ_ARROW_CHECK,subwindow,time1,price1); case OBJ_ARROW_LEFT_PRICE : return ::ObjectCreate(chart_id,name,OBJ_ARROW_LEFT_PRICE,subwindow,time1,price1); case OBJ_ARROW_RIGHT_PRICE : return ::ObjectCreate(chart_id,name,OBJ_ARROW_RIGHT_PRICE,subwindow,time1,price1); case OBJ_ARROW_BUY : return ::ObjectCreate(chart_id,name,OBJ_ARROW_BUY,subwindow,time1,price1); case OBJ_ARROW_SELL : return ::ObjectCreate(chart_id,name,OBJ_ARROW_SELL,subwindow,time1,price1); case OBJ_ARROW : return ::ObjectCreate(chart_id,name,OBJ_ARROW,subwindow,time1,price1); //--- Graphical objects case OBJ_TEXT : return ::ObjectCreate(chart_id,name,OBJ_TEXT,subwindow,time1,price1); case OBJ_LABEL : return ::ObjectCreate(chart_id,name,OBJ_LABEL,subwindow,0,0); case OBJ_BUTTON : return ::ObjectCreate(chart_id,name,OBJ_BUTTON,subwindow,0,0); case OBJ_CHART : return ::ObjectCreate(chart_id,name,OBJ_CHART,subwindow,0,0); case OBJ_BITMAP : return ::ObjectCreate(chart_id,name,OBJ_BITMAP,subwindow,time1,price1); case OBJ_BITMAP_LABEL : return ::ObjectCreate(chart_id,name,OBJ_BITMAP_LABEL,subwindow,0,0); case OBJ_EDIT : return ::ObjectCreate(chart_id,name,OBJ_EDIT,subwindow,0,0); case OBJ_EVENT : return ::ObjectCreate(chart_id,name,OBJ_EVENT,subwindow,time1,0); case OBJ_RECTANGLE_LABEL : return ::ObjectCreate(chart_id,name,OBJ_RECTANGLE_LABEL,subwindow,0,0); //--- default: return false; } } //+------------------------------------------------------------------+
このメソッドは、オブジェクトを特徴とするチャートのID、その名前、タイプ、チャートサブウィンドウ、および5つのピボットポイント座標を受け取ります。最初の座標(時間と価格)は必須ですが、残りの座標には事前定義されたデフォルト値があり、標準グラフィカルオブジェクトを作成できます。このメソッドでは、最後のエラーコードをリセットし、オブジェクトタイプに応じてObjectCreate()関数の実行結果を返します。オブジェクト作成エラーの場合、上記で検討したCreateNewStdGraphObjectAndGetCtrlObj()メソッドを呼び出して、エラーコードとその説明を含むエラーメッセージを操作ログに送信します。
これで、クラスに実装された改善をテストし、標準のグラフィカルオブジェクトをプログラムする準備が整いました。
テスト
すべてのグラフィカルオブジェクトを作成するのではなく、垂直線のみに制限します。Ctrlキーを押しながらチャートを左クリックすると作成されます。オブジェクトの作成、同じ名前のオブジェクトを作成しようとしたときのエラーの処理、時間座標の変更の処理、3つ以上のピボットポイントを持つオブジェクトのピボットポイント座標の変更の追跡を確認してみましょう。
テストを実行するには、前の記事のEAを\MQL5\Experts\TestDoEasy\Part89\でTestDoEasyPart89.mq5として保存します。
EAのOnChartEvent()ハンドラで、Ctrlキーを押しながらフォームオブジェクトを作成するためのコードブロックを無効にし、マウスクリック座標でCtrlキーを押しながらチャートをクリックして、指定した名前の垂直線を作成するコードブロックを追加します。
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- If working in the tester, exit if(MQLInfoInteger(MQL_TESTER)) return; //--- If the mouse is moved /* if(id==CHARTEVENT_MOUSE_MOVE) { CForm *form=NULL; datetime time=0; double price=0; int wnd=0; //--- If Ctrl is not pressed, if(!IsCtrlKeyPressed()) { //--- clear the list of created form objects, allow scrolling a chart with the mouse and show the context menu list_forms.Clear(); ChartSetInteger(ChartID(),CHART_MOUSE_SCROLL,true); ChartSetInteger(ChartID(),CHART_CONTEXT_MENU,true); return; } //--- If X and Y chart coordinates are successfully converted into time and price, if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- get the bar index the cursor is hovered over int index=iBarShift(Symbol(),PERIOD_CURRENT,time); if(index==WRONG_VALUE) return; //--- Get the bar index by index CBar *bar=engine.SeriesGetBar(Symbol(),Period(),index); if(bar==NULL) return; //--- Convert the coordinates of a chart from the time/price representation of the bar object to the X and Y coordinates int x=(int)lparam,y=(int)dparam; if(!ChartTimePriceToXY(ChartID(),0,bar.Time(),(bar.Open()+bar.Close())/2.0,x,y)) return; //--- Disable moving a chart with the mouse and showing the context menu ChartSetInteger(ChartID(),CHART_MOUSE_SCROLL,false); ChartSetInteger(ChartID(),CHART_CONTEXT_MENU,false); //--- Create the form object name and hide all objects except one having such a name string name="FormBar_"+(string)index; HideFormAllExceptOne(name); //--- If the form object with such a name does not exist yet, if(!IsPresentForm(name)) { //--- create a new form object form=bar.CreateForm(index,name,x,y,114,16); if(form==NULL) return; //--- Set activity and unmoveability flags for the form form.SetActive(true); form.SetMovable(false); //--- Set the opacity of 200 form.SetOpacity(200); //--- The form background color is set as the first color from the color array form.SetColorBackground(array_clr[0]); //--- Form outlining frame color form.SetColorFrame(C'47,70,59'); //--- Draw the shadow drawing flag form.SetShadow(true); //--- Calculate the shadow color as the chart background color converted to the monochrome one color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100); //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units //--- Otherwise, use the color specified in the settings for drawing the shadow color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3); //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes //--- Set the shadow opacity to 200, while the blur radius is equal to 4 form.DrawShadow(2,2,clr,200,3); //--- Fill the form background with a vertical gradient form.Erase(array_clr,form.Opacity()); //--- Draw an outlining rectangle at the edges of the form form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity()); //--- If failed to add the form object to the list, remove the form and exit the handler if(!list_forms.Add(form)) { delete form; return; } //--- Capture the form appearance form.Done(); } //--- If the form object exists, if(form!=NULL) { //--- draw a text with the bar type description on it and show the form. The description corresponds to the mouse cursor position form.TextOnBG(0,bar.BodyTypeDescription(),form.Width()/2,form.Height()/2-1,FRAME_ANCHOR_CENTER,C'7,28,21'); form.Show(); } //--- Re-draw the chart ChartRedraw(); } } */ if(id==CHARTEVENT_CLICK) { if(!IsCtrlKeyPressed()) return; datetime time=0; double price=0; int sw=0; if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,sw,time,price)) engine.GetGraphicObjCollection().CreateLineVertical(ChartID(),"LineVertical",0,time); } engine.GetGraphicObjCollection().OnChartEvent(id,lparam,dparam,sparam); } //+------------------------------------------------------------------+
EAをコンパイルし、チャート上で起動します。
まず、Ctrlキーを押しながらチャートをクリックして垂直線を作成し、線IDと、チャートに沿って線を移動したときにオブジェクトのプロパティがどのように変化するかを確認します。同じ線を再作成すると、操作ログにエラーメッセージが表示されます。
次に、等距離のチャネルを作成し、そのID値を確認して、3つのピボットポイントのプロパティの変更がどのように追跡されるかを確認します。
次の段階
次の記事では、グラフィカルオブジェクトをプログラミングするための機能の作業を続けます。
質問、コメント、提案はコメント欄にお願いします。
*連載のこれまでの記事:
- DoEasyライブラリのグラフィックス(第83部): 抽象標準グラフィカルオブジェクトのクラス
- DoEasyライブラリのグラフィックス(第84部): 抽象標準グラフィカルオブジェクトの子孫クラス
- DoEasyライブラリのグラフィックス(第85部): グラフィカルオブジェクトコレクション - 新規作成オブジェクトの追加
- DoEasyライブラリのグラフィックス(第86部): グラフィカルオブジェクトコレクション - プロパティ変更の管理
- DoEasyライブラリのグラフィックス(第87部): グラフィカルオブジェクトコレクション - プロパティ変更の管理
- DoEasyライブラリのグラフィックス(第88部): グラフィカルオブジェクトコレクション - 動的に変化するオブジェクトのプロパティを格納するための2次元動的配列
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/10119
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索