English Русский 中文 Español Deutsch Português
DoEasyライブラリのグラフィックス(第88部): グラフィカルオブジェクトコレクション - 動的に変化するオブジェクトのプロパティを格納するための2次元動的配列

DoEasyライブラリのグラフィックス(第88部): グラフィカルオブジェクトコレクション - 動的に変化するオブジェクトのプロパティを格納するための2次元動的配列

MetaTrader 5 | 20 12月 2021, 08:43
692 0
Artyom Trishkin
Artyom Trishkin

内容


概念

これまでのすべての記事では、単純な配列を使用してオブジェクトのプロパティデータを格納していました。整数、実数、文字列のプロパティの1次元配列の3つの配列があります。このような配列の各セルには、Defines.mqhで設定されたオブジェクトプロパティ列挙に対応する特定のオブジェクトプロパティの値が格納されます。今のところ、これはかなりうまく機能していますが、グラフィカル(およびその他の)オブジェクトの場合、単一のプロパティがこのプロパティの個々のユニットの値を返す可能性があると思います。

説明します。たとえば、グラフィカルオブジェクトにはtimeプロパティがあります。価格/時間座標によってチャート上に配置されたグラフィカルオブジェクトは、チャート上に配置するために使用されるいくつかのピボットポイントを備えています。プロパティIDとしてOBJPROP_TIMEを指定することによってObjectGetInteger()関数を使用して受け取ることができるピボットが1つしかないオブジェクト(Arrow)があるとします。このような構造は、オブジェクトの唯一のピボットポイントに対応するチャート時間を返します。

ObjectGetInteger(0, Name, OBJPROP_TIME);

しかし、TrendLineのように、オブジェクトに2つのピボットポイントがある場合はどうなるでしょうか。両方のピボットポイントの時間を取得するのにどうすればいいのでしょうか。ObjectGetInteger()関数のprop_modifier 仮パラメータは、これに役立ちます。デフォルト値は0で、これは最初のピボットポイントに対応します。2番目のポイントのデータを取得するには、その値を1に設定する必要があります(3番目のポイントを2)。

ObjectGetInteger(0, Name, OBJPROP_TIME, 0);
ObjectGetInteger(0, Name, OBJPROP_TIME, 1);
ObjectGetInteger(0, Name, OBJPROP_TIME, 2);
ObjectGetInteger(0, Name, OBJPROP_TIME, n);

これまでのところ、すべてがシンプルでわかりやすいです。オブジェクトから取得されたすべてのデータは配列(整数データはlong配列、実数データはdouble配列、文字列データはstring配列)に設定されます。つまり、2次元配列を使用して、prop_modifierで必要なピボットポイントを指定することで取得できるデータを保存できます。すべてが論理的なようです。ポイント0はゼロ次元、ポイント1は1次元、ポイント2 は2次元に格納されます。

array[TIME][0] = ObjectGetInteger(0, Name, OBJPROP_TIME, 0);
array[TIME][1] = ObjectGetInteger(0, Name, OBJPROP_TIME, 1);
array[TIME][2] = ObjectGetInteger(0, Name, OBJPROP_TIME, 2);
//...
array[TIME][n] = ObjectGetInteger(0, Name, OBJPROP_TIME, n);

ただし、落とし穴があります。まず、取得されるデータの量は、多数のオブジェクトプロパティごとに異なる場合があります。たとえば、Fibo Linesオブジェクトの場合、チャート上でオブジェクトを見つけるために使用されるピボットポイントは2つありますが、オブジェクトのレベル数は異なります。デフォルトでは9つあり、ユーザがいつでも変更できます。次に、単一のオブジェクトプロパティの一部の「マルチプロパティ」を動的に変更できます。

つまり、オブジェクトのピボットポイントを格納する配列の2番目の次元のサイズを事前に知ることはできません。さらに、これらのプロパティは動的に変更できます。これを考慮すると、次の理由により、異なるオブジェクトのプロパティを格納するために2次元配列を使用することはできません。

  • すべてのオブジェクトは、プロパティを格納するための配列を定義する基本オブジェクトの子孫です。各プロパティには、2番目の配列次元の事前定義されたサイズが必要です。これは、オブジェクトごとおよびそのプロパティごとに異なる場合があります。MQLで2次元配列を作成するときは、各オブジェクトの各プロパティの抽象クラスで不明な2次元の値を指定する必要があります。
  • この種の各「多次元」プロパティは、ユーザとプログラムの両方が動的に変更できます。ただし、MQLでは、多次元配列の非ゼロ次元を動的に変更することはできません。
しかし、解決策があります。任意の次元で動的に変更できる多次元動的配列のカスタムクラスを作成します。
このような配列を作成するには、CObjectクラスとその子孫のインスタンスへのポインタの動的配列のクラス(CArrayObj)を使用します。

新しく作成されたクラスに基づいて、通常の配列の代わりにオブジェクトプロパティを格納するためのオブジェクトクラスを作成します。これにより、適切なグラフィカルオブジェクトのプロパティを変更するときに、いつでも配列の2次元に格納されているデータの数を変更して、オブジェクトクラスのプロパティを変更できます。

現在のタスクは次のとおりです。多次元動的配列のクラスを作成し、それを使用してオブジェクトプロパティを格納するための2次元動的配列を作成し、オブジェクトプロパティを格納する3つの配列をそれに置き換えます。抽象グラフィカルオブジェクトのクラスを再配置し、オブジェクトのプロパティを動的配列に格納し、プロパティの変更を追跡するための新しい可能性をテストします。

動的多次元配列クラス

CArrayObjクラスは、実際には、CObject基本クラスから派生したオブジェクトのインスタンスへのポインタを格納する配列です。したがって、配列にはCObjectから派生した任意のオブジェクトを格納できます。つまり、配列セルには、longdoublestringのいずれかの型のデータと、別のCArrayObj配列または他の配列が含まれている可能性があります。 CArrayObj配列ではすべてがかなり明確ですが、データの場合は状況がより複雑になります。データはCObjectクラスから派生していないため、このようなデータを格納するためのクラスを作成する必要があります。さらに、配列内の各オブジェクト(および配列オブジェクト自体)は、指定された型である必要があります。これは、配列セルに正確に何(整数、実数、文字列のデータを含む単純なオブジェクト、またはデータを含むオブジェクトや別のオブジェクト配列を含む別のオブジェクト)が格納されているかを明確に理解するために必要です。これは、あるクラスオブジェクトを別のクラスオブジェクトにコピーするためのメソッドを作成するために必要です。データをセルにコピーするか(コピーされた配列の対応するセルにデータがある場合)、ソースに新しいデータ配列を作成してそ(コピーされた配列の対応するセルに配列が含まれている場合)こからデータをコピーするかを正確に知るためです。 すぐに必要なオブジェクトタイプを設定しましょう。\MQL5\Include\DoEasy\Defines.mqhで、必要な型の定数をライブラリオブジェクトタイプのリストに追加します(理解を深めるために、完全な列挙を以下に示します) 。

//+------------------------------------------------------------------+
//| Enumerations                                                     |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of library object types                                     |
//+------------------------------------------------------------------+
enum ENUM_OBJECT_DE_TYPE
  {
//--- Graphics
   OBJECT_DE_TYPE_GBASE =  COLLECTION_ID_LIST_END+1,              // "Base object of all library graphical objects" object type
   OBJECT_DE_TYPE_GELEMENT,                                       // "Graphical element" object type
   OBJECT_DE_TYPE_GFORM,                                          // Form object type
   OBJECT_DE_TYPE_GSHADOW,                                        // Shadow object type
//--- Animation
   OBJECT_DE_TYPE_GFRAME,                                         // "Single animation frame" object type
   OBJECT_DE_TYPE_GFRAME_TEXT,                                    // "Single text animation frame" object type
   OBJECT_DE_TYPE_GFRAME_QUAD,                                    // "Single rectangular animation frame" object type
   OBJECT_DE_TYPE_GFRAME_GEOMETRY,                                // "Single geometric animation frame" object type
   OBJECT_DE_TYPE_GANIMATIONS,                                    // "Animations" object type
//--- Managing graphical objects
   OBJECT_DE_TYPE_GELEMENT_CONTROL,                               // "Managing graphical objects" object type
//--- Standard graphical objects
   OBJECT_DE_TYPE_GSTD_OBJ,                                       // "Standard graphical object" object type
   OBJECT_DE_TYPE_GSTD_VLINE              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_VLINE,            // "Vertical line" object type
   OBJECT_DE_TYPE_GSTD_HLINE              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_HLINE,            // "Horizontal line" object type
   OBJECT_DE_TYPE_GSTD_TREND              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_TREND,            // "Trend line" object type
   OBJECT_DE_TYPE_GSTD_TRENDBYANGLE       =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_TRENDBYANGLE,     // "Trend line by angle" object type
   OBJECT_DE_TYPE_GSTD_CYCLES             =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_CYCLES,           // Cyclic lines" object type
   OBJECT_DE_TYPE_GSTD_ARROWED_LINE       =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROWED_LINE,     // "Arrowed line" object type
   OBJECT_DE_TYPE_GSTD_CHANNEL            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_CHANNEL,          // "Equidistant channel" object type
   OBJECT_DE_TYPE_GSTD_STDDEVCHANNEL      =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_STDDEVCHANNEL,    // "Standard deviation channel" object type
   OBJECT_DE_TYPE_GSTD_REGRESSION         =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_REGRESSION,       // "Linear regression channel" object type
   OBJECT_DE_TYPE_GSTD_PITCHFORK          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_PITCHFORK,        // "Andrews' pitchfork" object type
   OBJECT_DE_TYPE_GSTD_GANNLINE           =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_GANNLINE,         // "Gann line" object type
   OBJECT_DE_TYPE_GSTD_GANNFAN            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_GANNFAN,          // "Gann fan" object type
   OBJECT_DE_TYPE_GSTD_GANNGRID           =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_GANNGRID,         // "Gann grid" object type
   OBJECT_DE_TYPE_GSTD_FIBO               =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBO,             // "Fibo levels" object type
   OBJECT_DE_TYPE_GSTD_FIBOTIMES          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBOTIMES,        // "Fibo time zones" object type
   OBJECT_DE_TYPE_GSTD_FIBOFAN            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBOFAN,          // "Fibo fan" object type
   OBJECT_DE_TYPE_GSTD_FIBOARC            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBOARC,          // "Fibo arcs" object type
   OBJECT_DE_TYPE_GSTD_FIBOCHANNEL        =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_FIBOCHANNEL,      // "Fibo channel" object type
   OBJECT_DE_TYPE_GSTD_EXPANSION          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_EXPANSION,        // "Fibo expansion" object type
   OBJECT_DE_TYPE_GSTD_ELLIOTWAVE5        =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ELLIOTWAVE5,      // "Elliott 5 waves" object type
   OBJECT_DE_TYPE_GSTD_ELLIOTWAVE3        =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ELLIOTWAVE3,      // "Elliott 3 waves" object type
   OBJECT_DE_TYPE_GSTD_RECTANGLE          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_RECTANGLE,        // "Rectangle" object type
   OBJECT_DE_TYPE_GSTD_TRIANGLE           =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_TRIANGLE,         // "Triangle" object type
   OBJECT_DE_TYPE_GSTD_ELLIPSE            =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ELLIPSE,          // "Ellipse" object type
   OBJECT_DE_TYPE_GSTD_ARROW_THUMB_UP     =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_THUMB_UP,   // "Thumb up" object type
   OBJECT_DE_TYPE_GSTD_ARROW_THUMB_DOWN   =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_THUMB_DOWN, // "Thumb down" object type
   OBJECT_DE_TYPE_GSTD_ARROW_UP           =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_UP,         // "Arrow up" object type
   OBJECT_DE_TYPE_GSTD_ARROW_DOWN         =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_DOWN,       // "Arrow down" object type
   OBJECT_DE_TYPE_GSTD_ARROW_STOP         =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_STOP,       // "Stop sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW_CHECK        =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_CHECK,      // "Check mark" object type
   OBJECT_DE_TYPE_GSTD_ARROW_LEFT_PRICE   =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_LEFT_PRICE, // "Left price label" object type
   OBJECT_DE_TYPE_GSTD_ARROW_RIGHT_PRICE  =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_RIGHT_PRICE,// "Right price label" object type
   OBJECT_DE_TYPE_GSTD_ARROW_BUY          =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_BUY,        // "Buy sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW_SELL         =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW_SELL,       // "Sell sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_ARROW,            // "Arrow" object type
   OBJECT_DE_TYPE_GSTD_TEXT               =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_TEXT,             // "Text" object type
   OBJECT_DE_TYPE_GSTD_LABEL              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_LABEL,            // "Text label" object type
   OBJECT_DE_TYPE_GSTD_BUTTON             =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_BUTTON,           // "Button" object type
   OBJECT_DE_TYPE_GSTD_CHART              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_CHART,            // "Chart" object type
   OBJECT_DE_TYPE_GSTD_BITMAP             =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_BITMAP,           // "Bitmap" object type
   OBJECT_DE_TYPE_GSTD_BITMAP_LABEL       =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_BITMAP_LABEL,     // "Bitmap label" object type
   OBJECT_DE_TYPE_GSTD_EDIT               =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_EDIT,             // "Input field" object type
   OBJECT_DE_TYPE_GSTD_EVENT              =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_EVENT,            // "Event object which corresponds to an event in Economic Calendar" object type
   OBJECT_DE_TYPE_GSTD_RECTANGLE_LABEL    =  OBJECT_DE_TYPE_GSTD_OBJ+1+OBJ_RECTANGLE_LABEL,  // "Rectangle Label object used to create and design the custom graphical interface" object type
   
//--- Objects
   OBJECT_DE_TYPE_BASE  =  OBJECT_DE_TYPE_GSTD_RECTANGLE_LABEL+1, // Base object for all library objects
   OBJECT_DE_TYPE_BASE_EXT,                                       // Extended base object for all library objects
   
   OBJECT_DE_TYPE_ACCOUNT,                                        // "Account" object type
   OBJECT_DE_TYPE_BOOK_ORDER,                                     // "Book order" object type
   OBJECT_DE_TYPE_BOOK_BUY,                                       // "Book buy order" object type
   OBJECT_DE_TYPE_BOOK_BUY_MARKET,                                // "Book buy order at market price" object type
   OBJECT_DE_TYPE_BOOK_SELL,                                      // "Book sell order" object type
   OBJECT_DE_TYPE_BOOK_SELL_MARKET,                               // "Book sell order at market price" object type
   OBJECT_DE_TYPE_BOOK_SNAPSHOT,                                  // "Book snapshot" object type
   OBJECT_DE_TYPE_BOOK_SERIES,                                    // "Book snapshot series" object type
   
   OBJECT_DE_TYPE_CHART,                                          // "Chart" object type
   OBJECT_DE_TYPE_CHART_WND,                                      // "Chart window" object type
   OBJECT_DE_TYPE_CHART_WND_IND,                                  // "Chart window indicator" object type
   
   OBJECT_DE_TYPE_EVENT,                                          // "Event" object type
   OBJECT_DE_TYPE_EVENT_BALANCE,                                  // "Balance operation event" object type
   OBJECT_DE_TYPE_EVENT_MODIFY,                                   // "Pending order/position modification event" object type
   OBJECT_DE_TYPE_EVENT_ORDER_PLASED,                             // "Placing a pending order event" object type
   OBJECT_DE_TYPE_EVENT_ORDER_REMOVED,                            // "Pending order removal event" object type
   OBJECT_DE_TYPE_EVENT_POSITION_CLOSE,                           // "Position closure event" object type
   OBJECT_DE_TYPE_EVENT_POSITION_OPEN,                            // "Position opening event" object type
   
   OBJECT_DE_TYPE_IND_BUFFER,                                     // "Indicator buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_ARROW,                               // "Arrow rendering buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_BAR,                                 // "Bar buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_CALCULATE,                           // "Calculated buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_CANDLE,                              // "Candle buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_FILLING,                             // "Filling buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_HISTOGRAMM,                          // "Histogram buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_HISTOGRAMM2,                         // "Histogram 2 buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_LINE,                                // "Line buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_SECTION,                             // "Section buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_ZIGZAG,                              // "Zigzag buffer" object type
   OBJECT_DE_TYPE_INDICATOR,                                      // "Indicator" object type
   OBJECT_DE_TYPE_IND_DATA,                                       // "Indicator data" object type
   OBJECT_DE_TYPE_IND_DATA_LIST,                                  // "Indicator data list" object type
   
   OBJECT_DE_TYPE_IND_AC,                                         // "Accelerator Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_AD,                                         // "Accumulation/Distribution indicator" object type
   OBJECT_DE_TYPE_IND_ADX,                                        // "Average Directional Index indicator" object type
   OBJECT_DE_TYPE_IND_ADXW,                                       // "ADX indicator by Welles Wilder" object type
   OBJECT_DE_TYPE_IND_ALLIGATOR,                                  // "Alligator indicator" object type
   OBJECT_DE_TYPE_IND_AMA,                                        // "Adaptive Moving Average indicator" object type
   OBJECT_DE_TYPE_IND_AO,                                         // "Awesome Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_ATR,                                        // "Average True Range" object type
   OBJECT_DE_TYPE_IND_BANDS,                                      // "Bollinger Bands® indicator" object type
   OBJECT_DE_TYPE_IND_BEARS,                                      // "Bears Power indicator" object type
   OBJECT_DE_TYPE_IND_BULLS,                                      // "Bulls Power indicator" object type
   OBJECT_DE_TYPE_IND_BWMFI,                                      // "Market Facilitation Index indicator" object type
   OBJECT_DE_TYPE_IND_CCI,                                        // "Commodity Channel Index indicator" object type
   OBJECT_DE_TYPE_IND_CHAIKIN,                                    // "Chaikin Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_CUSTOM,                                     // "Custom indicator" object type
   OBJECT_DE_TYPE_IND_DEMA,                                       // "Double Exponential Moving Average indicator" object type
   OBJECT_DE_TYPE_IND_DEMARKER,                                   // "DeMarker indicator" object type
   OBJECT_DE_TYPE_IND_ENVELOPES,                                  // "Envelopes indicator" object type
   OBJECT_DE_TYPE_IND_FORCE,                                      // "Force Index indicator" object type
   OBJECT_DE_TYPE_IND_FRACTALS,                                   // "Fractals indicator" object type
   OBJECT_DE_TYPE_IND_FRAMA,                                      // "Fractal Adaptive Moving Average indicator" object type
   OBJECT_DE_TYPE_IND_GATOR,                                      // "Gator Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_ICHIMOKU,                                   // "Ichimoku Kinko Hyo indicator" object type
   OBJECT_DE_TYPE_IND_MA,                                         // "Moving Average indicator" object type
   OBJECT_DE_TYPE_IND_MACD,                                       // "Moving Average Convergence/Divergence indicator" object type
   OBJECT_DE_TYPE_IND_MFI,                                        // "Money Flow Index indicator" object type
   OBJECT_DE_TYPE_IND_MOMENTUM,                                   // "Momentum indicator" object type
   OBJECT_DE_TYPE_IND_OBV,                                        // "On Balance Volume indicator" object type
   OBJECT_DE_TYPE_IND_OSMA,                                       // "Moving Average of Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_RSI,                                        // "Relative Strength Index indicator" object type
   OBJECT_DE_TYPE_IND_RVI,                                        // "Relative Vigor Index indicator" object type
   OBJECT_DE_TYPE_IND_SAR,                                        // "Parabolic SAR indicator" object type
   OBJECT_DE_TYPE_IND_STDEV,                                      // "Standard Deviation indicator" object type
   OBJECT_DE_TYPE_IND_STOCH,                                      // "Stochastic Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_TEMA,                                       // "Triple Exponential Moving Average indicator" object
   OBJECT_DE_TYPE_IND_TRIX,                                       // "Triple Exponential Moving Averages Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_VIDYA,                                      // "Variable Index Dynamic Average indicator" object type
   OBJECT_DE_TYPE_IND_VOLUMES,                                    // "Volumes indicator" object type
   OBJECT_DE_TYPE_IND_WPR,                                        // "Williams' Percent Range indicator" object type
   
   OBJECT_DE_TYPE_MQL5_SIGNAL,                                    // "mql5 signal" object type
   
   OBJECT_DE_TYPE_ORDER_DEAL_POSITION,                            // "Order/Deal/Position" object type
   OBJECT_DE_TYPE_HISTORY_BALANCE,                                // "Historical balance operation" object type
   OBJECT_DE_TYPE_HISTORY_DEAL,                                   // "Historical deal" object type
   OBJECT_DE_TYPE_HISTORY_ORDER_MARKET,                           // "Historical market order" object type
   OBJECT_DE_TYPE_HISTORY_ORDER_PENDING,                          // "Historical removed pending order" object type
   OBJECT_DE_TYPE_MARKET_ORDER,                                   // "Market order" object type
   OBJECT_DE_TYPE_MARKET_PENDING,                                 // "Pending order" object type
   OBJECT_DE_TYPE_MARKET_POSITION,                                // "Market position" object type
   
   OBJECT_DE_TYPE_PENDING_REQUEST,                                // "Pending trading request" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_POSITION_OPEN,                  // "Pending request to open a position" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_POSITION_CLOSE,                 // "Pending request to close a position" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_POSITION_SLTP,                  // "Pending request to modify position stop orders" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_ORDER_PLACE,                    // "Pending request to place a pending order" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_ORDER_REMOVE,                   // "Pending request to delete a pending order" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_ORDER_MODIFY,                   // "Pending request to modify pending order parameters" object type
   
   OBJECT_DE_TYPE_SERIES_BAR,                                     // "Bar" object type
   OBJECT_DE_TYPE_SERIES_PERIOD,                                  // "Period timeseries" object type
   OBJECT_DE_TYPE_SERIES_SYMBOL,                                  // "Symbol timeseries" object type
   
   OBJECT_DE_TYPE_SYMBOL,                                         // "Symbol" object type
   OBJECT_DE_TYPE_SYMBOL_BONDS,                                   // "Bond symbol" object type
   OBJECT_DE_TYPE_SYMBOL_CFD,                                     // "CFD (contract for difference) symbol" object type
   OBJECT_DE_TYPE_SYMBOL_COLLATERAL,                              // "Non-tradable asset symbol" object type" object type
   OBJECT_DE_TYPE_SYMBOL_COMMODITY,                               // "Commodity symbol" object type
   OBJECT_DE_TYPE_SYMBOL_COMMON,                                  // "Common group symbol" object type
   OBJECT_DE_TYPE_SYMBOL_CRYPTO,                                  // "Cryptocurrency symbol" object type
   OBJECT_DE_TYPE_SYMBOL_CUSTOM,                                  // "Custom symbol" object type
   OBJECT_DE_TYPE_SYMBOL_EXCHANGE,                                // "Exchange symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FUTURES,                                 // "Futures symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX,                                      // "Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX_EXOTIC,                               // "Exotic Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX_MAJOR,                                // "Major Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX_MINOR,                                // "Minor Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX_RUB,                                  // "RUB Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_INDEX,                                   // "Index symbol" object type
   OBJECT_DE_TYPE_SYMBOL_INDICATIVE,                              // "Indicative symbol" object type
   OBJECT_DE_TYPE_SYMBOL_METALL,                                  // "Metal symbol" object type
   OBJECT_DE_TYPE_SYMBOL_OPTION,                                  // "Option symbol" object type
   OBJECT_DE_TYPE_SYMBOL_STOCKS,                                  // "Stock symbol" object type
   
   OBJECT_DE_TYPE_TICK,                                           // "Tick" object type
   OBJECT_DE_TYPE_NEW_TICK,                                       // "New tick" object type
   OBJECT_DE_TYPE_TICKSERIES,                                     // "Tick data series" object type
   
   OBJECT_DE_TYPE_TRADE,                                          // "Trading object" object type
   
   OBJECT_DE_TYPE_LONG,                                           // "Long type data" object type
   OBJECT_DE_TYPE_DOUBLE,                                         // "Double type data" object type
   OBJECT_DE_TYPE_STRING,                                         // "String type data" object type
   OBJECT_DE_TYPE_OBJECT,                                         // "Object type data" object type
  };

//+------------------------------------------------------------------+
//| Search and sorting data                                          |
//+------------------------------------------------------------------+

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

   MSG_LIB_SYS_FAILED_ADD_BUFFER,                     // Failed to add buffer object to the list
   MSG_LIB_SYS_FAILED_CREATE_BUFFER_OBJ,              // Failed to create \"Indicator buffer\" object
   MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST,                // Failed to add object to the list
   
   MSG_LIB_SYS_FAILED_CREATE_LONG_DATA_OBJ,           // Failed to create long data object
   MSG_LIB_SYS_FAILED_CREATE_DOUBLE_DATA_OBJ,         // Failed to create double data object
   MSG_LIB_SYS_FAILED_CREATE_STRING_DATA_OBJ,         // Failed to create string data object
   
   MSG_LIB_SYS_FAILED_DECREASE_LONG_ARRAY,            // Failed to decrease long array size
   MSG_LIB_SYS_FAILED_DECREASE_DOUBLE_ARRAY,          // Failed to decrease double array size
   MSG_LIB_SYS_FAILED_DECREASE_STRING_ARRAY,          // Failed to decrease string array size
   
   MSG_LIB_SYS_FAILED_GET_LONG_DATA_OBJ,              // Failed to get long data object
   MSG_LIB_SYS_FAILED_GET_DOUBLE_DATA_OBJ,            // Failed to get double data object
   MSG_LIB_SYS_FAILED_GET_STRING_DATA_OBJ,            // Failed to get string data object
   
   MSG_LIB_SYS_REQUEST_OUTSIDE_LONG_ARRAY,            // Request outside long array
   MSG_LIB_SYS_REQUEST_OUTSIDE_DOUBLE_ARRAY,          // Request outside double array
   MSG_LIB_SYS_REQUEST_OUTSIDE_STRING_ARRAY,          // Request outside string array
   
   MSG_LIB_TEXT_YES,                                  // Yes
   MSG_LIB_TEXT_NO,                                   // No
   MSG_LIB_TEXT_AND,                                  // and

...

   MSG_GRAPH_OBJ_TEXT_ANCHOR_RIGHT_UPPER,             // Anchor point at the upper right corner
   MSG_GRAPH_OBJ_TEXT_ANCHOR_UPPER,                   // Anchor point at the upper center
   MSG_GRAPH_OBJ_TEXT_ANCHOR_CENTER,                  // Anchor point at the very center of the object
   
   MSG_GRAPH_OBJ_TEXT_TIME_PRICE,                     // Price/time coordinates
   MSG_GRAPH_OBJ_TEXT_PIVOT,                          // Pivot point
   MSG_GRAPH_OBJ_TEXT_LEVELSVALUE_ALL,                // Level values
   MSG_GRAPH_OBJ_TEXT_LEVEL,                          // Level
   MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_ON,              // On state
   MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_OFF,             // Off state

//--- CGraphElementsCollection
   MSG_GRAPH_OBJ_FAILED_GET_ADDED_OBJ_LIST,           // Failed to get the list of newly added objects
   MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST,         // Failed to remove a graphical object from the list
   
   MSG_GRAPH_OBJ_CREATE_EVN_CTRL_INDICATOR,           // Indicator for controlling and sending events created
   MSG_GRAPH_OBJ_FAILED_CREATE_EVN_CTRL_INDICATOR,    // Failed to create the indicator for controlling and sending events
   MSG_GRAPH_OBJ_CLOSED_CHARTS,                       // Chart windows closed:
   MSG_GRAPH_OBJ_OBJECTS_ON_CLOSED_CHARTS,            // Objects removed together with charts:
   
  };
//+------------------------------------------------------------------+

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

   {"Не удалось добавить объект-буфер в список","Failed to add buffer object to list"},
   {"Не удалось создать объект \"Индикаторный буфер\"","Failed to create object \"Indicator buffer\""},
   {"Не удалось добавить объект в список","Failed to add object to the list"},
   
   {"Не удалось создать объект long-данных","Failed to create long-data object"},
   {"Не удалось создать объект double-данных","Failed to create double-data object"},
   {"Не удалось создать объект string-данных","Failed to create string-data object"},
   
   {"Не удалось уменьшить размер long-массива","Failed to reduce the size of the long-array"},
   {"Не удалось уменьшить размер double-массива","Failed to reduce the size of the double-array"},
   {"Не удалось уменьшить размер string-массива","Failed to reduce the size of the string-array"},

   {"Не удалось получить объект long-данных","Failed to get long-data object"},
   {"Не удалось получить объект double-данных","Failed to get double-data object"},
   {"Не удалось получить объект string-данных","Failed to get string-data object"},
   
   {"Запрос за пределами long-массива","Data requested outside the long-array"},
   {"Запрос за пределами double-массива","Data requested outside the double-array"},
   {"Запрос за пределами string-массива","Data requested outside the string-array"},
   

   {"Да","Yes"},
   {"Нет","No"},
   {"и","and"},

...

   {"Точка привязки в правом верхнем углу","Anchor point at the upper right corner"},
   {"Точка привязки сверху по центру","Anchor point above in the center"},
   {"Точка привязки строго по центру объекта","Anchor point strictly in the center of the object"},
   
   {"Координаты цена/время","Price/time coordinates"},
   {"Опорная точка ","Pivot point "},
   {"Значения уровней","Level values"},
   {"Уровень ","Level "},
   {"Состояние \"On\"","State \"On\""},
   {"Состояние \"Off\"","State \"Off\""},
   
//--- CGraphElementsCollection
   {"Не удалось получить список вновь добавленных объектов","Failed to get the list of newly added objects"},
   {"Не удалось изъять графический объект из списка","Failed to detach graphic object from the list"},
   
   {"Создан индикатор контроля и отправки событий","An indicator for monitoring and sending events has been created"},
   {"Не удалось создать индикатор контроля и отправки событий","Failed to create indicator for monitoring and sending events"},
   {"Закрыто окон графиков: ","Closed chart windows: "},
   {"С ними удалено объектов: ","Objects removed with them: "},
   
  };
//+---------------------------------------------------------------------+


\MQL5\Include\DoEasy\Services\サービス関数フォルダで、 CXDimArrayクラスの新しいXDimArray.mqhファイルを作成します。

整数、実数、文字列のプロパティを格納するために通常の配列の代わりを導入したいので、これらの配列を任意の次元で多次元かつ動的にしながら、多次元動的配列の3つの完全に同一のクラスを作成します。それぞれが独自の型(long — 整数データ、double — 実数データ、string — テキストデータ)を格納します。

クラスの階層は次のとおりです。

  • CObject --> 抽象データ型クラス --> データ型クラス
  • CArrayObjクラス --> データ型クラスのリストを格納する1次元のクラス
  • CArrayObjクラス --> 1次元のクラスオブジェクトのリストを格納する多次元配列クラス

各データ型には、整数、実数、および文字列データを格納するための個別のクラスが必要です。いずれの場合も、クラスは基本データ型クラスから派生し、派生クラスに格納されているデータ型を設定します。

単一配列次元のクラスは、CArrayObjクラスから派生します。実際、これはデータオブジェクトまたは他のリストへのポインタを格納するリストです。

多次元配列クラスは、単一の配列次元のクラスオブジェクトのインスタンスへのポインタを格納するCArrayObjリストです。つまり、リストは最初の配列次元であり、単一次元のクラスは動的に拡張可能な最初の次元のオブジェクトです。サイズ1の1次元のオブジェクトが1つだけ含まれている場合、それにアクセスすると、エントリarray[0][0]に対応します。サイズ1の同じ次元の2つのオブジェクトがある場合、最初のオブジェクトへのアクセスはエントリarray[0][0]に対応し、2番目のオブジェクトへのアクセスは[0][1]に対応します。
当然、1つの次元のオブジェクトのサイズが1を超える場合、それらにアクセスすると、エントリに対応します。

array[0][0],  array[0][1],  array[0][2], ...,  array[0][N],
array[1][0],  array[1][1],  array[1][2], ...,  array[1][N].

もちろん、アクセスは適切な方法を使用して実行されます。配列の最初の次元と2番目の次元の両方を動的に変更できます。

2次元の動的配列のみが必要なため、ここで3番目以降の次元を追加することは検討しません。これらのクラスに基づいて、任意の数の次元を持つ動的配列を開発することが可能です。次元を変更(増加/減少)したり、任意の次元の任意の配列セルに新しい次元を追加したりすることができます。

それぞれが独自のデータ型を格納することを目的とした3つの同一のクラスを作成するので、1つの型のみのクラスについて詳しく考えてみましょう。

作成済みのCXDimArrayクラスのXDimArray.mqh ファイルに、CArrayObjクラスとライブラリメッセージクラスのファイルを含めCObject基本オブジェクトから派生した抽象データユニットのクラスを書き込みます

//+------------------------------------------------------------------+
//|                                                    XDimArray.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "Message.mqh"
//+------------------------------------------------------------------+
//| Abstract data unit class                                         |
//+------------------------------------------------------------------+
class CDataUnit : public CObject
  {
private:
   int               m_type;  
protected:
                     CDataUnit(int type)  { this.m_type=type;        }
public:
   virtual int       Type(void)     const { return this.m_type;      }
                     CDataUnit(){ this.m_type=OBJECT_DE_TYPE_OBJECT; }
  };
//+------------------------------------------------------------------+

ここには、格納されたデータ型を子孫オブジェクトに格納するためのprivate変数子孫オブジェクトに格納されたデータ型が渡されるprotectedパラメトリックコンストラクタm_type変数に設定された保存データ型を返すpublic仮想メソッドがあります。
デフォルトのコンストラクタでは、OBJECT_DE_TYPE_OBJECTデータ型がデフォルトでm_type変数に設定されています

次に、このクラスに整数データユニットを追加します。

//+------------------------------------------------------------------+
//| Integer data unit class                                          |
//+------------------------------------------------------------------+
class CDataUnitLong : public CDataUnit
  {
public:
   long              Value;
                     CDataUnitLong() : CDataUnit(OBJECT_DE_TYPE_LONG){}
  };
//+------------------------------------------------------------------+

このクラスには、整数値を格納するためのpublicフィールド変数と、クラスコンストラクタがあります。オブジェクトが整数データ型を格納することを示すOBJECT_DE_TYPE_LONG 型は、クラスコンストラクタ初期化リストの親クラスコンストラクタに渡されます。

次に、単一のlong配列次元のオブジェクトのクラスを作成します。

//+------------------------------------------------------------------+
//| Class of a single long array dimension                           |
//+------------------------------------------------------------------+
class CDimLong : public CArrayObj
  {

  }

クラス本体にすべてのメソッドを記述します。各メソッドは詳細にコメントされています。

クラスのprivateセクションで、配列から長いデータオブジェクトを受け取るメソッドを追加します。

//+------------------------------------------------------------------+
//| Class of a single long array dimension                           |
//+------------------------------------------------------------------+
class CDimLong : public CArrayObj
  {
private:
//--- Get long data object from the array
   CDataUnitLong    *GetData(const string source,const int index) const
                       {
                        //--- Get the pointer to the object by the index passed to the method. If the passed index is less than zero, it is set to zero
                        CDataUnitLong *data=this.At(index<0 ? 0 : index);
                        //--- If failed to receive the object
                        if(data==NULL)
                          {
                           //--- if the passed index exceeds the number of objects in the list, display a message informing of exceeding the list size
                           if(index>this.Total()-1)
                              ::Print(source,CMessage::Text(MSG_LIB_SYS_REQUEST_OUTSIDE_LONG_ARRAY)," (",index,"/",this.Total(),")");
                           //--- otherwise, display the message informing of failing to get the pointer to the object
                           else
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_GET_LONG_DATA_OBJ);
                          }
                        //--- Return the pointer to the object or NULL in case of an error
                        return data;
                       }

このメソッドは、配列の範囲外エラーに対する制御を実装します。つまり、渡されたインデックスが存在しない配列セルを示している場合、操作ログメッセージはそのことを通知します。メソッドに渡されるインデックスがゼロ未満の場合(これは発生しないはずです)、値はゼロに調整されます。有効な配列インデックスにアクセスしてもオブジェクトを取得できない場合は、操作ログに適切なエラーメッセージを表示します。その結果、オブジェクトへのポインタを返すか、エラーの場合はNULLを返します。このようなエラーをログに記録すると、このクラスを使用するときに必要なデータのインデックスを正しく指定するのに役立ちます。配列データを受信するために、他のクラスメソッドからメソッドにアクセスします。このメソッドは、配列オブジェクトにアクセスするときにエラーを通知します。

次に、指定された数のセルとオブジェクトを配列の最後に追加するメソッドを実装します。

//--- Add the specified number of cells with objects to the end of the array
   bool              AddQuantity(const string source,const int total,CObject *object)
                       {
                        //--- Declare the variable for storing the result of adding objects to the list
                        bool res=true;
                        //--- in the list by the number of added objects passed to the method
                        for(int i=0;i<total;i++)
                          {
                           //--- if failed to add the object to the list
                           if(!this.Add(object))
                             {
                              //--- display the appropriate message, add 'false' to the variable value
                              //--- and move on to the loop next iteration
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                              res &=false;
                              continue;
                             }
                          }
                        //--- Return the total result of adding the specified number of objects to the list
                        return res;
                       }

このメソッドは、配列の最後に追加されるオブジェクトの数と、インスタンスが追加されるオブジェクトへのポインタを受け取ります。次に、指定された数の反復処理で、オブジェクトへのポインタをリストに追加し、オブジェクトをリストに追加した結果を返します。

このメソッドには論理エラーがあり、配列に追加されたオブジェクトの数が2を超えても機能しません。次の記事で修正します。すでにこれを見つけている方、おめでとうございます。それは私の仕事が無駄ではないことを意味します。

クラスのpublicセクションで、配列を初期化するためのメソッドを追加します。

public:
//--- Initialize the array
   void              Initialize(const int total,const long value=0)
                       {
                        //--- Clear the array and increase its size by the value specified in the parameters by setting the default value
                        this.Clear();
                        this.Increase(total,value);
                       }

親クラスのClear()メソッドを使用して配列をクリアし、Increase()メソッドを使用して指定された値だけサイズを増やします。

//--- Increase the number of data cells by the specified value, return the number of added elements
   int               Increase(const int total,const long value=0)
                       {
                        //--- Save the current array size
                        int size_prev=this.Total();
                        //--- Create a new long data object
                        CDataUnitLong *data=new CDataUnitLong();
                        //--- If failed to create an object, inform of that and return zero
                        if(data==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_LONG_DATA_OBJ));
                           return 0;
                          }
                        //--- Set the specified value to a newly created object
                        data.Value=value;
                        //--- Add the specified number of object instances to the list
                        //--- and return the difference between the obtained and previous array size
                        this.AddQuantity(DFUN,total,data);
                        return this.Total()-size_prev;
                       }

このメソッドは、指定された量のlongデータを配列に追加し、追加されたデータの量を返します。

データセルの数を指定された値だけ減らすメソッドを書いてみましょう。

//--- Decrease the number of data cells by the specified value, return the number of removed elements. The very first element always remains
   int               Decrease(const int total)
                       {
                        //--- If not a single cell remains after removing array cells, return zero
                        if(total>this.Total()-1)
                           return 0;
                        //--- Save the current array size
                        int total_prev=this.Total();
                        //--- Calculate the initial index the array cells should be removed from
                        int from=this.Total()-total;
                        //--- The final index is always an array end
                        int to=this.Total()-1;
                        //--- If failed to remove the specified number of array cells, inform of that in the journal
                        if(!this.DeleteRange(from,to))
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_DECREASE_LONG_ARRAY);
                        //--- return the difference between the previous array size and the one obtained as a result of deleting cells
                        return total_prev-this.Total();
                       }

配列には少なくとも1つの要素が含まれている必要があるため、まず、必要な数を削除しても配列に少なくとも1つの要素が残るようにしてください。次に、親クラスのDeleteRange()メソッドを使用して、指定された数のリストの最後から要素を削除します。その結果、削除された要素の数を返します。

新しい配列サイズを設定するメソッドを記述します。

//--- Set a new array size
   bool              SetSize(const int size,const long initial_value=0)
                       {
                        //--- If the zero size is passed, return 'false'
                        if(size==0)
                           return false;
                        //--- Calculate the number of cells to be added or removed for receiving the required array size
                        int total=fabs(size-this.Total());
                        //--- If the passed array size exceeds the current one,
                        //--- return the result of adding the calculated number of arrays to the array
                        if(size>this.Total())
                           return(this.Increase(total,initial_value)==total);
                        //--- otherwise, if the passed array size is less than the current one, 
                        //--- return the result of removing the calculated number of arrays from the array
                        else if(size<this.Total())
                           return(Decrease(total)==total);
                        //--- If the passed size is equal to the current one, simply return 'true'
                        return true;
                       }

このメソッドは、上記で検討したメソッドを使用して、配列の要素を削除/追加し、指定されたサイズと同じサイズにします。

指定された配列セルに値を設定するメソッドを追加します。

//--- Set the value to the specified array cell
   bool              Set(const int index,const long value)
                       {
                        //--- Get the pointer to the data object by a specified index
                        CDataUnitLong *data=this.GetData(DFUN,index);
                        //--- If failed to get the object, return 'false'
                        if(data==NULL)
                           return false;
                        //--- Return the value, passed to the method, to the obtained object and return 'true'
                        data.Value=value;
                        return true;
                       }

ここでは、指定されたインデックスによってデータオブジェクトを取得し、メソッドに渡される値を設定します。オブジェクトが正常に受信されたら、trueを返します。失敗した場合(GetData() privateメソッドが操作ログでそのことを通知します)、falseを返します。

以下は、配列内のデータ数を返すメソッドです。

//--- Return the amount of data (the array size is defined using the Total() method of the CArrayObj parent class)
   int               Size(void) const { return this.Total(); }

このメソッドは、CArrayObjクラスの親であるCArrayクラスのTotal()メソッドを使用して、リスト内の要素の数を返すだけです。

指定されたインデックスで値を返すメソッドを記述しましょう。

//--- Returns the value at the specified index
   long              Get(const int index) const
                       {
                        //--- Get the pointer to the data object by index
                        CDataUnitLong *data=this.GetData(DFUN,index);
                        //--- If the object is received successfully,
                        //--- return the value set in the object,
                        //--- otherwise, return zero
                        return(data!=NULL ? data.Value : 0);
                       }

インデックスでリストからデータオブジェクトへのポインタを取得し、指定されたオブジェクトに設定された値を返します。エラーの場合は、ゼロを返します。

オーバーロードされたGet()メソッドは、リンクを介してメソッドに渡されたデータを変数に受信したときにブール値を返します。

   bool              Get(const int index, long &value) const
                       {
                        //--- Set the initial value to 'value' passed to the method via a link
                        value=0;
                        //--- Get the pointer to the data object by index
                        CDataUnitLong *data=this.GetData(DFUN,index);
                        //--- If failed to get the object, return 'false'
                        if(data==NULL)
                           return false;
                        //--- Set the value stored in the object to 'value' and return 'true'
                        value = data.Value;
                        return true;
                       }


デフォルトのコンストラクタで、Initialize()メソッドを使用して配列を初期化し、配列サイズとデフォルト値をそれぞれ1と0に指定します。
パラメトリックコンストラクタ
で、必要な配列サイズとデフォルト値を指定します。
クラスデストラクタで、配列要素を削除し、配列メモリを完全に解放しながら配列をクリアします

//--- Constructors
                     CDimLong(void)                               { this.Initialize(1);            }
                     CDimLong(const int total,const long value=0) { this.Initialize(total,value);  }
//--- Destructor
                    ~CDimLong(void)
                       {
                        this.Clear();
                        this.Shutdown();
                       }
  };
//+------------------------------------------------------------------+


次に、同じファイルに動的多次元長配列のクラスを作成します。

//+------------------------------------------------------------------+
//| Dynamic multidimensional long array class                        |
//+------------------------------------------------------------------+
class CXDimArrayLong : public CArrayObj
  {
  
  }

このクラスは、上記のクラスのオブジェクトを格納するリストであり、データを含むオブジェクトを格納するリストでもあります。したがって、クラスは最初の次元であり、クラスに格納されているリストは次元データのリストです。

より明確にします。

CXDimArrayLongクラスリストのインデックス0は、リストの最初にあるCDimLongクラスオブジェクトを指します。CDimLongクラスのインデックス0は、CDimLongクラスリストの最初にあるCDataUnitLongクラスオブジェクトを指します。

これは、エントリ配列[0][0]と同じです。

CXDimArrayLongクラスリストのインデックス1は、リストの2番目にあるCDimLongクラスオブジェクトを指します。 CDimLongクラスのインデックス0は、CDimLongクラスリストの最初にあるCDataUnitLongクラスオブジェクトを指します。

これは、エントリ配列[1][0]と同じです。

------

CXDimArrayLongクラスリストのインデックス0は、リストの最初にあるCDimLongクラスオブジェクトを指します。 CDimLongクラスのインデックス1は、CDimLongクラスリストの2番目にあるCDataUnitLongクラスオブジェクトを指します。

これは、エントリ配列[0][1]と同じです。

CXDimArrayLongクラスリストのインデックス1は、リストの2番目にあるCDimLongクラスオブジェクトを指します。 CDimLongクラスのインデックス1は、CDimLongクラスリストの2番目にあるCDataUnitLongクラスオブジェクトを指します。

これは、エントリ配列[1][1]と同じです。

など


クラスのprivateセクションで、最初の次元からデータ配列を返すメソッドを追加します。

//+------------------------------------------------------------------+
//| Dynamic multidimensional long array class                        |
//+------------------------------------------------------------------+
class CXDimArrayLong : public CArrayObj
  {
private:
//--- Return the data array from the first dimensionality
   CDimLong         *GetDim(const string source,const int index) const
                       {
                        //--- Get the first dimension array object by index
                        CDimLong *dim=this.At(index<0 ? 0 : index);
                        //--- If failed to get the pointer to the object,
                        if(dim==NULL)
                          {
                           //--- if the index is outside the array, inform of the request outside the array
                           if(index>this.Total()-1)
                              ::Print(source,CMessage::Text(MSG_LIB_SYS_REQUEST_OUTSIDE_LONG_ARRAY)," (",index,"/",this.Total(),")");
                           //--- otherwise, inform of the error when receiving the pointer to the array
                           else
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_GET_LONG_DATA_OBJ);
                          }
                        //--- Return either the pointer to the object or NULL in case of an error
                        return dim;
                       }

このメソッドは、指定されたインデックスによってCDimLongクラスオブジェクトへのポインタを受け取ります。インデックスがゼロ未満の場合は、ゼロに等しいインデックスを使用します。インデックスが配列の外側を指している場合は、操作ログ内の配列外の要求を通知します。オブジェクトの受信に失敗した場合は、操作ログ内のオブジェクト受信エラーを通知します。その結果、オブジェクトへのポインタを返すか、エラーの場合はNULLを返します。

クラスのprivateセクションで、最初の次元に新しい次元を追加するメソッドを記述します。

//--- Add a new dimension to the first dimensionality
   bool              AddNewDim(const string source,const int size,const long initial_value=0)
                       {
                        //--- Create a new array object 
                        CDimLong *dim=new CDimLong(size,initial_value);
                        //--- If failed to create an object, inform of that and return 'false'
                        if(dim==NULL)
                          {
                           CMessage::ToLog(source,MSG_LIB_SYS_FAILED_CREATE_LONG_DATA_OBJ);
                           return false;
                          }
                        //--- If failed to add the object to the list, remove the object, inform of the error in the journal and return 'false'
                        if(!this.Add(dim))
                          {
                           delete dim;
                           CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           return false;
                          }
                        //--- Object successfully created and added to the list
                        return true;
                       }

このメソッドは、新しいCDimLongクラスオブジェクトを作成し、それをリストの最後に追加して、最初の次元のサイズを増やします。

クラスのpublicセクションで、配列を操作するためのメソッドを記述します。すべてのメソッドは、コードコメントで詳細に説明されています。ここで繰り返しても意味がないと思います。それらをそのまま考えてみましょう。

public:
//--- Increase the number of data cells by the specified 'total' value in the first dimensionality,
//--- return the number of added elements to the dimensionality. Added cells' size is 'size'
   int               IncreaseRangeFirst(const int total,const int size,const long initial_value=0)
                       {
                        //--- Save the current array size
                        int total_prev=this.Total();
                        //--- In the loop by the specified number, add new objects to the array
                        for(int i=0;i<total;i++)
                           this.AddNewDim(DFUN,size,initial_value);
                        //--- Return the difference between the obtained and previous array size
                        return(this.Total()-total_prev);
                       }
//--- Increase the number of data cells by the specified 'total' value in the specified 'range' dimensionality,
//--- return the number of added elements to the changed dimensionality
   int               IncreaseRange(const int range,const int total,const long initial_value=0)
                       {
                        //--- Get the pointer to the array by 'range' index
                        CDimLong *dim=this.GetDim(DFUN,range);
                        //--- Return the result of increasing the array size by 'total' or zero in case of an error
                        return(dim!=NULL ? dim.Increase(total,initial_value) : 0);
                       }
//--- Decrease the number of cells with data in the first dimensionality by the specified value,
//--- return the number of removed elements. The very first element always remains
   int               DecreaseRangeFirst(const int total)
                       {
                        //--- Make sure at least one element remains in the array after the decrease,
                        //--- if not, return 'false'
                        if(total>this.Total()-1)
                           return 0;
                        //--- Save the current array size
                        int total_prev=this.Total();
                        //--- Calculate the initial index to remove the array elements from
                        int from=this.Total()-total;
                        //--- The final index is always the last array element
                        int to=this.Total()-1;
                        //--- If failed to remove the specified number of elements, inform of that in the journal
                        if(!this.DeleteRange(from,to))
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_DECREASE_LONG_ARRAY);
                        //--- Return the number of removed array elements
                        return total_prev-this.Total();
                       }                      
//--- Decrease the number of data cells by the specified value in the specified dimensionality,
//--- return the number of removed elements. The very first element always remains
   int               DecreaseRange(const int range,const int total)
                       {
                        //--- Get the pointer to the array by 'range' index
                        CDimLong *dim=this.GetDim(DFUN,range);
                        //--- Return the result of decreasing the array size by 'total' or zero in case of an error
                        return(dim!=NULL ? dim.Decrease(total) : 0);
                       }
//--- Set the new array size in the specified dimensionality
   bool              SetSizeRange(const int range,const int size,const long initial_value=0)
                       {
                        //--- Get the pointer to the array by 'range' index
                        CDimLong *dim=this.GetDim(DFUN,range);
                        //--- Return the result of setting the array size to 'size' or 'false' in case of an error
                        return(dim!=NULL ? dim.SetSize(size,initial_value) : false);
                       }
//--- Set the value to the specified array cell of the specified dimension
   bool              Set(const int index,const int range,const long value)
                       {
                        //--- Get the pointer to the array by 'index'
                        CDimLong *dim=this.GetDim(DFUN,index);
                        //--- Return the result of setting the value to the array cell by 'range' index or 'false' in case of an error
                        return(dim!=NULL ? dim.Set(range,value) : false);
                       }
//--- Return the value at the specified index of the specified dimension
   long              Get(const int index,const int range) const
                       {
                        //--- Get the pointer to the array by 'index'
                        CDimLong *dim=this.GetDim(DFUN,index);
                        //--- Return the result of receiving the value from the array cell by 'range' index or 0 in case of an error
                        return(dim!=NULL ? dim.Get(range) : 0);
                       }
   bool              Get(const int index,const int range,long &value) const
                       {
                        //--- Get the pointer to the array by 'index'
                        CDimLong *dim=this.GetDim(DFUN,index);
                        //--- Return the result of receiving the value from the array cell by 'range' index to the 'value' variable
                        //--- or 'false' in case of an error ('value' is set to zero)
                        return(dim!=NULL ? dim.Get(range,value) : false);
                       }
//--- Return the amount of data (size of the specified dimension array)
   int               Size(const int range) const
                       {
                        //--- Get the pointer to the array by 'range' index
                        CDimLong *dim=this.GetDim(DFUN,range);
                        //--- Return the size of the obtained array by index or zero in case of an error
                        return(dim!=NULL ? dim.Size() : 0);
                       }
//--- Return the total amount of data (the total size of all dimensions)
   int               Size(void) const
                       {
                        //--- Set the initial size
                        int size=0;
                        //--- In the loop by all arrays in the list,
                        for(int i=0;i<this.Total();i++)
                          {
                           //--- get the next array.
                           CDimLong *dim=this.GetDim(DFUN,i);
                           //--- If failed to get the array, move on to the next one
                           if(dim==NULL)
                              continue;
                           //--- Add the array size to the size value
                           size+=dim.Size();
                          }
                        //--- Return the obtained value
                        return size;
                       }
//--- Constructor
                     CXDimArrayLong()
                       {
                        //--- Clear the list and add a single array to it
                        this.Clear();
                        this.Add(new CDimLong(1));
                       }
                     CXDimArrayLong(int first_dim_size,const int dim_size,const long initial_value=0)
                       {
                        //--- Clear the list
                        this.Clear();
                        int total=(first_dim_size<1 ? 1 : first_dim_size);
                        //--- In the loop by the necessary number of arrays calculated in 'total' from first_dim_size,
                        //--- add new arrays with the specified number of elements in dim_size to the list
                        for(int i=0;i<total;i++)
                           this.Add(new CDimLong(dim_size,initial_value));
                       }
//--- Destructor
                    ~CXDimArrayLong()
                       {
                        //--- Remove array elements and
                        //--- clear the array while completely freeing the array memory
                        this.Clear();
                        this.Shutdown();
                       }
  };
//+------------------------------------------------------------------+

ご覧のとおり、主に、CDimLongクラスを作成するときに、上記ですでに検討した、取得したCDimLongクラスオブジェクトのメソッドを使用します。ご質問がある場合は、下のコメント欄でお気軽にお問い合わせください。

ここで、double型とstring型のデータに対してまったく同じクラスを作成する必要があります。クラスは、上記で説明したものと完全に同じです。

//+------------------------------------------------------------------+
//| Real data unit class                                             |
//+------------------------------------------------------------------+
class CDataUnitDouble : public CDataUnit
  {
public:
   double            Value;
//--- Constructor
                     CDataUnitDouble() : CDataUnit(OBJECT_DE_TYPE_DOUBLE){}
  };
//+------------------------------------------------------------------+
//| Class of a single double array dimension                         |
//+------------------------------------------------------------------+
class CDimDouble : public CArrayObj
  {
private:
//--- Get long data object from the array
   CDataUnitDouble  *GetData(const string source,const int index) const
                       {
                        CDataUnitDouble *data=this.At(index<0 ? 0 : index);
                        if(data==NULL)
                          {
                           if(index>this.Total()-1)
                              ::Print(source,CMessage::Text(MSG_LIB_SYS_REQUEST_OUTSIDE_DOUBLE_ARRAY)," (",index,"/",this.Total(),")");
                           else
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_GET_DOUBLE_DATA_OBJ);
                          }
                        return data;
                       }
//--- Add the specified number of cells with objects to the end of the array
   bool              AddQuantity(const string source,const int total,CObject *object)
                       {
                        bool res=true;
                        for(int i=0;i<total;i++)
                          {
                           if(!this.Add(object))
                             {
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                              res &=false;
                              continue;
                             }
                          }
                        return res;
                       }
public:
//--- Initialize the array
   void              Initialize(const int total,const double value=0)
                       {
                        this.Clear();
                        this.Increase(total,value);
                       }
//--- Increase the number of data cells by the specified value, return the number of added elements
   int               Increase(const int total,const double value=0)
                       {
                        int size_prev=this.Total();
                        CDataUnitDouble *data=new CDataUnitDouble();
                        if(data==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_DOUBLE_DATA_OBJ));
                           return 0;
                          }
                        data.Value=value;
                        this.AddQuantity(DFUN,total,data);
                        return this.Total()-size_prev;
                       }
//--- Decrease the number of data cells by the specified value, return the number of removed elements. The very first element always remains
   int               Decrease(const int total)
                       {
                        if(total>this.Total()-1)
                           return 0;
                        int total_prev=this.Total();
                        int from=this.Total()-total;
                        int to=this.Total()-1;
                        if(!this.DeleteRange(from,to))
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_DECREASE_DOUBLE_ARRAY);
                        return total_prev-this.Total();
                       }
//--- Set a new array size
   bool              SetSize(const int size,const double initial_value=0)
                       {
                        if(size==0)
                           return false;
                        int total=fabs(size-this.Total());
                        if(size>this.Total())
                           return(this.Increase(total,initial_value)==total);
                        else if(size<this.Total())
                           return(Decrease(total)==total);
                        return true;
                       }
//--- Set the value to the specified array cell
   bool              Set(const int index,const double value)
                       {
                        CDataUnitDouble *data=this.GetData(DFUN,index);
                        if(data==NULL)
                           return false;
                        data.Value=value;
                        return true;
                       }
//--- Return the amount of data (array size)
   int               Size(void) const { return this.Total(); }
   
//--- Returns the value at the specified index
   double            Get(const int index) const
                       {
                        CDataUnitDouble *data=this.GetData(DFUN,index);
                        return(data!=NULL ? data.Value : 0);
                       }
   bool              Get(const int index, double &value) const
                       {
                        value=0;
                        CDataUnitDouble *data=this.GetData(DFUN,index);
                        if(data==NULL)
                           return false;
                        value = data.Value;
                        return true;
                       }
//--- Constructors
                     CDimDouble(void)                                { this.Initialize(1);            }
                     CDimDouble(const int total,const double value=0){ this.Initialize(total,value);  }
//--- Destructor
                    ~CDimDouble(void)
                       {
                        this.Clear();
                        this.Shutdown();
                       }
  };
//+------------------------------------------------------------------+
//| Dynamic multidimensional double array class                      |
//+------------------------------------------------------------------+
class CXDimArrayDouble : public CArrayObj
  {
private:
//--- Return the data array from the first dimensionality
   CDimDouble       *GetDim(const string source,const int index) const
                       {
                        CDimDouble *dim=this.At(index<0 ? 0 : index);
                        if(dim==NULL)
                          {
                           if(index>this.Total()-1)
                              ::Print(source,CMessage::Text(MSG_LIB_SYS_REQUEST_OUTSIDE_DOUBLE_ARRAY)," (",index,"/",this.Total(),")");
                           else
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_GET_DOUBLE_DATA_OBJ);
                          }
                        return dim;
                       }
//--- Add a new dimension to the first dimensionality
   bool              AddNewDim(const string source,const int size,const double initial_value=0)
                       {
                        CDimDouble *dim=new CDimDouble(size,initial_value);
                        if(dim==NULL)
                          {
                           CMessage::ToLog(source,MSG_LIB_SYS_FAILED_CREATE_DOUBLE_DATA_OBJ);
                           return false;
                          }
                        if(!this.Add(dim))
                          {
                           delete dim;
                           CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           return false;
                          }
                        return true;
                       }
public:
//--- Increase the number of data cells by the specified 'total' value in the first dimensionality,
//--- return the number of added elements to the dimensionality. Added cells' size is 'size'
   int               IncreaseRangeFirst(const int total,const int size,const long initial_value=0)
                       {
                        int total_prev=this.Total();
                        for(int i=0;i<total;i++)
                           this.AddNewDim(DFUN,size,initial_value);
                        return(this.Total()-total_prev);
                       }
//--- Increase the number of data cells by the specified 'total' value in the specified 'range' dimensionality,
//--- return the number of added elements to the changed dimensionality
   int               IncreaseRange(const int range,const int total,const double initial_value=0)
                       {
                        CDimDouble *dim=this.GetDim(DFUN,range);
                        return(dim!=NULL ? dim.Increase(total,initial_value) : 0);
                       }
//--- Decrease the number of cells with data in the first dimensionality by the specified value,
//--- return the number of removed elements. The very first element always remains
   int               DecreaseRangeFirst(const int total)
                       {
                        if(total>this.Total()-1)
                           return 0;
                        int total_prev=this.Total();
                        int from=this.Total()-total;
                        int to=this.Total()-1;
                        if(!this.DeleteRange(from,to))
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_DECREASE_DOUBLE_ARRAY);
                        return total_prev-this.Total();
                       }                      
//--- Decrease the number of data cells by the specified value in the specified dimensionality,
//--- return the number of removed elements. The very first element always remains
   int               DecreaseRange(const int range,const int total)
                       {
                        CDimDouble *dim=this.GetDim(DFUN,range);
                        return(dim!=NULL ? dim.Decrease(total) : 0);
                       }
//--- Set the new array size in the specified dimensionality
   bool              SetSizeRange(const int range,const int size,const double initial_value=0)
                       {
                        CDimDouble *dim=this.GetDim(DFUN,range);
                        return(dim!=NULL ? dim.SetSize(size,initial_value) : false);
                       }
//--- Set the value to the specified array cell of the specified dimension
   bool              Set(const int index,const int range,const double value)
                       {
                        CDimDouble *dim=this.GetDim(DFUN,index);
                        return(dim!=NULL ? dim.Set(range,value) : false);
                       }
//--- Return the value at the specified index of the specified dimension
   double            Get(const int index,const int range) const
                       {
                        CDimDouble *dim=this.GetDim(DFUN,index);
                        return(dim!=NULL ? dim.Get(range) : 0);
                       }
   bool              Get(const int index,const int range,double &value) const
                       {
                        CDimDouble *dim=this.GetDim(DFUN,index);
                        return(dim!=NULL ? dim.Get(range,value) : false);
                       }
//--- Return the amount of data (size of the specified dimension array)
   int               Size(const int range) const
                       {
                        CDimDouble *dim=this.GetDim(DFUN,range);
                        return(dim!=NULL ? dim.Size() : 0);
                       }
//--- Return the total amount of data (the total size of all dimensions)
   int               Size(void) const
                       {
                        int size=0;
                        for(int i=0;i<this.Total();i++)
                          {
                           CDimDouble *dim=this.GetDim(DFUN,i);
                           if(dim==NULL)
                              continue;
                           size+=dim.Size();
                          }
                        return size;
                       }
//--- Constructor
                     CXDimArrayDouble()
                       {
                        this.Clear();
                        this.Add(new CDimDouble(1));
                       }
                     CXDimArrayDouble(int first_dim_size,const int dim_size,const double initial_value=0)
                       {
                        this.Clear();
                        int total=(first_dim_size<1 ? 1 : first_dim_size);
                        for(int i=0;i<total;i++)
                           this.Add(new CDimDouble(dim_size,initial_value));
                       }
//--- Destructor
                    ~CXDimArrayDouble()
                       {
                        this.Clear();
                        this.Shutdown();
                       }
  };
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| String data unit class                                           |
//+------------------------------------------------------------------+
class CDataUnitString : public CDataUnit
  {
public:
   string            Value;
                     CDataUnitString() : CDataUnit(OBJECT_DE_TYPE_STRING){}
  };
//+------------------------------------------------------------------+
//| Class of a single string array dimension                         |
//+------------------------------------------------------------------+
class CDimString : public CArrayObj
  {
private:
//--- Get long data object from the array
   CDataUnitString  *GetData(const string source,const int index)
                       {
                        CDataUnitString *data=this.At(index<0 ? 0 : index);
                        if(data==NULL)
                          {
                           if(index>this.Total()-1)
                              ::Print(source,CMessage::Text(MSG_LIB_SYS_REQUEST_OUTSIDE_STRING_ARRAY)," (",index,"/",this.Total(),")");
                           else
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_GET_STRING_DATA_OBJ);
                          }
                        return data;
                       }
//--- Add the specified number of cells with objects to the end of the array
   bool              AddQuantity(const string source,const int total,CObject *object)
                       {
                        bool res=true;
                        for(int i=0;i<total;i++)
                          {
                           if(!this.Add(object))
                             {
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                              res &=false;
                              continue;
                             }
                          }
                        return res;
                       }
public:
//--- Initialize the array
   void              Initialize(const int total,const string value="")
                       {
                        this.Clear();
                        this.Increase(total,value);
                       }
//--- Increase the number of data cells by the specified value, return the number of added elements
   int               Increase(const int total,const string value="")
                       {
                        int size_prev=this.Total();
                        CDataUnitString *data=new CDataUnitString();
                        if(data==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_STRING_DATA_OBJ));
                           return 0;
                          }
                        data.Value=value;
                        this.AddQuantity(DFUN,total,data);
                        return this.Total()-size_prev;
                       }
//--- Decrease the number of data cells by the specified value, return the number of removed elements. The very first element always remains
   int               Decrease(const int total)
                       {
                        if(total>this.Total()-1)
                           return 0;
                        int total_prev=this.Total();
                        int from=this.Total()-total;
                        int to=this.Total()-1;
                        if(!this.DeleteRange(from,to))
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_DECREASE_STRING_ARRAY);
                        return total_prev-this.Total();
                       }
//--- Set a new array size
   bool              SetSize(const int size,const string initial_value="")
                       {
                        if(size==0)
                           return false;
                        int total=fabs(size-this.Total());
                        if(size>this.Total())
                           return(this.Increase(total,initial_value)==total);
                        else if(size<this.Total())
                           return(Decrease(total)==total);
                        return true;
                       }
//--- Set the value to the specified array cell
   bool              Set(const int index,const string value)
                       {
                        CDataUnitString *data=this.GetData(DFUN,index);
                        if(data==NULL)
                           return false;
                        data.Value=value;
                        return true;
                       }
//--- Return the amount of data (array size)
   int               Size(void) const { return this.Total(); }
   
//--- Returns the value at the specified index
   string            Get(const int index)
                       {
                        CDataUnitString *data=this.GetData(DFUN,index);
                        return(data!=NULL ? data.Value : "");
                       }
   bool              Get(const int index, string &value)
                       {
                        value="";
                        CDataUnitString *data=this.GetData(DFUN,index);
                        if(data==NULL)
                           return false;
                        value = data.Value;
                        return true;
                       }
//--- Constructors
                     CDimString(void)                                   { this.Initialize(1);            }
                     CDimString(const int total,const string value="")  { this.Initialize(total,value);  }
//--- Destructor
                    ~CDimString(void)
                       {
                        this.Clear();
                        this.Shutdown();
                       }
  };
//+------------------------------------------------------------------+
//| Dynamic multidimensional string array class                      |
//+------------------------------------------------------------------+
class CXDimArrayString : public CArrayObj
  {
private:
//--- Return the data array from the first dimensionality
   CDimString       *GetDim(const string source,const int index) const
                       {
                        CDimString *dim=this.At(index<0 ? 0 : index);
                        if(dim==NULL)
                          {
                           if(index>this.Total()-1)
                              ::Print(source,CMessage::Text(MSG_LIB_SYS_REQUEST_OUTSIDE_STRING_ARRAY)," (",index,"/",this.Total(),")");
                           else
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_GET_STRING_DATA_OBJ);
                          }
                        return dim;
                       }
//--- Add a new dimension to the first dimensionality
   bool              AddNewDim(const string source,const int size,const string initial_value="")
                       {
                        CDimString *dim=new CDimString(size,initial_value);
                        if(dim==NULL)
                          {
                           CMessage::ToLog(source,MSG_LIB_SYS_FAILED_CREATE_STRING_DATA_OBJ);
                           return false;
                          }
                        if(!this.Add(dim))
                          {
                           delete dim;
                           CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           return false;
                          }
                        return true;
                       }
public:
//--- Increase the number of data cells by the specified 'total' value in the first dimensionality,
//--- return the number of added elements to the dimensionality. Added cells' size is 'size'
   int               IncreaseRangeFirst(const int total,const int size,const string initial_value="")
                       {
                        int total_prev=this.Total();
                        for(int i=0;i<total;i++)
                           this.AddNewDim(DFUN,size,initial_value);
                        return(this.Total()-total_prev);
                       }
//--- Increase the number of data cells by the specified 'total' value in the specified 'range' dimensionality,
//--- return the number of added elements to the changed dimensionality
   int               IncreaseRange(const int range,const int total,const string initial_value="")
                       {
                        CDimString *dim=this.GetDim(DFUN,range);
                        return(dim!=NULL ? dim.Increase(total,initial_value) : 0);
                       }
//--- Decrease the number of cells with data in the first dimensionality by the specified value,
//--- return the number of removed elements. The very first element always remains
   int               DecreaseRangeFirst(const int total)
                       {
                        if(total>this.Total()-1)
                           return 0;
                        int total_prev=this.Total();
                        int from=this.Total()-total;
                        int to=this.Total()-1;
                        if(!this.DeleteRange(from,to))
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_DECREASE_STRING_ARRAY);
                        return total_prev-this.Total();
                       }                      
//--- Decrease the number of data cells by the specified value in the specified dimensionality,
//--- return the number of removed elements. The very first element always remains
   int               DecreaseRange(const int range,const int total)
                       {
                        CDimString *dim=this.GetDim(DFUN,range);
                        return(dim!=NULL ? dim.Decrease(total) : 0);
                       }
//--- Set the new array size in the specified dimensionality
   bool              SetSizeRange(const int range,const int size,const string initial_value="")
                       {
                        CDimString *dim=this.GetDim(DFUN,range);
                        return(dim!=NULL ? dim.SetSize(size,initial_value) : false);
                       }
//--- Set the value to the specified array cell of the specified dimension
   bool              Set(const int index,const int range,const string value)
                       {
                        CDimString *dim=this.GetDim(DFUN,index);
                        return(dim!=NULL ? dim.Set(range,value) : false);
                       }
//--- Return the value at the specified index of the specified dimension
   string            Get(const int index,const int range) const
                       {
                        CDimString *dim=this.GetDim(DFUN,index);
                        return(dim!=NULL ? dim.Get(range) : "");
                       }
   bool              Get(const int index,const int range, string &value) const
                       {
                        CDimString *dim=this.GetDim(DFUN,index);
                        return(dim!=NULL ? dim.Get(range,value) : false);
                       }
//--- Return the amount of data (size of the specified dimension array)
   int               Size(const int range) const
                       {
                        CDimString *dim=this.GetDim(DFUN,range);
                        return(dim!=NULL ? dim.Size() : 0);
                       }
//--- Return the total amount of data (the total size of all dimensions)
   int               Size(void) const
                       {
                        int size=0;
                        for(int i=0;i<this.Total();i++)
                          {
                           CDimString *dim=this.GetDim(DFUN,i);
                           if(dim==NULL)
                              continue;
                           size+=dim.Size();
                          }
                        return size;
                       }
//--- Constructor
                     CXDimArrayString()
                       {
                        this.Clear();
                        this.Add(new CDimString(1));
                       }
                     CXDimArrayString(int first_dim_size,const int dim_size,const string initial_value="")
                       {
                        this.Clear();
                        int total=(first_dim_size<1 ? 1 : first_dim_size);
                        for(int i=0;i<total;i++)
                           this.Add(new CDimString(dim_size,initial_value));
                       }
//--- Destructor
                    ~CXDimArrayString()
                       {
                        this.Clear();
                        this.Shutdown();
                       }
  };
//+------------------------------------------------------------------+


整数、実数、文字列のプロパティを格納する単純な配列の処理を、上記で検討したクラスによって提供される動的配列の処理に置き換えることで、抽象グラフィカルオブジェクトクラスを新しいレベルに引き上げる準備が整いました。

グラフィカルオブジェクトクラスの変更を開始する前に、新しく作成されたクラスを他のクラスと同じようにライブラリに表示する必要があります。これを行うには、クラスを含むファイルをライブラリサービス関数ファイル( \MQL5\Include\DoEasy\Services\DELib.mqh)にインクルードします。

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property strict  // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\Defines.mqh"
#include "Message.mqh"
#include "TimerCounter.mqh"
#include "Pause.mqh"
#include "Colors.mqh"
#include "XDimArray.mqh"
//+------------------------------------------------------------------+
//| Service functions                                                |
//+------------------------------------------------------------------+

これらのクラスはすべてのライブラリクラスに表示されるようになります。

オブジェクトのプロパティを格納するための2次元動的配列

ほとんどすべてのライブラリオブジェクトには、整数、実数、文字列のオブジェクトプロパティを格納する配列があります。配列は1次元であり、必要なプロパティの数に対応する厳密に設定されたサイズを持っています。この構造は、動的に変化するオブジェクトプロパティの数を管理する必要に直面するまでは便利でした。抽象標準グラフィカルオブジェクトクラスからライブラリオブジェクトの調整を開始します。以降のすべてのオブジェクトは、動的多次元配列クラスに基づく新しい機能を使用して作成されます。おそらく、後で動的配列も処理するために以前に作成したオブジェクトを作成すると思います。

抽象標準グラフィカルオブジェクトファイル(\MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqhのprivateセクションには、プロパティを格納するための配列(現在および 前のもの)および配列内の指定されたプロパティの実際のインデックスを受け取るためのメソッドがあります。

//+------------------------------------------------------------------+
//|                                                 GStdGraphObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\GBaseObj.mqh"
//+------------------------------------------------------------------+
//| The class of the abstract standard graphical object              |
//+------------------------------------------------------------------+
class CGStdGraphObj : public CGBaseObj
  {
private:
   long              m_long_prop[GRAPH_OBJ_PROP_INTEGER_TOTAL];         // Integer properties
   double            m_double_prop[GRAPH_OBJ_PROP_DOUBLE_TOTAL];        // Real properties
   string            m_string_prop[GRAPH_OBJ_PROP_STRING_TOTAL];        // String properties

   long              m_long_prop_prev[GRAPH_OBJ_PROP_INTEGER_TOTAL];    // Integer properties before change
   double            m_double_prop_prev[GRAPH_OBJ_PROP_DOUBLE_TOTAL];   // Real properties before change
   string            m_string_prop_prev[GRAPH_OBJ_PROP_STRING_TOTAL];   // String properties before change

//--- Return the index of the array the (1) double and (2) string properties are actually located at
   int               IndexProp(ENUM_GRAPH_OBJ_PROP_DOUBLE property)  const { return(int)property-GRAPH_OBJ_PROP_INTEGER_TOTAL;                              }
   int               IndexProp(ENUM_GRAPH_OBJ_PROP_STRING property)  const { return(int)property-GRAPH_OBJ_PROP_INTEGER_TOTAL-GRAPH_OBJ_PROP_DOUBLE_TOTAL;  }

public:

次に、これらすべての配列とメソッドを新しいクラスに転送する必要があります。このクラスは、オブジェクトなどの単一のオブジェクトプロパティ( ピボットポイントの価格と時間、または数が動的に変化する可能性のあるオブジェクトレベルの色、スタイル、幅、説明)の変更を追跡するために、2番目の次元が動的に変更されるオブジェクトのプロパティを格納するための動的な2次元配列になります。

クラスが完全にデバッグされるまで、抽象標準グラフィカルオブジェクトクラスのprivateセクションに直接配置します。関数全体がデバッグされて準備ができたら、動的2次元オブジェクトプロパティ配列のクラスを別のファイルに移動して、オブジェクト内に新たに書き込むのではなく、他のオブジェクトでアクセスできるようにします。

上記で指定したすべての配列とメソッドをprivateセクションから削除し、代わりに新しいクラスのオブジェクトプロパティを定義します。

//+------------------------------------------------------------------+
//|                                                 GStdGraphObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\GBaseObj.mqh"
//+------------------------------------------------------------------+
//| The class of the abstract standard graphical object              |
//+------------------------------------------------------------------+
class CGStdGraphObj : public CGBaseObj
  {
private:
   //--- Object property class
   class CDataPropObj
     {
      
     }

新しいクラスのprivateセクションで、CXDimArrayLong動的多次元配列クラスによって導入されるプロパティオブジェクトを格納するためのリスト整数、実数、および文字列オブジェクトプロパティの数を格納するための変数を宣言します。配列のインデックスを返す2つのメソッド(実際には、doublestringのオブジェクトプロパティを格納)も宣言します。

//+------------------------------------------------------------------+
//| The class of the abstract standard graphical object              |
//+------------------------------------------------------------------+
class CGStdGraphObj : public CGBaseObj
  {
private:
   //--- Object property class
   class CDataPropObj
     {
   private:
      CArrayObj         m_list;        // list of property objects
      int               m_total_int;   // Number of integer parameters
      int               m_total_dbl;   // Number of real parameters
      int               m_total_str;   // Number of string parameters
      //--- Return the index of the array the (1) double and (2) string properties are actually located at
      int               IndexProp(ENUM_GRAPH_OBJ_PROP_DOUBLE property)              const { return(int)property-this.m_total_int;                     }
      int               IndexProp(ENUM_GRAPH_OBJ_PROP_STRING property)              const { return(int)property-this.m_total_int-this.m_total_dbl;    }

クラスのpublicセクションで、プロパティオブジェクトのリストを返すメソッド整数、実数、文字列のプロパティのオブジェクトへのポインタ指定されたオブジェクトプロパティを設定するメソッドと受け取るメソッドを宣言します。

   //--- Object property class
   class CDataPropObj
     {
   private:
      CArrayObj         m_list;        // list of property objects
      int               m_total_int;   // Number of integer parameters
      int               m_total_dbl;   // Number of real parameters
      int               m_total_str;   // Number of string parameters
      //--- Return the index of the array the (1) double and (2) string properties are actually located at
      int               IndexProp(ENUM_GRAPH_OBJ_PROP_DOUBLE property)              const { return(int)property-this.m_total_int;                     }
      int               IndexProp(ENUM_GRAPH_OBJ_PROP_STRING property)              const { return(int)property-this.m_total_int-this.m_total_dbl;    }
   public:
      //--- Return the pointer to (1) the list of property objects, as well as to the object of (2) integer, (3) real and (4) string properties
      CArrayObj        *GetList(void)                                                     { return &this.m_list;                                      }
      CXDimArrayLong   *Long()                                                      const { return this.m_list.At(0);                                 }
      CXDimArrayDouble *Double()                                                    const { return this.m_list.At(1);                                 }
      CXDimArrayString *String()                                                    const { return this.m_list.At(2);                                 }
      //--- Set object's (1) integer, (2) real and (3) string properties
      void              Set(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value)    { this.Long().Set(property,index,value);                    }
      void              Set(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value)   { this.Double().Set(this.IndexProp(property),index,value);  }
      void              Set(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value)   { this.String().Set(this.IndexProp(property),index,value);  }
      //--- Return object’s (1) integer, (2) real and (3) string property from the properties array
      long              Get(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index)         const { return this.Long().Get(property,index);                   }
      double            Get(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index)          const { return this.Double().Get(this.IndexProp(property),index); }
      string            Get(ENUM_GRAPH_OBJ_PROP_STRING property,int index)          const { return this.String().Get(this.IndexProp(property),index); }

CArrayObjリストは、上記で作成された動的配列のクラスオブジェクトのインスタンスへの3つのポインタを格納します(クラスコンストラクターで作成されてリストに配置される整数、実数、文字列のポインタ)。SetメソッドとGetメソッドは、以前に使用されていたメソッドと似ていますが、パラメータがもう1つある点が異なります。オブジェクトプロパティインデックスとは別に、配列の2次元でプロパティインデックスも示します。ほとんどのプロパティでは、インデックスは常にゼロに等しくなります。ただし、いくつかの同じタイプのオブジェクトプロパティについては、価格、時間などの1番目、2番目、3番目以降のプロパティを受け取るためのプロパティ修飾子インデックスを指定します。

また、クラスのpublicセクションに、指定された1次元データ配列のサイズを返すメソッドを記述します

      //--- Return the size of the specified first dimension data array
      int               Size(const int range) const
                          {
                           if(range<this.m_total_int)
                              return this.Long().Size(range);
                           else if(range<this.m_total_int+this.m_total_dbl)
                              return this.Double().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range));
                           else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str)
                              return this.String().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range));
                           return 0;
                          }

このメソッドは、プロパティ配列の最初の次元(範囲)の必要なプロパティのインデックスを渡します。次に、以下を確認します。
プロパティ値が整数プロパティの総数よりも少ない場合、これは整数プロパティリクエストです。 LongオブジェクトのSize()メソッドを使用して整数プロパティ配列のサイズを返します
プロパティ値が整数プロパティの総数+実数の数よりも少ない場合、これは実数のリクエストです。DoubleオブジェクトのSize()メソッドを使用して実数配列のサイズを返します
プロパティ値が整数プロパティの総数+実数プロパティの数+文字列プロパティの数よりも小さい場合、これは文字列プロパティのリクエストです。StringオブジェクトのSize()メソッドを使用して文字列プロパティ配列のサイズを返します
動的配列のオブジェクトクラスを作成するときに、上記のSize()メソッドを検討しました。

クラスのpublicセクションで、指定された次元で配列サイズを設定するメソッドを記述します。

      //--- Set the array size in the specified dimensionality
      bool              SetSizeRange(const int range,const int size)
                          {
                           if(range<this.m_total_int)
                              return this.Long().SetSizeRange(range,size);
                           else if(range<this.m_total_int+this.m_total_dbl)
                              return this.Double().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range),size);
                           else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str)
                              return this.String().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range),size);
                           return false;
                          }

メソッドロジックは、上記で検討したサイズ受信メソッドと同じです。

クラスコンストラクタは、整数、実数、および文字列オブジェクトのプロパティの数を受け取ります。これらの値は、適切なクラス変数に割り当てられます。次に、整数、実数、および文字列の動的多次元配列の新しいオブジェクトがリストに追加されます。配列の最初の次元の次元は、パラメータで渡された適切なプロパティの数に等しくなりますが、2番目の次元のサイズはプロパティ配列ごとに1に設定されます。

      //--- Constructor
                        CDataPropObj(const int prop_total_integer,const int prop_total_double,const int prop_total_string)
                          {
                           this.m_total_int=prop_total_integer;
                           this.m_total_dbl=prop_total_double;
                           this.m_total_str=prop_total_string;
                           this.m_list.Add(new CXDimArrayLong(this.m_total_int, 1));
                           this.m_list.Add(new CXDimArrayDouble(this.m_total_dbl,1));
                           this.m_list.Add(new CXDimArrayString(this.m_total_str,1));
                          }

クラスデストラクタで、リストから要素を削除し、配列のメモリを解放します。

      //--- Destructor
                       ~CDataPropObj()
                          {
                           m_list.Clear();
                           m_list.Shutdown();
                          }

その結果、オブジェクトプロパティクラスは次のようになります。

   //--- Object property class
   class CDataPropObj
     {
   private:
      CArrayObj         m_list;        // list of property objects
      int               m_total_int;   // Number of integer parameters
      int               m_total_dbl;   // Number of real parameters
      int               m_total_str;   // Number of string parameters
      //--- Return the index of the array the (1) double and (2) string properties are actually located at
      int               IndexProp(ENUM_GRAPH_OBJ_PROP_DOUBLE property)              const { return(int)property-this.m_total_int;                     }
      int               IndexProp(ENUM_GRAPH_OBJ_PROP_STRING property)              const { return(int)property-this.m_total_int-this.m_total_dbl;    }
   public:
      //--- Return the pointer to (1) the list of property objects, as well as to the object of (2) integer, (3) real and (4) string properties
      CArrayObj        *GetList(void)                                                     { return &this.m_list;                                      }
      CXDimArrayLong   *Long()                                                      const { return this.m_list.At(0);                                 }
      CXDimArrayDouble *Double()                                                    const { return this.m_list.At(1);                                 }
      CXDimArrayString *String()                                                    const { return this.m_list.At(2);                                 }
      //--- Set object's (1) integer, (2) real and (3) string properties
      void              Set(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value)    { this.Long().Set(property,index,value);                    }
      void              Set(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value)   { this.Double().Set(this.IndexProp(property),index,value);  }
      void              Set(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value)   { this.String().Set(this.IndexProp(property),index,value);  }
      //--- Return object’s (1) integer, (2) real and (3) string property from the properties array
      long              Get(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index)         const { return this.Long().Get(property,index);                   }
      double            Get(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index)          const { return this.Double().Get(this.IndexProp(property),index); }
      string            Get(ENUM_GRAPH_OBJ_PROP_STRING property,int index)          const { return this.String().Get(this.IndexProp(property),index); }
      
      //--- Return the size of the specified first dimension data array
      int               Size(const int range) const
                          {
                           if(range<this.m_total_int)
                              return this.Long().Size(range);
                           else if(range<this.m_total_int+this.m_total_dbl)
                              return this.Double().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range));
                           else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str)
                              return this.String().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range));
                           return 0;
                          }
      //--- Set the array size in the specified dimensionality
      bool              SetSizeRange(const int range,const int size)
                          {
                           if(range<this.m_total_int)
                              return this.Long().SetSizeRange(range,size);
                           else if(range<this.m_total_int+this.m_total_dbl)
                              return this.Double().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range),size);
                           else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str)
                              return this.String().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range),size);
                           return false;
                          }
      //--- Constructor
                        CDataPropObj(const int prop_total_integer,const int prop_total_double,const int prop_total_string)
                          {
                           this.m_total_int=prop_total_integer;
                           this.m_total_dbl=prop_total_double;
                           this.m_total_str=prop_total_string;
                           this.m_list.Add(new CXDimArrayLong(this.m_total_int, 1));
                           this.m_list.Add(new CXDimArrayDouble(this.m_total_dbl,1));
                           this.m_list.Add(new CXDimArrayString(this.m_total_str,1));
                          }
      //--- Destructor
                       ~CDataPropObj()
                          {
                           m_list.Clear();
                           m_list.Shutdown();
                          }
     };

ただし、オブジェクトプロパティの変更を追跡するには、そのすべてのプロパティの過去の状態を記憶し、現在の状態と比較する必要があります。これを実現するために、以前は2セットのオブジェクトプロパティを保持していましたが、新しく作成したクラスの2つのオブジェクトを含む別のクラスを作成することにします。最初のオブジェクトは現在のプロパティを格納するためのものであり、2番目のオブジェクトは前のプロパティを格納するためのものです。

また、クラスのprivateセクションで、現在および以前のプロパティの新しいデータクラスを宣言します。

   class CProperty
     {
      
     }

すべてのクラスフィールドとメソッドはpublicです。クラスを見てみましょう。これは比較的小さく、以前に検討されたクラスのオブジェクトを格納します。

   //--- Data class of the current and previous properties
   class CProperty
     {
   public:
      CDataPropObj     *Curr;    // Pointer to the current properties object
      CDataPropObj     *Prev;    // Pointer to the previous properties object
      //--- Set the array size ('size') in the specified dimension ('range')
      bool              SetSizeRange(const int range,const int size)
                          {
                           return(this.Curr.SetSizeRange(range,size) && this.Prev.SetSizeRange(range,size) ? true : false);
                          }
      //--- Return the size of the specified array of the (1) current and (2) previous first dimension data
      int               CurrSize(const int range)  const { return Curr.Size(range); }
      int               PrevSize(const int range)  const { return Prev.Size(range); }
      //--- Copy the current data to the previous one
      void              CurrentToPrevious(void)
                          {
                           //--- Copy all integer properties
                           for(int i=0;i<this.Curr.Long().Total();i++)
                              for(int r=0;r<this.Curr.Long().Size(i);r++)
                                 this.Prev.Long().Set(i,r,this.Curr.Long().Get(i,r));
                           //--- Copy all real properties
                           for(int i=0;i<this.Curr.Double().Total();i++)
                              for(int r=0;r<this.Curr.Double().Size(i);r++)
                                 this.Prev.Double().Set(i,r,this.Curr.Double().Get(i,r));
                           //--- Copy all string properties
                           for(int i=0;i<this.Curr.String().Total();i++)
                              for(int r=0;r<this.Curr.String().Size(i);r++)
                                 this.Prev.String().Set(i,r,this.Curr.String().Get(i,r));
                          }
      //--- Constructor
                        CProperty(const int prop_int_total,const int prop_double_total,const int prop_string_total)
                          {
                           this.Curr=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total);
                           this.Prev=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total);
                          }
     };

以前に作成したクラスのメソッドを処理するほかに、現在のプロパティを以前のプロパティにコピーするためのメソッドを追加しました。同じオブジェクトの2つの独立したコピーが必要なため、コピーは要素ごとに実行されます。CArrayObjクラスのAssignArrayメソッドを使用した場合、プロパティ値ではなくポインターをコピーします。これにより、オブジェクトの正確なコピーが作成されますが、あるオブジェクトのプロパティを変更すると、別のオブジェクトのプロパティが変更されることになります。これは必要ありません。

したがって、単純な配列を、実装したばかりの動的配列クラスオブジェクトに置き換えることは(まだ完全ではありませんが)、CPropertyクラスオブジェクトをグラフィカルオブジェクトプロパティへのポインターとして使用することを意味します。また、ライブラリクラスに複数の変更を加える必要があります。プロパティインデックスに加えて、価格と時間のピボットポイントのインデックス、またはプロパティを取得または設定するレベルのインデックスも指定する必要があります。


ライブラリクラスの改善

抽象グラフィカルオブジェクトクラスのprivateセクション(現在作業中)の。新しく記述されたプロパティクラスの直後に、グラフィカルオブジェクトプロパティのオブジェクトへのポインタオブジェクトピボットポイントの数を格納するための変数および単一のオブジェクトプロパティの複数の値を設定するためのメソッドを宣言します。

   CProperty        *Prop;                                              // Pointer to the properties object
   int               m_pivots;                                          // Number of object reference points
//--- Read and set (1) the time and (2) the price of the specified object pivot point
   void              SetTimePivot(const int index);
   void              SetPricePivot(const int index);
//--- Read and set (1) color, (2) style, (3) width, (4) value, (5) text of the specified object level
   void              SetLevelColor(const int index);
   void              SetLevelStyle(const int index);
   void              SetLevelWidth(const int index);
   void              SetLevelValue(const int index);
   void              SetLevelText(const int index);
//--- Read and set the BMP file name for the "Bitmap Level" object. Index: 0 - ON, 1 - OFF
   void              SetBMPFile(const int index);

クラスのpublicセクションで、すべてのGetメソッドとSetメソッドに、プロパティ配列の2番目の次元のインデックスを示すもう1つの変数を追加します。プロパティは、GetメソッドとSetメソッドを使用してCurrおよび CPropertyクラスのPrevフィールドから返され、受信されます。

public:
//--- Set object's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value)     { this.Prop.Curr.Set(property,index,value);  }
   void              SetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value)    { this.Prop.Curr.Set(property,index,value);  }
   void              SetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value)    { this.Prop.Curr.Set(property,index,value);  }
//--- Return object’s (1) integer, (2) real and (3) string property from the properties array
   long              GetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index)          const { return this.Prop.Curr.Get(property,index); }
   double            GetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index)           const { return this.Prop.Curr.Get(property,index); }
   string            GetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index)           const { return this.Prop.Curr.Get(property,index); }
      
//--- Set object's previous (1) integer, (2) real and (3) string properties
   void              SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Prop.Prev.Set(property,index,value);  }
   void              SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value){ this.Prop.Prev.Set(property,index,value);  }
   void              SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value){ this.Prop.Prev.Set(property,index,value);  }
//--- Return object’s (1) integer, (2) real and (3) string property from the previous properties array
   long              GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index)      const { return this.Prop.Prev.Get(property,index); }
   double            GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index)       const { return this.Prop.Prev.Get(property,index); }
   string            GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index)       const { return this.Prop.Prev.Get(property,index); }

2番目の次元のインデックスが指定されているため、GetProperty()、SetProperty()、GetPropertyPrev()、およびSetPropertyPrev()メソッドが使用されるクラスコード全体に沿って変更を行う必要があります。これは多くの記事スペースを必要とするため、ここでは複数の変更すべてについて説明しません。これらはすべて、以下に添付されているクラスコードに含まれています。代わりに、新しいメソッドといくつかの古いメソッドを考えてみましょう。

クラスのpublicセクションで、ピボットポイントとオブジェクトレベルの説明を返すメソッドを宣言します

//--- Return the description of the (1) (ENUM_OBJECT) graphical object type
   virtual string    TypeDescription(void)                                    const { return CMessage::Text(MSG_GRAPH_STD_OBJ_ANY);          }
//--- Return the description of the coordinate of the specified graphical object (1) price and (2) time
   virtual string    PriceDescription(const int index)      const { return ::DoubleToString(this.GetProperty(GRAPH_OBJ_PROP_PRICE,index),this.m_digits);       }
   virtual string    TimeDescription(const int index)       const { return ::TimeToString(this.GetProperty(GRAPH_OBJ_PROP_TIME,index),TIME_DATE|TIME_MINUTES); }
//--- Return the description of the specified level (1) color, (2) style, (3) width, (4) value
   virtual string    LevelColorDescription(const int index) const { return ::ColorToString((color)this.GetProperty(GRAPH_OBJ_PROP_LEVELCOLOR,index),true); }
   virtual string    LevelStyleDescription(const int index) const { return LineStyleDescription((ENUM_LINE_STYLE)this.GetProperty(GRAPH_OBJ_PROP_LEVELSTYLE,index)); }
   virtual string    LevelWidthDescription(const int index) const { return (string)this.GetProperty(GRAPH_OBJ_PROP_LEVELWIDTH,index); }
   virtual string    LevelValueDescription(const int index) const { return ::DoubleToString(this.GetProperty(GRAPH_OBJ_PROP_LEVELVALUE,index),5); }

//--- Return the descriptions of all (1) times, (2) prices, (3) pivot point times and prices,
//--- (4) level values, (6) all properties of all levels, (5) BMP files of the graphical object
   string            TimesDescription(void)        const;
   string            PricesDescription(void)       const;
   string            TimePricesDescription(void)   const;
   string            LevelColorsDescription(void)  const;
   string            LevelStylesDescription(void)  const;
   string            LevelWidthsDescription(void)  const;
   string            LevelValuesDescription(void)  const;
   string            LevelTextsDescription(void)   const;
   string            LevelsAllDescription(void)    const;
   string            BMPFilesDescription(void)     const;

protectedパラメトリッククラスコンストラクタで、さらに別のパラメータ、つまりその構築に必要なオブジェクトピボットポイントの数を渡します(つまり、子孫オブジェクトクラスをさらに改善して、このコンストラクタにピボットポイントの数を渡す必要があります) 。

//--- Default constructor
                     CGStdGraphObj(){ this.m_type=OBJECT_DE_TYPE_GSTD_OBJ; m_group=WRONG_VALUE; }
protected:
//--- Protected parametric constructor
                     CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type,
                                   const ENUM_GRAPH_OBJ_BELONG belong,
                                   const ENUM_GRAPH_OBJ_GROUP group,
                                   const long chart_id, const int pivots,
                                   const string name);

クラスコンストラクタの実装を見てみましょう。

//+------------------------------------------------------------------+
//| Protected parametric constructor                                 |
//+------------------------------------------------------------------+
CGStdGraphObj::CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type,
                             const ENUM_GRAPH_OBJ_BELONG belong,
                             const ENUM_GRAPH_OBJ_GROUP group,
                             const long chart_id,const int pivots,
                             const string name)
  {
   //--- Create the property object with the default values
   this.Prop=new CProperty(GRAPH_OBJ_PROP_INTEGER_TOTAL,GRAPH_OBJ_PROP_DOUBLE_TOTAL,GRAPH_OBJ_PROP_STRING_TOTAL);
   
//--- Set the number of pivot points and object levels
   this.m_pivots=pivots;
   int levels=(int)::ObjectGetInteger(chart_id,name,OBJPROP_LEVELS);

//--- Set the property array dimensionalities according to the number of pivot points and levels
   this.Prop.SetSizeRange(GRAPH_OBJ_PROP_TIME,this.m_pivots);
   this.Prop.SetSizeRange(GRAPH_OBJ_PROP_PRICE,this.m_pivots);
   this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELCOLOR,levels);
   this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELSTYLE,levels);
   this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELWIDTH,levels);
   this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELVALUE,levels);
   this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELTEXT,levels);
   this.Prop.SetSizeRange(GRAPH_OBJ_PROP_BMPFILE,2);
   
//--- Set the object (1) type, type of graphical (2) object, (3) element, (4) subwindow affiliation and (5) index, as well as (6) chart symbol Digits
   this.m_type=obj_type;
   this.SetName(name);
   CGBaseObj::SetChartID(chart_id);
   CGBaseObj::SetTypeGraphObject(CGBaseObj::GraphObjectType(obj_type));
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_STANDARD);
   CGBaseObj::SetBelong(belong);
   CGBaseObj::SetGroup(group);
   CGBaseObj::SetSubwindow(chart_id,name);
   CGBaseObj::SetDigits((int)::SymbolInfoInteger(::ChartSymbol(chart_id),SYMBOL_DIGITS));
   
//--- Save the integer properties inherent in all graphical objects but not present in the current one
   this.SetProperty(GRAPH_OBJ_PROP_CHART_ID,0,CGBaseObj::ChartID());                // Chart ID
   this.SetProperty(GRAPH_OBJ_PROP_WND_NUM,0,CGBaseObj::SubWindow());               // Chart subwindow index
   this.SetProperty(GRAPH_OBJ_PROP_TYPE,0,CGBaseObj::TypeGraphObject());            // Graphical object type (ENUM_OBJECT)
   this.SetProperty(GRAPH_OBJ_PROP_ELEMENT_TYPE,0,CGBaseObj::TypeGraphElement());   // Graphical element type (ENUM_GRAPH_ELEMENT_TYPE)
   this.SetProperty(GRAPH_OBJ_PROP_BELONG,0,CGBaseObj::Belong());                   // Graphical object affiliation
   this.SetProperty(GRAPH_OBJ_PROP_GROUP,0,CGBaseObj::Group());                     // Graphical object group
   this.SetProperty(GRAPH_OBJ_PROP_ID,0,0);                                         // Object ID
   this.SetProperty(GRAPH_OBJ_PROP_NUM,0,0);                                        // Object index in the list
   
//--- Save the properties inherent in all graphical objects and present in a graphical object
   this.PropertiesRefresh();
   
//--- Save basic properties in the parent object
   this.m_create_time=(datetime)this.GetProperty(GRAPH_OBJ_PROP_CREATETIME,0);
   this.m_back=(bool)this.GetProperty(GRAPH_OBJ_PROP_BACK,0);
   this.m_selected=(bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTED,0);
   this.m_selectable=(bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTABLE,0);
   this.m_hidden=(bool)this.GetProperty(GRAPH_OBJ_PROP_HIDDEN,0);

//--- Save the current properties to the previous ones
   this.PropertiesCopyToPrevData();
  }
//+-------------------------------------------------------------------+

ここでは、最初に、整数、実数、文字列のプロパティの数を指定して、グラフィカルオブジェクトプロパティクラスのオブジェクトを作成しました。次に、いくつかのパラメータ(ピボットポイントの価格と時間、レベルの数、および各レベルのプロパティ)を備えたプロパティについて、2次元で配列のサイズを設定します。 パラメータが1つしかないプロパティを設定および取得する場合は、2番目の次元でゼロに等しいパラメータインデックスを指定します

今回は、CGStdGraphObjオブジェクトをすべてのプロパティで比較するメソッドで、ループ内のプロパティ2番目の次元のサイズで比較します

//+------------------------------------------------------------------+
//| Compare CGStdGraphObj objects by all properties                  |
//+------------------------------------------------------------------+
bool CGStdGraphObj::IsEqual(CGStdGraphObj *compared_obj) const
  {
   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;
      for(int j=0;j<Prop.CurrSize(prop);j++)
         if(this.GetProperty(prop,j)!=compared_obj.GetProperty(prop,j)) return false; 
     }
   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;
      for(int j=0;j<Prop.CurrSize(prop);j++)
         if(this.GetProperty(prop,j)!=compared_obj.GetProperty(prop,j)) return false; 
     }
   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;
      for(int j=0;j<Prop.CurrSize(prop);j++)
         if(this.GetProperty(prop,j)!=compared_obj.GetProperty(prop,j)) return false; 
     }
   return true;
  }
//+------------------------------------------------------------------+

グラフィックオブジェクトのプロパティを取得および保存するメソッドで、複数の値を持つすべてのプロパティが、プロパティの数によってループ内に入力されるようになりました。

//+------------------------------------------------------------------+
//| Get and save the integer properties                              |
//+------------------------------------------------------------------+
void CGStdGraphObj::GetAndSaveINT(void)
  {
   //--- Properties inherent in all graphical objects and present in a graphical object
   this.SetProperty(GRAPH_OBJ_PROP_CREATETIME,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_CREATETIME));
   this.SetProperty(GRAPH_OBJ_PROP_CREATETIME,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_CREATETIME));  // Object creation time
   this.SetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_TIMEFRAMES));  // Object visibility on timeframes
   this.SetProperty(GRAPH_OBJ_PROP_BACK,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_BACK));              // Background object
   this.SetProperty(GRAPH_OBJ_PROP_ZORDER,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ZORDER));          // Priority of a graphical object for receiving the event of clicking on a chart
   this.SetProperty(GRAPH_OBJ_PROP_HIDDEN,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_HIDDEN));          // Disable displaying the name of a graphical object in the terminal object list
   this.SetProperty(GRAPH_OBJ_PROP_SELECTED,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_SELECTED));      // Object selection
   this.SetProperty(GRAPH_OBJ_PROP_SELECTABLE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_SELECTABLE));  // Object availability
   for(int i=0;i<this.m_pivots;i++)                                                                                  // Point time coordinates
      this.SetTimePivot(i);
   this.SetProperty(GRAPH_OBJ_PROP_COLOR,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_COLOR));            // Color
   this.SetProperty(GRAPH_OBJ_PROP_STYLE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_STYLE));            // Style
   this.SetProperty(GRAPH_OBJ_PROP_WIDTH,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_WIDTH));            // Line width
   //--- Properties belonging to different graphical objects
   this.SetProperty(GRAPH_OBJ_PROP_FILL,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_FILL));              // Fill an object with color
   this.SetProperty(GRAPH_OBJ_PROP_READONLY,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_READONLY));      // Ability to edit text in the Edit object
   this.SetProperty(GRAPH_OBJ_PROP_LEVELS,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_LEVELS));          // Number of levels
   for(int i=0;i<this.Levels();i++)                                                                                  // Level data
     {
      this.SetLevelColor(i);
      this.SetLevelStyle(i);
      this.SetLevelWidth(i);
     }
   this.SetProperty(GRAPH_OBJ_PROP_ALIGN,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ALIGN));            // Horizontal text alignment in the Edit object (OBJ_EDIT)
   this.SetProperty(GRAPH_OBJ_PROP_FONTSIZE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_FONTSIZE));      // Font size
   this.SetProperty(GRAPH_OBJ_PROP_RAY_LEFT,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_RAY_LEFT));      // Ray goes to the left
   this.SetProperty(GRAPH_OBJ_PROP_RAY_RIGHT,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_RAY_RIGHT));    // Ray goes to the right
   this.SetProperty(GRAPH_OBJ_PROP_RAY,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_RAY));                // Vertical line goes through all windows of a chart
   this.SetProperty(GRAPH_OBJ_PROP_ELLIPSE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ELLIPSE));        // Display the full ellipse of the Fibonacci Arc object
   this.SetProperty(GRAPH_OBJ_PROP_ARROWCODE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ARROWCODE));    // Arrow code for the "Arrow" object
   this.SetProperty(GRAPH_OBJ_PROP_ANCHOR,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ANCHOR));          // Position of the binding point of the graphical object
   this.SetProperty(GRAPH_OBJ_PROP_XDISTANCE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_XDISTANCE));    // Distance from the base corner along the X axis in pixels
   this.SetProperty(GRAPH_OBJ_PROP_YDISTANCE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_YDISTANCE));    // Distance from the base corner along the Y axis in pixels
   this.SetProperty(GRAPH_OBJ_PROP_DIRECTION,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_DIRECTION));    // Gann object trend
   this.SetProperty(GRAPH_OBJ_PROP_DEGREE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_DEGREE));          // Elliott wave marking level
   this.SetProperty(GRAPH_OBJ_PROP_DRAWLINES,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_DRAWLINES));    // Display lines for Elliott wave marking
   this.SetProperty(GRAPH_OBJ_PROP_STATE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_STATE));            // Button state (pressed/released)
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_ID,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_CHART_ID));// Chart object ID (OBJ_CHART).
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PERIOD,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_PERIOD));    // Chart object period
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_DATE_SCALE));  // Time scale display flag for the Chart object
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_PRICE_SCALE));// Price scale display flag for the Chart object
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_CHART_SCALE));// Chart object scale
   this.SetProperty(GRAPH_OBJ_PROP_XSIZE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_XSIZE));            // Object width along the X axis in pixels.
   this.SetProperty(GRAPH_OBJ_PROP_YSIZE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_YSIZE));            // Object height along the Y axis in pixels.
   this.SetProperty(GRAPH_OBJ_PROP_XOFFSET,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_XOFFSET));        // X coordinate of the upper-left corner of the visibility area.
   this.SetProperty(GRAPH_OBJ_PROP_YOFFSET,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_YOFFSET));        // Y coordinate of the upper-left corner of the visibility area.
   this.SetProperty(GRAPH_OBJ_PROP_BGCOLOR,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_BGCOLOR));        // Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
   this.SetProperty(GRAPH_OBJ_PROP_CORNER,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_CORNER));          // Chart corner for binding a graphical object
   this.SetProperty(GRAPH_OBJ_PROP_BORDER_TYPE,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_BORDER_TYPE));// Border type for "Rectangle border"
   this.SetProperty(GRAPH_OBJ_PROP_BORDER_COLOR,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_BORDER_COLOR));// Border color for OBJ_EDIT and OBJ_BUTTON
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Get and save the real properties                                 |
//+------------------------------------------------------------------+
void CGStdGraphObj::GetAndSaveDBL(void)
  {
   for(int i=0;i<this.m_pivots;i++)                                                                               // Point prices coordinates
      SetPricePivot(i);
   for(int i=0;i<this.Levels();i++)                                                                               // Level values
      this.SetLevelValue(i);
   this.SetProperty(GRAPH_OBJ_PROP_SCALE,0,::ObjectGetDouble(this.ChartID(),this.Name(),OBJPROP_SCALE));          // Scale (property of Gann objects and Fibonacci Arcs objects)
   this.SetProperty(GRAPH_OBJ_PROP_ANGLE,0,::ObjectGetDouble(this.ChartID(),this.Name(),OBJPROP_ANGLE));          // Angle
   this.SetProperty(GRAPH_OBJ_PROP_DEVIATION,0,::ObjectGetDouble(this.ChartID(),this.Name(),OBJPROP_DEVIATION));  // Deviation of the standard deviation channel
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Get and save the string properties                               |
//+------------------------------------------------------------------+
void CGStdGraphObj::GetAndSaveSTR(void)
  {
   this.SetProperty(GRAPH_OBJ_PROP_TEXT,0,::ObjectGetString(this.ChartID(),this.Name(),OBJPROP_TEXT));            // Object description (the text contained in the object)
   this.SetProperty(GRAPH_OBJ_PROP_TOOLTIP,0,::ObjectGetString(this.ChartID(),this.Name(),OBJPROP_TOOLTIP));      // Tooltip text
   for(int i=0;i<this.Levels();i++)                                                                               // Level descriptions
      this.SetLevelText(i);
   this.SetProperty(GRAPH_OBJ_PROP_FONT,0,::ObjectGetString(this.ChartID(),this.Name(),OBJPROP_FONT));            // Font
   this.SetProperty(GRAPH_OBJ_PROP_BMPFILE,0,::ObjectGetString(this.ChartID(),this.Name(),OBJPROP_BMPFILE));      // BMP file name for the "Bitmap Level" object
   this.SetProperty(GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL,0,::ObjectGetString(this.ChartID(),this.Name(),OBJPROP_SYMBOL));// Chart object symbol 
  }
//+------------------------------------------------------------------+

現在のデータを前のデータにコピーするメソッドで、現在のプロパティを前のプロパティにコピーするために特別に作成された現在のプロパティオブジェクトのメソッドを呼び出します。

//+------------------------------------------------------------------+
//| Copy the current data to the previous one                        |
//+------------------------------------------------------------------+
void CGStdGraphObj::PropertiesCopyToPrevData(void)
  {
   this.Prop.CurrentToPrevious();
  }
//+------------------------------------------------------------------+

オブジェクトのプロパティの変更をチェックするメソッドでは、最初にプロパティが複数であるかどうかを確認します。はいの場合は、プロパティインスタンスの数でループの変化を確認しますそれ以外の場合は、2つのオブジェクトのプロパティを比較するだけです

//+------------------------------------------------------------------+
//| Check object property changes                                    |
//+------------------------------------------------------------------+
void CGStdGraphObj::PropertiesCheckChanged(void)
  {
   bool changed=false;
   int begin=0, end=GRAPH_OBJ_PROP_INTEGER_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_INTEGER prop=(ENUM_GRAPH_OBJ_PROP_INTEGER)i;
      if(!this.SupportProperty(prop)) continue;
      if(prop==GRAPH_OBJ_PROP_TIME || (prop>=GRAPH_OBJ_PROP_LEVELCOLOR && prop<=GRAPH_OBJ_PROP_LEVELWIDTH))
        {
         int total=(prop==GRAPH_OBJ_PROP_TIME ? this.m_pivots : this.Levels());
         for(int j=0;j<Prop.CurrSize(prop);j++)
           {
            if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j))
              {
               changed=true;
               ::Print(DFUN,this.Name(),", property index: ",j," ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop));
              }
           }
        }
      else if(this.GetProperty(prop,0)!=this.GetPropertyPrev(prop,0))
        {
         changed=true;
         ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop));
        }
     }

   begin=end; end+=GRAPH_OBJ_PROP_DOUBLE_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_DOUBLE prop=(ENUM_GRAPH_OBJ_PROP_DOUBLE)i;
      if(!this.SupportProperty(prop)) continue;
      if(prop==GRAPH_OBJ_PROP_PRICE || GRAPH_OBJ_PROP_LEVELVALUE)
        {
         int total=(prop==GRAPH_OBJ_PROP_PRICE ? this.m_pivots : this.Levels());
         for(int j=0;j<Prop.CurrSize(prop);j++)
           {
            if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j))
              {
               changed=true;
               ::Print(DFUN,this.Name(),", property index: ",j," ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop));
              }
           }
        }
      else if(this.GetProperty(prop,0)!=this.GetPropertyPrev(prop,0))
        {
         changed=true;
         ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),GetPropertyDescription(prop));
        }
     }

   begin=end; end+=GRAPH_OBJ_PROP_STRING_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_STRING prop=(ENUM_GRAPH_OBJ_PROP_STRING)i;
      if(!this.SupportProperty(prop)) continue;
      if(prop==GRAPH_OBJ_PROP_LEVELTEXT || prop==GRAPH_OBJ_PROP_BMPFILE)
        {
         int total=(prop==GRAPH_OBJ_PROP_LEVELTEXT ? this.Levels() : 2);
         for(int j=0;j<Prop.CurrSize(prop);j++)
           {
            if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j))
              {
               changed=true;
               ::Print(DFUN,this.Name(),", property index: ",j," ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop));
              }
           }
        }
      else if(this.GetProperty(prop,0)!=this.GetPropertyPrev(prop,0))
        {
         changed=true;
         ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),GetPropertyDescription(prop));
        }
     }
   if(changed)
      PropertiesCopyToPrevData();
  }
//+------------------------------------------------------------------+


以下は、オブジェクトのプロパティを読み取って設定し、プロパティの説明を返すメソッドです。

//+------------------------------------------------------------------+
//| Read and set the time of the specified pivot point               |
//+------------------------------------------------------------------+
void CGStdGraphObj::SetTimePivot(const int index)
  {
   this.SetProperty(GRAPH_OBJ_PROP_TIME,index,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_TIME,index));
  }
//+------------------------------------------------------------------+
//| Read and set the price of the specified pivot point              |
//+------------------------------------------------------------------+
void CGStdGraphObj::SetPricePivot(const int index)
  {
   this.SetProperty(GRAPH_OBJ_PROP_PRICE,index,::ObjectGetDouble(this.ChartID(),this.Name(),OBJPROP_PRICE,index));
  }
//+------------------------------------------------------------------+
//| Read and set the color of the specified level                    |
//+------------------------------------------------------------------+
void CGStdGraphObj::SetLevelColor(const int index)
  {
   this.SetProperty(GRAPH_OBJ_PROP_LEVELCOLOR,index,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_LEVELCOLOR,index));
  }
//+------------------------------------------------------------------+
//| Read and set the style of the specified level                    |
//+------------------------------------------------------------------+
void CGStdGraphObj::SetLevelStyle(const int index)
  {
   this.SetProperty(GRAPH_OBJ_PROP_LEVELSTYLE,index,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_LEVELSTYLE,index));
  }
//+------------------------------------------------------------------+
//| Read and set the width of the specified level                    |
//+------------------------------------------------------------------+
void CGStdGraphObj::SetLevelWidth(const int index)
  {
   this.SetProperty(GRAPH_OBJ_PROP_LEVELWIDTH,index,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_LEVELWIDTH,index));
  }
//+------------------------------------------------------------------+
//| Read and set the value of the specified level                    |
//+------------------------------------------------------------------+
void CGStdGraphObj::SetLevelValue(const int index)
  {
   this.SetProperty(GRAPH_OBJ_PROP_LEVELVALUE,index,::ObjectGetDouble(this.ChartID(),this.Name(),OBJPROP_LEVELVALUE,index));
  }
//+------------------------------------------------------------------+
//| Read and set the text of the specified level                     |
//+------------------------------------------------------------------+
void CGStdGraphObj::SetLevelText(const int index)
  {
   this.SetProperty(GRAPH_OBJ_PROP_LEVELTEXT,index,::ObjectGetString(this.ChartID(),this.Name(),OBJPROP_LEVELTEXT,index));
  }
//+------------------------------------------------------------------+
//| Read and set the BMP file name                                   |
//| for the Bitmap Label object.                                     |
//| Index: 0 - ON, 1 - OFF                                           |
//+------------------------------------------------------------------+
void CGStdGraphObj::SetBMPFile(const int index)
  {
   this.SetProperty(GRAPH_OBJ_PROP_BMPFILE,index,::ObjectGetString(this.ChartID(),this.Name(),OBJPROP_BMPFILE,index));
  }
//+------------------------------------------------------------------+
//| Return the descriptions of all pivot point times                 |
//+------------------------------------------------------------------+
string CGStdGraphObj::TimesDescription(void) const
  {
   string txt="";
   for(int i=0;i<this.m_pivots;i++)
      txt+=" - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_PIVOT)+(string)i+": "+this.TimeDescription(i)+(i<this.m_pivots-1 ? "\n" : "");
   return txt;
  }
//+------------------------------------------------------------------+
//| Return the prices of all pivot points                            |
//+------------------------------------------------------------------+
string CGStdGraphObj::PricesDescription(void) const
  {
   string txt="";
   for(int i=0;i<this.m_pivots;i++)
      txt+=" - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_PIVOT)+(string)i+": "+this.PriceDescription(i)+(i<this.m_pivots-1 ? "\n" : "");
   return txt;
  }
//+------------------------------------------------------------------+
//| Return the descriptions of all pivot points                      |
//+------------------------------------------------------------------+
string CGStdGraphObj::TimePricesDescription(void) const
  {
   string txt="";
   for(int i=0;i<this.m_pivots;i++)
      txt+=(" - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_PIVOT)+(string)i+": "+this.TimeDescription(i)+" / "+this.PriceDescription(i)+(i<this.m_pivots-1 ? "\n" : ""));
   return txt;
  }
//+------------------------------------------------------------------+
//| Return the descriptions of all level colors                      |
//+------------------------------------------------------------------+
string CGStdGraphObj::LevelColorsDescription(void) const
  {
   string txt="";
   for(int i=0;i<this.Levels();i++)
      txt+=(" - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_LEVEL)+(string)i+": "+this.LevelColorDescription(i)+(i<this.Levels()-1 ? "\n" : ""));
   return txt;
  }
//+------------------------------------------------------------------+
//| Return the descriptions of all level styles                      |
//+------------------------------------------------------------------+
string CGStdGraphObj::LevelStylesDescription(void) const
  {
   string txt="";
   for(int i=0;i<this.Levels();i++)
      txt+=(" - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_LEVEL)+(string)i+": "+LineStyleDescription(this.LevelStyle(i))+(i<this.Levels()-1 ? "\n" : ""));
   return txt;
  }
//+------------------------------------------------------------------+
//| Return the descriptions of all level width                       |
//+------------------------------------------------------------------+
string CGStdGraphObj::LevelWidthsDescription(void) const
  {
   string txt="";
   for(int i=0;i<this.Levels();i++)
      txt+=(" - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_LEVEL)+(string)i+": "+this.LevelWidthDescription(i)+(i<this.Levels()-1 ? "\n" : ""));
   return txt;
  }
//+------------------------------------------------------------------+
//| Return the descriptions of all level values                      |
//+------------------------------------------------------------------+
string CGStdGraphObj::LevelValuesDescription(void) const
  {
   string txt="";
   for(int i=0;i<this.Levels();i++)
      txt+=(" - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_LEVEL)+(string)i+": "+this.LevelValueDescription(i)+(i<this.Levels()-1 ? "\n" : ""));
   return txt;
  }
//+------------------------------------------------------------------+
//| Return the descriptions of all level texts                       |
//+------------------------------------------------------------------+
string CGStdGraphObj::LevelTextsDescription(void) const
  {
   string txt="";
   for(int i=0;i<this.Levels();i++)
      txt+=(" - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_LEVEL)+(string)i+": "+this.LevelText(i)+(i<this.Levels()-1 ? "\n" : ""));
   return txt;
  }
//+------------------------------------------------------------------+
//| Return the descriptions of the graphical object BMP files        |
//+------------------------------------------------------------------+
string CGStdGraphObj::BMPFilesDescription(void) const
  {
   string txt=
     (
      " - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_ON) +" (0): \""+BMPFile(0)+"\"\n"+
      " - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_OFF)+" (1): \""+BMPFile(1)+"\""
     );
   return txt;
  }
//+------------------------------------------------------------------+
//| Return the descriptions of all values of all levels              |
//+------------------------------------------------------------------+
string CGStdGraphObj::LevelsAllDescription(void) const
  {
   string txt="";
   for(int i=0;i<this.Levels();i++)
     {
      txt+=
        (
         " - "+CMessage::Text(MSG_GRAPH_OBJ_TEXT_LEVEL)+" "+(string)i+"\n"+
         "    "+CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELCOLOR)+": "+LevelColorDescription(i)+"\n"+
         "    "+CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELSTYLE)+": "+LevelStyleDescription(i)+"\n"+
         "    "+CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELWIDTH)+": "+LevelWidthDescription(i)+"\n"+
         "    "+CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELVALUE)+": "+LevelValueDescription(i)+"\n"+
         "    "+CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELTEXT) +": "+LevelText(i)
        );
     }
   return txt;
  }
//+------------------------------------------------------------------+

これらのメソッドにはコメントはほとんど必要ないと思います。考慮されるすべてのメソッドと変更とは別に、クラスは2番目の次元のインデックスを指定するための複数の変更を備えています。ここでは説明しません。以下の添付ファイルでご覧ください。

クラスコンストラクタには、子クラスを作成するときにピボットポイントの数を渡す新しい変数があるため、そのような各オブジェクトのコンストラクターを修正する必要があります。2つのグラフィカルオブジェクトクラスファイルのみを検討します。

\MQL5\Include\DoEasy\Objects\Graph\Standard\GStdArrowBuyObj.mqh から購入サイングラフィカルオブジェクトクラスファイルを開き、オブジェクトピボットポイントの数のパラメータを親クラスコンストラクタに渡します

//+------------------------------------------------------------------+
//| Buy graphical object                                             |
//+------------------------------------------------------------------+
class CGStdArrowBuyObj : public CGStdGraphObj
  {
private:

public:
   //--- Constructor
                     CGStdArrowBuyObj(const long chart_id,const string name) : 
                        CGStdGraphObj(OBJECT_DE_TYPE_GSTD_ARROW_BUY,GRAPH_OBJ_BELONG_NO_PROGRAM,GRAPH_OBJ_GROUP_ARROWS,chart_id,1,name)
                          {
                           //--- Specify the object property
                           CGStdGraphObj::SetProperty(GRAPH_OBJ_PROP_ANCHOR,0,ANCHOR_TOP);
                          }
   //--- Supported object properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property);
   virtual bool      SupportProperty(ENUM_GRAPH_OBJ_PROP_STRING property);
//--- Return the graphical object anchor point position
   ENUM_ARROW_ANCHOR Anchor(void)            const { return (ENUM_ARROW_ANCHOR)this.GetProperty(GRAPH_OBJ_PROP_ANCHOR,0); }
//--- Display a short description of the object in the journal
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);
//--- Return the object short name
   virtual string    Header(const bool symbol=false);
//--- Return the description of the (ENUM_OBJECT) graphical object type
   virtual string    TypeDescription(void)   const { return StdGraphObjectTypeDescription(OBJ_ARROW_BUY);  }
//--- Return the description of the graphical object anchor point position
   virtual string    AnchorDescription(void) const { return AnchorForArrowObjDescription(this.Anchor()); }

  };
//+------------------------------------------------------------------+

このオブジェクトにはピボットポイントが1つだけあります。次に、いくつかのピボットポイントを持つオブジェクトについて考えてみましょう。

\MQL5\Include\DoEasy\Objects\Graph\Standard\GStdTrendObj.mqhから「トレンドライン」オブジェクトクラスファイルを開き、ピボットポイントの数(2に等しい)を親クラスコンストラクタ渡すようにします

//+------------------------------------------------------------------+
//| "Trend line" graphical object                                    |
//+------------------------------------------------------------------+
class CGStdTrendObj : public CGStdGraphObj
  {
private:

public:
   //--- Constructor
                     CGStdTrendObj(const long chart_id,const string name) :
                        CGStdGraphObj(OBJECT_DE_TYPE_GSTD_TREND,GRAPH_OBJ_BELONG_NO_PROGRAM,GRAPH_OBJ_GROUP_LINES,chart_id,2,name)
                          {
                           //--- Get and save the object properties
                           CGStdGraphObj::SetProperty(GRAPH_OBJ_PROP_RAY_LEFT,0,::ObjectGetInteger(chart_id,name,OBJPROP_RAY_LEFT));
                           CGStdGraphObj::SetProperty(GRAPH_OBJ_PROP_RAY_RIGHT,0,::ObjectGetInteger(chart_id,name,OBJPROP_RAY_RIGHT));
                          }
   //--- Supported object properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property);
   virtual bool      SupportProperty(ENUM_GRAPH_OBJ_PROP_STRING property);
//--- Display a short description of the object in the journal
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);
//--- Return the object short name
   virtual string    Header(const bool symbol=false);
//--- Return the description of the (ENUM_OBJECT) graphical object type
   virtual string    TypeDescription(void)   const { return StdGraphObjectTypeDescription(OBJ_TREND); }
  };
//+------------------------------------------------------------------+

このような変更は、\MQL5\Include\DoEasy\Objects\Graph\Standard\のクラスごとに行われました。各オブジェクトには、それを構築するために使用される正確な数のピボットポイントがあります。以下に添付されているファイルですべての変更を表示できます。

それでは、\MQL5\Include\DoEasy\Services\Select.mqhのCSelectクラスを改善しましょう。ここでは、GetProperty()メソッドにアクセスする各メソッドに2次元目のインデックスを追加する必要があります。

//+------------------------------------------------------------------+
//| Methods of working with standard graphical object data           |
//+------------------------------------------------------------------+
   //--- Return the list of objects with one of (1) integer, (2) real and (3) string properties meeting a specified criterion
   static CArrayObj *ByGraphicStdObjectProperty(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByGraphicStdObjectProperty(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByGraphicStdObjectProperty(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value,ENUM_COMPARER_TYPE mode);
   //--- Return the graphical object index in the list with the maximum value of the (1) integer, (2) real and (3) string properties
   static int        FindGraphicStdObjectMax(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_INTEGER property,int index);
   static int        FindGraphicStdObjectMax(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index);
   static int        FindGraphicStdObjectMax(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_STRING property,int index);
   //--- Return the graphical object index in the list with the minimum value of the (1) integer, (2) real and (3) string properties
   static int        FindGraphicStdObjectMin(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_INTEGER property,int index);
   static int        FindGraphicStdObjectMin(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index);
   static int        FindGraphicStdObjectMin(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_STRING property,int index);
//---
  };
//+------------------------------------------------------------------+

いくつかのメソッドの実装について考えてみましょう。

//+------------------------------------------------------------------+
//| Return the list of objects with one integer                      |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByGraphicStdObjectProperty(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,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++)
     {
      CGStdGraphObj *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      long obj_prop=obj.GetProperty(property,index);
      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::FindGraphicStdObjectMax(CArrayObj *list_source,ENUM_GRAPH_OBJ_PROP_INTEGER property,int index)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int idx=0;
   CGStdGraphObj *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CGStdGraphObj *obj=list_source.At(i);
      long obj1_prop=obj.GetProperty(property,index);
      max_obj=list_source.At(idx);
      long obj2_prop=max_obj.GetProperty(property,index);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) idx=i;
     }
   return idx;
  }
//+------------------------------------------------------------------+

すべての変更はcolorで強調表示されます。残りのメソッドは、上記のメソッドと同じように変更されます。以下に添付されているファイルで、それらに精通することができます。

次に、\MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqhのグラフィカルオブジェクトコレクションクラスを変更しましょう。

GetList() publicメソッドで、配列の2次元目ののインデックスを表示するようにします

public:
//--- Return itself
   CGraphElementsCollection *GetObject(void)                                                             { return &this;                        }
//--- Return the full collection list of standard graphical objects "as is"
   CArrayObj        *GetListGraphObj(void)                                                               { return &this.m_list_all_graph_obj;   }
//--- Return the full collection list of graphical elements on canvas "as is"
   CArrayObj        *GetListCanvElm(void)                                                                { return &this.m_list_all_canv_elm_obj;}
//--- Return the list of graphical elements by a selected (1) integer, (2) real and (3) string properties meeting the compared criterion
   CArrayObj        *GetList(ENUM_CANV_ELEMENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByGraphCanvElementProperty(this.GetListCanvElm(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_CANV_ELEMENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByGraphCanvElementProperty(this.GetListCanvElm(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_CANV_ELEMENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByGraphCanvElementProperty(this.GetListCanvElm(),property,value,mode);  }
//--- Return the list of graphical objects by a selected (1) integer, (2) real and (3) string properties meeting the compared criterion
   CArrayObj        *GetList(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value,ENUM_COMPARER_TYPE mode=EQUAL)    { return CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),property,index,value,mode); }
   CArrayObj        *GetList(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value,ENUM_COMPARER_TYPE mode=EQUAL)   { return CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),property,index,value,mode); }
   CArrayObj        *GetList(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value,ENUM_COMPARER_TYPE mode=EQUAL)   { return CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),property,index,value,mode); }

改善されたCSelectクラスメソッドへのアクセスを特徴とするすべてのメソッド、配列の2次元目のインデックスの表示を追加します

//+------------------------------------------------------------------+
//| Return the first free graphical object ID                        |
//+------------------------------------------------------------------+
long CGraphElementsCollection::GetFreeGraphObjID(void)
  {
   int index=CSelect::FindGraphicStdObjectMax(this.GetListGraphObj(),GRAPH_OBJ_PROP_ID,0);
   CGStdGraphObj *obj=this.m_list_all_graph_obj.At(index);
   return(obj!=NULL ? obj.ObjectID()+1 : 1);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|Find an object present in the collection but not on a chart       |
//+------------------------------------------------------------------+
CGStdGraphObj *CGraphElementsCollection::FindMissingObj(const long chart_id)
  {
   CArrayObj *list=CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_CHART_ID,0,chart_id,EQUAL);
   if(list==NULL)
      return NULL;
   for(int i=0;i<list.Total();i++)
     {
      CGStdGraphObj *obj=list.At(i);
      if(obj==NULL)
         continue;
      if(!this.IsPresentGraphObjOnChart(obj.ChartID(),obj.Name()))
         return obj;
     }
   return NULL;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------------------+
//| Return the flag indicating the presence of the graphical object class object |
//| in the graphical object collection list                                      |
//+------------------------------------------------------------------------------+
bool CGraphElementsCollection::IsPresentGraphObjInList(const long chart_id,const string name)
  {
   CArrayObj *list=CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_CHART_ID,0,chart_id,EQUAL);
   list=CSelect::ByGraphicStdObjectProperty(list,GRAPH_OBJ_PROP_NAME,0,name,EQUAL);
   return(list==NULL || list.Total()==0 ? false : true);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Remove a graphical object by a chart ID                          |
//| from the graphical object collection list                        |
//+------------------------------------------------------------------+
void CGraphElementsCollection::DeleteGraphObjectsFromList(const long chart_id)
  {
   CArrayObj *list=CSelect::ByGraphicStdObjectProperty(GetListGraphObj(),GRAPH_OBJ_PROP_CHART_ID,0,chart_id,EQUAL);
   if(list==NULL)
      return;
   for(int i=list.Total();i>WRONG_VALUE;i--)
     {
      CGStdGraphObj *obj=list.At(i);
      if(obj==NULL)
         continue;
      this.DeleteGraphObjFromList(obj);
     }
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Return a graphical object by chart name and ID                   |
//+------------------------------------------------------------------+
CGStdGraphObj *CGraphElementsCollection::GetStdGraphObject(const string name,const long chart_id)
  {
   CArrayObj *list=this.GetList(GRAPH_OBJ_PROP_CHART_ID,0,chart_id);
   list=CSelect::ByGraphicStdObjectProperty(list,GRAPH_OBJ_PROP_NAME,0,name,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(0) : NULL);
  }
//+------------------------------------------------------------------+

グラフィカルオブジェクトをコレクションに追加するメソッドでは、短いオブジェクトの説明ではなく完全なオブジェクトの説明を表示します。これにより、テスト中でオブジェクトのプロパティの完全なリストを確認できます。

//+------------------------------------------------------------------+
//| Add a graphical object to the collection                         |
//+------------------------------------------------------------------+
bool CGraphElementsCollection::AddGraphObjToCollection(const string source,CChartObjectsControl *obj_control)
  {
   //--- Get the list of the last added graphical objects from the class for managing graphical objects
   CArrayObj *list=obj_control.GetListNewAddedObj();
   //--- If failed to obtain the list, inform of that and return 'false'
   if(list==NULL)
     {
      CMessage::ToLog(DFUN_ERR_LINE,MSG_GRAPH_OBJ_FAILED_GET_ADDED_OBJ_LIST);
      return false;
     }
   //--- If the list is empty, return 'false'
   if(list.Total()==0)
      return false;
   //--- Declare the variable for storing the result
   bool res=true;
   //--- In the loop by the list of newly added standard graphical objects,
   for(int i=0;i<list.Total();i++)
     {
      //--- retrieve the next object from the list and
      CGStdGraphObj *obj=list.Detach(i);
      //--- if failed to get the object, inform of that, add 'false' to the resulting variable and move on to the next one
      if(obj==NULL)
        {
         CMessage::ToLog(source,MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST);
         res &=false;
         continue;
        }
      //--- if failed to add the object to the collection list, inform of that,
      //--- remove the object, add 'false' to the resulting variable and move on to the next one
      if(!this.m_list_all_graph_obj.Add(obj))
        {
         CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
         delete obj;
         res &=false;
         continue;
        }
      //--- The object has been successfully retrieved from the list of newly added graphical objects and introduced into the collection -
      //--- find the next free object ID, write it to the property and display the short object description in the journal
      else
        {
         obj.SetObjectID(this.GetFreeGraphObjID());
         obj.Print();
        }
     }
   //--- Return the result of adding the object to the collection
   return res;
  }
//+------------------------------------------------------------------+

私がここで実装しようとしていた改善はこれですべてです。私が記事で考慮しなかった小さいが多数の変更は、以下のファイルで見つけることができます。


2つのアンカーポイントを使用したオブジェクトイベントのテスト

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

ライブラリファイルで行われているため、EAを変更する必要はありません。

EAをコンパイルし、チャート上で起動します。


2つのピボットポイントを持つオブジェクトを追加するとき、および2つのピボットポイントのいずれかを変更するとき、EAは操作ログに適切なイベントエントリを表示します。3つ以上のピボットポイントで構成されるオブジェクトをチャートに追加すると、ポイント変更エントリがなくなるか、別のポイントを変更するときに1つのポイントのデータが変更されます。これは、上記の論理エラーが原因で発生します。次の記事で修正します。


次の段階

次の記事では、標準のグラフィカルオブジェクトイベントと動的配列クラスの作業を続けます。

ライブラリの現在のバージョンのすべてのファイルは、テストおよびダウンロードできるように、MQL5のテストEAファイルと一緒に以下に添付されています。EAが正しく機能するには、前の記事のライブラリの指標ファイルが必要であることにご注意ください

質問や提案はコメント欄にお願いします。

目次に戻る

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

DoEasyライブラリのグラフィックス(第82部): ライブラリオブジェクトのリファクタリングとグラフィカルオブジェクトのコレクション
DoEasyライブラリのグラフィックス(第83部): 抽象標準グラフィカルオブジェクトのクラス
DoEasyライブラリのグラフィックス(第84部): 抽象標準グラフィカルオブジェクトの子孫クラス
DoEasyライブラリのグラフィックス(第85部): グラフィカルオブジェクトコレクション - 新規作成オブジェクトの追加
DoEasyライブラリのグラフィックス(第86部): グラフィカルオブジェクトコレクション - プロパティ変更の管理
DoEasyライブラリのグラフィックス(第87部): グラフィカルオブジェクトコレクション - プロパティ変更の管理

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

添付されたファイル |
MQL5.zip (4164.99 KB)
時間の取扱い(第1部):基本 時間の取扱い(第1部):基本
時間の処理、証券会社のオフセット、夏時間または冬時間への変更を簡素化および明確化する関数とコードスニペット。正確なタイミングは取引において重要な要素になることがあります。現在時刻でロンドンやニューヨークの証券取引所がすでに開いているかまだ開いていないか、外国為替取引の取引時間はいつ開始および終了するかなどです。手動で取引して生活しているトレーダーにとって、これは大きな問題ではありません。
MQL5.communityでのチャネルとグループチャットの使用 MQL5.communityでのチャネルとグループチャットの使用
MQL5.com Webサイトには、世界中のトレーダーが集まっています。ユーザーは記事を公開し、無料コードを共有し、市場で製品を販売し、フリーランスの注文を実行し、取引シグナルをコピーできます。フォーラム、トレーダーチャット、MetaTraderチャネルでは彼らとコミュニケーションをとることができます。
EAコンストラクタの開発の試み EAコンストラクタの開発の試み
この記事では、既製のEAの形で一連の取引機能を提供します。この方法では、指標を追加して入力を変更するだけで、複数の取引ストラテジーを取得できます。
DoEasyライブラリのグラフィックス(第87部): グラフィカルオブジェクトコレクション - プロパティ変更の管理 DoEasyライブラリのグラフィックス(第87部): グラフィカルオブジェクトコレクション - プロパティ変更の管理
本稿では、標準のグラフィカルオブジェクトイベントの追跡作業を継続し、ユーザがターミナルで開いたチャートに配置されたグラフィカルオブジェクトのプロパティの変更を制御できる機能を作成します。