English Русский 中文 Español Deutsch Português
DoEasyライブラリのグラフィックス(第74部): CCanvasクラスを使用した基本的グラフィック要素

DoEasyライブラリのグラフィックス(第74部): CCanvasクラスを使用した基本的グラフィック要素

MetaTrader 5 | 4 10月 2021, 10:39
186 0
Artyom Trishkin
Artyom Trishkin

内容


概念

前回の記事で、グラフィックを処理するための大きなライブラリセクションの作業を開始しました。つまり、CCanvas標準ライブラリクラスに基づいてすべてのライブラリグラフィカルオブジェクトのメインオブジェクトとなるフォームオブジェクトの開発を開始しました。また、いくつかのメカニズムをテストし、さらなる開発の準備をしました。ただし、注意深く分析すると、選択した概念はライブラリオブジェクトを構築する概念とは異なることがわかりました。フォームオブジェクトは基本オブジェクトよりもはるかに複雑です。

キャンバス上の基本グラフィカルオブジェクトの「要素」の概念を紹介します。この概念は、残りのグラフィカルオブジェクトを構築するために使用されます。たとえば、フォームオブジェクトは、プログラムでグラフィカルな構造を描画するための最低限のオブジェクトでもありますが、デザイン用の独立したオブジェクトにすることもできるもので、すでにオブジェクトフレーム、さまざまな形状、テキストを描画する機能があります。対照的に、要素オブジェクトは、ライブラリの「グラフィカル」階層内の後続のすべてのオブジェクトを作成するための基礎として機能します。次に例を示します。

  • 基本グラフィカルオブジェクトCObjectの子孫で、ターミナルで構築できるグラフィカルオブジェクトに固有のプロパティが含まれています。
  • キャンバス上の要素オブジェクトには、キャンバスオブジェクトに基づくオブジェクトのプロパティがあります。
  • フォームオブジェクトは、要素オブジェクトの外観をデザインするための追加のプロパティと機能を備えています。
  • ウィンドウオブジェクトは、要素オブジェクトとフォームオブジェクトに基づく複合オブジェクトです。
  • など

新しい概念に基づいて、CGBaseObjライブラリグラフィカルオブジェクトの基本クラスを作り直し、基本ライブラリオブジェクトを構築するという概念全体を完全に繰り返す新しい「グラフィック要素」オブジェクトを作成します。後で、このようなアプローチにより、必要なグラフィカルオブジェクトをすばやく検索したり並べ替えたり、動作やレンダリングを管理したりできるようになります。


ライブラリクラスの改善

\MQL5\Include\DoEasy\Data.mqhに、新しいメッセージインデックスを追加します

   MSG_LIB_SYS_FAILED_CREATE_STORAGE_FOLDER,          // Failed to create folder for storing files. Error: 
   MSG_LIB_SYS_FAILED_ADD_ACC_OBJ_TO_LIST,            // Error. Failed to add current account object to collection list
   MSG_LIB_SYS_FAILED_CREATE_CURR_ACC_OBJ,            // Error. Failed to create account object with current account data
   MSG_LIB_SYS_FAILED_OPEN_FILE_FOR_WRITE,            // Could not open file for writing
   MSG_LIB_SYS_INPUT_ERROR_NO_SYMBOL,                 // Input error: no symbol
   MSG_LIB_SYS_FAILED_CREATE_SYM_OBJ,                 // Failed to create symbol object
   MSG_LIB_SYS_FAILED_ADD_SYM_OBJ,                    // Failed to add symbol
   MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ,                 // Failed to create the graphical element object

また、新しく追加したインデックスに対応するテキストも追加します。

   {"Не удалось создать папку хранения файлов. Ошибка: ","Could not create file storage folder. Error: "},
   {"Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию","Error. Failed to add current account object to collection list"},
   {"Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта","Error. Failed to create account object with current account data"},
   {"Не удалось открыть для записи файл ","Could not open file for writing: "},
   {"Ошибка входных данных: нет символа ","Input error: no "},
   {"Не удалось создать объект-символ ","Failed to create symbol object "},
   {"Не удалось добавить символ ","Failed to add "},
   {"Не удалось создать объект-графический элемент ","Failed to create graphic element object "},

\MQL5\Include\DoEasy\Defines.mqhの新しい「グラフィック要素」オブジェクトの場合、その型をグラフィカルオブジェクト型の列挙リストに追加し、整数および文字列プロパティも追加します。

//+------------------------------------------------------------------+
//| The list of graphical element types                              |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_ELEMENT,                        // Element
   GRAPH_ELEMENT_TYPE_FORM,                           // Form
   GRAPH_ELEMENT_TYPE_WINDOW,                         // Window
  };
//+------------------------------------------------------------------+
//| Integer properties of the graphical element on the canvas        |
//+------------------------------------------------------------------+
enum ENUM_CANV_ELEMENT_PROP_INTEGER
  {
   CANV_ELEMENT_PROP_ID = 0,                          // Form ID
   CANV_ELEMENT_PROP_TYPE,                            // Graphical element type
   CANV_ELEMENT_PROP_NUM,                             // Element index in the list
   CANV_ELEMENT_PROP_CHART_ID,                        // Chart ID
   CANV_ELEMENT_PROP_WND_NUM,                         // Chart subwindow index
   CANV_ELEMENT_PROP_COORD_X,                         // Form's X coordinate on the chart
   CANV_ELEMENT_PROP_COORD_Y,                         // Form's Y coordinate on the chart
   CANV_ELEMENT_PROP_WIDTH,                           // Form width
   CANV_ELEMENT_PROP_HEIGHT,                          // Form height
   CANV_ELEMENT_PROP_RIGHT,                           // Form right border
   CANV_ELEMENT_PROP_BOTTOM,                          // Form bottom border
   CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,                  // Active area offset from the left edge of the form
   CANV_ELEMENT_PROP_ACT_SHIFT_TOP,                   // Active area offset from the top edge of the form
   CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,                 // Active area offset from the right edge of the form
   CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,                // Active area offset from the bottom edge of the form
   CANV_ELEMENT_PROP_OPACITY,                         // Form opacity
   CANV_ELEMENT_PROP_COLOR_BG,                        // Form background color
   CANV_ELEMENT_PROP_MOVABLE,                         // Form moveability flag
   CANV_ELEMENT_PROP_ACTIVE,                          // Form activity flag
   CANV_ELEMENT_PROP_COORD_ACT_X,                     // X coordinate of the form's active area
   CANV_ELEMENT_PROP_COORD_ACT_Y,                     // Y coordinate of the form's active area
   CANV_ELEMENT_PROP_ACT_RIGHT,                       // Right border of the form's active area
   CANV_ELEMENT_PROP_ACT_BOTTOM,                      // Bottom border of the form's active area
  };
#define CANV_ELEMENT_PROP_INTEGER_TOTAL (23)          // Total number of integer properties
#define CANV_ELEMENT_PROP_INTEGER_SKIP  (0)           // Number of integer properties not used in sorting
//+------------------------------------------------------------------+
//| Real properties of the graphical element on the canvas           |
//+------------------------------------------------------------------+
enum ENUM_CANV_ELEMENT_PROP_DOUBLE
  {
   CANV_ELEMENT_PROP_DUMMY = CANV_ELEMENT_PROP_INTEGER_TOTAL, // DBL stub
  };
#define CANV_ELEMENT_PROP_DOUBLE_TOTAL  (1)           // Total number of real properties
#define CANV_ELEMENT_PROP_DOUBLE_SKIP   (1)           // Number of real properties not used in sorting
//+------------------------------------------------------------------+
//| String properties of the graphical element on the canvas         |
//+------------------------------------------------------------------+
enum ENUM_CANV_ELEMENT_PROP_STRING
  {
   CANV_ELEMENT_PROP_NAME_OBJ = (CANV_ELEMENT_PROP_INTEGER_TOTAL+CANV_ELEMENT_PROP_DOUBLE_TOTAL), // Form object name
   CANV_ELEMENT_PROP_NAME_RES,                        // Graphical resource name
  };
#define CANV_ELEMENT_PROP_STRING_TOTAL  (2)           // Total number of string properties
//+------------------------------------------------------------------+

キャンバスベースのオブジェクトにはまだライブラリオブジェクトを構築する概念には必要な実数プロパティがないため、実数プロパティスタブを唯一の実数プロパティとして追加しました。

グラフィック要素オブジェクトをプロパティで並べ替えるには、列挙型を追加して可能な並べ替え基準を指定します。

//+------------------------------------------------------------------+
//| Possible sorting criteria of graphical elements on the canvas    |
//+------------------------------------------------------------------+
#define FIRST_CANV_ELEMENT_DBL_PROP  (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP)
#define FIRST_CANV_ELEMENT_STR_PROP  (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP+CANV_ELEMENT_PROP_DOUBLE_TOTAL-CANV_ELEMENT_PROP_DOUBLE_SKIP)
enum ENUM_SORT_CANV_ELEMENT_MODE
  {
//--- Sort by integer properties
   SORT_BY_CANV_ELEMENT_ID = 0,                       // Sort by form ID
   SORT_BY_CANV_ELEMENT_TYPE,                         // Sort by graphical element type
   SORT_BY_CANV_ELEMENT_NUM,                          // Sort by form index in the list
   SORT_BY_CANV_ELEMENT_CHART_ID,                     // Sort by chart ID
   SORT_BY_CANV_ELEMENT_WND_NUM,                      // Sort by chart window index
   SORT_BY_CANV_ELEMENT_COORD_X,                      // Sort by the form X coordinate on the chart
   SORT_BY_CANV_ELEMENT_COORD_Y,                      // Sort by the form Y coordinate on the chart
   SORT_BY_CANV_ELEMENT_WIDTH,                        // Sort by the form width
   SORT_BY_CANV_ELEMENT_HEIGHT,                       // Sort by the form height
   SORT_BY_CANV_ELEMENT_RIGHT,                        // Sort by the form right border
   SORT_BY_CANV_ELEMENT_BOTTOM,                       // Sort by the form bottom border
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_LEFT,               // Sort by the active area offset from the left edge of the form
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_TOP,                // Sort by the active area offset from the top edge of the form
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_RIGHT,              // Sort by the active area offset from the right edge of the form
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_BOTTOM,             // Sort by the active area offset from the bottom edge of the form
   SORT_BY_CANV_ELEMENT_OPACITY,                      // Sort by the form opacity
   SORT_BY_CANV_ELEMENT_COLOR_BG,                     // Sort by the form background color
   SORT_BY_CANV_ELEMENT_MOVABLE,                      // Sort by the form moveability flag
   SORT_BY_CANV_ELEMENT_ACTIVE,                       // Sort by the form activity flag
   SORT_BY_CANV_ELEMENT_COORD_ACT_X,                  // Sort by X coordinate of the form active area
   SORT_BY_CANV_ELEMENT_COORD_ACT_Y,                  // Sort by Y coordinate of the form active area
   SORT_BY_CANV_ELEMENT_ACT_RIGHT,                    // Sort by the right border of the form active area
   SORT_BY_CANV_ELEMENT_ACT_BOTTOM,                   // Sort by the bottom border of the form active area
//--- Sort by real properties

//--- Sort by string properties
   SORT_BY_CANV_ELEMENT_NAME_OBJ = FIRST_CANV_ELEMENT_STR_PROP,// Sort by the form object name
   SORT_BY_CANV_ELEMENT_NAME_RES,                     // Sort by the graphical resource name
  };
//+------------------------------------------------------------------+

これらの列挙はすべて最初の記事で説明されて何度も検討されたため、ここでは詳しく説明しません。

「グラフィック要素」オブジェクトを作成する前に、MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqhにあるすべてのライブラリグラフィカルオブジェクトの基本オブジェクトクラスを修正します。

オブジェクトでは、作成されたオブジェクトタイプ、チャートID、サブウィンドウのインデックスなど、グラフィカルオブジェクトのすべての一般的なプロパティを格納し、グラフィカルオブジェクト、その名前および名前の接頭辞が設定されます。ライブラリのグラフィカルオブジェクトはすべて、クラスから継承されます。

既存のクラスを修正するよりも、このクラスを完全に再作成する方が便利です。したがって、ファイルからすべてを削除し、必要なものを追加します。

//+------------------------------------------------------------------+
//|                                                     GBaseObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\DELib.mqh"
#include <Graphics\Graphic.mqh>
//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CGBaseObj : public CObject
  {
private:
   int               m_type;                             // Object type
protected:
   string            m_name_prefix;                      // Object name prefix
   string            m_name;                             // Object name
   long              m_chart_id;                         // Chart ID
   int               m_subwindow;                        // Subwindow index
   int               m_shift_y;                          // Subwindow Y coordinate shift
   
public:
//--- Return the values of class variables
   string            Name(void)                          const { return this.m_name;      }
   long              ChartID(void)                       const { return this.m_chart_id;  }
   int               SubWindow(void)                     const { return this.m_subwindow; }
//--- The virtual method returning the object type
   virtual int       Type(void)                          const { return this.m_type;      }

//--- Constructor/destructor
                     CGBaseObj();
                    ~CGBaseObj();
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CGBaseObj::CGBaseObj() : m_shift_y(0), m_type(0), m_name_prefix(::MQLInfoString(MQL_PROGRAM_NAME)+"_")
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CGBaseObj::~CGBaseObj()
  {
  }
//+------------------------------------------------------------------+

ライブラリサービス関数のファイル標準ライブラリCGraphicクラスファイルはすぐにファイルにインクルードされます。CCanvasクラスファイルはすでにCGraphicに含まれています。同時に、CGraphicクラスには、さまざまなグラフを描画するためのさまざまなメソッドがあります。将来的にもこれが必要になります。

このクラスは標準ライブラリの基本クラスから継承されます。これにより、CObjectクラスオブジェクトとしてグラフィック要素を作成し、ライブラリのグラフィカルオブジェクトのリストを、すでにすべてのオブジェクトを適切なコレクションに保存しているのと同じ方法で保存できるようになります。

m_type private変数は、上記で説明したENUM_GRAPH_ELEMENT_TYPE列挙型からのオブジェクト型を格納するためのものです。
デフォルトでは、オブジェクト型はゼロに等しく、標準ライブラリの基本クラスのType()仮想メソッドによって返されます。

   //--- method of identifying the object
   virtual int       Type(void)                                    const { return(0);      }

ここでそのメソッドも再定義し、作成されたグラフィカルオブジェクトの時間に応じてm_type変数が返されます。

以下は、Protectedクラス変数です。

  • m_name_prefix — プログラムとの関係によってグラフィカルオブジェクトを識別するためのオブジェクトの名前接頭辞を格納します。したがって、ここではライブラリに基づいてプログラムの名前を保存します。
  • m_name - グラフィカルオブジェクト名を格納します。完全なオブジェクト名は、接頭辞と名前を合計することによって作成されます。したがって、オブジェクトを作成するときは、新しく作成されたオブジェクトに一意の名前を指定するだけで済みますが、「グラフィック要素」オブジェクトクラスはそれ自体で名前に接頭辞を追加します。接頭辞を使用すると、オブジェクトを作成したプログラムでオブジェクトを識別できます。
  • m_chart_id — グラフィカルオブジェクトが作成されるチャートのIDを設定します。
  • m_subwindow — グラフィカルオブジェクトが構築されているチャートのサブウィンドウ
  • m_shift_y — チャートサブウィンドウで作成されたオブジェクトのY座標のオフセット

Publicメソッドは、適切なクラス変数の値を返すだけです。

public:
//--- Return the values of class variables
   string            Name(void)                          const { return this.m_name;      }
   long              ChartID(void)                       const { return this.m_chart_id;  }
   int               SubWindow(void)                     const { return this.m_subwindow; }
//--- The virtual method returning the object type
   virtual int       Type(void)                          const { return this.m_type;      }

クラスコンストラクタの初期化リストで、 Y座標オフセットを設定オブジェクト型(デフォルトは0)、プログラム名とアンダースコアで構成される名前の接頭辞を設定します。

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CGBaseObj::CGBaseObj() : m_shift_y(0), m_type(0), m_name_prefix(::MQLInfoString(MQL_PROGRAM_NAME)+"_")
  {
  }
//+------------------------------------------------------------------+


キャンバスに基づくすべてのライブラリグラフィカルオブジェクトの基本オブジェクト

Canvasクラスに基づく「グラフィック要素」オブジェクトクラスの開発を始めましょう。
\MQL5\Include\DoEasy\Objects\Graph\で、CGCnvElementクラスの新しいファイルGCnvElement.mqhを作成します。

クラスの継承元となるライブラリベースのグラフィカルオブジェクトのファイルをクラスファイルにインクルードします

//+------------------------------------------------------------------+
//|                                                  GCnvElement.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "GBaseObj.mqh"
//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CGCnvElement : public CGBaseObj
  {
  }

クラスのprotectedセクションで、CCanvasクラスとCPauseクラスのオブジェクトを宣言し、要素とそのアクティブ領域に対する指定された座標の位置を返す2つのメソッドを宣言します。

protected:
   CCanvas           m_canvas;                                 // CCanvas class object
   CPause            m_pause;                                  // Pause class object
//--- Return the cursor position relative to the (1) entire element and (2) the element's active area
   bool              CursorInsideElement(const int x,const int y);
   bool              CursorInsideActiveArea(const int x,const int y);

private:

クラスのprivateセクションで、オブジェクトプロパティを格納するための配列を宣言し、適切な配列に指定されたプロパティの実際のインデックスを返す2つのメソッドを記述します。

private:
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];    // Integer properties
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];   // Real properties
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];   // String properties

//--- Return the index of the array the order's (1) double and (2) string properties are located at
   int               IndexProp(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  const { return(int)property-CANV_ELEMENT_PROP_INTEGER_TOTAL;                                 }
   int               IndexProp(ENUM_CANV_ELEMENT_PROP_STRING property)  const { return(int)property-CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_DOUBLE_TOTAL;  }

public:

クラスのpublicセクションには、プロパティを配列に設定して配列からプロパティを返すためのライブラリクラスオブジェクトの標準メソッド、指定されたプロパティをサポートするオブジェクトのフラグを返すメソッド、2つのオブジェクトを比較するメソッドがあります。

public:
//--- Set object's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                      }
   void              SetProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;    }
   void              SetProperty(ENUM_CANV_ELEMENT_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;    }
//--- Return object’s (1) integer, (2) real and (3) string property from the properties array
   long              GetProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property)        const { return this.m_long_prop[property];                     }
   double            GetProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];   }
   string            GetProperty(ENUM_CANV_ELEMENT_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];   }

//--- Return the flag of the object supporting this property
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property)          { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)           { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)           { return true; }

//--- Compare CGCnvElement objects with each other by all possible properties (for sorting the lists by a specified object property)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CGCnvElement objects with each other by all properties (to search equal objects)
   bool              IsEqual(CGCnvElement* compared_obj) const;
//--- Creates the control

これらのメソッドはすべて、ライブラリオブジェクトに標準で、最初の記事で検討しました。

クラスのpublicセクションには、キャンバス上に「グラフィック要素」オブジェクトを作成するメソッド、作成されたキャンバスオブジェクトへのポインタを返すメソッド、キャンバスの更新頻度を設定するメソッド、チャート上でキャンバスをシフトするメソッド、および オブジェクトプロパティへの簡略化されたアクセスのメソッドがあります。

//--- Creates the control
   bool              Create(const long chart_id,
                            const int wnd_num,
                            const string name,
                            const int x,
                            const int y,
                            const int w,
                            const int h,
                            const color colour,
                            const uchar opacity,
                            const bool redraw=false);
                                
//--- Return the pointer to a canvas object
   CCanvas          *CanvasObj(void)                                                   { return &this.m_canvas;               }
//--- Set the canvas update frequency
   void              SetFrequency(const ulong value)                                   { this.m_pause.SetWaitingMSC(value);   }
//--- Update the coordinates (shift the canvas)
   bool              Move(const int x,const int y,const bool redraw=false);
   
//--- Constructors/Destructor
                     CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                                  const int     element_id,
                                  const int     element_num,
                                  const long    chart_id,
                                  const int     wnd_num,
                                  const string  name,
                                  const int     x,
                                  const int     y,
                                  const int     w,
                                  const int     h,
                                  const color   colour,
                                  const uchar   opacity,
                                  const bool    movable=true,
                                  const bool    activity=true,
                                  const bool    redraw=false);
                     CGCnvElement(){;}
                    ~CGCnvElement();
     
//+------------------------------------------------------------------+
//| Methods of simplified access to object properties                |
//+------------------------------------------------------------------+
//--- Set the (1) X, (2) Y coordinates, (3) element width and (4) height,
   bool              SetCoordX(const int coord_x);
   bool              SetCoordY(const int coord_y);
   bool              SetWidth(const int width);
   bool              SetHeight(const int height);
//--- Set the shift of the (1) left, (2) top, (3) right, (4) bottom edge of the active area relative to the element,
//--- (5) all shifts of the active area edges relative to the element and (6) the element opacity
   void              SetActiveAreaLeftShift(const int value)   { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,fabs(value));    }
   void              SetActiveAreaRightShift(const int value)  { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,fabs(value));   }
   void              SetActiveAreaTopShift(const int value)    { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,fabs(value));     }
   void              SetActiveAreaBottomShift(const int value) { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,fabs(value));  }
   void              SetActiveAreaShift(const int left_shift,const int bottom_shift,const int right_shift,const int top_shift);
   void              SetOpacity(const uchar value,const bool redraw=false);
   
//--- Return the shift (1) of the left, (2) right, (3) top and (4) bottom edge of the element active area
   int               ActiveAreaLeftShift(void)           const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT);    }
   int               ActiveAreaRightShift(void)          const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT);   }
   int               ActiveAreaTopShift(void)            const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP);     }
   int               ActiveAreaBottomShift(void)         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM);  }
//--- Return the coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the element active area
   int               ActiveAreaLeft(void)                const { return int(this.CoordX()+this.ActiveAreaLeftShift());              }
   int               ActiveAreaRight(void)               const { return int(this.RightEdge()-this.ActiveAreaRightShift());          }
   int               ActiveAreaTop(void)                 const { return int(this.CoordY()+this.ActiveAreaTopShift());               }
   int               ActiveAreaBottom(void)              const { return int(this.BottomEdge()-this.ActiveAreaBottomShift());        }
//--- Return (1) the opacity, coordinate (2) of the right and (3) bottom element edge
   uchar             Opacity(void)                       const { return (uchar)this.GetProperty(CANV_ELEMENT_PROP_OPACITY);         }
   int               RightEdge(void)                     const { return this.CoordX()+this.m_canvas.Width();                        }
   int               BottomEdge(void)                    const { return this.CoordY()+this.m_canvas.Height();                       }
//--- Return the (1) X, (2) Y coordinates, (3) element width and (4) height,
   int               CoordX(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_COORD_X);           }
   int               CoordY(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_COORD_Y);           }
   int               Width(void)                         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_WIDTH);             }
   int               Height(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_HEIGHT);            }
//--- Return the element (1) moveability and (2) activity flag
   bool              Movable(void)                       const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_MOVABLE);          }
   bool              Active(void)                        const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_ACTIVE);           }
//--- Return (1) the object name, (2) the graphical resource name, (3) the chart ID and (4) the chart subwindow index
   string            NameObj(void)                       const { return this.GetProperty(CANV_ELEMENT_PROP_NAME_OBJ);               }
   string            NameRes(void)                       const { return this.GetProperty(CANV_ELEMENT_PROP_NAME_RES);               }
   long              ChartID(void)                       const { return this.GetProperty(CANV_ELEMENT_PROP_CHART_ID);               }
   int               WindowNum(void)                     const { return (int)this.GetProperty(CANV_ELEMENT_PROP_WND_NUM);           }
                    
  };
//+------------------------------------------------------------------+

宣言されたメソッドの実装について詳しく考えてみましょう。

以下は、パラメトリッククラスコンストラクタです。

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           const int      element_id,
                           const int      element_num,
                           const long     chart_id,
                           const int      wnd_num,
                           const string   name,
                           const int      x,
                           const int      y,
                           const int      w,
                           const int      h,
                           const color    colour,
                           const uchar    opacity,
                           const bool     movable=true,
                           const bool     activity=true,
                           const bool     redraw=false)
                                          
  {
   this.m_name=this.m_name_prefix+name;
   this.m_chart_id=chart_id;
   this.m_subwindow=wnd_num;
   if(this.Create(chart_id,wnd_num,this.m_name,x,y,w,h,colour,opacity,redraw))
     {
      this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,this.m_canvas.ResourceName()); // Graphical resource name
      this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,CGBaseObj::ChartID());         // Chart ID
      this.SetProperty(CANV_ELEMENT_PROP_WND_NUM,CGBaseObj::SubWindow());        // Chart subwindow index
      this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,CGBaseObj::Name());            // Element object name
      this.SetProperty(CANV_ELEMENT_PROP_TYPE,element_type);                     // Graphical element type
      this.SetProperty(CANV_ELEMENT_PROP_ID,element_id);                         // Element ID
      this.SetProperty(CANV_ELEMENT_PROP_NUM,element_num);                       // Element index in the list
      this.SetProperty(CANV_ELEMENT_PROP_COORD_X,x);                             // Element's X coordinate on the chart
      this.SetProperty(CANV_ELEMENT_PROP_COORD_Y,y);                             // Element's Y coordinate on the chart
      this.SetProperty(CANV_ELEMENT_PROP_WIDTH,w);                               // Element width
      this.SetProperty(CANV_ELEMENT_PROP_HEIGHT,h);                              // Element height
      this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,0);                      // Active area offset from the left edge of the element
      this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,0);                       // Active area offset from the upper edge of the element
      this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,0);                     // Active area offset from the right edge of the element
      this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,0);                    // Active area offset from the bottom edge of the element
      this.SetProperty(CANV_ELEMENT_PROP_OPACITY,opacity);                       // Element opacity
      this.SetProperty(CANV_ELEMENT_PROP_COLOR_BG,colour);                       // Element color
      this.SetProperty(CANV_ELEMENT_PROP_MOVABLE,movable);                       // Element moveability flag
      this.SetProperty(CANV_ELEMENT_PROP_ACTIVE,activity);                       // Element activity flag
      this.SetProperty(CANV_ELEMENT_PROP_RIGHT,this.RightEdge());                // Element right border
      this.SetProperty(CANV_ELEMENT_PROP_BOTTOM,this.BottomEdge());              // Element bottom border
      this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_X,this.ActiveAreaLeft());     // X coordinate of the element active area
      this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y,this.ActiveAreaTop());      // Y coordinate of the element active area
      this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.ActiveAreaRight());      // Right border of the element active area
      this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.ActiveAreaBottom());    // Bottom border of the element active area
     }
   else
     {
      ::Print(CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.m_name);
     }
  }
//+------------------------------------------------------------------+

ここではまず、親クラスで作成されたオブジェクト名接頭辞とコンストラクタパラメータで渡された名前で構成されるオブジェクト名を作成します。一意のオブジェクト名は「Prefix_Object_Name」のようになります。
次に、パラメータで親クラス変数に渡されるチャートIDサブウィンドウインデックスを設定します。
キャンバス上にグラフィカルオブジェクトを作成するメソッドが後に呼び出されます。オブジェクトが正常に作成された場合、すべてのデータを要素オブジェクトのプロパティに書き込みます。CCanvasクラスのグラフィカルオブジェクトの作成に失敗した場合、操作ログでそのことを通知します。接頭辞付きの名前はすでに作成されており、チャートIDはそのサブウィンドウと一緒に設定されています。したがって、Create()メソッドを新たに呼び出して、CCanvasクラスオブジェクトの作成を再試行できます。デフォルトでは、オブジェクトの作成時にアクティブ領域のオフセットは両側からゼロに設定されます。つまり、オブジェクトのアクティブ領域は、作成されたグラフィック要素のサイズと一致します。作成後、アクティブエリアのサイズと位置は、以下で検討する適切な方法を使用していつでも変更できます。

クラスデストラクタで、CCanvasクラスの作成されたオブジェクトを破棄します。

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CGCnvElement::~CGCnvElement()
  {
   this.m_canvas.Destroy();
  }
//+------------------------------------------------------------------+

以下は。指定されたプロパティによってグラフィック要素オブジェクトを比較するメソッドです。

//+----------------------------------------------------------------------+
//|Compare CGCnvElement objects with each other by the specified property|
//+----------------------------------------------------------------------+
int CGCnvElement::Compare(const CObject *node,const int mode=0) const
  {
   const CGCnvElement *obj_compared=node;
//--- compare integer properties of two objects
   if(mode<CANV_ELEMENT_PROP_INTEGER_TOTAL)
     {
      long value_compared=obj_compared.GetProperty((ENUM_CANV_ELEMENT_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_CANV_ELEMENT_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare real properties of two objects
   else if(mode<CANV_ELEMENT_PROP_DOUBLE_TOTAL+CANV_ELEMENT_PROP_INTEGER_TOTAL)
     {
      double value_compared=obj_compared.GetProperty((ENUM_CANV_ELEMENT_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_CANV_ELEMENT_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare string properties of two objects
   else if(mode<ORDER_PROP_DOUBLE_TOTAL+ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_STRING_TOTAL)
     {
      string value_compared=obj_compared.GetProperty((ENUM_CANV_ELEMENT_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_CANV_ELEMENT_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+

このメソッドは、すべてのライブラリオブジェクトに標準で、以前に検討されました。つまり、メソッドは、指定されたパラメータを現在のオブジェクトの適切なパラメータと比較する必要があるオブジェクトを受け取ります。渡されたパラメータに応じて、同様のパラメータを取得し、2つのオブジェクトのパラメータを比較した結果を返します(more/less/equalの場合は1/-1/0)。

以下は、グラフィック要素オブジェクトをすべてのプロパティで比較するメソッドです。

//+------------------------------------------------------------------+
//| Compare CGCnvElement objects with each other by all properties   |
//+------------------------------------------------------------------+
bool CGCnvElement::IsEqual(CGCnvElement *compared_obj) const
  {
   int beg=0, end=CANV_ELEMENT_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CANV_ELEMENT_PROP_INTEGER prop=(ENUM_CANV_ELEMENT_PROP_INTEGER)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=CANV_ELEMENT_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CANV_ELEMENT_PROP_DOUBLE prop=(ENUM_CANV_ELEMENT_PROP_DOUBLE)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=CANV_ELEMENT_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CANV_ELEMENT_PROP_STRING prop=(ENUM_CANV_ELEMENT_PROP_STRING)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   return true;
  }
//+------------------------------------------------------------------+

このメソッドは、すべてのライブラリオブジェクトに標準で、パラメータを現在のオブジェクトのパラメータと比較する必要があるオブジェクトを受け取ります。すべてのオブジェクトプロパティによる3つのループで、2つのオブジェクトの新しいプロパティをそれぞれ比較します。等しくないプロパティがある場合、比較されたオブジェクトは等しくないので、メソッドはfalseを返します。3つのループが完了した場合、2つの比較されたオブジェクトのすべてのプロパティは等しくなり、trueが返されます。

以下は、グラフィック要素オブジェクトを作成するメソッドです。

//+------------------------------------------------------------------+
//| Create the graphical element object                              |
//+------------------------------------------------------------------+
bool CGCnvElement::Create(const long chart_id,     // Chart ID
                          const int wnd_num,       // Chart subwindow
                          const string name,       // Element name
                          const int x,             // X coordinate
                          const int y,             // Y coordinate
                          const int w,             // Width
                          const int h,             // Height
                          const color colour,      // Background color
                          const uchar opacity,     // Opacity
                          const bool redraw=false) // Flag indicating the need to redraw
                         
  {
   if(this.m_canvas.CreateBitmapLabel(chart_id,wnd_num,name,x,y,w,h,COLOR_FORMAT_ARGB_NORMALIZE))
     {
      this.m_canvas.Erase(::ColorToARGB(colour,opacity));
      this.m_canvas.Update(redraw);
      this.m_shift_y=(int)::ChartGetInteger(chart_id,CHART_WINDOW_YDISTANCE,wnd_num);
      return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

このメソッドは、構築に必要なすべてのパラメータを受け取り、CCanvasクラスのCreateBitmapLabel()メソッドの2番目の形式が呼び出されます。チャートオブジェクトにバインドされたグラフィカルリソースが正常に作成されると、グラフィック要素が色で塗りつぶされ、変更をを画面上に表示するためにUpdate()メソッドが呼び出されます。 メソッドは画面再描画フラグを受け取ります。複数のグラフィック要素で構成される複合オブジェクトを更新する場合は、すべての複合オブジェクト要素に変更を加えた後にチャートを再描画して、各要素が変更された後に複数のチャートが更新されないようにする必要があります。次に、m_shift親クラス変数がサブウィンドウのY座標のオフセットを受け取り、trueが返されます。CCanvasクラスオブジェクトが作成されていない場合はfalseを返します。

以下は、要素に対するカーソル位置を返すメソッドです。

//+------------------------------------------------------------------+
//| Return the cursor position relative to the element               |
//+------------------------------------------------------------------+
bool CGCnvElement::CursorInsideElement(const int x,const int y)
  {
   return(x>=this.CoordX() && x<=this.RightEdge() && y>=this.CoordY() && y<=this.BottomEdge());
  }
//+------------------------------------------------------------------+

このメソッドは、XおよびYカーソル座標の整数座標と、要素の寸法に対する渡された座標の位置を受け取ります。 trueは、カーソルが要素内にある場合にのみ返されます。

以下は、要素のアクティブ領域に対するカーソル位置を返すメソッドです。

//+------------------------------------------------------------------+
//| Return the cursor position relative to the element active area   |
//+------------------------------------------------------------------+
bool CGCnvElement::CursorInsideActiveArea(const int x,const int y)
  {
   return(x>=this.ActiveAreaLeft() && x<=this.ActiveAreaRight() && y>=this.ActiveAreaTop() && y<=this.ActiveAreaBottom());
  }
//+------------------------------------------------------------------+

メソッドのロジックは、前のメソッドロジックと似ています。ただし、カーソル座標の位置は、要素のアクティブ領域の境界を基準にして返されます。trueは、カーソルがアクティブ領域内にある場合にのみ返されます。

以下は、要素の座標を更新するメソッドです。

//+------------------------------------------------------------------+
//| Update the coordinate elements                                   |
//+------------------------------------------------------------------+
bool CGCnvElement::Move(const int x,const int y,const bool redraw=false)
  {
//--- Leave if the element is not movable or inactive
   if(!this.Movable())
      return false;
//--- If failed to set new values into graphical object properties, return 'false'
   if(!this.SetCoordX(x) || !this.SetCoordY(y))
      return false;
   //--- If the update flag is activated, redraw the chart.
   if(redraw)
      ::ChartRedraw(this.ChartID());
   //--- Return 'true'
   return true;
  }
//+------------------------------------------------------------------+

このメソッドは、配置する必要のあるグラフィック要素の左上隅の新しい座標と、チャートの再描画フラグを受け取ります。次に、オブジェクトの移動可能性フラグを確認し、オブジェクトが移動できない場合はそのままにします以下で検討するメソッドを使用してオブジェクトに新しい座標を設定できなかった場合falseを返します。次に、チャートの再描画フラグが設定されている場合はチャートを更新し、trueを返します

以下は、新しいX座標を設定するメソッドです。

//+------------------------------------------------------------------+
//| Set the new  X coordinate                                        |
//+------------------------------------------------------------------+
bool CGCnvElement::SetCoordX(const int coord_x)
  {
   int x=(int)::ObjectGetInteger(this.ChartID(),this.NameObj(),OBJPROP_XDISTANCE);
   if(coord_x==x)
     {
      if(coord_x==GetProperty(CANV_ELEMENT_PROP_COORD_X))
         return true;
      this.SetProperty(CANV_ELEMENT_PROP_COORD_X,coord_x);
      return true;
     }
   if(::ObjectSetInteger(this.ChartID(),this.NameObj(),OBJPROP_XDISTANCE,coord_x))
     {
      this.SetProperty(CANV_ELEMENT_PROP_COORD_X,coord_x);
      return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

メソッドは必要なX座標値を受け取ります。次に、オブジェクトからこの座標を取得します渡された座標がオブジェクトの座標と等しい場合、オブジェクトは移動しません。ただし、オブジェクトのプロパティに同じ値が設定されているかどうかを確認する必要があります。値が一致する場合はtrueを返し、そうでない場合は渡された新しい座標値をオブジェクトプロパティに設定してtrueを返します
渡された座標とオブジェクトの座標が一致しない場合は、新しい座標をオブジェクトに設定します設定が成功した場合は、オブジェクトプロパティに値を書き込み、trueを返しますそれ以外の場合は、falseを返します

以下は、新しいY座標を設定するメソッドです。

//+------------------------------------------------------------------+
//| Set the new Y coordinate                                         |
//+------------------------------------------------------------------+
bool CGCnvElement::SetCoordY(const int coord_y)
  {
   int y=(int)::ObjectGetInteger(this.ChartID(),this.NameObj(),OBJPROP_YDISTANCE);
   if(coord_y==y)
     {
      if(coord_y==GetProperty(CANV_ELEMENT_PROP_COORD_Y))
         return true;
      this.SetProperty(CANV_ELEMENT_PROP_COORD_Y,coord_y);
      return true;
     }
   if(::ObjectSetInteger(this.ChartID(),this.NameObj(),OBJPROP_YDISTANCE,coord_y))
     {
      this.SetProperty(CANV_ELEMENT_PROP_COORD_Y,coord_y);
      return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

メソッドロジックは、上記のX座標の設定に似ています。

以下は、新しいオブジェクトの幅を設定するメソッドです。

//+------------------------------------------------------------------+
//| Set the new width                                                |
//+------------------------------------------------------------------+
bool CGCnvElement::SetWidth(const int width)
  {
   return this.m_canvas.Resize(width,this.m_canvas.Height());
  }
//+------------------------------------------------------------------+

このメソッドは、オブジェクトの新しい幅と、グラフィカルリソースのサイズを変更するResize()メソッドを呼び出した結果を受け取ります。
Resize()メソッドは、オブジェクトの新しい幅現在の高さを渡します。

以下は、オブジェクトの新しい高さを設定するメソッドです。

//+------------------------------------------------------------------+
//| Set the new height                                               |
//+------------------------------------------------------------------+
bool CGCnvElement::SetHeight(const int height)
  {
   return this.m_canvas.Resize(this.m_canvas.Width(),height);
  }
//+------------------------------------------------------------------+

このメソッドは、オブジェクトの新しい高さと、グラフィカルリソースのサイズを変更するResize()メソッドを呼び出した結果を受け取ります。
Resize()メソッドは、オブジェクトの新しい幅現在の高さを渡します。

リソースのサイズを変更すると、キャンバスに描画された前の画像が上書きされることに注意してください。
したがって、これらのメソッドは後で改良されます。

以下は、要素に対するアクティブ領域のすべてのシフトを設定するメソッドです。

//+------------------------------------------------------------------+
//| Set all shifts of the active area relative to the element        |
//+------------------------------------------------------------------+
void CGCnvElement::SetActiveAreaShift(const int left_shift,const int bottom_shift,const int right_shift,const int top_shift)
  {
   this.SetActiveAreaLeftShift(left_shift);
   this.SetActiveAreaBottomShift(bottom_shift);
   this.SetActiveAreaRightShift(right_shift);
   this.SetActiveAreaTopShift(top_shift);
  }
//+------------------------------------------------------------------+

このメソッドは、「グラフィック要素」オブジェクトのエッジから必要な内側へのシフトのすべての値を受け取ります。適切なメソッドを呼び出すことにより、4つのシフトすべてが1つずつ設定されます。

以下は、要素の不透明度を設定するメソッドです。

//+------------------------------------------------------------------+
//| Set the element opacity                                          |
//+------------------------------------------------------------------+
void CGCnvElement::SetOpacity(const uchar value,const bool redraw=false)
  {
   this.m_canvas.TransparentLevelSet(value);
   this.SetProperty(CANV_ELEMENT_PROP_OPACITY,value);
   this.m_canvas.Update(redraw);
  }
//+------------------------------------------------------------------+

このメソッドは、必要なオブジェクトの不透明度の値(0 — 完全に透明、255 — 完全に不透明)とチャートの再描画フラグを受け取ります。
次に、CCanvasクラスのTransparentLevelSet()メソッドを呼び出し新しいプロパティ値をオブジェクトプロパティに書き込み渡された再描画フラグでオブジェクトを更新します

「グラフィック要素」オブジェクトの準備が整いました。次に、これらのオブジェクトを保存するリストで並べ替える機能が必要です。これを実現するには、すべてのライブラリオブジェクトを並べ替えて検索するメソッドを設定するCSelectクラスが必要です。

\MQL5\Include\DoEasy\Services\Select.mqhを開き、「グラフィック要素」オブジェクトクラスファイルのインクルードを追加し、クラス本体の最後にプロパティで「グラフィック要素」オブジェクトを並べ替えて検索するメソッドを宣言します

//+------------------------------------------------------------------+
//|                                                       Select.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "..\Objects\Orders\Order.mqh"
#include "..\Objects\Events\Event.mqh"
#include "..\Objects\Accounts\Account.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
#include "..\Objects\PendRequest\PendRequest.mqh"
#include "..\Objects\Series\SeriesDE.mqh"
#include "..\Objects\Indicators\Buffer.mqh"
#include "..\Objects\Indicators\IndicatorDE.mqh"
#include "..\Objects\Indicators\DataInd.mqh"
#include "..\Objects\Ticks\DataTick.mqh"
#include "..\Objects\Book\MarketBookOrd.mqh"
#include "..\Objects\MQLSignalBase\MQLSignal.mqh"
#include "..\Objects\Chart\ChartObj.mqh"
#include "..\Objects\Graph\GCnvElement.mqh"
//+------------------------------------------------------------------+

...

//+--------------------------------------------------------------------------+
//| The methods of working with data of the graphical elements on the canvas |
//+--------------------------------------------------------------------------+
   //--- Return the list of objects with one of (1) integer, (2) real and (3) string properties meeting a specified criterion
   static CArrayObj *ByGraphCanvElementProperty(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByGraphCanvElementProperty(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByGraphCanvElementProperty(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode);
   //--- Return the chart index with the maximum value of the (1) integer, (2) real and (3) string properties
   static int        FindGraphCanvElementMax(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_INTEGER property);
   static int        FindGraphCanvElementMax(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_DOUBLE property);
   static int        FindGraphCanvElementMax(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_STRING property);
   //--- Return the chart index with the minimum value of the (1) integer, (2) real and (3) string properties
   static int        FindGraphCanvElementMin(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_INTEGER property);
   static int        FindGraphCanvElementMin(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_DOUBLE property);
   static int        FindGraphCanvElementMin(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_STRING property);
//---
  };
//+------------------------------------------------------------------+

ファイルの最後に、新しく宣言されたメソッドの実装を追加します。

//+------------------------------------------------------------------+
//+---------------------------------------------------------------------------+
//| The methods of working with data of the graphical elements on the canvas  |
//+---------------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Return the list of objects with one integer                      |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByGraphCanvElementProperty(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   int total=list_source.Total();
   for(int i=0; i<total; i++)
     {
      CGCnvElement *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      long obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Return the list of objects with one real                         |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByGraphCanvElementProperty(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   for(int i=0; i<list_source.Total(); i++)
     {
      CGCnvElement *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      double obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Return the list of objects with one string                       |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByGraphCanvElementProperty(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   for(int i=0; i<list_source.Total(); i++)
     {
      CGCnvElement *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      string obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Return the object index in the list                              |
//| with the maximum integer property value                          |
//+------------------------------------------------------------------+
int CSelect::FindGraphCanvElementMax(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_INTEGER property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CGCnvElement *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CGCnvElement *obj=list_source.At(i);
      long obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      long obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the object index in the list                              |
//| with the maximum real property value                             |
//+------------------------------------------------------------------+
int CSelect::FindGraphCanvElementMax(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_DOUBLE property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CGCnvElement *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CGCnvElement *obj=list_source.At(i);
      double obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      double obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the object index in the list                              |
//| with the maximum string property value                           |
//+------------------------------------------------------------------+
int CSelect::FindGraphCanvElementMax(CArrayObj *list_source,ENUM_CANV_ELEMENT_PROP_STRING property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CGCnvElement *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CGCnvElement *obj=list_source.At(i);
      string obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      string obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the object index in the list                              |
//| with the minimum integer property value                          |
//+------------------------------------------------------------------+
int CSelect::FindGraphCanvElementMin(CArrayObj* list_source,ENUM_CANV_ELEMENT_PROP_INTEGER property)
  {
   int index=0;
   CGCnvElement *min_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CGCnvElement *obj=list_source.At(i);
      long obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      long obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the object index in the list                              |
//| with the minimum real property value                             |
//+------------------------------------------------------------------+
int CSelect::FindGraphCanvElementMin(CArrayObj* list_source,ENUM_CANV_ELEMENT_PROP_DOUBLE property)
  {
   int index=0;
   CGCnvElement *min_obj=NULL;
   int total=list_source.Total();
   if(total== 0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CGCnvElement *obj=list_source.At(i);
      double obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      double obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the object index in the list                              |
//| with the minimum string property value                           |
//+------------------------------------------------------------------+
int CSelect::FindGraphCanvElementMin(CArrayObj* list_source,ENUM_CANV_ELEMENT_PROP_STRING property)
  {
   int index=0;
   CGCnvElement *min_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CGCnvElement *obj=list_source.At(i);
      string obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      string obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+

メソッドについては、CSelectクラスの作成について説明した第3部で説明されています。

結果をテストしてみましょう。


検証

テストを実行するには、前の記事のEAを使用して、\MQL5\Experts\TestDoEasy\Part74\TestDoEasyPart74.mq5として保存します。

CObjectクラスとその子孫のインスタンスへのポインターの動的配列のクラス、標準ライブラリ、CSelectおよびCGCnvElementライブラリクラスファイルを含むファイルを含め、作成された「グラフィック要素」オブジェクトの数を指定し、作成されたグラフィック要素を格納するリストを宣言します

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart74.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//--- includes
#include <Arrays\ArrayObj.mqh>
#include <DoEasy\Services\Select.mqh>
#include <DoEasy\Objects\Graph\GCnvElement.mqh>
//--- defines
#define        FORMS_TOTAL (2)
//--- input parameters
sinput   bool  InpMovable  = true;  // Movable flag
//--- global variables
CArrayObj      list_elements;
//+------------------------------------------------------------------+

EAのOnInit()ハンドラで、必要なすべてのパラメータをクラスコンストラクタに渡して、新しいグラフィック要素オブジェクトを作成します。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set the permissions to send cursor movement and mouse scroll events
   ChartSetInteger(ChartID(),CHART_EVENT_MOUSE_MOVE,true);
   ChartSetInteger(ChartID(),CHART_EVENT_MOUSE_WHEEL,true);
//--- Set EA global variables

//--- Create the specified number of graphical elements on the canvas
   int total=FORMS_TOTAL;
   for(int i=0;i<total;i++)
     {
      //--- When creating an object, pass all the required parameters to it
      CGCnvElement *element=new CGCnvElement(GRAPH_ELEMENT_TYPE_ELEMENT,i,0,ChartID(),0,"Element_0"+(string)(i+1),300,40+(i*80),100,70,clrSilver,200,InpMovable,true,true);
      if(element==NULL)
         continue;
      //--- Add objects to the list
      if(!list_elements.Add(element))
        {
         delete element;
         continue;
        }
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

OnDeinit()ハンドラで、チャートからすべてのコメントを削除します

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();
   Comment("");
  }
//+------------------------------------------------------------------+

OnChartEvent()ハンドラで、オブジェクトのクリックをキャプチャし、sparamハンドラパラメータで設定されたクリックされたオブジェクトの名前に対応する名前の要素オブジェクトを取得し、不透明度レベルを5増やします。チャートのコメントに、処理されたオブジェクト名と不透明度レベルを含むメッセージを表示します。

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- If clicking on an object
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- In the new list, get the element object with the name corresponding to the sparam string parameter value of the OnChartEvent() handler
      CArrayObj *obj_list=CSelect::ByGraphCanvElementProperty(GetPointer(list_elements),CANV_ELEMENT_PROP_NAME_OBJ,sparam,EQUAL);
      if(obj_list!=NULL && obj_list.Total()>0)
        {
         //--- Get the pointer to the object in the list
         CGCnvElement *obj=obj_list.At(0);
         //--- and set the new opacity level for it
         uchar opasity=obj.Opacity();
         if((opasity+5)>255)
            opasity=0;
         else 
            opasity+=5;
         //--- Set the new opacity to the object and display the object name and opacity level in the journal
         obj.SetOpacity(opasity);
         Comment(DFUN,"Object name: ",obj.NameObj(),", opasity=",opasity);
        }
     }
  }
//+------------------------------------------------------------------+

EAをコンパイルし、銘柄チャートで起動します。「グラフィック要素」オブジェクトをクリックすると、不透明度が最大255に増加し、最大値(255)に達すると、0から255に増加し、チャートのコメントにクリックしたオブジェクトの名前と不透明度レベルが表示されます。



次の段階

次の記事では、「グラフィック要素」オブジェクトの開発を継続し、グラフィカルプリミティブとテキストを表示するためのメソッドの追加を開始します。

ライブラリの現在のバージョンのすべてのファイルは、テストおよびダウンロードできるように、MQL5のテストEAファイルと一緒に以下に添付されています。
質問や提案はコメント欄にお願いします。

目次に戻る

**連載のこれまでの記事:

DoEasyライブラリのグラフィックス(第73部): グラフィック要素のフォームオブジェクト

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/9493

添付されたファイル |
MQL5.zip (3957.08 KB)
DoEasyライブラリのグラフィックス(第75部): 基本的なグラフィック要素でプリミティブとテキストを処理するメソッド DoEasyライブラリのグラフィックス(第75部): 基本的なグラフィック要素でプリミティブとテキストを処理するメソッド
本稿では引き続き、CCanvas標準ライブラリクラスを使用したすべてのライブラリグラフィカルオブジェクトの基本的なグラフィック要素クラスを開発します。グラフィカルプリミティブを描画するメソッドとグラフィック要素オブジェクトにテキストを表示するメソッドを作成します。
取引のための組合せ論と確率論(第I部):基本 取引のための組合せ論と確率論(第I部):基本
この連載では、確率論の実用的応用を見つけて、取引と価格設定のプロセスの説明を試みます。最初の記事では、組合せ論と確率の基礎を調べ、確率論の枠組みでフラクタルを適用する方法の最初の例を分析します。
クラスター分析(第I部):インジケーターラインの傾きをマスターする クラスター分析(第I部):インジケーターラインの傾きをマスターする
クラスター分析は、人工知能の最も重要な要素の1つです。この記事では、指標の傾きのクラスター分析を適用して、市場が横ばいであるかトレンドに従っているのかを判断するためのしきい値の取得を試みます。
DoEasyライブラリのグラフィックス(第73部): グラフィック要素のフォームオブジェクト DoEasyライブラリのグラフィックス(第73部): グラフィック要素のフォームオブジェクト
本稿からは、ライブラリでのグラフィックの使用に関する新しい大きなセクションを始めます。本稿では、マウスステータスオブジェクト、すべてのグラフィック要素の基本オブジェクト、およびライブラリのグラフィック要素のフォームオブジェクトのクラスを作成します。