DoEasy - コントロール(第6部):パネルコントロール、内部コンテンツに合わせたコンテナサイズの自動変更
内容
概念
本稿では、パネルにバインドされたオブジェクトのDockプロパティがアクティブに設定されている場合のパネルの自動サイズ変更を実装します。バインドされたオブジェクトのいずれかにプロパティが設定されている場合は、そのバインド場所に配置する必要がありますが、パネルのサイズをバインドされたすべてのオブジェクトの合計サイズに調整する必要があります。つまり、パネルに接続されたオブジェクトのいずれかでDockプロパティが設定されると、パネルサイズが変更されます。プロパティが多数の次々に接続されたオブジェクトに対して設定されている場合、次にオブジェクトがバインドされるごとに変更された内部コンテンツに合わせて、パネルサイズを調整する必要があります。
新しいオブジェクト配置に合わせてパネルサイズを調整すると、不快な視覚効果が生じます。それらを回避するために、オブジェクトをパネルにバインドして変更する一括処理を最適化しました。最後のバインドされたオブジェクトが本来あるべき場所に配置された後にのみ、視覚的にパネルサイズを調整します。
現在の記事では、コンテナ内のオブジェクトの一括配置処理の最適化を続けます。
WinFormsオブジェクトの作業に加えて、MetaTrader 5ビルド3260で以前に発表された銘柄ライブラリオブジェクトに新しいプロパティを追加します。
- 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テキスト ラベルオブジェクトを含む新しいコントロールの開発を開始します。
**連載のこれまでの記事:
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
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索