English Русский 中文 Español Deutsch Português
preview
DoEasy - コントロール(第6部):パネルコントロール、内部コンテンツに合わせたコンテナサイズの自動変更

DoEasy - コントロール(第6部):パネルコントロール、内部コンテンツに合わせたコンテナサイズの自動変更

MetaTrader 5 | 19 8月 2022, 07:54
245 0
Artyom Trishkin
Artyom Trishkin

内容


概念

本稿では、パネルにバインドされたオブジェクトのDockプロパティがアクティブに設定されている場合のパネルの自動サイズ変更を実装します。バインドされたオブジェクトのいずれかにプロパティが設定されている場合は、そのバインド場所に配置する必要がありますが、パネルのサイズをバインドされたすべてのオブジェクトの合計サイズに調整する必要があります。つまり、パネルに接続されたオブジェクトのいずれかでDockプロパティが設定されると、パネルサイズが変更されます。プロパティが多数の次々に接続されたオブジェクトに対して設定されている場合、次にオブジェクトがバインドされるごとに変更された内部コンテンツに合わせて、パネルサイズを調整する必要があります。

新しいオブジェクト配置に合わせてパネルサイズを調整すると、不快な視覚効果が生じます。それらを回避するために、オブジェクトをパネルにバインドして変更する一括処理を最適化しました。最後のバインドされたオブジェクトが本来あるべき場所に配置された後にのみ、視覚的にパネルサイズを調整します。
現在の記事では、コンテナ内のオブジェクトの一括配置処理の最適化を続けます。

WinFormsオブジェクトの作業に加えて、MetaTrader 5ビルド3260で以前に発表された銘柄ライブラリオブジェクトに新しいプロパティを追加します。

MQL5:ENUM_SYMBOL_INFO_DOUBLE列挙の新しいプロパティ:

  • SYMBOL_SWAP_SUNDAY
  • SYMBOL_SWAP_MONDAY
  • SYMBOL_SWAP_TUESDAY
  • SYMBOL_SWAP_WEDNESDAY
  • SYMBOL_SWAP_THURSDAY
  • SYMBOL_SWAP_FRIDAY
  • SYMBOL_SWAP_SATURDAY

値を使用して、特定の曜日のスワップ計算レートを取得します。1:シングル スワップ、3:トリプル スワップ、0:スワップなし。

新しいプロパティは、新しく作成されたWinFormsオブジェクトのクラス変数として追加されます。同時に、すべてのライブラリ オブジェクトは、ライブラリの作成に特化した最初の記事で説明されている特定の概念に従って構築されます。各オブジェクトには、整数、実数、文字列オブジェクトプロパティの3つの列挙にある一連のプロパティがあります。今回の記事では、以前に追加されたすべての新しいWinFormsオブジェクトプロパティがこれらの列挙型の定数になるようにします。この場合、新しいプロパティは、各グラフィカルオブジェクトの一般的なプロパティ リストに配置されます。後で、これにより、すべてのWinFormsオブジェクトプロパティを使用してそれらをグラフィカル要素に表示できるようになります。たとえば、ターミナルでEAのグラフィカルシェルやMS Visual Studioのような指標を視覚的に構築するためのプログラムのGUIなどです。


ライブラリクラスの改善

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

   MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3245,          // Property not supported in MetaTrader 5 versions lower than 3245
   MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260,          // Property not supported in MetaTrader 5 versions lower than 3260
   MSG_LIB_PROP_NOT_SUPPORTED_POSITION,               // Property not supported for position


...

   MSG_SYM_PROP_SUBSCRIPTION_DELAY,                   // Delay for quotes passed by symbol for instruments working on subscription basis
   MSG_SYM_PROP_SWAP_SUNDAY,                          // Swap accrual ratio. Sunday
   MSG_SYM_PROP_SWAP_MONDAY,                          // Swap accrual ratio. Monday
   MSG_SYM_PROP_SWAP_TUESDAY,                         // Swap accrual ratio. Tuesday
   MSG_SYM_PROP_SWAP_WEDNESDAY,                       // Swap accrual ratio. Wednesday
   MSG_SYM_PROP_SWAP_THURSDAY,                        // Swap accrual ratio. Thursday
   MSG_SYM_PROP_SWAP_FRIDAY,                          // Swap accrual ratio. Friday
   MSG_SYM_PROP_SWAP_SATURDAY,                        // Swap accrual ratio. Saturday
   MSG_SYM_PROP_SWAP_1,                               // Single swap accrual
   MSG_SYM_PROP_SWAP_3,                               // Triple swap accrual
   MSG_SYM_PROP_SWAP_0,                               // No swap accrual
   //---
   MSG_SYM_PROP_BIDHIGH,                              // Maximal Bid of the day


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

   {"Свойство не поддерживается в MetaTrader5 версии ниже 3245","The property is not supported in MetaTrader5, build lower than 3245"},
   {"Свойство не поддерживается в MetaTrader5 версии ниже 3260","The property is not supported in MetaTrader5, build lower than 3260"},
   {"Свойство не поддерживается у позиции","Property not supported for position"},


...

   {"Размер задержки у котировок, передаваемых по символу, для инструментов, работающих по подписке","Delay size for quotes transmitted per symbol for instruments working by subscription"},
   {"Коэффициент начисления свопов. Воскресение","Swap rate. Sunday"},
   {"Коэффициент начисления свопов. Понедельник","Swap rate. Monday"},
   {"Коэффициент начисления свопов. Вторник","Swap rate. Tuesday"},
   {"Коэффициент начисления свопов. Среда","Swap rate. Wednesday"},
   {"Коэффициент начисления свопов. Четверг","Swap rate. Thursday"},
   {"Коэффициент начисления свопов. Пятница","Swap rate. Friday"},
   {"Коэффициент начисления свопов. Суббота","Swap rate. Saturday"},
   {"Одиночное начисление свопов","Single swap accrual"},
   {"Тройное начисление свопов","Triple swap accrual"},
   {"Начисление свопов отсутствует","No accrual"},
   
   {"Максимальный Bid за день","Maximal Bid of the day"},



\MQL5\Include\DoEasy\Defines.mqhで、銘柄オブジェクトの実数プロパティの列挙に新しいプロパティを追加し、実数銘柄プロパティの数を68から75に増やします

   SYMBOL_PROP_PRICE_SENSITIVITY,                           // Option/warrant sensitivity.  Shows by how many points the price of the option's underlying asset should change so that the price of the option changes by one point
   SYMBOL_PROP_SWAP_SUNDAY,                                 // Swap accrual ratio (Sunday)
   SYMBOL_PROP_SWAP_MONDAY,                                 // Swap accrual ratio (Monday)
   SYMBOL_PROP_SWAP_TUESDAY,                                // Swap accrual ratio (Tuesday)
   SYMBOL_PROP_SWAP_WEDNESDAY,                              // Swap accrual ratio (Wednesday)
   SYMBOL_PROP_SWAP_THURSDAY,                               // Swap accrual ratio (Thursday)
   SYMBOL_PROP_SWAP_FRIDAY,                                 // Swap accrual ratio (Friday)
   SYMBOL_PROP_SWAP_SATURDAY,                               // Swap accrual ratio (Saturday)
  };
#define SYMBOL_PROP_DOUBLE_TOTAL     (75)                   // Total number of real properties
#define SYMBOL_PROP_DOUBLE_SKIP      (0)                    // Number of real symbol properties not used in sorting
//+------------------------------------------------------------------+


銘柄オブジェクトを並べ替え、新しいプロパティで選択を実行できるようにするには、追加されたプロパティに対応する新しい定数を、可能な銘柄オブジェクトの並べ替え条件の列挙に追加します。

   SORT_BY_SYMBOL_PRICE_SENSITIVITY,                        // Sort by option/warrant sensitivity
   SORT_BY_SYMBOL_SWAP_SUNDAY,                              // Sort by swap accrual ratio (Sunday)
   SORT_BY_SYMBOL_SWAP_MONDAY,                              // Sort by swap accrual ratio (Monday)
   SORT_BY_SYMBOL_SWAP_TUESDAY,                             // Sort by swap accrual ratio (Tuesday)
   SORT_BY_SYMBOL_SWAP_WEDNESDAY,                           // Sort by swap accrual ratio (Wednesday)
   SORT_BY_SYMBOL_SWAP_THURSDAY,                            // Sort by swap accrual ratio (Thursday)
   SORT_BY_SYMBOL_SWAP_FRIDAY,                              // Sort by swap accrual ratio (Friday)
   SORT_BY_SYMBOL_SWAP_SATURDAY,                            // Sort by swap accrual ratio (Saturday)
//--- Sort by string properties
   SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP,                // Sort by a symbol name



canvasベースのグラフィカル要素の整数プロパティの列挙で、これらのプロパティを格納するWinFormsオブジェクトの以前に追加された変数に対応するプロパティを追加し、オブジェクトの整数プロパティの数を25から38に増やします

   CANV_ELEMENT_PROP_ENABLED,                         // Element availability flag
   CANV_ELEMENT_PROP_FORE_COLOR,                      // Default text color for all control objects
   CANV_ELEMENT_PROP_BOLD_TYPE,                       // Font width type
   CANV_ELEMENT_PROP_BORDER_STYLE,                    // Control frame style
   CANV_ELEMENT_PROP_AUTOSIZE,                        // Flag of the element auto resizing depending on the content
   CANV_ELEMENT_PROP_DOCK_MODE,                       // Mode of binding control borders to the container
   CANV_ELEMENT_PROP_MARGIN_TOP,                      // Top margin between the fields of this and another control
   CANV_ELEMENT_PROP_MARGIN_BOTTOM,                   // Bottom margin between the fields of this and another control
   CANV_ELEMENT_PROP_MARGIN_LEFT,                     // Left margin between the fields of this and another control
   CANV_ELEMENT_PROP_MARGIN_RIGHT,                    // Right margin between the fields of this and another control
   CANV_ELEMENT_PROP_PADDING_TOP,                     // Top margin inside the control
   CANV_ELEMENT_PROP_PADDING_BOTTOM,                  // Bottom margin inside the control
   CANV_ELEMENT_PROP_PADDING_LEFT,                    // Left margin inside the control
   CANV_ELEMENT_PROP_PADDING_RIGHT,                   // Right margin inside the control
  };
#define CANV_ELEMENT_PROP_INTEGER_TOTAL (38)          // Total number of integer properties
#define CANV_ELEMENT_PROP_INTEGER_SKIP  (0)           // Number of integer properties not used in sorting


WinFormsオブジェクトの可能な並べ替え条件の列挙で、新しく追加された整数プロパティによる並べ替えを追加します

   SORT_BY_CANV_ELEMENT_ENABLED,                      // Sort by the element availability flag
   SORT_BY_CANV_ELEMENT_FORE_COLOR,                   // Sort by default text color for all control objects
   SORT_BY_CANV_ELEMENT_BOLD_TYPE,                    // Sort by font width type
   SORT_BY_CANV_ELEMENT_BORDER_STYLE,                 // Sort by control frame style
   SORT_BY_CANV_ELEMENT_AUTOSIZE,                     // Sort by the flag of the element auto resizing depending on the content
   SORT_BY_CANV_ELEMENT_DOCK_MODE,                    // Sort by mode of binding control borders to the container
   SORT_BY_CANV_ELEMENT_MARGIN_TOP,                   // Sort by top margin between the fields of this and another control
   SORT_BY_CANV_ELEMENT_MARGIN_BOTTOM,                // Sort by bottom margin between the fields of this and another control
   SORT_BY_CANV_ELEMENT_MARGIN_LEFT,                  // Sort by left margin between the fields of this and another control
   SORT_BY_CANV_ELEMENT_MARGIN_RIGHT,                 // Sort by right margin between the fields of this and another control
   SORT_BY_CANV_ELEMENT_PADDING_TOP,                  // Sort by top margin inside the control
   SORT_BY_CANV_ELEMENT_PADDING_BOTTOM,               // Sort by bottom margin inside the control
   SORT_BY_CANV_ELEMENT_PADDING_LEFT,                 // Sort by left margin inside the control
   SORT_BY_CANV_ELEMENT_PADDING_RIGHT,                // Sort by right margin inside the control
//--- Sort by real properties

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


WinFormsオブジェクトは、WinFormsオブジェクトのみに固有のグラフィカルオブジェクトプロパティによって選択および並び替えできるようになります。


新しいプロパティが銘柄オブジェクトに追加されたので、銘柄オブジェクトクラスでそれらの処理を実装する必要があります。

\MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqhクラスファイルで必要な改善をおこないます。

クラスのprotectedセクションにある選択された銘柄の実数プロパティをパラメータから受け取って返すメソッドのブロックで、指定された曜日のスワップ比率を返すメソッドを宣言します

   double            SymbolMarginHedged(void)            const;
   double            SymbolSwapRatio(ENUM_DAY_OF_WEEK day)const;
   bool              SymbolMarginLong(void);



クラスのpublicセクションで、指定された曜日のスワップ発生率の説明を返すメソッドを宣言します

   string            GetSectorDescription(void)                   const;
   string            GetIndustryDescription(void)                 const;
   string            GetSwapRatioDescription(const ENUM_DAY_OF_WEEK day)const;



銘柄オブジェクトの実数プロパティへの簡単なアクセスのためのメソッドのブロックで、各曜日のスワップ発生率を返すメソッドを記述し、指定された曜日のスワップ発生率を返すメソッドを宣言します

   double            PriceSensitivity(void)                       const { return this.GetProperty(SYMBOL_PROP_PRICE_SENSITIVITY);                           }
   double            SwapRatioSunday(void)                        const { return this.GetProperty(SYMBOL_PROP_SWAP_SUNDAY);                                 }
   double            SwapRatioMonday(void)                        const { return this.GetProperty(SYMBOL_PROP_SWAP_MONDAY);                                 }
   double            SwapRatioTuesday(void)                       const { return this.GetProperty(SYMBOL_PROP_SWAP_TUESDAY);                                }
   double            SwapRatioWednesday(void)                     const { return this.GetProperty(SYMBOL_PROP_SWAP_WEDNESDAY);                              }
   double            SwapRatioThursday(void)                      const { return this.GetProperty(SYMBOL_PROP_SWAP_THURSDAY);                               }
   double            SwapRatioFriday(void)                        const { return this.GetProperty(SYMBOL_PROP_SWAP_FRIDAY);                                 }
   double            SwapRatioSaturday(void)                      const { return this.GetProperty(SYMBOL_PROP_SWAP_SATURDAY);                               }
   double            SwapRatioDay(const ENUM_DAY_OF_WEEK day)     const;
   double            NormalizedPrice(const double price)          const;



追跡されたプロパティの変更のパラメータを受け取り、設定するためのメソッドのブロックで、新しい銘柄オブジェクトプロパティを処理するためのメソッドを追加します

   //--- Option/warrant sensitivity
   //--- setting the controlled maximum Bid price (1) increase, (2) decrease value and (3) option/warrant sensitivity control level in points
   //--- getting (4) option/warrant sensitivity change value in points,
   //--- getting the flag of the option/warrant sensitivity change exceeding the (5) increase, (6) decrease value
   void              SetControlPriceSensitivityInc(const double value)        { this.SetControlledValueINC(SYMBOL_PROP_PRICE_SENSITIVITY,::fabs(value));             }
   void              SetControlPriceSensitivityDec(const double value)        { this.SetControlledValueDEC(SYMBOL_PROP_PRICE_SENSITIVITY,::fabs(value));             }
   void              SetControlPriceSensitivityLevel(const double value)      { this.SetControlledValueLEVEL(SYMBOL_PROP_PRICE_SENSITIVITY,::fabs(value));           }
   double            GetValueChangedPriceSensitivity(void)              const { return this.GetPropDoubleChangedValue(SYMBOL_PROP_PRICE_SENSITIVITY);                }
   bool              IsIncreasedPriceSensitivity(void)                  const { return (bool)this.GetPropDoubleFlagINC(SYMBOL_PROP_PRICE_SENSITIVITY);               }
   bool              IsDecreasedPriceSensitivity(void)                  const { return (bool)this.GetPropDoubleFlagDEC(SYMBOL_PROP_PRICE_SENSITIVITY);               }
//--- Swap accrual ratio
   //--- setting the controlled Sunday swap accrual ratio (1) increase, (2) decrease and (3) control levels
   //--- get (4) the swap accrual ratio change (Sunday),
   //--- get the swap accrual ratio change for Sunday exceeding the (5) increase and (6) decrease values
   void              SetControlSwapSundayInc(const double value)              { this.SetControlledValueINC(SYMBOL_PROP_SWAP_SUNDAY,::fabs(value));                   }
   void              SetControlSwapSundayDec(const double value)              { this.SetControlledValueDEC(SYMBOL_PROP_SWAP_SUNDAY,::fabs(value));                   }
   void              SetControlSwapSundayLevel(const double value)            { this.SetControlledValueLEVEL(SYMBOL_PROP_SWAP_SUNDAY,::fabs(value));                 }
   double            GetValueChangedSwapSunday(void)                    const { return this.GetPropDoubleChangedValue(SYMBOL_PROP_SWAP_SUNDAY);                      }
   bool              IsIncreasedSwapSunday(void)                        const { return (bool)this.GetPropDoubleFlagINC(SYMBOL_PROP_SWAP_SUNDAY);                     }
   bool              IsDecreasedSwapSunday(void)                        const { return (bool)this.GetPropDoubleFlagDEC(SYMBOL_PROP_SWAP_SUNDAY);                     }
   //--- setting the controlled Monday swap accrual ratio (1) increase, (2) decrease and (3) control levels
   //--- get (4) the swap accrual ratio change (Monday),
   //--- get the swap accrual ratio change for Monday exceeding the (5) increase and (6) decrease values
   void              SetControlSwapMondayInc(const double value)              { this.SetControlledValueINC(SYMBOL_PROP_SWAP_MONDAY,::fabs(value));                   }
   void              SetControlSwapMondayDec(const double value)              { this.SetControlledValueDEC(SYMBOL_PROP_SWAP_MONDAY,::fabs(value));                   }
   void              SetControlSwapMondayLevel(const double value)            { this.SetControlledValueLEVEL(SYMBOL_PROP_SWAP_MONDAY,::fabs(value));                 }
   double            GetValueChangedSwapMonday(void)                    const { return this.GetPropDoubleChangedValue(SYMBOL_PROP_SWAP_MONDAY);                      }
   bool              IsIncreasedSwapMonday(void)                        const { return (bool)this.GetPropDoubleFlagINC(SYMBOL_PROP_SWAP_MONDAY);                     }
   bool              IsDecreasedSwapMonday(void)                        const { return (bool)this.GetPropDoubleFlagDEC(SYMBOL_PROP_SWAP_MONDAY);                     }
   //--- setting the controlled Tuesday swap accrual ratio (1) increase, (2) decrease and (3) control levels
   //--- get (4) the swap accrual ratio change (Tuesday),
   //--- get the swap accrual ratio change for Tuesday exceeding the (5) increase and (6) decrease values
   void              SetControlSwapTuesdayInc(const double value)             { this.SetControlledValueINC(SYMBOL_PROP_SWAP_TUESDAY,::fabs(value));                  }
   void              SetControlSwapTuesdayDec(const double value)             { this.SetControlledValueDEC(SYMBOL_PROP_SWAP_TUESDAY,::fabs(value));                  }
   void              SetControlSwapTuesdayLevel(const double value)           { this.SetControlledValueLEVEL(SYMBOL_PROP_SWAP_TUESDAY,::fabs(value));                }
   double            GetValueChangedSwapTuesday(void)                   const { return this.GetPropDoubleChangedValue(SYMBOL_PROP_SWAP_TUESDAY);                     }
   bool              IsIncreasedSwapTuesday(void)                       const { return (bool)this.GetPropDoubleFlagINC(SYMBOL_PROP_SWAP_TUESDAY);                    }
   bool              IsDecreasedSwapTuesday(void)                       const { return (bool)this.GetPropDoubleFlagDEC(SYMBOL_PROP_SWAP_TUESDAY);                    }
   //--- setting the controlled Wednesday swap accrual ratio (1) increase, (2) decrease and (3) control levels
   //--- get (4) the swap accrual ratio change (Wednesday),
   //--- get the swap accrual ratio change for Wednesday exceeding the (5) increase and (6) decrease values
   void              SetControlSwapWednesdayInc(const double value)           { this.SetControlledValueINC(SYMBOL_PROP_SWAP_WEDNESDAY,::fabs(value));                }
   void              SetControlSwapWednesdayDec(const double value)           { this.SetControlledValueDEC(SYMBOL_PROP_SWAP_WEDNESDAY,::fabs(value));                }
   void              SetControlSwapWednesdayLevel(const double value)         { this.SetControlledValueLEVEL(SYMBOL_PROP_SWAP_WEDNESDAY,::fabs(value));              }
   double            GetValueChangedSwapWednesday(void)                 const { return this.GetPropDoubleChangedValue(SYMBOL_PROP_SWAP_WEDNESDAY);                   }
   bool              IsIncreasedSwapWednesday(void)                     const { return (bool)this.GetPropDoubleFlagINC(SYMBOL_PROP_SWAP_WEDNESDAY);                  }
   bool              IsDecreasedSwapWednesday(void)                     const { return (bool)this.GetPropDoubleFlagDEC(SYMBOL_PROP_SWAP_WEDNESDAY);                  }
   //--- setting the controlled Thursday swap accrual ratio (1) increase, (2) decrease and (3) control levels
   //--- get (4) the swap accrual ratio change (Thursday),
   //--- get the swap accrual ratio change for Thursday exceeding the (5) increase and (6) decrease values
   void              SetControlSwapThursdayInc(const double value)            { this.SetControlledValueINC(SYMBOL_PROP_SWAP_THURSDAY,::fabs(value));                 }
   void              SetControlSwapThursdayDec(const double value)            { this.SetControlledValueDEC(SYMBOL_PROP_SWAP_THURSDAY,::fabs(value));                 }
   void              SetControlSwapThursdayLevel(const double value)          { this.SetControlledValueLEVEL(SYMBOL_PROP_SWAP_THURSDAY,::fabs(value));               }
   double            GetValueChangedSwapThursday(void)                  const { return this.GetPropDoubleChangedValue(SYMBOL_PROP_SWAP_THURSDAY);                    }
   bool              IsIncreasedSwapThursday(void)                      const { return (bool)this.GetPropDoubleFlagINC(SYMBOL_PROP_SWAP_THURSDAY);                   }
   bool              IsDecreasedSwapThursday(void)                      const { return (bool)this.GetPropDoubleFlagDEC(SYMBOL_PROP_SWAP_THURSDAY);                   }
   //--- setting the controlled Friday swap accrual ratio (1) increase, (2) decrease and (3) control levels
   //--- get (4) the swap accrual ratio change (Friday),
   //--- get the swap accrual ratio change for Friday exceeding the (5) increase and (6) decrease values
   void              SetControlSwapFridayInc(const double value)              { this.SetControlledValueINC(SYMBOL_PROP_SWAP_FRIDAY,::fabs(value));                   }
   void              SetControlSwapFridayDec(const double value)              { this.SetControlledValueDEC(SYMBOL_PROP_SWAP_FRIDAY,::fabs(value));                   }
   void              SetControlSwapFridayLevel(const double value)            { this.SetControlledValueLEVEL(SYMBOL_PROP_SWAP_FRIDAY,::fabs(value));                 }
   double            GetValueChangedSwapFriday(void)                    const { return this.GetPropDoubleChangedValue(SYMBOL_PROP_SWAP_FRIDAY);                      }
   bool              IsIncreasedSwapFriday(void)                        const { return (bool)this.GetPropDoubleFlagINC(SYMBOL_PROP_SWAP_FRIDAY);                     }
   bool              IsDecreasedSwapFriday(void)                        const { return (bool)this.GetPropDoubleFlagDEC(SYMBOL_PROP_SWAP_FRIDAY);                     }
   //--- setting the controlled Saturday swap accrual ratio (1) increase, (2) decrease and (3) control levels
   //--- get (4) the swap accrual ratio change (Saturday),
   //--- get the swap accrual ratio change for Saturday exceeding the (5) increase and (6) decrease values
   void              SetControlSwapSaturdayInc(const double value)            { this.SetControlledValueINC(SYMBOL_PROP_SWAP_SATURDAY,::fabs(value));                 }
   void              SetControlSwapSaturdayDec(const double value)            { this.SetControlledValueDEC(SYMBOL_PROP_SWAP_SATURDAY,::fabs(value));                 }
   void              SetControlSwapSaturdayLevel(const double value)          { this.SetControlledValueLEVEL(SYMBOL_PROP_SWAP_SATURDAY,::fabs(value));               }
   double            GetValueChangedSwapSaturday(void)                  const { return this.GetPropDoubleChangedValue(SYMBOL_PROP_SWAP_SATURDAY);                    }
   bool              IsIncreasedSwapSaturday(void)                      const { return (bool)this.GetPropDoubleFlagINC(SYMBOL_PROP_SWAP_SATURDAY);                   }
   bool              IsDecreasedSwapSaturday(void)                      const { return (bool)this.GetPropDoubleFlagDEC(SYMBOL_PROP_SWAP_SATURDAY);                   }

//--- Return a trading object
   CTradeObj        *GetTradeObj(void)                                           { return &this.m_trade; }

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


これらのメソッドを使用すると、制御されるパラメータを変更する追跡値をプログラムから直接設定できます。このような変更を登録するとき、プログラムでイベントに関するシグナルを受け取る必要があります。ライブラリオブジェクトの対話性を開発する際に、それらを既に考慮しました

Protectedパラメトリッククラスコンストラクタで、銘柄オブジェクトの新しいプロパティを保存するようにします。

   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SUNDAY)]                      = this.SymbolSwapRatio(SUNDAY);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_MONDAY)]                      = this.SymbolSwapRatio(MONDAY);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_TUESDAY)]                     = this.SymbolSwapRatio(TUESDAY);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_WEDNESDAY)]                   = this.SymbolSwapRatio(WEDNESDAY);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_THURSDAY)]                    = this.SymbolSwapRatio(THURSDAY);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_FRIDAY)]                      = this.SymbolSwapRatio(FRIDAY);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SATURDAY)]                    = this.SymbolSwapRatio(SATURDAY);
//--- Save string properties
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_NAME)]                             = this.m_name;


SymbolSwapRatio()メソッド(以下で検討)を使用して受け取った値は、ここでオブジェクトプロパティの配列に設定されます。

宣言された新しいメソッドの実装をクラス本体の外で書きましょう。

以下は、指定された曜日のスワップ発生率を返すprotectedメソッドです。

//+------------------------------------------------------------------+
//|Return the swap accrual ratio for a specified day of the week     |
//+------------------------------------------------------------------+
double CSymbol::SymbolSwapRatio(ENUM_DAY_OF_WEEK day) const
  {
#ifdef __MQL4__ 
   return 0;
#else 
   switch(day)
     {
      case MONDAY    :  return ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_MONDAY);
      case TUESDAY   :  return ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_TUESDAY);
      case WEDNESDAY :  return ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_WEDNESDAY);
      case THURSDAY  :  return ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_THURSDAY);
      case FRIDAY    :  return ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_FRIDAY);
      case SATURDAY  :  return ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_SATURDAY);
      //---SUNDAY
      default        :  return (int)::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_SUNDAY);
     }
#endif 
  }
//+------------------------------------------------------------------+


MQL4にはそのような銘柄はないので、ゼロを返しますMQL5の場合メソッドに渡された曜日に応じて適切な銘柄プロパティを返します 。このメソッドは、クラスコンストラクタで銘柄プロパティをその実数プロパティの列挙に設定するために使用されます。

以下は、指定された曜日のスワップ発生率を返すpublicメソッドです。

//+------------------------------------------------------------------+
//|Return the swap accrual ratio for a specified day of the week     |
//+------------------------------------------------------------------+
double CSymbol::SwapRatioDay(const ENUM_DAY_OF_WEEK day) const
  {
   switch(day)
     {
      case MONDAY    :  return this.SwapRatioMonday();
      case TUESDAY   :  return this.SwapRatioTuesday();
      case WEDNESDAY :  return this.SwapRatioWednesday();
      case THURSDAY  :  return this.SwapRatioThursday();
      case FRIDAY    :  return this.SwapRatioFriday();
      case SATURDAY  :  return this.SwapRatioSaturday();
      //---SUNDAY
      default        :  return this.SwapRatioSunday();
     }
  }
//+------------------------------------------------------------------+


ここでは、メソッドに渡された曜日に応じて、publicメソッドを使用してプロパティ値を取得し、実数オブジェクトプロパティの列挙に設定された特定の曜日のプロパティ値を返します

銘柄の実数プロパティの説明を返すメソッドで、銘柄オブジェクトの新しいプロパティの説明を返すようにします。

      property==SYMBOL_PROP_PRICE_SENSITIVITY   ?  CMessage::Text(MSG_SYM_PROP_PRICE_SENSITIVITY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==SYMBOL_PROP_SWAP_SUNDAY      ?  CMessage::Text(MSG_SYM_PROP_SWAP_SUNDAY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         #ifdef __MQL5__
         (::TerminalInfoInteger(TERMINAL_BUILD)<3260 ?  ": ("+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260)+")" : 
                                                        ": "+this.GetSwapRatioDescription(SUNDAY))
         #else ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4) #endif 
         )  :
      property==SYMBOL_PROP_SWAP_MONDAY      ?  CMessage::Text(MSG_SYM_PROP_SWAP_MONDAY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         #ifdef __MQL5__
         (::TerminalInfoInteger(TERMINAL_BUILD)<3260 ?  ": ("+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260)+")" : 
                                                        ": "+this.GetSwapRatioDescription(MONDAY))
         #else ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4) #endif 
         )  :
      property==SYMBOL_PROP_SWAP_TUESDAY     ?  CMessage::Text(MSG_SYM_PROP_SWAP_TUESDAY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         #ifdef __MQL5__
         (::TerminalInfoInteger(TERMINAL_BUILD)<3260 ?  ": ("+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260)+")" : 
                                                        ": "+this.GetSwapRatioDescription(TUESDAY))
         #else ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4) #endif 
         )  :
      property==SYMBOL_PROP_SWAP_WEDNESDAY   ?  CMessage::Text(MSG_SYM_PROP_SWAP_WEDNESDAY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         #ifdef __MQL5__
         (::TerminalInfoInteger(TERMINAL_BUILD)<3260 ?  ": ("+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260)+")" : 
                                                        ": "+this.GetSwapRatioDescription(WEDNESDAY))
         #else ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4) #endif 
         )  :
      property==SYMBOL_PROP_SWAP_THURSDAY    ?  CMessage::Text(MSG_SYM_PROP_SWAP_THURSDAY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         #ifdef __MQL5__
         (::TerminalInfoInteger(TERMINAL_BUILD)<3260 ?  ": ("+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260)+")" : 
                                                        ": "+this.GetSwapRatioDescription(THURSDAY))
         #else ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4) #endif 
         )  :
      property==SYMBOL_PROP_SWAP_FRIDAY      ?  CMessage::Text(MSG_SYM_PROP_SWAP_FRIDAY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         #ifdef __MQL5__
         (::TerminalInfoInteger(TERMINAL_BUILD)<3260 ?  ": ("+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260)+")" : 
                                                        ": "+this.GetSwapRatioDescription(FRIDAY))
         #else ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4) #endif 
         )  :
      property==SYMBOL_PROP_SWAP_SATURDAY    ?  CMessage::Text(MSG_SYM_PROP_SWAP_SATURDAY)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
         #ifdef __MQL5__
         (::TerminalInfoInteger(TERMINAL_BUILD)<3260 ?  ": ("+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260)+")" : 
                                                        ": "+this.GetSwapRatioDescription(SATURDAY))
         #else ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4) #endif 
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+


ここでターミナルのビルドを確認し、3260未満の場合、そのようなプロパティはこのバージョンではサポートされていないことが通知されます。それ以外の場合、MQL5のプロパティの説明を取得しますが、MQL4の場合、プロパティがサポートされていないという通知が表示されます。

以下は、指定された曜日のスワップ発生率の説明を返すメソッドです。

//+------------------------------------------------------------------+
//| Return the swap accrual ratio description                        |
//| for a specified day of the week                                  |
//+------------------------------------------------------------------+
string CSymbol::GetSwapRatioDescription(const ENUM_DAY_OF_WEEK day) const
  {
   double ratio=this.SwapRatioDay(day);
   return
     (
      ratio==0 ? CMessage::Text(MSG_SYM_PROP_SWAP_0)  :
      ratio==1 ? CMessage::Text(MSG_SYM_PROP_SWAP_1)  :
      ratio==3 ? CMessage::Text(MSG_SYM_PROP_SWAP_3)  : 
      ::DoubleToString(ratio,3)
     );
  }
//+------------------------------------------------------------------+


ここでは、まずメソッドに渡された曜日のプロパティ値を取得し、次に プロパティ値のテキスト記述(値が 0、1、3のいずれかの場合)を返すか、テキストに変換されたdouble値を小数点以下3桁まで表示します(表示される小数点以下の桁数は、十分な数のテストを実行した後にのみ定義できます)。

オブジェクトをグラフィカルオブジェクトファイル(および将来的にすべてのライブラリオブジェクト)に保存するには、オブジェクトプロパティ構造体を使用する必要があります。すべてのプロパティは構造体に保存されますが、構造体自体はファイルに保存されます。同様に、構造体をファイルから読み取ってオブジェクトのプロパティを復元できます。
グラフィカルオブジェクトに新しいプロパティがあるため、それらを構造体に追加する必要があります。

\MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh、オブジェクト構造体に新しいプロパティを追加します

private:
   int               m_shift_coord_x;                          // Offset of the X coordinate relative to the base object
   int               m_shift_coord_y;                          // Offset of the Y coordinate relative to the base object
   struct SData
     {
      //--- Object integer properties
      int            id;                                       // Element ID
      int            type;                                     // Graphical element type
      int            number;                                   // Element index in the list
      long           chart_id;                                 // Chart ID
      int            subwindow;                                // Chart subwindow index
      int            coord_x;                                  // Element X coordinate on the chart
      int            coord_y;                                  // Element Y coordinate on the chart
      int            width;                                    // Element width
      int            height;                                   // Element height
      int            edge_right;                               // Element right border
      int            edge_bottom;                              // Element bottom border
      int            act_shift_left;                           // Active area offset from the left edge of the element
      int            act_shift_top;                            // Active area offset from the top edge of the element
      int            act_shift_right;                          // Active area offset from the right edge of the element
      int            act_shift_bottom;                         // Active area offset from the bottom edge of the element
      bool           movable;                                  // Element moveability flag
      bool           active;                                   // Element activity flag
      bool           interaction;                              // Flag of interaction with the outside environment
      int            coord_act_x;                              // X coordinate of the element active area
      int            coord_act_y;                              // Y coordinate of the element active area
      int            coord_act_right;                          // Right border of the element active area
      int            coord_act_bottom;                         // Bottom border of the element active area
      long           zorder;                                   // Priority of a graphical object for receiving the event of clicking on a chart
      bool           enabled;                                  // Element availability flag
      int            belong;                                   // Graphical element affiliation
      color          fore_color;                               // Default text color for all control objects
      int            bold_type;                                // Font width type
      int            border_style;                             // Control frame style
      bool           autosize;                                 // Flag of the element auto resizing depending on the content
      int            dock_mode;                                // Mode of binding control borders to the container
      int            margin_top;                               // Top margin between the fields of this and another control
      int            margin_bottom;                            // Bottom margin between the fields of this and another control
      int            margin_left;                              // Left margin between the fields of this and another control
      int            margin_right;                             // Right margin between the fields of this and another control
      int            padding_top;                              // Top margin inside the control
      int            padding_bottom;                           // Bottom margin inside the control
      int            padding_left;                             // Left margin inside the control
      int            padding_right;                            // Right margin inside the control
      uchar          opacity;                                  // Element opacity
      color          color_bg;                                 // Element background color
      //--- Object real properties

      //--- Object string properties
      uchar          name_obj[64];                             // Graphical element object name
      uchar          name_res[64];                             // Graphical resource name
     };
   SData             m_struct_obj;                             // Object structure



オブジェクト構造体を作成するメソッドで、オブジェクトプロパティを構造体フィールドに書き込むようにします。

   this.m_struct_obj.coord_act_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM);      // Bottom border of the element active area
   this.m_struct_obj.belong=(int)this.GetProperty(CANV_ELEMENT_PROP_BELONG);                    // Graphical element affiliation
   this.m_struct_obj.zorder=this.GetProperty(CANV_ELEMENT_PROP_ZORDER);                         // Priority of a graphical object for receiving the on-chart mouse click event
   this.m_struct_obj.fore_color=(color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR);          // Default text color for all control objects
   this.m_struct_obj.bold_type=(int)this.GetProperty(CANV_ELEMENT_PROP_BOLD_TYPE);              // Font width type
   this.m_struct_obj.border_style=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_STYLE);        // Control frame style
   this.m_struct_obj.autosize=this.GetProperty(CANV_ELEMENT_PROP_AUTOSIZE);                     // Flag of the element auto resizing depending on the content
   this.m_struct_obj.dock_mode=(int)this.GetProperty(CANV_ELEMENT_PROP_DOCK_MODE);              // Mode of binding control borders to the container
   this.m_struct_obj.margin_top=(int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_TOP);            // Top margin between the fields of this and another control
   this.m_struct_obj.margin_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM);      // Bottom margin between the fields of this and another control
   this.m_struct_obj.margin_left=(int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT);          // Left margin between the fields of this and another control
   this.m_struct_obj.margin_right=(int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT);        // Right margin between the fields of this and another control
   this.m_struct_obj.padding_top=(int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_TOP);          // Top margin inside the control
   this.m_struct_obj.padding_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM);    // Bottom margin inside the control
   this.m_struct_obj.padding_left=(int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_LEFT);        // Left margin inside the control
   this.m_struct_obj.padding_right=(int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT);      // Right margin inside the control
   this.m_struct_obj.color_bg=this.m_color_bg;                                                  // Element background color
   this.m_struct_obj.opacity=this.m_opacity;                                                    // Element opacity



構造体からオブジェクトを作成するメソッドで、構造体のフィールドからオブジェクトプロパティを読み取るようにします。

   this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.m_struct_obj.coord_act_bottom);           // Bottom border of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_BELONG,this.m_struct_obj.belong);                         // Graphical element affiliation
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,this.m_struct_obj.fore_color);                 // Default text color for all control objects
   this.SetProperty(CANV_ELEMENT_PROP_BOLD_TYPE,this.m_struct_obj.bold_type);                   // Font width type
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,this.m_struct_obj.border_style);             // Control frame style
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE,this.m_struct_obj.autosize);                     // Flag of the element auto resizing depending on the content
   this.SetProperty(CANV_ELEMENT_PROP_DOCK_MODE,this.m_struct_obj.dock_mode);                   // Mode of binding control borders to the container
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_TOP,this.m_struct_obj.margin_top);                 // Top margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM,this.m_struct_obj.margin_bottom);           // Bottom margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT,this.m_struct_obj.margin_left);               // Left margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT,this.m_struct_obj.margin_right);             // Right margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_TOP,this.m_struct_obj.padding_top);               // Top margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM,this.m_struct_obj.padding_bottom);         // Bottom margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_LEFT,this.m_struct_obj.padding_left);             // Left margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT,this.m_struct_obj.padding_right);           // Right margin inside the control
   this.SetZorder(this.m_struct_obj.zorder,false);                                              // Priority of a graphical object for receiving the on-chart mouse click event
   this.m_color_bg=this.m_struct_obj.color_bg;                                                  // Element background color
   this.m_opacity=this.m_struct_obj.opacity;                                                    // Element opacity


これで、ライブラリオブジェクトのプロパティをファイルに保存し始めると、すべてのグラフィカルオブジェクトがファイルに正しく保存され、そこから復元されるようになります。


\MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqhのWinFormsオブジェクトの基本クラスを少し改善しましょう。

まず、これらのオブジェクトを選択し、それらのプロパティで並べ替える必要があります。これを実現するには、CSelectクラスファイルをインクルードします。

//+------------------------------------------------------------------+
//|                                                  WinFormBase.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\Form.mqh"
#include "..\..\..\Services\Select.mqh"
//+------------------------------------------------------------------+


これで、継承されたすべてのクラスでCSelectクラスを使用して、WinFormsオブジェクトをそのプロパティで選択および並べ替えることができます。

さらに、オブジェクトを再描画するメソッド内のすべての接続されたオブジェクトを処理するループに再描画フラグのチェックを追加して、再描画フラグがアクティブな場合にのみオブジェクトが実際に再描画されるようにします。そうでない場合は、バインドされたオブジェクトを再描画する必要はありません(たとえば、パネルオブジェクトのプロパティを変更するときに視覚的なアーティファクトを取り除くため)。再描画フラグがリセットされると、コンテナにバインドされたオブジェクトは、他のメソッドでプロパティが変更されるため、実際には再描画されませんが、ここではすべてのオブジェクトが実際に再描画されます。

したがって、フラグのチェックを追加し、フラグが設定されている場合にのみオブジェクトの再描画を呼び出します

//+------------------------------------------------------------------+
//| Redraw the object                                                |
//+------------------------------------------------------------------+
void CWinFormBase::Redraw(bool redraw)
  {
//--- If the object type is less than the "Base WinForms object", exit
   if(this.TypeGraphElement()<GRAPH_ELEMENT_TYPE_WF_BASE)
      return;
//--- Get the "Shadow" object
   CShadowObj *shadow=this.GetShadowObj();
//--- If the object has a shadow and the "Shadow" object exists, redraw it
   if(this.IsShadow() && shadow!=NULL)
     {
      //--- remove the previously drawn shadow,
      shadow.Erase();
      //--- save the relative shadow coordinates,
      int x=shadow.CoordXRelative();
      int y=shadow.CoordYRelative();
      //--- redraw the shadow,
      if(redraw)
         shadow.Draw(0,0,shadow.Blur(),redraw);
      //--- restore relative shadow coordinates
      shadow.SetCoordXRelative(x);
      shadow.SetCoordYRelative(y);
     }
//--- If the redraw flag is set,
   if(redraw)
     {
      //--- completely redraw the object and save its new initial look
      this.Erase(this.m_array_colors_bg,this.Opacity(),this.m_gradient_v,this.m_gradient_c,redraw);
      this.Done();
     }
//--- otherwise, remove the object
   else
      this.Erase();
//--- Redraw all bound objects with the redraw flag
   for(int i=0;i<this.ElementsTotal();i++)
     {
      CWinFormBase *element=this.GetElement(i);
      if(element==NULL)
         continue;
      if(redraw)
         element.Redraw(redraw);
     }
//--- If the redraw flag is set and if this is the main object the rest are bound to,
//--- redraw the chart to display changes immediately
   if(redraw && this.GetMain()==NULL)
      ::ChartRedraw(this.ChartID());
  }
//+------------------------------------------------------------------+


次に、\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Panel.mqhのPanel WinFormsオブジェクトのクラスを改良してみましょう。

クラスのprivateセクションで、Dockオブジェクトのバインディング座標を計算するメソッドを宣言します

//--- Set the underlay as a coordinate system zero
   void              SetUnderlayAsBase(void);
//--- Calculate Dock objects' binding coordinates
   void              CalculateCoords(CArrayObj *list);

protected:


この記事ではメソッドを実装しないので、クラス本体の外側に空のメソッドを追加します。

//+------------------------------------------------------------------+
//| Calculate Dock objects' binding coordinates                      |
//+------------------------------------------------------------------+
void CPanel::CalculateCoords(CArrayObj *list)
  {
   
  }
//+------------------------------------------------------------------+

テキストラベル(Label) WinFormsオブジェクトクラスを作成した後、その実装に対処します。これにより、オブジェクトがDockプロパティの値に従ってバインドされると、オブジェクトの並べ替えを視覚的に確認できます。同時に、コンテナにバインドされたオブジェクトの正しい動きを処理し、メインコンテナ (パネル) に接続されます。

クラスのprotectedセクションから、幅と高さによってコンテナを超える Dockオブジェクトの境界の最大値を返すメソッドの宣言を削除します

protected:
//--- Return the maximum value of Dock object borders going beyond the container by width and (2) height
   int               GetExcessMaxX(void);
   int               GetExcessMaxY(void);
//--- Set (1) X, (2) Y coordinate, (3) width, (4) height and (5) all underlay parameters


また、クラス本体の外側に設定されたメソッドの実装を削除します。

CSelectライブラリ クラスを使用して必要な値を検索できるようになったため、これらのメソッドは不要になりました。

クラスのpublicセクションで、バインドされたオブジェクトのリストを返すメソッドをWinFormsタイプbasic以上で宣言します

public:
//--- Return the underlay
   CGCnvElement     *GetUnderlay(void)                               { return this.m_underlay;              }
//--- Return the list of bound objects with WinForms type basic and higher
   CArrayObj        *GetListWinFormsObj(void);



パネルオブジェクトはフレームなしで作成する必要があります。パネルにフレームが必要な場合は、オブジェクトの作成後に追加できます。したがって、クラスコンストラクタでフレームタイプを不在として設定します

//--- Constructors
                     CPanel(const long chart_id,
                           const int subwindow,
                           const string name,
                           const int x,
                           const int y,
                           const int w,
                           const int h);
                     CPanel(const string name) : CWinFormBase(::ChartID(),0,name,0,0,0,0)
                       {
                        CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_PANEL);
                        CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_PANEL);
                        this.m_type=OBJECT_DE_TYPE_GWF_PANEL; 
                        this.SetForeColor(CLR_DEF_FORE_COLOR);
                        this.SetFontBoldType(FW_TYPE_NORMAL);
                        this.SetMarginAll(3);
                        this.SetPaddingAll(0);
                        this.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false);
                        this.SetBorderStyle(FRAME_STYLE_NONE);
                        this.SetAutoScroll(false);
                        this.SetAutoScrollMarginAll(0);
                        this.SetAutoSize(false,false);
                        this.SetAutoSizeMode(CANV_ELEMENT_AUTO_SIZE_MODE_GROW,false);
                        this.Initialize();
                        if(this.CreateUnderlayObj())
                           this.SetUnderlayAsBase();
                       }
//--- Destructor
                    ~CPanel();
  };
//+------------------------------------------------------------------+
//| Constructor indicating the chart and subwindow ID                |
//+------------------------------------------------------------------+
CPanel::CPanel(const long chart_id,
               const int subwindow,
               const string name,
               const int x,
               const int y,
               const int w,
               const int h) : CWinFormBase(chart_id,subwindow,name,x,y,w,h)
  {
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_PANEL);
   CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_PANEL);
   this.m_type=OBJECT_DE_TYPE_GWF_PANEL;
   this.SetForeColor(CLR_DEF_FORE_COLOR);
   this.SetFontBoldType(FW_TYPE_NORMAL);
   this.SetMarginAll(3);
   this.SetPaddingAll(0);
   this.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false);
   this.SetBorderStyle(FRAME_STYLE_NONE);
   this.SetAutoScroll(false);
   this.SetAutoScrollMarginAll(0);
   this.SetAutoSize(false,false);
   this.SetAutoSizeMode(CANV_ELEMENT_AUTO_SIZE_MODE_GROW,false);
   this.Initialize();
   if(this.CreateUnderlayObj())
      this.SetUnderlayAsBase();
   this.SetCoordXInit(x);
   this.SetCoordYInit(y);
   this.SetWidthInit(w);
   this.SetHeightInit(h);
  }
//+------------------------------------------------------------------+


最後のコンストラクタで、フレームタイプの設定に加えて、フレームの作成を削除します

   this.Initialize();
   this.DrawFormFrame(this.FrameWidthTop(),this.FrameWidthBottom(),this.FrameWidthLeft(),this.FrameWidthRight(),this.ColorFrame(),this.Opacity(),this.BorderStyle());
   if(this.CreateUnderlayObj())
      this.SetUnderlayAsBase();



以前は、バインドされたオブジェクトをDockバインドの順序で配置するメソッドには、コンテナ(パネル)に自動サイズ変更フラグが設定されていない場合のオブジェクトの場所の処理が含まれていませんでした。今回の記事では、ただ固定パネルハンドラからバインディングモードハンドラをコピーします。ただし、事前にアンダーレイのチェックを追加しますが、オブジェクトのリストは、WinFormsオブジェクトのみのリストを返す新しいメソッドを使用して受信されます。パネルの自動サイズ変更モードが有効になっている場合は、 まずパネルサイズを元のサイズに変更し、次に、パネルサイズをコンテンツに合わせて調整するメソッドを呼び出します。その後、ループ内で、すべてのバインドされたオブジェクトのバインドモードを処理し、パネルサイズを内部で変更されたオブジェクトに再調整します

//+------------------------------------------------------------------+
//| Place bound objects in the order of their Dock binding           |
//+------------------------------------------------------------------+
bool CPanel::ArrangeObjects(const bool redraw)
  {
//--- If the panel has no underlay, return 'false'
   if(this.m_underlay==NULL)
      return false;
//--- Get the list of bound objects with WinForms type basic and higher
   CArrayObj *list=this.GetListWinFormsObj();
   CWinFormBase *prev=NULL, *obj=NULL, *elm=NULL;
   //--- If auto resizing mode is enabled
   if(this.AutoSize())
     {
      //--- Return the original panel size and then adjust it to the objects located inside it
      this.Resize(this.GetWidthInit(),this.GetHeightInit(),false);
      this.AutoSizeProcess(false);
      //--- In the loop by all bound objects,
      for(int i=0;i<list.Total();i++)
        {
         //--- Get the current and previous elements from the list
         obj=list.At(i);
         prev=list.At(i-1);
         //--- If there is no previous element, set the underlay as a previous element
         if(prev==NULL)
            this.SetUnderlayAsBase();
         //--- If the object has not been received or its type is less than the base WinForms object or the current element has no underlay, move on
         if(obj==NULL)
            continue;
         int x=0, y=0; // Object binding coordinates
         //--- Depending on the current object binding mode...
         //--- Top
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_TOP)
           {
            //--- If failed to change the object size (for the entire underlay width and by the initial object height), move on to the next one
            if(!obj.Resize(this.GetWidthUnderlay(),obj.GetHeightInit(),false))
               continue;
            //--- Get the pointer to the object at the top whose edges are used to bind the current one
            CGCnvElement *coord_base=this.GetTopObj();
            //--- Get the object binding coordinates
            x=this.GetCoordXUnderlay();
            y=(coord_base.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? coord_base.CoordY() : coord_base.BottomEdge()+1);
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
            //--- Set the current object as the top one whose edges will be used to bind the next one
            this.m_obj_top=obj;
           }
         //--- Bottom
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_BOTTOM)
           {
            //--- If failed to change the object size (for the entire underlay width and by the initial object height), move on to the next one
            if(!obj.Resize(this.GetWidthUnderlay(),obj.GetHeightInit(),false))
               continue;
            //--- Get the pointer to the object at the bottom whose edges are used to bind the current one
            CGCnvElement *coord_base=this.GetBottomObj();
            //--- Get the object binding coordinates
            x=this.GetCoordXUnderlay();
            y=(coord_base.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? coord_base.BottomEdge()-obj.Height() : coord_base.CoordY()-obj.Height()-1);
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
            //--- Set the current object as the bottom one whose edges will be used to bind the next one
            this.m_obj_bottom=obj;
           }
         //--- Left
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_LEFT)
           {
            //--- If failed to change the object size (for the initial object width and the entire underlay height), move on to the next one
            if(!obj.Resize(obj.GetWidthInit(),this.GetHeightUnderlay(),false))
               continue;
            //--- Get the pointer to the object at the left whose edges are used to bind the current one
            CGCnvElement *coord_base=this.GetLeftObj();
            //--- Get the object binding coordinates
            x=(coord_base.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? coord_base.CoordX() : coord_base.RightEdge()+1);
            y=this.GetCoordYUnderlay();
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
            //--- Set the current object as the left one whose edges will be used to bind the next one
            this.m_obj_left=obj;
           }
         //--- Right
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_RIGHT)
           {
            //--- If failed to change the object size (for the initial object width and the entire underlay height), move on to the next one
            if(!obj.Resize(obj.GetWidthInit(),this.GetHeightUnderlay(),false))
               continue;
            //--- Get the pointer to the object at the right whose edges are used to bind the current one
            CGCnvElement *coord_base=this.GetRightObj();
            //--- Get the object binding coordinates
            x=(coord_base.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? m_underlay.RightEdge()-obj.Width() : coord_base.CoordX()-obj.Width()-1);
            y=this.GetCoordYUnderlay();
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
            //--- Set the current object as the right one whose edges will be used to bind the next one
            this.m_obj_right=obj;
           }
         //--- Binding with filling
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_FILL)
           {
            //--- If failed to change the object size (for the entire underlay width and height), move on to the next one
            if(!obj.Resize(this.GetWidthUnderlay(),this.GetHeightUnderlay(),false))
               continue;
            //--- Set the underlay as a binding object
            this.SetUnderlayAsBase();
            //--- Get the object binding coordinates
            x=this.GetLeftObj().CoordX();
            y=this.GetTopObj().CoordY();
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
           }
         //--- No binding
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_NONE)
           {
            //--- Reset the object size
            obj.Resize(obj.GetWidthInit(),obj.GetHeightInit(),false);
            //--- Get the initial object location coordinates
            x=this.GetCoordXUnderlay()+obj.CoordXRelativeInit();
            y=this.GetCoordYUnderlay()+obj.CoordYRelativeInit();
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
           }
         //--- Calculate and set the relative object coordinates
         obj.SetCoordXRelative(x-this.m_underlay.CoordX());
         obj.SetCoordYRelative(y-this.m_underlay.CoordY());
        }
      this.Resize(this.GetWidthInit(),this.GetHeightInit(),false);
      this.AutoSizeProcess(false);
     }
   //--- If auto resizing mode disabled 
   else
     {
      //--- In the loop by all bound objects,
      for(int i=0;i<list.Total();i++)
        {
         //--- Get the current and previous elements from the list
         obj=list.At(i);
         prev=list.At(i-1);
         //--- If there is no previous element, set the underlay as a previous element
         if(prev==NULL)
            this.SetUnderlayAsBase();
         //--- If the object has not been received or its type is less than the base WinForms object or the current element has no underlay, move on
         if(obj==NULL)
            continue;
         int x=0, y=0; // Object binding coordinates
         //--- Depending on the current object binding mode...
         //--- Top
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_TOP)
           {
            //--- If failed to change the object size (for the entire underlay width and by the initial object height), move on to the next one
            if(!obj.Resize(this.GetWidthUnderlay(),obj.GetHeightInit(),false))
               continue;
            //--- Get the pointer to the object at the top whose edges are used to bind the current one
            CGCnvElement *coord_base=this.GetTopObj();
            //--- Get the object binding coordinates
            x=this.GetCoordXUnderlay();
            y=(coord_base.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? coord_base.CoordY() : coord_base.BottomEdge()+1);
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
            //--- Set the current object as the top one whose edges will be used to bind the next one
            this.m_obj_top=obj;
           }
         //--- Bottom
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_BOTTOM)
           {
            //--- If failed to change the object size (for the entire underlay width and by the initial object height), move on to the next one
            if(!obj.Resize(this.GetWidthUnderlay(),obj.GetHeightInit(),false))
               continue;
            //--- Get the pointer to the object at the bottom whose edges are used to bind the current one
            CGCnvElement *coord_base=this.GetBottomObj();
            //--- Get the object binding coordinates
            x=this.GetCoordXUnderlay();
            y=(coord_base.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? coord_base.BottomEdge()-obj.Height()-1 : coord_base.CoordY()-obj.Height()-1);
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
            //--- Set the current object as the bottom one whose edges will be used to bind the next one
            this.m_obj_bottom=obj;
           }
         //--- Left
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_LEFT)
           {
            //--- If failed to change the object size (for the initial object width and the entire underlay height), move on to the next one
            if(!obj.Resize(obj.GetWidthInit(),this.GetHeightUnderlay(),false))
               continue;
            //--- Get the pointer to the object at the left whose edges are used to bind the current one
            CGCnvElement *coord_base=this.GetLeftObj();
            //--- Get the object binding coordinates
            x=(coord_base.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? coord_base.CoordX() : coord_base.RightEdge()+1);
            y=this.GetCoordYUnderlay();
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
            //--- Set the current object as the left one whose edges will be used to bind the next one
            this.m_obj_left=obj;
           }
         //--- Right
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_RIGHT)
           {
            //--- If failed to change the object size (for the initial object width and the entire underlay height), move on to the next one
            if(!obj.Resize(obj.GetWidthInit(),this.GetHeightUnderlay(),false))
               continue;
            //--- Get the pointer to the object at the right whose edges are used to bind the current one
            CGCnvElement *coord_base=this.GetRightObj();
            //--- Get the object binding coordinates
            x=(coord_base.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? m_underlay.RightEdge()-obj.Width() : coord_base.CoordX()-obj.Width()-1);
            y=this.GetCoordYUnderlay();
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
            //--- Set the current object as the right one whose edges will be used to bind the next one
            this.m_obj_right=obj;
           }
         //--- Binding with filling
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_FILL)
           {
            //--- If failed to change the object size (for the entire underlay width and height), move on to the next one
            if(!obj.Resize(this.GetWidthUnderlay(),this.GetHeightUnderlay(),false))
               continue;
            //--- Set the underlay as a binding object
            this.SetUnderlayAsBase();
            //--- Get the object binding coordinates
            x=this.GetLeftObj().CoordX();
            y=this.GetTopObj().CoordY();
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
           }
         //--- No binding
         if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_NONE)
           {
            //--- Reset the object size
            obj.Resize(obj.GetWidthInit(),obj.GetHeightInit(),false);
            //--- Get the initial object location coordinates
            x=this.GetCoordXUnderlay()+obj.CoordXRelativeInit();
            y=this.GetCoordYUnderlay()+obj.CoordYRelativeInit();
            //--- If failed to move the object to the obtained coordinates, move on to the next one
            if(!obj.Move(x,y,false))
               continue;
           }
         //--- Calculate and set the relative object coordinates
         obj.SetCoordXRelative(x-this.m_underlay.CoordX());
         obj.SetCoordYRelative(y-this.m_underlay.CoordY());
        }
     }
//--- Redraw the object with the redraw flag and return 'true'
   this.Redraw(redraw); 
   return true;
  }
//+------------------------------------------------------------------+


ここでは、単一のループですべてを実行できます。つまり、2つの別個の同一のループで2つのブロックに分割することなく、さらにパネルの自動サイズ変更フラグをチェックできます。これによって、コードが半分になります。しかし、パネルの自動サイズ変更フラグを処理するコードブロックをさらに改良する必要がある場合に備えて、そのままにしておくことにしました。すべてがデバッグされ、それ以上の変更や改善が必要ないことが明らかになって初めて、このメソッドのコードを最適化します。

CSelectクラスを使用して必要なデータを取得できるようになったため、コンテンツに合わせて要素のサイズを調整するメソッドも改訂されました。

//+------------------------------------------------------------------+
//| Adjust the element size to fit its content                       |
//+------------------------------------------------------------------+
bool CPanel::AutoSizeProcess(const bool redraw)
  {
//--- Get the list of bound objects with WinForms type basic and higher
   CArrayObj *list=this.GetListWinFormsObj();
//--- Get object indices in the list with the maximum and minimum X and Y coordinates
   int imaxx=CSelect::FindGraphCanvElementMax(list,CANV_ELEMENT_PROP_COORD_X);
   int iminx=CSelect::FindGraphCanvElementMin(list,CANV_ELEMENT_PROP_COORD_X);
   int imaxy=CSelect::FindGraphCanvElementMax(list,CANV_ELEMENT_PROP_COORD_Y);
   int iminy=CSelect::FindGraphCanvElementMin(list,CANV_ELEMENT_PROP_COORD_Y);
//--- Get objects with the maximum and minimum X and Y coordinates from the list
   CWinFormBase *maxx=list.At(imaxx);
   CWinFormBase *minx=list.At(iminx);
   CWinFormBase *maxy=list.At(imaxy);
   CWinFormBase *miny=list.At(iminy);
//--- If at least one of the four objects is not received, return 'false'
   if(maxx==NULL || minx==NULL || maxy==NULL || miny==NULL)
      return false;
//--- Get the minimum X and Y coordinate
   int min_x=minx.CoordX();
   int min_y=fmin(miny.CoordY(),maxy.BottomEdge());
//--- Calculate the total width and height of all bound objects
   int w=maxx.RightEdge()-min_x;
   int h=int(fmax(miny.CoordY(),maxy.BottomEdge())-min_y);
//--- Calculate the number of pixels, by which we need to resize the panel in width and height
   int excess_x=w-this.m_underlay.Width();
   int excess_y=h-this.m_underlay.Height();
//--- Calculate the offset, by which the bound objects are to be moved
   int shift_x=m_underlay.CoordX()-min_x;
   int shift_y=m_underlay.CoordY()-min_y;
//--- If failed to change the panel size, return 'true'
   if(excess_x==0 && excess_y==0)
      return true;
//--- If it is necessary to move the attached objects inside the panel along the X or Y coordinate
   bool res=true;
   if(shift_x>0 || shift_y>0)
     {
      //--- In the loop by all attached objects,
      for(int i=0;i<list.Total();i++)
        {
         //--- get the next object.
         CWinFormBase *obj=list.At(i);
         if(obj==NULL)
            continue;
         //--- If the object needs to be shifted horizontally, write the shift result to 'res'
         if(shift_x>0)
            res &=obj.Move(obj.CoordX()+shift_x,obj.CoordY());
         //--- If the object needs to be shifted vertically, write the shift result to 'res'
         if(shift_y>0)
            res &=obj.Move(obj.CoordX(),obj.CoordY()+shift_y);
         //--- Set new relative object X and Y coordinates
         obj.SetCoordXRelative(obj.CoordX()-this.m_underlay.CoordX());
         obj.SetCoordYRelative(obj.CoordY()-this.m_underlay.CoordY());
        }
     }
//--- Return the result of resizing the panel
   return
     (
      //--- If we failed to move at least one bound object, return 'false'
      !res ? false :
      //--- Otherwise, if only a size increase
      this.AutoSizeMode()==CANV_ELEMENT_AUTO_SIZE_MODE_GROW ? 
      this.Resize(this.Width()+(excess_x>0  ? excess_x : 0),this.Height()+(excess_y>0  ? excess_y : 0),redraw) :
      //--- if both increase and decrease
      this.Resize(this.Width()+(excess_x!=0 ? excess_x : 0),this.Height()+(excess_y!=0 ? excess_y : 0),redraw)
     );
  }
//+------------------------------------------------------------------+


メソッドのロジックはコードのコメントで完全に説明されています。Y軸座標の最小値を取得する際に、取得した値に関連した奇妙な動作に遭遇することがあります...オブジェクトが最初に構築されるとき、最大座標は最大値で返され、最小座標は最小値で返されるということです。すべてが正しいです。ただし、オブジェクトを再配置した後、最大座標は最小値で返され、最小座標は最大値で返されます。この動作の理由をまだ見つけることができず、2つの値のどちらかを選択する必要がありました。最大値を要求すると2つの最大値が取得され最小値を要求すると2つの最小値が取得されます
なぜXオフセットとYオフセットを計算するのでしょうか。オブジェクトをパネルの右端または下端にバインドする場合、オブジェクトはパネルの右端または下端から作成されるため、パネルの左側または上側を超えることができます。パネル(およびその他のグラフィック要素)の座標原点は左上隅から始まるため、パネルのサイズを拡大すると、パネルは右または下に拡大され、内部にあるすべてのオブジェクトのサイズに適合します。したがって、パネルは内部に配置されたすべてのオブジェクトに対応するサイズになりますが、パネル座標の原点はすべてのオブジェクトの表示原点に対応しなくなります。したがって、オブジェクトバインディングモードに応じて、計算された量だけこれらのオブジェクトを右または下に移動する必要があります。

以下は、WinForms baseタイプ以上のアタッチされたオブジェクトのリストを返すメソッドです。

//+------------------------------------------------------------------+
//| Return the list of bound objects                                 |
//| of WinForms base type and higher                                 |
//+------------------------------------------------------------------+
CArrayObj *CPanel::GetListWinFormsObj(void)
  {
   return CSelect::ByGraphCanvElementProperty(this.GetListElements(),CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_BASE,EQUAL_OR_MORE);
  }
//+------------------------------------------------------------------+


このメソッドは、WinForms Baseタイプ以上のオブジェクトのみを含むリストを返すだけです。つまり、WinForms基本オブジェクトまたはその子孫のいずれかです。オブジェクトは、CSelectクラスを使用して、パネルにバインドされたすべてのオブジェクトの一般的なリストから、種類別に並べ替えることによって選択されます。

\MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqhのCGraphElementsCollectionクラスのPanel WinFormsオブジェクトを作成するメソッドで最適化を実行し、論理エラーを排除しましょう。

フレームの色が設定されていない可能性がありますがオブジェクトフレームが2回描画されているため、間違っています。さらに、-1に等しいデフォルト値としてメソッドに渡された場合、パネルのフレームサイズも設定されていない可能性があります。この値のチェックがなかったため、値が-1の場合にデフォルトのフレームサイズを設定する代わりに設定されました。

すべてのパネルを作成するメソッドで、同一または同様の変更が行われました。

//--- Create a WinForms Panel object graphical object on canvas on a specified chart and subwindow with the vertical gradient filling
   int               CreatePanelVGradient(const long chart_id,
                                          const int subwindow,
                                          const string name,
                                          const int x,
                                          const int y,
                                          const int w,
                                          const int h,
                                          color &clr[],
                                          const uchar opacity,
                                          const bool movable,
                                          const bool activity,
                                          const int  frame_width=-1,
                                          ENUM_FRAME_STYLE frame_style=FRAME_STYLE_BEVEL,
                                          const bool shadow=false,
                                          const bool redraw=false)
                       {
                        int id=this.m_list_all_canv_elm_obj.Total();
                        CPanel *obj=new CPanel(chart_id,subwindow,name,x,y,w,h);
                        ENUM_ADD_OBJ_RET_CODE res=this.AddOrGetCanvElmToCollection(obj,id);
                        if(res==ADD_OBJ_RET_CODE_ERROR)
                           return WRONG_VALUE;
                        obj.SetID(id);
                        obj.SetActive(activity);
                        obj.SetMovable(movable);
                        obj.SetColorsBackground(clr);
                        obj.SetColorFrame(obj.ColorBackground());
                        obj.SetBorderStyle(frame_style);
                        obj.SetOpacity(opacity,false);
                        obj.SetFrameWidthAll(frame_width==WRONG_VALUE ? DEF_FRAME_WIDTH_SIZE : frame_width);
                        //--- Draw the shadow drawing flag
                        obj.SetShadow(shadow);
                        if(shadow)
                          {
                           color clrS=obj.ChangeColorLightness(obj.ChangeColorSaturation(obj.ColorBackground(),-100),-20);
                           obj.DrawShadow(3,3,clrS,CLR_DEF_SHADOW_OPACITY,DEF_SHADOW_BLUR);
                          }
                        obj.DrawRectangle(0,0,obj.Width()-1,obj.Height()-1,obj.ColorFrame(),obj.Opacity());
                        if(redraw)
                          {
                           obj.Erase(clr,opacity,true,false,redraw);
                           obj.DrawRectangle(0,0,obj.Width()-1,obj.Height()-1,obj.ColorFrame(),obj.Opacity());
                          } 
                        obj.SetActiveAreaShift(obj.FrameWidthLeft(),obj.FrameWidthBottom(),obj.FrameWidthRight(),obj.FrameWidthTop());
                        obj.Done();
                        return obj.ID();
                       }


フレームの色をパネルの背景色と同じに設定します(グラデーションの最初または唯一のものに)。フレームサイズを設定するときは、メソッドに渡された値を確認します。-1の場合、Defines.mqhのDEF_FRAME_WIDTH_SIZEマクロ置換に設定されているデフォルト値を設定します再描画フラグが設定されている場合は、パネルを背景色またはグラデーションでペイントし、上に輪郭を描く四角形を描画します。この場合、フレームはCPanelクラスの仮想Erase()メソッドで描画されます。

このような改善は、パネルを作成するすべてのメソッドで行われています。記事に添付されているファイルでご覧ください。


検証

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

コンテナにバインドされたパネルオブジェクトは、デフォルトでフレームなしで作成されるようになったため、OnInit()ハンドラでそれぞれのフレームの幅とタイプを指定します。.後続の各パネルの色は、ループインデックスから計算された値だけ明るくなります(ループインデックス * 4に等しい量だけ背景色が明るくなります)。これは、パネルのバインド方法を変更するときに、コンテナ内のパネルの配置の変更を明確に確認するために必要です。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set EA global variables
   ArrayResize(array_clr,2);        // Array of gradient filling colors
   array_clr[0]=C'26,100,128';      // Original ≈Dark-azure color
   array_clr[1]=C'35,133,169';      // Lightened original color
//--- Create the array with the current symbol and set it to be used in the library
   string array[1]={Symbol()};
   engine.SetUsedSymbols(array);
   //--- Create the timeseries object for the current symbol and period, and show its description in the journal
   engine.SeriesCreate(Symbol(),Period());
   engine.GetTimeSeriesCollection().PrintShort(false); // Short descriptions
//--- Create WinForms Panel object
   CPanel *pnl=NULL;
   pnl=engine.CreateWFPanel("WFPanel",50,50,230,150,array_clr,200,true,true,false,-1,FRAME_STYLE_BEVEL,true,false);
   if(pnl!=NULL)
     {
      //--- Set Padding to 4
      pnl.SetPaddingAll(4);
      //--- Set the flags of relocation, auto resizing and auto changing mode from the inputs
      pnl.SetMovable(InpMovable);
      pnl.SetAutoSize(InpAutoSize,false);
      pnl.SetAutoSizeMode((ENUM_CANV_ELEMENT_AUTO_SIZE_MODE)InpAutoSizeMode,false);
      //--- In the loop, create 6 bound panel objects
      for(int i=0;i<6;i++)
        {
         //--- create the panel object with coordinates along the X axis in the center and 10 along the Y axis, the width of 80 and the height of 50
         CPanel *prev=pnl.GetElement(i-1);
         int xb=0, yb=0;
         int x=(i<3 ? (prev==NULL ? xb : prev.CoordXRelative()) : xb+prev.Width()+20);
         int y=(i<3 ? (prev==NULL ? yb : prev.BottomEdgeRelative()+16) : (i==3 ? yb : prev.BottomEdgeRelative()+16));
         if(pnl.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_PANEL,pnl,x,y,80,40,C'0xCD,0xDA,0xD7',200,true,false))
           {
            CPanel *obj=pnl.GetElement(i);
            if(obj==NULL)
               continue;
            obj.SetFrameWidthAll(3);
            obj.SetBorderStyle(FRAME_STYLE_BEVEL);
            obj.SetColorBackground(obj.ChangeColorLightness(obj.ColorBackground(),4*i));
           }
        }
      pnl.Redraw(true);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+



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


そのため、パネルはそれに接続されているオブジェクトの一般的なサイズに適応し、さまざまなバインド方法が正しく機能し、パネルのサイズも正しく変更されます。異なるバインド方法でオブジェクトを配置すると、希望どおりに配置されません。それらはパネルの端に接続されるべきではなく、リスト内の後続の各オブジェクトは、。同じバインディングがある場合、前のオブジェクトの端に接続される必要があります特に、最後のオブジェクトがコンテナの幅と高さ全体に引き伸ばされますが、これは正しくありません。これは、以前にパネルの端にバインドされたオブジェクトの内側の端に制限する必要があるためです。つまり、それらの間の空き領域内に設定する必要があります。今後の記事で、バインドされたオブジェクトの正しい動作を実装します。


次の段階

次の記事では、Panelオブジェクトの作業を続け、WinFormsテキスト ラベルオブジェクトを含む新しいコントロールの開発を開始します。

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

目次に戻る

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

DoEasyコントロール(第1部):最初のステップ
DoEasyコントロール(第2部):CPanelクラスでの作業
DoEasyコントロール(第3部):バインドされたコントロールの作成
DoEasyコントロール(第4部):パネルコントロール、Padding、Dockパラメータ
DoEasy.コントロール(第5部):WinForms基本オブジェクト、Panelコントロール、AutoSizeパラメータ


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

添付されたファイル |
MQL5.zip (4351.9 KB)
OBVによる取引システムの設計方法を学ぶ OBVによる取引システムの設計方法を学ぶ
今回は、初心者向けのシリーズとして、人気のあるいくつかの指標をもとに取引システムを設計する方法について、新しい記事をお届けします。今回は、新しい指標であるOBV (On Balance Volume)を学び、その使い方とそれに基づいた取引システムの設計を学びます。
ビデオ:シンプルな自動取引 – MQL5でシンプルなエキスパートアドバイザーを作成する方法 ビデオ:シンプルな自動取引 – MQL5でシンプルなエキスパートアドバイザーを作成する方法
私のコースの学生の大半は、MQL5を理解するのが本当に難しいと感じていました。これに加えて、彼らはいくつかのプロセスを自動化する簡単な方法を探していました。この記事に含まれる情報を読んで、今すぐMQL5のを使い始める方法を見つけてください。これまでに何らかの形のプログラミングをおこなったことがない場合でも、観察した前のイラストを理解できない場合でも.です。
一からの取引エキスパートアドバイザーの開発(第16部):Web上のデータにアクセスする(II) 一からの取引エキスパートアドバイザーの開発(第16部):Web上のデータにアクセスする(II)
Webからエキスパートアドバイザー(EA)にデータを入力する方法はそれほど明らかにはわかりません。MetaTrader 5が提供するすべての可能性を理解しなければ、そう簡単にはいきません。
ニューラルネットワークが簡単に(第14部):データクラスタリング ニューラルネットワークが簡単に(第14部):データクラスタリング
前回の記事を公開してから1年以上が経過しました。アイデアを修正して新しいアプローチを開発するには、これはかなりの時間です。この新しい記事では、以前に使用された教師あり学習法から逸れようと思います。今回は、教師なし学習アルゴリズムについて説明します。特に、クラスタリングアルゴリズムの1つであるk-meansについて検討していきます。