DoEasyライブラリのグラフィックス(第88部): グラフィカルオブジェクトコレクション - 動的に変化するオブジェクトのプロパティを格納するための2次元動的配列
内容
概念
これまでのすべての記事では、単純な配列を使用してオブジェクトのプロパティデータを格納していました。整数、実数、文字列のプロパティの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から派生した任意のオブジェクトを格納できます。つまり、配列セルには、long、double、stringのいずれかの型のデータと、別の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つのメソッド(実際には、doubleとstringのオブジェクトプロパティを格納)も宣言します。
//+------------------------------------------------------------------+ //| 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つのポイントのデータが変更されます。これは、上記の論理エラーが原因で発生します。次の記事で修正します。
次の段階
次の記事では、標準のグラフィカルオブジェクトイベントと動的配列クラスの作業を続けます。
質問や提案はコメント欄にお願いします。
**連載のこれまでの記事:
DoEasyライブラリのグラフィックス(第82部): ライブラリオブジェクトのリファクタリングとグラフィカルオブジェクトのコレクション
DoEasyライブラリのグラフィックス(第83部): 抽象標準グラフィカルオブジェクトのクラス
DoEasyライブラリのグラフィックス(第84部): 抽象標準グラフィカルオブジェクトの子孫クラス
DoEasyライブラリのグラフィックス(第85部): グラフィカルオブジェクトコレクション - 新規作成オブジェクトの追加
DoEasyライブラリのグラフィックス(第86部): グラフィカルオブジェクトコレクション - プロパティ変更の管理
DoEasyライブラリのグラフィックス(第87部): グラフィカルオブジェクトコレクション - プロパティ変更の管理
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/10091
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索