DoEasyライブラリのグラフィックス(第94部): 複合グラフィカルオブジェクトの移動と削除
目次
概念
前回の記事で、複合グラフィカルオブジェクトの開発を開始しました。複合グラフィカルオブジェクトを定義するために、新しいタイプのグラフィカル要素、つまり拡張された標準グラフィカルオブジェクトを導入しました。複合グラフィカルオブジェクトの作成に関与するすべてのグラフィカルオブジェクトは、そのタイプである必要があります。今のところ、特定の複合グラフィカルオブジェクトを作成するためのクラスは作成していません。代わりに、事前定義された複合グラフィカルオブジェクトの作成を可能にする機能を実装します。これは、当然、プログラムと「オンザフライ」の両方でカスタム複合グラフィカルオブジェクトを作成する可能性を排除するものではありません。
機能に関する作業をいくつかの部分に分割します。まず、複合グラフィカルオブジェクトを管理および作成するために必要なツールキットを作成します。次に、そのようなオブジェクトの事前定義されたクラスを追加します(実際、ここでのすべてはユーザーの個々のニーズに依存します。事前定義された複合グラフィカルオブジェクトのクラスはここでは例としてのみ使用されます)。次に、複合グラフィカルオブジェクトを視覚的、手動、リアルタイム、チャート上で直接作成できるようにする機能の実装を開始します。
実際、ここでは、前の記事で実装したものを微調整します。座標アンカーポイントを従属オブジェクトに設定し、座標を受け取る方法を紹介します。さらに、従属オブジェクトを接続した基本オブジェクトの移動をテストします(この段階で、単一のオブジェクトイベントを追跡するだけでなく、より複雑な形式で複合オブジェクトの座標点を移動する機能も必要であることがわかります)。 また、複合グラフィカルオブジェクトを削除するための機能を作成します。
グラフィカルオブジェクトの座標点を移動すると、マウスボタンを離したときにのみCHARTEVENT_OBJECT_DRAGイベントが発生します。したがって、このイベントのみを追跡する場合、基本グラフィカルオブジェクトを(マウスボタンを離さずに)移動すると、それに接続されているすべてのオブジェクトが変更されないままになります。ボタンを離してイベントが発生すると、バインドされたオブジェクトは基本オブジェクトのアンカーポイントに移動します。これは、押されたマウスボタンでマウスの動きを追跡する必要があることを意味します。さらに、ボタンが基本グラフィカルオブジェクト、つまりその座標(または中央)アンカーポイントで押されたことを知る必要があります。また、オブジェクトの座標点とその従属オブジェクトのアンカー点の位置を再計算できます。
基本オブジェクトの終了座標を修正し、それらを使用してそれにバインドされているすべての従属グラフィカルオブジェクトの座標を再計算するために、CHARTEVENT_OBJECT_DRAGイベントは再配置の最後でも処理する必要があります。
現在の記事では、CHARTEVENT_OBJECT_DRAGイベントの処理と、基本オブジェクト座標の新しい場所に従ったバインドされたオブジェクトの座標の再計算を実装します。基本オブジェクトが削除されると、複合グラフィカルオブジェクトも削除されます。このようなイベントが発生した場合は、それにバインドされているすべてのグラフィカルオブジェクトを削除します。今のところ、簡単化のために、マウスを使用して基本オブジェクトにバインドされているすべてのグラフィカルオブジェクトを選択する機能を無効にします。したがって、複合グラフィカルオブジェクトを削除するには、基本オブジェクトを選択して削除する必要があります。マウスを使用してバインドされたオブジェクトを選択することはできなくなります。これは、複合グラフィカルオブジェクトの破壊から保護するための最初で最も簡単な方法です。
ただし、オブジェクトリストを開いて(Ctrl + B)、バインドされたオブジェクトのプロパティを選択して選択できるようにするか、グラフィカルオブジェクトリストウィンドウからすぐに削除することができます。後で、複合グラフィカルオブジェクトの意図された破壊の処理も実装します。基本オブジェクトにバインドされているグラフィカルオブジェクトを削除する場合、複合グラフィカルオブジェクトの構築に関与しているすべてのオブジェクトを削除します。つまり、複合オブジェクトを構成するオブジェクトのいずれかが削除されたときに、複合オブジェクト全体が削除されるようにします。今後の記事では、バインドされたグラフィカルオブジェクトを基本オブジェクトから切断する機能も紹介します。
ライブラリクラスの改善
いつものように、最初に新しいライブラリメッセージを実装しましょう。
\MQL5\Include\DoEasy\Data.mqhファイルに新しいメッセージのインデックスを追加します。
//--- CGraphElementsCollection MSG_GRAPH_OBJ_FAILED_GET_ADDED_OBJ_LIST, // Failed to get the list of newly added objects MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST, // Failed to remove a graphical object from the list MSG_GRAPH_OBJ_FAILED_DELETE_OBJ_FROM_LIST, // Failed to remove a graphical object from the list MSG_GRAPH_OBJ_FAILED_DELETE_OBJ_FROM_CHART, // Failed to remove a graphical object from the chart MSG_GRAPH_OBJ_FAILED_ADD_OBJ_TO_DEL_LIST, // Failed to set a graphical object to the list of removed objects MSG_GRAPH_OBJ_FAILED_ADD_OBJ_TO_RNM_LIST, // Failed to set a graphical object to the list of renamed objects
...
//--- CLinkedPivotPoint MSG_GRAPH_OBJ_EXT_NOT_ANY_PIVOTS_X, // Not a single pivot point is set for the object along the X axis MSG_GRAPH_OBJ_EXT_NOT_ANY_PIVOTS_Y, // Not a single pivot point is set for the object along the Y axis MSG_GRAPH_OBJ_EXT_NOT_ATACHED_TO_BASE, // The object is not attached to the basic graphical object MSG_GRAPH_OBJ_EXT_FAILED_CREATE_PP_DATA_OBJ, // Failed to create a data object for the X and Y pivot points MSG_GRAPH_OBJ_EXT_NUM_BASE_PP_TO_SET_X, // Number of base object pivot points for calculating the X coordinate: MSG_GRAPH_OBJ_EXT_NUM_BASE_PP_TO_SET_Y, // Number of base object pivot points for calculating the Y coordinate: }; //+------------------------------------------------------------------+
また、新しく追加されたインデックスに対応するテキストメッセージも追加します。
//--- CGraphElementsCollection {"Не удалось получить список вновь добавленных объектов","Failed to get the list of newly added objects"}, {"Не удалось изъять графический объект из списка","Failed to detach graphic object from the list"}, {"Не удалось удалить графический объект из списка","Failed to delete graphic object from the list"}, {"Не удалось удалить графический объект с графика","Failed to delete graphic object from the chart"}, {"Не удалось поместить графический объект в список удалённых объектов","Failed to place graphic object in the list of deleted objects"}, {"Не удалось поместить графический объект в список переименованных объектов","Failed to place graphic object in the list of renamed objects"},
...
//--- CLinkedPivotPoint {"Для объекта не установлено ни одной опорной точки по оси X","The object does not have any pivot points set along the x-axis"}, {"Для объекта не установлено ни одной опорной точки по оси Y","The object does not have any pivot points set along the y-axis"}, {"Объект не привязан к базовому графическому объекту","The object is not attached to the base graphical object"}, {"Не удалось создать объект данных опорной точки X и Y.","Failed to create X and Y reference point data object"}, {"Количество опорных точек базового объекта для расчёта координаты X: ","Number of reference points of the base object to set the X coordinate: "}, {"Количество опорных точек базового объекта для расчёта координаты Y: ","Number of reference points of the base object to set the Y coordinate: "}, }; //+---------------------------------------------------------------------+
\MQL5\Include\DoEasy\Objects\Graph\Standard\に格納されている抽象標準グラフィカルオブジェクトのすべての子孫クラスファイル、つまりその 簡単なオブジェクトの説明を表示するメソッドを次のように少々改善 します。
//+------------------------------------------------------------------+ //| Display a short description of the object in the journal | //+------------------------------------------------------------------+ void CGStdArrowBuyObj::PrintShort(const bool dash=false,const bool symbol=false) { ::Print ( (dash ? " - " : "")+this.Header(symbol)," \"",CGBaseObj::Name(),"\": ID ",(string)this.GetProperty(GRAPH_OBJ_PROP_ID,0), ", ",::TimeToString(CGBaseObj::TimeCreate(),TIME_DATE|TIME_MINUTES|TIME_SECONDS) ); } //+------------------------------------------------------------------+
短いオブジェクト名を表示するすべての仮想メソッドは、親クラスのメソッドと同様の入力のセットを持っている必要があるため、これらのメソッドは未使用の入力を特徴としていました(まだしています)。そのうちの1つを実装して、メソッドから返されるテキストの前にハイフンを表示します。メソッドがtrueに等しいdashフラグを受け取った場合、短いオブジェクト名を表示する前にハイフンが設定されます(例は、以下の現在の記事に記載されています)。これは、ヘッダーを作成し、その下にオブジェクト名の列挙を表示する場合に便利です。
このような変更(考慮されたものと完全に同一)は、抽象標準グラフィカルオブジェクトのクラスから派生したすべてのクラスファイルですでに行われています。以下に添付されているファイルでご覧ください。
ここで検討するすべての基本的な変更は、抽象標準グラフィカルオブジェクト\MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqhのクラスに関係しています。
同じファイルにある依存オブジェクトピボットポイントデータのクラスで、配列は座標を持つm_property_x[][2]という名前で宣言され、X座標とY座標の1つのクラスに2つの配列を使用した実験の後でそのままにされました。後に、配列名が正しくないままであったので、このアイデアを放棄しました。そのため、名前がm_property[][2]に変更されました。
クラスのpublicセクションには、クラスに座標が格納されている軸の名前を表示するメソッド、プロパティを返すメソッド、 配列に格納されているプロパティの修飾子、依存するグラフィカルオブジェクトが接続されている座標のポイントを計算するために使用されるいくつかの基本オブジェクトピボットポイントの説明を返すメソッドがあります。このメソッドはデバッグに使用されます。
//+------------------------------------------------------------------+ //| Class of the dependent object pivot point data | //+------------------------------------------------------------------+ class CPivotPointData { private: bool m_axis_x; int m_property[][2]; public: //--- (1) Set and (2) return the flag indicating that the pivot point belongs to the X coordinate void SetAxisX(const bool axis_x) { this.m_axis_x=axis_x; } bool IsAxisX(void) const { return this.m_axis_x; } string AxisDescription(void) const { return(this.m_axis_x ? "X" : "Y");} //--- Return the number of base object pivot points for calculating the coordinate of the dependent one int GetBasePivotsNum(void) const { return ::ArrayRange(this.m_property,0); } //--- Add the new pivot point of the base object for calculating the coordinate of a dependent one bool AddNewBasePivotPoint(const string source,const int pivot_prop,const int pivot_num) { //--- Get the array size int pivot_index=this.GetBasePivotsNum(); //--- if failed to increase the array size, inform of that and return 'false' if(::ArrayResize(this.m_property,pivot_index+1)!=pivot_index+1) { CMessage::ToLog(source,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); return false; } //--- Return the result of changing the values of a newly added new array dimension return this.ChangeBasePivotPoint(source,pivot_index,pivot_prop,pivot_num); } //--- Change the specified pivot point of the base object for calculating the coordinate of a dependent one bool ChangeBasePivotPoint(const string source,const int pivot_index,const int pivot_prop,const int pivot_num) { //--- Get the array size. If it is zero, inform of that and return 'false' int n=this.GetBasePivotsNum(); if(n==0) { CMessage::ToLog(source,(this.IsAxisX() ? MSG_GRAPH_OBJ_EXT_NOT_ANY_PIVOTS_X : MSG_GRAPH_OBJ_EXT_NOT_ANY_PIVOTS_Y)); return false; } //--- If the specified index goes beyond the array range, inform of that and return 'false' if(pivot_index<0 || pivot_index>n-1) { CMessage::ToLog(source,MSG_LIB_SYS_REQUEST_OUTSIDE_ARRAY); return false; } //--- Set the values, passed to the method, in the specified array cells by index this.m_property[pivot_index][0]=pivot_prop; this.m_property[pivot_index][1]=pivot_num; return true; } //--- Return(1) a property and (2) a modifier of the property from the array int GetProperty(const string source,const int index) const { if(index<0 || index>this.GetBasePivotsNum()-1) { CMessage::ToLog(source,MSG_LIB_SYS_REQUEST_OUTSIDE_ARRAY); return WRONG_VALUE; } return this.m_property[index][0]; } int GetPropertyModifier(const string source,const int index) const { if(index<0 || index>this.GetBasePivotsNum()-1) { CMessage::ToLog(source,MSG_LIB_SYS_REQUEST_OUTSIDE_ARRAY); return WRONG_VALUE; } return this.m_property[index][1]; } //--- Return the description of the number of pivot points for setting the coordinate string GetBasePivotsNumDescription(void) const { return CMessage::Text(IsAxisX() ? MSG_GRAPH_OBJ_EXT_NUM_BASE_PP_TO_SET_X : MSG_GRAPH_OBJ_EXT_NUM_BASE_PP_TO_SET_Y)+ (string)this.GetBasePivotsNum(); } //--- Constructor/destructor CPivotPointData(void){;} ~CPivotPointData(void){;} }; //+------------------------------------------------------------------+
すべてのメソッドは非常に簡単です。それらのロジックは、コードから明確になっている必要があります。ここでそれらにこだわるつもりはありません。
複合オブジェクトのXおよびYピボットポイントのデータクラスに、検討したばかりの新しいメソッドを呼び出した結果を返すメソッドを追加します。
//+------------------------------------------------------------------+ //| Class of data on X and Y pivot points of a composite object | //+------------------------------------------------------------------+ class CPivotPointXY : public CObject { private: CPivotPointData m_pivot_point_x; // X coordinate pivot point CPivotPointData m_pivot_point_y; // Y coordinate pivot point public: //--- Return the pointer to the (1) X and (2) Y coordinate pivot point data object CPivotPointData *GetPivotPointDataX(void) { return &this.m_pivot_point_x; } CPivotPointData *GetPivotPointDataY(void) { return &this.m_pivot_point_y; } //--- Return the number of base object pivot points for calculating the (1) X and (2) Y coordinate int GetBasePivotsNumX(void) const { return this.m_pivot_point_x.GetBasePivotsNum(); } int GetBasePivotsNumY(void) const { return this.m_pivot_point_y.GetBasePivotsNum(); } //--- Add the new pivot point of the base object for calculating the X coordinate of a dependent one bool AddNewBasePivotPointX(const int pivot_prop,const int pivot_num) { return this.m_pivot_point_x.AddNewBasePivotPoint(DFUN,pivot_prop,pivot_num); } //--- Add the new pivot point of the base object for calculating the Y coordinate of a dependent one bool AddNewBasePivotPointY(const int pivot_prop,const int pivot_num) { return this.m_pivot_point_y.AddNewBasePivotPoint(DFUN,pivot_prop,pivot_num); } //--- Add new pivot points of the base object for calculating the X and Y coordinates of a dependent one bool AddNewBasePivotPointXY(const int pivot_prop_x,const int pivot_num_x, const int pivot_prop_y,const int pivot_num_y) { bool res=true; res &=this.m_pivot_point_x.AddNewBasePivotPoint(DFUN,pivot_prop_x,pivot_num_x); res &=this.m_pivot_point_y.AddNewBasePivotPoint(DFUN,pivot_prop_y,pivot_num_y); return res; } //--- Change the specified pivot point of the base object for calculating the X coordinate of a dependent one bool ChangeBasePivotPointX(const int pivot_index,const int pivot_prop,const int pivot_num) { return this.m_pivot_point_x.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop,pivot_num); } //--- Change the specified pivot point of the base object for calculating the Y coordinate of a dependent one bool ChangeBasePivotPointY(const int pivot_index,const int pivot_prop,const int pivot_num) { return this.m_pivot_point_y.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop,pivot_num); } //--- Change specified pivot points of the base object for calculating the X and Y coordinates bool ChangeBasePivotPointXY(const int pivot_index, const int pivot_prop_x,const int pivot_num_x, const int pivot_prop_y,const int pivot_num_y) { bool res=true; res &=this.m_pivot_point_x.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop_x,pivot_num_x); res &=this.m_pivot_point_y.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop_y,pivot_num_y); return res; } //--- Return (1) the property for calculating the X coordinate and (2) the X coordinate property modifier int GetPropertyX(const string source,const int index) const { return this.m_pivot_point_x.GetProperty(source,index); } int GetPropertyModifierX(const string source,const int index) const { return this.m_pivot_point_x.GetPropertyModifier(source,index); } //--- Return (1) the property for calculating the Y coordinate and (2) the Y coordinate property modifier int GetPropertyY(const string source,const int index) const { return this.m_pivot_point_y.GetProperty(source,index); } int GetPropertyModifierY(const string source,const int index) const { return this.m_pivot_point_y.GetPropertyModifier(source,index); } //--- Return the description of the number of pivot points for setting the (1) X and (2) Y coordinates string GetBasePivotsNumXDescription(void) const { return this.m_pivot_point_x.GetBasePivotsNumDescription(); } string GetBasePivotsNumYDescription(void) const { return this.m_pivot_point_y.GetBasePivotsNumDescription(); } //--- Constructor/destructor CPivotPointXY(void){ this.m_pivot_point_x.SetAxisX(true); this.m_pivot_point_y.SetAxisX(false); } ~CPivotPointXY(void){;} }; //+------------------------------------------------------------------+
これらの各メソッドは、X軸とY軸の座標にデータを格納している適切なクラスの同じ名前のメソッドを呼び出した結果を返します。
メソッドの名前は、データがメソッドによって返される正確な座標を指定するようになりました。たとえば、GetPropertyXまたはGetPropertyYです。
複合オブジェクトのピボットポイントのバインドされたデータのクラスは、主にメソッド名に関して大幅に改善されました。デバッグ中に、十分に自明ではなかったメソッドの名前が紛らわしくなったので、わかりやすくするために名前を変更しました。たとえば、X座標とY座標によって依存オブジェクトの新しいアンカーポイントを追加する CreateNewLinkedPivotPoint()メソッドの名前は、PivotPointが依存オブジェクトが接続される座標を計算するために基本オブジェクトのXまたはY座標を設定するために使用されるアンカーポイントであるため、かなり紛らわしいものでした。座標点自体は、複数のPivotPointを使用して計算できるため、新しい座標点が追加されたことを示すために、メソッドの名前をCreateNewLinkedCoord()に変更しました。
メソッドコードを短縮するために、三項演算子が追加されました。たとえば、メソッド
CPivotPointData *GetBasePivotPointDataX(const int index) const { CPivotPointXY *obj=this.GetLinkedPivotPointXY(index); if(obj==NULL) return NULL; return obj.GetPivotPointDataX(); }
は次のようになります。
CPivotPointData *GetBasePivotPointDataX(const int index_coord_point) const { CPivotPointXY *obj=this.GetLinkedCoord(index_coord_point); return(obj!=NULL ? obj.GetPivotPointDataX() : NULL); }
これは短くなりましたが完全に同じです。
また、クラスのpublicセクションは、必要な座標に対応する同じ名前のクラスメソッドを呼び出した結果を返すメソッドを備えているため、必要なデータの取得が簡単になります。
//--- Add the new pivot point of the base object for calculating the X coordinate for a specified anchor point of the dependent one bool AddNewBasePivotPointX(const int index_coord_point,const int pivot_prop,const int pivot_num) { CPivotPointData *obj=this.GetBasePivotPointDataX(index_coord_point); return(obj!=NULL ? obj.AddNewBasePivotPoint(DFUN,pivot_prop,pivot_num) : false); } //--- Add the new pivot point of the base object for calculating the Y coordinate for a specified anchor point of the dependent one bool AddNewBasePivotPointY(const int index_coord_point,const int pivot_prop,const int pivot_num) { CPivotPointData *obj=this.GetBasePivotPointDataY(index_coord_point); return(obj!=NULL ? obj.AddNewBasePivotPoint(DFUN,pivot_prop,pivot_num) : false); } //--- Add the new pivot points of the base object for calculating the X and Y coordinates for a specified anchor point of the dependent one bool AddNewBasePivotPointXY(const int index_coord_point, const int pivot_prop_x,const int pivot_num_x, const int pivot_prop_y,const int pivot_num_y) { CPivotPointData *objx=this.GetBasePivotPointDataX(index_coord_point); if(objx==NULL) return false; CPivotPointData *objy=this.GetBasePivotPointDataY(index_coord_point); if(objy==NULL) return false; bool res=true; res &=objx.AddNewBasePivotPoint(DFUN,pivot_prop_x,pivot_num_x); res &=objy.AddNewBasePivotPoint(DFUN,pivot_prop_y,pivot_num_y); return res; } //--- Change the specified pivot point of the base object for calculating the X coordinate for a specified anchor point of the dependent one bool ChangeBasePivotPointX(const int index_coord_point,const int pivot_index,const int pivot_prop,const int pivot_num) { CPivotPointData *obj=this.GetBasePivotPointDataX(index_coord_point); return(obj!=NULL ? obj.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop,pivot_num) : false); } //--- Change the specified pivot point of the base object for calculating the Y coordinate for a specified anchor point of the dependent one bool ChangeBasePivotPointY(const int index_coord_point,const int pivot_index,const int pivot_prop,const int pivot_num) { CPivotPointData *obj=this.GetBasePivotPointDataY(index_coord_point); return(obj!=NULL ? obj.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop,pivot_num) : false); } //--- Change the specified pivot points of the base object for calculating the X and Y coordinates for a specified anchor point bool ChangeBasePivotPointXY(const int index_coord_point, const int pivot_index, const int pivot_prop_x,const int pivot_num_x, const int pivot_prop_y,const int pivot_num_y) { CPivotPointData *objx=this.GetBasePivotPointDataX(index_coord_point); if(objx==NULL) return false; CPivotPointData *objy=this.GetBasePivotPointDataY(index_coord_point); if(objy==NULL) return false; bool res=true; res &=objx.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop_x,pivot_num_x); res &=objy.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop_y,pivot_num_y); return res; } //--- Return the property for calculating the X coordinate for a specified anchor point int GetPropertyX(const int index_coord_point,const int index) const { CPivotPointData *obj=this.GetBasePivotPointDataX(index_coord_point); return(obj!=NULL ? obj.GetProperty(DFUN,index) : WRONG_VALUE); } //--- Return the modifier of the X coordinate property for a specified anchor point int GetPropertyModifierX(const int index_coord_point,const int index) const { CPivotPointData *obj=this.GetBasePivotPointDataX(index_coord_point); return(obj!=NULL ? obj.GetPropertyModifier(DFUN,index) : WRONG_VALUE); } //--- Return the property for calculating the Y coordinate for a specified anchor point int GetPropertyY(const int index_coord_point,const int index) const { CPivotPointData *obj=this.GetBasePivotPointDataY(index_coord_point); return(obj!=NULL ? obj.GetProperty(DFUN,index) : WRONG_VALUE); } //--- Return the modifier of the Y coordinate property for a specified anchor point int GetPropertyModifierY(const int index_coord_point,const int index) const { CPivotPointData *obj=this.GetBasePivotPointDataY(index_coord_point); return(obj!=NULL ? obj.GetPropertyModifier(DFUN,index) : WRONG_VALUE); } //--- Return the description of the number of base object pivot points for calculating the X coordinate by index string GetBasePivotsNumXDescription(const int index_coord_point) const { CPivotPointData *obj=this.GetBasePivotPointDataX(index_coord_point); return(obj!=NULL ? obj.GetBasePivotsNumDescription() : "WRONG_VALUE"); } //--- Return the description of the number of base object pivot points for calculating the Y coordinate by index string GetBasePivotsNumYDescription(const int index_coord_point) const { CPivotPointData *obj=this.GetBasePivotPointDataY(index_coord_point); return(obj!=NULL ? obj.GetBasePivotsNumDescription() : "WRONG_VALUE"); } //--- Constructor/destructor CLinkedPivotPoint(void){;} ~CLinkedPivotPoint(void){;} }; //+------------------------------------------------------------------+
抽象標準グラフィカルオブジェクトのクラスのプロパティの説明を返すメソッドで、必要なプロパティのインデックスを追加します。
//--- Return the flag of the object supporting this property virtual bool SupportProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property) { return true; } virtual bool SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property) { return true; } virtual bool SupportProperty(ENUM_GRAPH_OBJ_PROP_STRING property) { return true; } //--- Get description of (1) integer, (2) real and (3) string properties string GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_INTEGER property,const int index=0); string GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_DOUBLE property,const int index=0); string GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_STRING property,const int index=0); //--- Return the description of the graphical object anchor point position virtual string AnchorDescription(void) const { return (string)this.GetProperty(GRAPH_OBJ_PROP_ANCHOR,0); }
これにより、メソッドがすべてを表示するのではなく、必要なグラフィカルオブジェクトプロパティのリストを表示するようにすることができます。
説明します。トレンドラインに2つのアンカーポイントがあるとします。プロパティ修飾子(上記メソッドのインデックス)は、取得するポイント(左または右)の座標を示すために、時間(X座標)または価格(Y座標)を設定するために使用されます。現時点では、メソッドはすべてのプロパティの完全なリストを表示します。ヘッダーの後に両方のアンカーポイントの値が続きます。
OnChartEvent: Time coordinate: - Pivot point 0: 2022.01.24 20:59 - Pivot point 1: 2022.01.26 22:00
...
OnChartEvent: Price coordinate: - Pivot point 0: 1.13284 - Pivot point 1: 1.11846
ただし、現時点では単一のポイントを表示することはできません。プロパティ名とその値を記述する必要があります。インデックスを使用するときに必要なアンカーポイントの名前と値を表示する簡単な方法を後に実装しますが、今のところ、インデックスのデフォルト値を設定します。これにより、複数のエラーから保護され、変更の挿入が容易になります。デフォルト値を削除し、完全な説明(現在のように)または単一のアンカーポイントの選択的な説明を表示するために発生するエラーの必要な処理を追加するだけです。
publicセクションで、接続されたオブジェクトの数を基本オブジェクトに返すメソッドを追加し、メソッド名を修正します。
//--- Return (1) the list of dependent objects, (2) dependent graphical object by index and (3) the number of dependent objects CArrayObj *GetListDependentObj(void) { return &this.m_list; } CGStdGraphObj *GetDependentObj(const int index) { return this.m_list.At(index); } int GetNumDependentObj(void) { return this.m_list.Total(); } //--- Return the name of the dependent object by index string NameDependent(const int index); //--- Add the dependent graphical object to the list bool AddDependentObj(CGStdGraphObj *obj); //--- Return the object of data on pivot points CLinkedPivotPoint*GetLinkedPivotPoint(void) { return &this.m_linked_pivots; } //--- Add a new pivot point for calculating X and Y coordinates to the current object bool AddNewLinkedCoord(const int pivot_prop_x,const int pivot_num_x,const int pivot_prop_y,const int pivot_num_y) { //--- If the current object is not bound to the base one, display the appropriate message and return 'false' if(this.BaseObjectID()==0) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_EXT_NOT_ATACHED_TO_BASE); return false; } //--- Return the result of adding a new connected pivot point from the CLinkedPivotPoint class to the current object return this.m_linked_pivots.CreateNewLinkedCoord(pivot_prop_x,pivot_num_x,pivot_prop_y,pivot_num_y); } //--- Add a new pivot point for calculating X and Y coordinates to the specified object bool AddNewLinkedCoord(CGStdGraphObj *obj,const int pivot_prop_x,const int pivot_num_x,const int pivot_prop_y,const int pivot_num_y) { //--- If the current object is not an extended one, display the appropriate message and return 'false' if(this.TypeGraphElement()!=GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_NOT_EXT_OBJ); return false; } //--- If a zero pointer to the object is passed, return 'false' if(obj==NULL) return false; //--- Return the result of adding a new connected pivot point from the CLinkedPivotPoint class to the specified object return obj.AddNewLinkedCoord(pivot_prop_x,pivot_num_x,pivot_prop_y,pivot_num_y); }
GetLinkedPivotsNum()メソッドの名前を変更し、座標を従属グラフィカルオブジェクトに設定するための新しいprivateメソッドを宣言します。
//--- Return the number of base object pivot points for calculating the (1) X and (2) Y coordinate in the current object int GetBasePivotsNumX(const int index) { return this.m_linked_pivots.GetBasePivotsNumX(index); } int GetBasePivotsNumY(const int index) { return this.m_linked_pivots.GetBasePivotsNumY(index); } //--- Return the number of base object pivot points for calculating the (1) X and (2) Y coordinate in the specified object int GetBasePivotsNumX(CGStdGraphObj *obj,const int index) const { return(obj!=NULL ? obj.GetBasePivotsNumX(index): 0); } int GetBasePivotsNumY(CGStdGraphObj *obj,const int index) const { return(obj!=NULL ? obj.GetBasePivotsNumY(index): 0); } //--- Return the number of base object pivot points for calculating the coordinates in the (1) current (2) object int GetLinkedCoordsNum(void) const { return this.m_linked_pivots.GetNumLinkedCoords(); } int GetLinkedPivotsNum(CGStdGraphObj *obj) const { return(obj!=NULL ? obj.GetLinkedCoordsNum() : 0); } private: //--- Set the X coordinate (1) from the specified property of the base object to the specified subordinate object, (2) from the base object void SetCoordXToDependentObj(CGStdGraphObj *obj,const int prop_from,const int modifier_from,const int modifier_to); void SetCoordXFromBaseObj(const int prop_from,const int modifier_from,const int modifier_to); //--- Set the Y coordinate (1) from the specified property of the base object to the specified subordinate object, (2) from the base object void SetCoordYToDependentObj(CGStdGraphObj *obj,const int prop_from,const int modifier_from,const int modifier_to); void SetCoordYFromBaseObj(const int prop_from,const int modifier_from,const int modifier_to); //--- Set the (1) integer, (2) real and (3) string property to the specified subordinate property void SetDependentINT(CGStdGraphObj *obj,const ENUM_GRAPH_OBJ_PROP_INTEGER prop,const long value,const int modifier); void SetDependentDBL(CGStdGraphObj *obj,const ENUM_GRAPH_OBJ_PROP_DOUBLE prop,const double value,const int modifier); void SetDependentSTR(CGStdGraphObj *obj,const ENUM_GRAPH_OBJ_PROP_STRING prop,const string value,const int modifier); public: //--- Default constructor CGStdGraphObj(){ this.m_type=OBJECT_DE_TYPE_GSTD_OBJ; this.m_species=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_ELEMENT_TYPE elm_type, const ENUM_GRAPH_OBJ_BELONG belong, const ENUM_GRAPH_OBJ_SPECIES species, const long chart_id, const int pivots, const string name); public: //+--------------------------------------------------------------------+ //|Methods of simplified access and setting graphical object properties| //+--------------------------------------------------------------------+
基本オブジェクトにバインドされたオブジェクトのリストに下位の標準グラフィカルオブジェクトを追加するメソッドでは、プロパティの設定を追加します。
//+------------------------------------------------------------------+ //| Add a subordinate standard graphical object to the list | //+------------------------------------------------------------------+ bool CGStdGraphObj::AddDependentObj(CGStdGraphObj *obj) { //--- If the current object is not an extended one, inform of that and return 'false' if(this.TypeGraphElement()!=GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) { CMessage::ToLog(MSG_GRAPH_OBJ_NOT_EXT_OBJ); return false; } //--- If failed to add the pointer to the passed object into the list, inform of that and return 'false' if(!this.m_list.Add(obj)) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_ADD_DEP_EXT_OBJ_TO_LIST); return false; } //--- Object added to the list - set its number in the list, //--- name and ID of the current object as the base one, //--- set the flags of object availability and selection //--- and the graphical element type - standard extended graphical object obj.SetNumber(this.m_list.Total()-1); obj.SetBaseName(this.Name()); obj.SetBaseObjectID(this.ObjectID()); obj.SetFlagSelected(false,false); obj.SetFlagSelectable(false,false); obj.SetTypeElement(GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED); return true; } //+------------------------------------------------------------------+
オブジェクト選択フラグをfalseに設定して、新しく追加されたオブジェクトが選択されないようにします。適切なフラグもfalseに設定して、オブジェクトの可用性をすぐに無効にします。次に、オブジェクトの「拡張された標準グラフィカルオブジェクト」タイプを設定します。マウスでオブジェクトを選択する機能は無効になり、拡張された標準のグラフィカルオブジェクトのリストで使用できるようになり、基本グラフィカルオブジェクトのタイプと名前でプログラムでオブジェクトを選択できるようになります。
以下は、基本オブジェクトの指定されたプロパティから指定された従属オブジェクトにX座標を設定するメソッドです。
//+--------------------------------------------------------------------+ //| Set the X coordinate from the specified property of the base object| //| to the specified subordinate object | //+--------------------------------------------------------------------+ void CGStdGraphObj::SetCoordXToDependentObj(CGStdGraphObj *obj,const int prop_from,const int modifier_from,const int modifier_to) { int prop=WRONG_VALUE; switch(obj.TypeGraphObject()) { case OBJ_LABEL : case OBJ_BUTTON : case OBJ_BITMAP_LABEL : case OBJ_EDIT : case OBJ_RECTANGLE_LABEL : case OBJ_CHART : prop=GRAPH_OBJ_PROP_XDISTANCE; break; default: prop=GRAPH_OBJ_PROP_TIME; break; } if(prop_from<GRAPH_OBJ_PROP_INTEGER_TOTAL) { this.SetDependentINT(obj,(ENUM_GRAPH_OBJ_PROP_INTEGER)prop,this.GetProperty((ENUM_GRAPH_OBJ_PROP_INTEGER)prop_from,modifier_from),modifier_to); } else if(prop_from<GRAPH_OBJ_PROP_INTEGER_TOTAL+GRAPH_OBJ_PROP_DOUBLE_TOTAL) { //--- Assigning a real property value to the integer value of the X coordinate is a bad idea unless you know what you are doing this.SetDependentINT(obj,(ENUM_GRAPH_OBJ_PROP_INTEGER)prop,(long)this.GetProperty((ENUM_GRAPH_OBJ_PROP_DOUBLE)prop_from,modifier_from),modifier_to); } else if(prop_from<GRAPH_OBJ_PROP_INTEGER_TOTAL+GRAPH_OBJ_PROP_DOUBLE_TOTAL+GRAPH_OBJ_PROP_STRING_TOTAL) { //--- Assigning a string property value to the integer value of the X coordinate is a bad idea unless you know what you are doing this.SetDependentINT(obj,(ENUM_GRAPH_OBJ_PROP_INTEGER)prop,(long)this.GetProperty((ENUM_GRAPH_OBJ_PROP_STRING)prop_from,modifier_from),modifier_to); } } //+------------------------------------------------------------------+
オブジェクトタイプに応じて必要なプロパティを選択します。これは、時間座標または画面ピクセル単位の座標である可能性があります。次に、メソッド入力で座標が渡されたプロパティを、ポインタによってメソッドに渡されたオブジェクトの座標プロパティ(プロパティ自体とその修飾子)に設定します。最後に、オブジェクト自体に設定されたプロパティの修飾子を指定します。その結果、グラフィカルオブジェクトは、パラメータがメソッドに渡されたアンカーポイントの必要な座標を特徴とします。
以下は、基本オブジェクトの指定されたプロパティから指定された従属オブジェクトに Y座標を設定するメソッドです。
//+--------------------------------------------------------------------+ //| Set the Y coordinate from the specified property of the base object| //| to the specified subordinate object | //+--------------------------------------------------------------------+ void CGStdGraphObj::SetCoordYToDependentObj(CGStdGraphObj *obj,const int prop_from,const int modifier_from,const int modifier_to) { int prop=WRONG_VALUE; switch(obj.TypeGraphObject()) { case OBJ_LABEL : case OBJ_BUTTON : case OBJ_BITMAP_LABEL : case OBJ_EDIT : case OBJ_RECTANGLE_LABEL : case OBJ_CHART : prop=GRAPH_OBJ_PROP_YDISTANCE; break; default: prop=GRAPH_OBJ_PROP_PRICE; break; } if(prop_from<GRAPH_OBJ_PROP_INTEGER_TOTAL) { if(prop==GRAPH_OBJ_PROP_YDISTANCE) this.SetDependentINT(obj,(ENUM_GRAPH_OBJ_PROP_INTEGER)prop,this.GetProperty((ENUM_GRAPH_OBJ_PROP_INTEGER)prop_from,modifier_from),modifier_to); else //--- Assigning an integer property value to the real value of the Y coordinate is allowed only if you know what you are doing this.SetDependentDBL(obj,(ENUM_GRAPH_OBJ_PROP_DOUBLE)prop,this.GetProperty((ENUM_GRAPH_OBJ_PROP_INTEGER)prop_from,modifier_from),modifier_to); } else if(prop_from<GRAPH_OBJ_PROP_INTEGER_TOTAL+GRAPH_OBJ_PROP_DOUBLE_TOTAL) { if(prop==GRAPH_OBJ_PROP_YDISTANCE) //--- Assigning a real property value to the integer value of the Y coordinate is a bad idea unless you know what you are doing this.SetDependentINT(obj,(ENUM_GRAPH_OBJ_PROP_INTEGER)prop,(long)this.GetProperty((ENUM_GRAPH_OBJ_PROP_DOUBLE)prop_from,modifier_from),modifier_to); else this.SetDependentDBL(obj,(ENUM_GRAPH_OBJ_PROP_DOUBLE)prop,this.GetProperty((ENUM_GRAPH_OBJ_PROP_DOUBLE)prop_from,modifier_from),modifier_to); } else if(prop_from<GRAPH_OBJ_PROP_INTEGER_TOTAL+GRAPH_OBJ_PROP_DOUBLE_TOTAL+GRAPH_OBJ_PROP_STRING_TOTAL) { //--- Assigning a string property value to the integer or real value of the Y coordinate is a bad idea unless you know what you are doing if(prop==GRAPH_OBJ_PROP_YDISTANCE) this.SetDependentINT(obj,(ENUM_GRAPH_OBJ_PROP_INTEGER)prop,(long)this.GetProperty((ENUM_GRAPH_OBJ_PROP_STRING)prop_from,modifier_from),modifier_to); else this.SetDependentDBL(obj,(ENUM_GRAPH_OBJ_PROP_DOUBLE)prop,(double)this.GetProperty((ENUM_GRAPH_OBJ_PROP_STRING)prop_from,modifier_from),modifier_to); } } //+------------------------------------------------------------------+
ここでは、すべてがX座標を設定するメソッドと似ています。ただし、例外があります。X座標は常に整数であり、時間またはピクセル数のいずれかですが、Y座標は整数(ピクセル数)または実際の値(価格)のいずれかです。したがって、ここでは、設定する結果のプロパティを確認する必要があります。それに応じて、値を整数プロパティまたは実数プロパティのいずれかに設定します。
以下は、メソッド設定指定された従属オブジェクトへの整数値です。
//+------------------------------------------------------------------+ //| Set the integer property | //| to the specified dependent object | //+------------------------------------------------------------------+ void CGStdGraphObj::SetDependentINT(CGStdGraphObj *obj,const ENUM_GRAPH_OBJ_PROP_INTEGER prop,const long value,const int modifier) { if(obj==NULL || obj.BaseObjectID()==0) return; switch(prop) { case GRAPH_OBJ_PROP_TIMEFRAMES : obj.SetVisibleOnTimeframes((int)value,false); break; // Object visibility on timeframes case GRAPH_OBJ_PROP_BACK : obj.SetFlagBack(value,false); break; // Background object case GRAPH_OBJ_PROP_ZORDER : obj.SetZorder(value,false); break; // Priority of a graphical object for receiving the event of clicking on a chart case GRAPH_OBJ_PROP_HIDDEN : obj.SetFlagHidden(value,false); break; // Disable displaying the name of a graphical object in the terminal object list case GRAPH_OBJ_PROP_SELECTED : obj.SetFlagSelected(value,false); break; // Object selection case GRAPH_OBJ_PROP_SELECTABLE : obj.SetFlagSelectable(value,false); break; // Object availability case GRAPH_OBJ_PROP_TIME : obj.SetTime(value,modifier); break; // Time coordinate case GRAPH_OBJ_PROP_COLOR : obj.SetColor((color)value); break; // Color case GRAPH_OBJ_PROP_STYLE : obj.SetStyle((ENUM_LINE_STYLE)value); break; // Style case GRAPH_OBJ_PROP_WIDTH : obj.SetWidth((int)value); break; // Line width case GRAPH_OBJ_PROP_FILL : obj.SetFlagFill(value); break; // Filling an object with color case GRAPH_OBJ_PROP_READONLY : obj.SetFlagReadOnly(value); break; // Ability to edit text in the Edit object case GRAPH_OBJ_PROP_LEVELS : obj.SetLevels((int)value); break; // Number of levels case GRAPH_OBJ_PROP_LEVELCOLOR : obj.SetLevelColor((color)value,modifier); break; // Level line color case GRAPH_OBJ_PROP_LEVELSTYLE : obj.SetLevelStyle((ENUM_LINE_STYLE)value,modifier); break; // Level line style case GRAPH_OBJ_PROP_LEVELWIDTH : obj.SetLevelWidth((int)value,modifier); break; // Level line width case GRAPH_OBJ_PROP_ALIGN : obj.SetAlign((ENUM_ALIGN_MODE)value); break; // Horizontal text alignment in the Edit object (OBJ_EDIT) case GRAPH_OBJ_PROP_FONTSIZE : obj.SetFontSize((int)value); break; // Font size case GRAPH_OBJ_PROP_RAY_LEFT : obj.SetFlagRayLeft(value); break; // Ray goes to the left case GRAPH_OBJ_PROP_RAY_RIGHT : obj.SetFlagRayRight(value); break; // Ray goes to the right case GRAPH_OBJ_PROP_RAY : obj.SetFlagRay(value); break; // Vertical line goes through all windows of a chart case GRAPH_OBJ_PROP_ELLIPSE : obj.SetFlagEllipse(value); break; // Display the full ellipse of the Fibonacci Arc object case GRAPH_OBJ_PROP_ARROWCODE : obj.SetArrowCode((uchar)value); break; // Arrow code for the Arrow object case GRAPH_OBJ_PROP_ANCHOR : obj.SetAnchor((int)value); break; // Position of the binding point of the graphical object case GRAPH_OBJ_PROP_XDISTANCE : obj.SetXDistance((int)value); break; // Distance from the base corner along the X axis in pixels case GRAPH_OBJ_PROP_YDISTANCE : obj.SetYDistance((int)value); break; // Distance from the base corner along the Y axis in pixels case GRAPH_OBJ_PROP_DIRECTION : obj.SetDirection((ENUM_GANN_DIRECTION)value); break; // Gann object trend case GRAPH_OBJ_PROP_DEGREE : obj.SetDegree((ENUM_ELLIOT_WAVE_DEGREE)value); break; // Elliott wave markup level case GRAPH_OBJ_PROP_DRAWLINES : obj.SetFlagDrawLines(value); break; // Display lines for Elliott wave markup case GRAPH_OBJ_PROP_STATE : obj.SetFlagState(value); break; // Button state (pressed/released) case GRAPH_OBJ_PROP_CHART_OBJ_CHART_ID : obj.SetChartObjChartID(value); break; // Chart object ID (OBJ_CHART) case GRAPH_OBJ_PROP_CHART_OBJ_PERIOD : obj.SetChartObjPeriod((ENUM_TIMEFRAMES)value); break; // Chart object period case GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE : obj.SetChartObjChartScale((int)value); break; // Time scale display flag for the Chart object case GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE : obj.SetFlagChartObjPriceScale(value); break; // Price scale display flag for the Chart object case GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE : obj.SetFlagChartObjDateScale(value); break; // Chart object scale case GRAPH_OBJ_PROP_XSIZE : obj.SetXSize((int)value); break; // Object distance along the X axis in pixels case GRAPH_OBJ_PROP_YSIZE : obj.SetYSize((int)value); break; // Object height along the Y axis in pixels case GRAPH_OBJ_PROP_XOFFSET : obj.SetXOffset((int)value); break; // X coordinate of the upper-left corner of the visibility area case GRAPH_OBJ_PROP_YOFFSET : obj.SetYOffset((int)value); break; // Y coordinate of the upper-left corner of the visibility area case GRAPH_OBJ_PROP_BGCOLOR : obj.SetBGColor((color)value); break; // Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL case GRAPH_OBJ_PROP_CORNER : obj.SetCorner((ENUM_BASE_CORNER)value); break; // Chart corner for binding a graphical object case GRAPH_OBJ_PROP_BORDER_TYPE : obj.SetBorderType((ENUM_BORDER_TYPE)value); break; // Border type for "Rectangle border" case GRAPH_OBJ_PROP_BORDER_COLOR : obj.SetBorderColor((color)value); break; // Border color for the OBJ_EDIT and OBJ_BUTTON objects case GRAPH_OBJ_PROP_BASE_ID : obj.SetBaseObjectID(value); break; // Base object ID case GRAPH_OBJ_PROP_GROUP : obj.SetGroup((int)value); break; // Graphical object group case GRAPH_OBJ_PROP_CHANGE_HISTORY : obj.SetAllowChangeMemory((bool)value); break; // Flag of storing the change history case GRAPH_OBJ_PROP_ID : // Object ID case GRAPH_OBJ_PROP_TYPE : // Graphical object type (ENUM_OBJECT) case GRAPH_OBJ_PROP_ELEMENT_TYPE : // Graphical element type (ENUM_GRAPH_ELEMENT_TYPE) case GRAPH_OBJ_PROP_SPECIES : // Graphical object species (ENUM_GRAPH_OBJ_SPECIES) case GRAPH_OBJ_PROP_BELONG : // Graphical object affiliation case GRAPH_OBJ_PROP_CHART_ID : // Chart ID case GRAPH_OBJ_PROP_WND_NUM : // Chart subwindow index case GRAPH_OBJ_PROP_NUM : // Object index in the list case GRAPH_OBJ_PROP_CREATETIME : // Object creation time default : break; } } //+------------------------------------------------------------------+
オブジェクトへの無効なポインタが渡された場合、またはこれが従属オブジェクトではない場合(基本オブジェクトにバインドされていない場合)—終了。次に、オブジェクトのメソッドに渡されるプロパティを設定するだけです。一部のオブジェクトプロパティは変更できないため、「switch」リストの最後にあり、いかなる方法でも処理されません。
以下は、指定された従属オブジェクトに不動産を設定するメソッドです。
//+------------------------------------------------------------------+ //|Set a real property to the specified subordinate object | //+------------------------------------------------------------------+ void CGStdGraphObj::SetDependentDBL(CGStdGraphObj *obj,const ENUM_GRAPH_OBJ_PROP_DOUBLE prop,const double value,const int modifier) { if(obj==NULL || obj.BaseObjectID()==0) return; switch(prop) { case GRAPH_OBJ_PROP_PRICE : obj.SetPrice(value,modifier); break; // Price coordinate case GRAPH_OBJ_PROP_LEVELVALUE : obj.SetLevelValue(value,modifier); break; // Level value case GRAPH_OBJ_PROP_SCALE : obj.SetScale(value); break; // Scale (property of Gann objects and Fibonacci Arcs objects) case GRAPH_OBJ_PROP_ANGLE : obj.SetAngle(value); break; // Angle case GRAPH_OBJ_PROP_DEVIATION : obj.SetDeviation(value); break; // Deviation of the standard deviation channel default: break; } } //+------------------------------------------------------------------+
以下は、指定された従属オブジェクトに文字列プロパティを設定するメソッドです。
//+------------------------------------------------------------------+ //| Set a string property to the specified subordinate object | //+------------------------------------------------------------------+ void CGStdGraphObj::SetDependentSTR(CGStdGraphObj *obj,const ENUM_GRAPH_OBJ_PROP_STRING prop,const string value,const int modifier) { if(obj==NULL || obj.BaseObjectID()==0) return; obj.SetProperty(prop,modifier,value); switch(prop) { case GRAPH_OBJ_PROP_TEXT : obj.SetText(value); break; // Object description (the text contained in the object) case GRAPH_OBJ_PROP_TOOLTIP : obj.SetTooltip(value); break; // Tooltip text case GRAPH_OBJ_PROP_LEVELTEXT : obj.SetLevelText(value,modifier); break; // Level description case GRAPH_OBJ_PROP_FONT : obj.SetFont(value); break; // Font case GRAPH_OBJ_PROP_BMPFILE : obj.SetBMPFile(value,modifier); break; // BMP file name for the "Bitmap Level" object case GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL : obj.SetChartObjSymbol(value); break; // Chart object symbol case GRAPH_OBJ_PROP_BASE_NAME : obj.SetBaseName(value); break; // Base object name case GRAPH_OBJ_PROP_NAME : // Object name default : break; } } //+------------------------------------------------------------------+
どちらのメソッドも、整数プロパティを設定するメソッドと同じです。
複合グラフィカルオブジェクトの移動と削除
複合グラフィカルオブジェクトを移動する場合(基本オブジェクトも移動した場合にのみ移動できます)、基本オブジェクトに接続されているすべての従属グラフィカルオブジェクトも再配置する必要があります。すでに述べたように、これは単純なイベント追跡では実行できません。イベントは、グラフィカルオブジェクトをドラッグした後にマウスボタンを離したときに発生するためです。オブジェクトは、最終的に変更されたプロパティを受け取ります。このプロパティは、オブジェクトにバインドされているオブジェクトに設定する必要があります。これにより、オブジェクトは、位置アンカー座標に対応する位置にも移動します。これは、複合グラフィカルオブジェクトを移動する最終段階になります。マウスでオブジェクトをドラッグしてまだ離していないうちに、チャート上のグラフィカルオブジェクトの位置の変化を追跡して、その座標をインタラクティブに追跡し、それに応じて基本オブジェクトにバインドされた従属オブジェクトを移動する必要があります。これは後で行います。ここでは、複合グラフィカルオブジェクトで基本オブジェクトを再配置した後、従属オブジェクトのロケーションポイントの再計算を実装します。
これを実現するために、次のコードブロックを同じ抽象グラフィカルオブジェクトクラスに追加して、オブジェクトプロパティの変更を確認します。
//+------------------------------------------------------------------+ //| Check object property changes | //+------------------------------------------------------------------+ void CGStdGraphObj::PropertiesCheckChanged(void) { CGBaseObj::ClearEventsList(); bool changed=false; int begin=0, end=GRAPH_OBJ_PROP_INTEGER_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_INTEGER prop=(ENUM_GRAPH_OBJ_PROP_INTEGER)i; if(!this.SupportProperty(prop)) continue; for(int j=0;j<Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j)) { changed=true; this.CreateAndAddNewEvent(GRAPH_OBJ_EVENT_CHANGE,this.ChartID(),prop,this.Name()); } } } begin=end; end+=GRAPH_OBJ_PROP_DOUBLE_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_DOUBLE prop=(ENUM_GRAPH_OBJ_PROP_DOUBLE)i; if(!this.SupportProperty(prop)) continue; for(int j=0;j<Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j)) { changed=true; this.CreateAndAddNewEvent(GRAPH_OBJ_EVENT_CHANGE,this.ChartID(),prop,this.Name()); } } } begin=end; end+=GRAPH_OBJ_PROP_STRING_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_STRING prop=(ENUM_GRAPH_OBJ_PROP_STRING)i; if(!this.SupportProperty(prop)) continue; for(int j=0;j<Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j) && prop!=GRAPH_OBJ_PROP_NAME) { changed=true; this.CreateAndAddNewEvent(GRAPH_OBJ_EVENT_CHANGE,this.ChartID(),prop,this.Name()); } } } if(changed) { for(int i=0;i<this.m_list_events.Total();i++) { CGBaseEvent *event=this.m_list_events.At(i); if(event==NULL) continue; ::EventChartCustom(::ChartID(),event.ID(),event.Lparam(),event.Dparam(),event.Sparam()); } if(this.AllowChangeHistory()) { int total=HistoryChangesTotal(); if(this.CreateNewChangeHistoryObj(total<1)) ::Print ( DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_SUCCESS_CREATE_SNAPSHOT)," #",(total==0 ? "0-1" : (string)total), ": ",this.HistoryChangedObjTimeChangedToString(total-1) ); } //--- If subordinate objects are attached to the base one (in a composite graphical object) if(this.m_list.Total()>0) { //--- In the loop by the number of added graphical objects, for(int i=0;i<this.m_list.Total();i++) { //--- get the next graphical object, CGStdGraphObj *dep=m_list.At(i); if(dep==NULL) continue; //--- get the data object of its pivot points, CLinkedPivotPoint *pp=dep.GetLinkedPivotPoint(); if(pp==NULL) continue; //--- get the number of coordinate points the object is attached to int num=pp.GetNumLinkedCoords(); //--- In the loop by the object coordinate points, for(int j=0;j<num;j++) { //--- get the number of coordinate points of the base object for setting the X coordinate int numx=pp.GetBasePivotsNumX(j); //--- In the loop by each coordinate point for setting the X coordinate, for(int nx=0;nx<numx;nx++) { //--- get the property for setting the X coordinate, its modifier //--- and set it in the object selected as the current one in the main loop int prop_from=pp.GetPropertyX(j,nx); int modifier_from=pp.GetPropertyModifierX(j,nx); this.SetCoordXToDependentObj(dep,prop_from,modifier_from,nx); } //--- Get the number of coordinate points of the base object for setting the Y coordinate int numy=pp.GetBasePivotsNumY(j); //--- In the loop by each coordinate point for setting the Y coordinate, for(int ny=0;ny<numy;ny++) { //--- get the property for setting the Y coordinate, its modifier //--- and set it in the object selected as the current one in the main loop int prop_from=pp.GetPropertyY(j,ny); int modifier_from=pp.GetPropertyModifierY(j,ny); this.SetCoordYToDependentObj(dep,prop_from,modifier_from,ny); } } } //--- Upon completion of the loop of handling all bound objects, redraw the chart to display all the changes ::ChartRedraw(m_chart_id); } //--- Save the current properties as the previous ones this.PropertiesCopyToPrevData(); } } //+------------------------------------------------------------------+
グラフィカルオブジェクトで変更が検出された場合は、オブジェクトに従属オブジェクトがあるかどうかを確認します。ある(リストが空でない場合)場合、各従属オブジェクトに沿ってループ内を移動し、オブジェクトで指定された位置座標に新しい値を設定し、基本オブジェクトの座標を識別します。これらの座標を使用して、値を取得し、従属オブジェクトの座標に設定します。ループが完了したら、チャートを更新して、新しいティックを待つのではなく、すべての変更をすぐに表示します。
複合グラフィカルオブジェクトは、すべての従属オブジェクトがバインドされている基本オブジェクトを削除することでチャートから削除できます。
基本オブジェクトの削除は、\MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqhのグラフィック要素のコレクションクラスで処理されます。
クラスのprivateセクションで、標準の拡張グラフィカルオブジェクトの削除を処理するメソッドを宣言します。
//--- Update the list of (1) all graphical objects, (2) on the specified chart, fill in the data on the number of new ones and set the event flag void Refresh(void); void Refresh(const long chart_id); //--- Event handler void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam); private: //--- Handle the removal of extended graphical objects void DeleteExtendedObj(CGStdGraphObj *obj); //--- Create a new graphical object, return the pointer to the chart management object
クラス本体の外側で実装しましょう。
//+------------------------------------------------------------------+ //| Handle the removal of extended graphical objects | //+------------------------------------------------------------------+ void CGraphElementsCollection::DeleteExtendedObj(CGStdGraphObj *obj) { if(obj==NULL) return; //--- Save the ID of the graphical object chart and the number of subordinate objects in its list long chart_id=obj.ChartID(); int total=obj.GetNumDependentObj(); //--- If the list of subordinate objects is not empty (this is the base object) if(total>0) { //--- In the loop, move along all dependent objects and remove them for(int n=total-1;n>WRONG_VALUE;n--) { //--- Get the next graphical object CGStdGraphObj *dep=obj.GetDependentObj(n); if(dep==NULL) continue; //--- If failed to remove it from the chart, display the appropriate message in the journal if(!::ObjectDelete(dep.ChartID(),dep.Name())) CMessage::ToLog(DFUN+dep.Name()+": ",MSG_GRAPH_OBJ_FAILED_DELETE_OBJ_FROM_CHART); } //--- Upon the loop completion, update the chart to display the changes and exit the method ::ChartRedraw(chart_id); return; } //--- If this is a subordinate object else if(obj.BaseObjectID()>0) { //--- Get the base object name and its ID string base_name=obj.BaseName(); long base_id=obj.BaseObjectID(); //--- Get the base object from the graphical object collection list CGStdGraphObj *base=GetStdGraphObject(base_name,chart_id); if(base==NULL) return; //--- get the number of dependent objects in its list int count=base.GetNumDependentObj(); //--- In the loop, move along all its dependent objects and remove them for(int n=count-1;n>WRONG_VALUE;n--) { //--- Get the next graphical object CGStdGraphObj *dep=base.GetDependentObj(n); //--- If failed to get the pointer or the object has already been removed from the chart, move on to the next one if(dep==NULL || !this.IsPresentGraphObjOnChart(dep.ChartID(),dep.Name())) continue; //--- If failed to delete the graphical object from the chart, //--- display the appropriate message in the journal and move on to the next one if(!::ObjectDelete(dep.ChartID(),dep.Name())) { CMessage::ToLog(DFUN+dep.Name()+": ",MSG_GRAPH_OBJ_FAILED_DELETE_OBJ_FROM_CHART); continue; } } //--- Remove the base object from the chart and from the list if(!::ObjectDelete(base.ChartID(),base.Name())) CMessage::ToLog(DFUN+base.Name()+": ",MSG_GRAPH_OBJ_FAILED_DELETE_OBJ_FROM_CHART); } //--- Update the chart for displaying the changes ::ChartRedraw(chart_id); } //+------------------------------------------------------------------+
メソッドロジック全体は、コードへのコメントで説明されています。つまり、基本オブジェクトが削除された場合(そのリストにはバインドされたオブジェクトが含まれます)、チャートからバインドされたすべてのオブジェクトを削除します。代わりに従属グラフィカルオブジェクトが削除された場合、バインドされたオブジェクトを認識し(複合グラフィカルオブジェクトの基本オブジェクトを検索)、バインドされた依存オブジェクトのリストに沿って移動し、それらをすべて削除する必要があります。
このメソッドは、グラフィカルオブジェクトの削除を処理するブロック内のすべてのグラフィカルオブジェクトのリストを更新するメソッドで呼び出されます。
//+------------------------------------------------------------------+ //| Update the list of all graphical objects | //+------------------------------------------------------------------+ void CGraphElementsCollection::Refresh(void) { this.RefreshForExtraObjects(); //--- Declare variables to search for charts long chart_id=0; int i=0; //--- In the loop by all open charts in the terminal (no more than 100) while(i<CHARTS_MAX) { //--- Get the chart ID chart_id=::ChartNext(chart_id); if(chart_id<0) break; //--- Get the pointer to the object for managing graphical objects //--- and update the list of graphical objects by chart ID CChartObjectsControl *obj_ctrl=this.RefreshByChartID(chart_id); //--- If failed to get the pointer, move on to the next chart if(obj_ctrl==NULL) continue; //--- If the number of objects on the chart changes if(obj_ctrl.IsEvent()) { //--- If a graphical object is added to the chart if(obj_ctrl.Delta()>0) { //--- Get the list of added graphical objects and move them to the collection list //--- (if failed to move the object to the collection, move on to the next object) if(!this.AddGraphObjToCollection(DFUN_ERR_LINE,obj_ctrl)) continue; } //--- If the graphical object has been removed else if(obj_ctrl.Delta()<0) { int index=WRONG_VALUE; //--- In the loop by the number of removed graphical objects for(int j=0;j<-obj_ctrl.Delta();j++) { // Find an extra object in the list CGStdGraphObj *obj=this.FindMissingObj(chart_id,index); if(obj!=NULL) { //--- Get the removed object parameters long lparam=obj.ChartID(); string sparam=obj.Name(); double dparam=(double)obj.TimeCreate(); //--- If this is an extended graphical object if(obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) { this.DeleteExtendedObj(obj); } //--- Move the graphical object class object to the list of removed objects //--- and send the event to the control program chart if(this.MoveGraphObjToDeletedObjList(index)) ::EventChartCustom(this.m_chart_id_main,GRAPH_OBJ_EVENT_DELETE,lparam,dparam,sparam); } } } } //--- Increase the loop index i++; } } //+------------------------------------------------------------------+
これは、複合標準グラフィカルオブジェクトの削除を処理するのに十分です。
結果をテストしてみましょう。
テスト
テストを実行するには、前の記事のEAを\MQL5\Experts\TestDoEasy\Part94\でTestDoEasyPart94.mq5として保存します。
OnChartEvent()ハンドラのチャートクリック処理のブロックで複合グラフィカルオブジェクトを形成する作成されたオブジェクトに関するジャーナルエントリの表示を削除することを除いて、EAに変更はありません。
if(id==CHARTEVENT_CLICK) { if(!IsCtrlKeyPressed()) return; //--- Get the chart click coordinates datetime time=0; double price=0; int sw=0; if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,sw,time,price)) { //--- Get the right point coordinates for a trend line datetime time2=iTime(Symbol(),PERIOD_CURRENT,1); double price2=iOpen(Symbol(),PERIOD_CURRENT,1); //--- Create the "Trend line" object string name_base="TrendLineExt"; engine.CreateLineTrend(name_base,0,true,time,price,time2,price2); //--- Get the object from the list of graphical objects by chart name and ID and pass its properties to the journal CGStdGraphObj *obj=engine.GraphGetStdGraphObjectExt(name_base,ChartID()); //--- Create the "Left price label" object string name_dep="PriceLeft"; engine.CreatePriceLabelLeft(name_dep,0,false,time,price); //--- Get the object from the list of graphical objects by chart name and ID and CGStdGraphObj *dep=engine.GraphGetStdGraphObject(name_dep,ChartID()); //--- add it to the list of graphical objects bound to the "Trend line" object obj.AddDependentObj(dep); //--- Set its pivot point by X and Y axis to the trend line left point dep.AddNewLinkedCoord(GRAPH_OBJ_PROP_TIME,0,GRAPH_OBJ_PROP_PRICE,0); //--- Create the "Right price label" object name_dep="PriceRight"; engine.CreatePriceLabelRight(name_dep,0,false,time2,price2); //--- Get the object from the list of graphical objects by chart name and ID and dep=engine.GraphGetStdGraphObject(name_dep,ChartID()); //--- add it to the list of graphical objects bound to the "Trend line" object obj.AddDependentObj(dep); //--- Set its pivot point by X and Y axis to the trend line right point dep.AddNewLinkedCoord(GRAPH_OBJ_PROP_TIME,1,GRAPH_OBJ_PROP_PRICE,1); } }
「左の価格ラベル」と「右の価格ラベル」オブジェクトを非拡張オブジェクトとして作成するという事実は、接続されているすべてのオブジェクトがAddDependentObj()メソッドで拡張グラフィカルオブジェクトのステータスを取得するようになっているため、問題にはなりません。
EAをコンパイルし、チャート上で起動します。
ご覧のとおり、従属オブジェクトは、マウスボタンを離したときにのみターゲット位置に設定されます。これは今後の記事で修正します。オブジェクトの削除は正しく機能します。すべての従属オブジェクトも削除されています。従属オブジェクトの1つを意図的に削除すると、複合グラフィカルオブジェクト全体が削除されます。
次の段階
次の記事では、複合グラフィカルオブジェクトの作業を続けます。
*連載のこれまでの記事:
DoEasyライブラリのグラフィックス(第89部): 抽象標準グラフィカルオブジェクトのプログラミング基本機能
DoEasyライブラリのグラフィックス(第90部): 標準グラフィカルオブジェクトのイベント基本機能
DoEasyライブラリのグラフィックス(第91部): 標準グラフィカルオブジェクトのイベントオブジェクト名変更履歴
DoEasyライブラリのグラフィックス(第92部): 標準グラフィカルオブジェクトのメモリクラス。オブジェクトプロパティの変更履歴
DoEasyライブラリのグラフィックス(第93部): 複合グラフィカルオブジェクトを作成するための機能の準備
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/10356
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索