English Русский 中文 Español Deutsch Português
preview
DoEasy - コントロール(第26部):ToolTip WinFormsオブジェクトの最終確認とProgressBarの開発開始

DoEasy - コントロール(第26部):ToolTip WinFormsオブジェクトの最終確認とProgressBarの開発開始

MetaTrader 5 | 18 1月 2023, 09:59
199 0
Artyom Trishkin
Artyom Trishkin

内容


概念

前回の記事で、ツールチップコントロールの開発を開始しました。オブジェクトにカーソルを合わせると、短いポーズの後にツールチップが表示されます。先に表示されていたツールチップは非表示になります。ツールチップが表示された後にカーソルを同じ位置に置いておくと、ツールチップが一定時間後に消えるはずです。前回は、ツールチップを割り当てたオブジェクトにカーソルを合わせるとすぐに表示されるようにしました。今回は、ツールチップの挙動を工夫し、MS Visual Studioでコンパイルされたプログラムの挙動とより整合性を持たせるために作業を継続します。オブジェクトにカーソルを合わせると、ポーズの後、ツールチップが画面にスムーズに表示されるようにします。カーソルをオブジェクトから離すと、ツールチップは非表示になります。オブジェクトにカーソルを置いたままにしておくと、しばらくしてツールチップがスムーズに消えます。この動作を実装するには、コレクションのグラフィック要素用に作成されたタイマーを使用する必要があります。各オブジェクトには、仮想タイマーイベントハンドラが定義されます。タイマーの実装は、その中で処理されるオブジェクトのクラスで具体的に実施する必要があります。

タイマーでどのオブジェクトを処理してどのオブジェクトを処理しないかをライブラリが理解できるように、アクティブなオブジェクトのリストを作成することにします。タイマーの中で処理が必要なオブジェクトへのポインタが格納されます。これにより、処理すべきオブジェクトの追跡が容易になり、すべてのグラフィック要素をループで常にスキャンする手間が省けます。ループはリストに追加されたオブジェクトのみとします。この方法によって、グラフィカルインターフェイスをアニメーション化できるようになります。オブジェクトはマウスとのインタラクションに反応するだけでなく、視覚効果のためにオブジェクトに指定されたアニメーションシーケンスを使用します。このように、普通のアニメーションアイコンでも簡単に作成し、利用することができるのです。アニメーションフレームを持つオブジェクトを作成し、アクティブなライブラリオブジェクトのリストに入れるだけで十分です。このようなオブジェクトのタイマーイベントハンドラでは、オブジェクト作成時に作成したアニメーションフレームを単純に交互に表示します。今日は、ToolTipコントロールのタイマーイベントハンドラを作成します。このハンドラによって、上記のツールチップの動作が実装されます。この動作はマウスとのインタラクションを意味するので、グラフィック要素コレクションイベントのハンドラとコレクションタイマーの両方で動作させることにします。

ToolTip WinFormsオブジェクトを仕上げた後は、ProgressBarコントロールの開発に着手します。オブジェクトの静的バージョン、つまりプロパティと外観だけを作成することにします。その操作については、次回以降に実装していきます。


ライブラリクラスの改善

\MQL5\Include\DoEasy\Defines.mqhで、キャンバス上のグラフィック要素のタイマーパラメータを追加します

//--- Parameters of the graphical objects collection timer
#define COLLECTION_GRAPH_OBJ_PAUSE        (250)                   // Graphical objects collection timer pause in milliseconds
#define COLLECTION_GRAPH_OBJ_COUNTER_STEP (16)                    // Graphical objects timer counter increment
#define COLLECTION_GRAPH_OBJ_COUNTER_ID   (10)                    // Graphical objects timer counter ID
//--- Parameters of the timer for the collection of graphical elements on canvas
#define COLLECTION_GRAPH_ELM_PAUSE        (16)                    // Graphical elements collection timer pause in milliseconds
#define COLLECTION_GRAPH_ELM_COUNTER_STEP (16)                    // Graphical elements timer counter increment
#define COLLECTION_GRAPH_ELM_COUNTER_ID   (11)                    // Graphical elements timer counter ID

//--- Collection list IDs

ライブラリオブジェクトの各コレクションは、独自のパラメータ(一時停止、タイマーカウンタの増分、そのID)を持つ独自のタイマーハンドラを持っています。新しいタイマーのために、ここにまったく同じパラメータを追加しました。

新しいProgressBarコントロールのデフォルト値を追加します。

#define CLR_DEF_CONTROL_HINT_BACK_COLOR               (C'0xFF,0xFF,0xE1')  // Hint control background color
#define CLR_DEF_CONTROL_HINT_BORDER_COLOR             (C'0x76,0x76,0x76')  // Hint control frame color
#define CLR_DEF_CONTROL_HINT_FORE_COLOR               (C'0x5A,0x5A,0x5A')  // Hint control text color

#define CLR_DEF_CONTROL_PROGRESS_BAR_BACK_COLOR       (C'0xF0,0xF0,0xF0')  // ProgressBar control background color
#define CLR_DEF_CONTROL_PROGRESS_BAR_BORDER_COLOR     (C'0xBC,0xBC,0xBC')  // ProgressBar control frame color
#define CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR       (C'0x00,0x78,0xD7')  // ProgressBar control text color
#define CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR        (C'0x06,0xB0,0x25')  // ProgressBar control progress line color


一部のグラフィックコントロールには、その視覚効果の要素が必要です。例えば、プログレスラインは、Windowsで実装されているように、バーに沿うようにグレア(光沢)を持たせることです。グレアを実装したオブジェクトはバーの上に重なり、バーに沿って移動します。ライブラリのオブジェクトタイプのリストに、オブジェクトタイプを設定する必要があります。

//+------------------------------------------------+
//| List of library object types                   |
//+------------------------------------------------+
enum ENUM_OBJECT_DE_TYPE
  {
//--- Graphics
   OBJECT_DE_TYPE_GBASE =  COLLECTION_ID_LIST_END+1,              // "Base object of all library graphical objects" object type
   OBJECT_DE_TYPE_GELEMENT,                                       // "Graphical element" object type
   OBJECT_DE_TYPE_GFORM,                                          // Form object type
   OBJECT_DE_TYPE_GFORM_CONTROL,                                  // "Form for managing pivot points of graphical object" object type
   OBJECT_DE_TYPE_GSHADOW,                                        // Shadow object type
   OBJECT_DE_TYPE_GGLARE,                                         // Glare object type
   //--- WinForms
   OBJECT_DE_TYPE_GWF_BASE,                                       // WinForms Base object type (base abstract WinForms object)
   OBJECT_DE_TYPE_GWF_CONTAINER,                                  // WinForms container object type
   OBJECT_DE_TYPE_GWF_COMMON,                                     // WinForms standard control object type
   OBJECT_DE_TYPE_GWF_HELPER,                                     // WinForms auxiliary control object type
//--- Animation


キャンバス上のグラフィック要素の新しいタイプをグラフィック要素タイプのリストに追加します。

//+------------------------------------------------+
//| The list of graphical element types            |
//+------------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_STANDARD,                       // Standard graphical object
   GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED,              // Extended standard graphical object
   GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                     // Shadow object
   GRAPH_ELEMENT_TYPE_GLARE_OBJ,                      // Glare object
   GRAPH_ELEMENT_TYPE_ELEMENT,                        // Element
   GRAPH_ELEMENT_TYPE_FORM,                           // Form
   GRAPH_ELEMENT_TYPE_WINDOW,                         // Window
   //--- WinForms
   GRAPH_ELEMENT_TYPE_WF_UNDERLAY,                    // Panel object underlay
   GRAPH_ELEMENT_TYPE_WF_BASE,                        // Windows Forms Base
   //--- 'Container' object types are to be set below
   GRAPH_ELEMENT_TYPE_WF_CONTAINER,                   // Windows Forms container base object
   GRAPH_ELEMENT_TYPE_WF_PANEL,                       // Windows Forms Panel
   GRAPH_ELEMENT_TYPE_WF_GROUPBOX,                    // Windows Forms GroupBox
   GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,                 // Windows Forms TabControl
   GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,             // Windows Forms SplitContainer
   //--- 'Standard control' object types are to be set below
   GRAPH_ELEMENT_TYPE_WF_COMMON_BASE,                 // Windows Forms base standard control
   GRAPH_ELEMENT_TYPE_WF_LABEL,                       // Windows Forms Label
   GRAPH_ELEMENT_TYPE_WF_BUTTON,                      // Windows Forms Button
   GRAPH_ELEMENT_TYPE_WF_CHECKBOX,                    // Windows Forms CheckBox
   GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON,                 // Windows Forms RadioButton
   GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX,           // Base list object of Windows Forms elements
   GRAPH_ELEMENT_TYPE_WF_LIST_BOX,                    // Windows Forms ListBox
   GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX,            // Windows Forms CheckedListBox
   GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX,             // Windows Forms ButtonListBox
   GRAPH_ELEMENT_TYPE_WF_TOOLTIP,                     // Windows Forms ToolTip
   GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,                // Windows Forms ProgressBar
   //--- Auxiliary elements of WinForms objects
   GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM,               // Windows Forms ListBoxItem
   GRAPH_ELEMENT_TYPE_WF_TAB_HEADER,                  // Windows Forms TabHeader
   GRAPH_ELEMENT_TYPE_WF_TAB_FIELD,                   // Windows Forms TabField
   GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER_PANEL,       // Windows Forms SplitContainerPanel
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON,                // Windows Forms ArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,             // Windows Forms UpArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,           // Windows Forms DownArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,           // Windows Forms LeftArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,          // Windows Forms RightArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX,        // Windows Forms UpDownArrowButtonsBox
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX,        // Windows Forms LeftRightArrowButtonsBox
   GRAPH_ELEMENT_TYPE_WF_SPLITTER,                    // Windows Forms Splitter
   GRAPH_ELEMENT_TYPE_WF_HINT_BASE,                   // Windows Forms HintBase
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT,              // Windows Forms HintMoveLeft
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT,             // Windows Forms HintMoveRight
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP,                // Windows Forms HintMoveUp
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN,              // Windows Forms HintMoveDown
   GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,            // Windows Forms BarProgressBar
  };
//+------------------------------------------------------------------+


コントロール(ここではツールチップ)は、マウスとインタラクションするときに複数の状態を持つことができます。オブジェクトはアニメーションであるため、その動作や状態を記述する必要があります。フェードインの開始を待つフェードイン状態、フェードアウトの開始を待つフェードアウト状態、または通常状態のこともあります。
その状態を新しいコントロールの表示状態リストに記述してみましょう。

//+------------------------------------------------+
//| The list of predefined icons                   |
//+------------------------------------------------+
enum ENUM_CANV_ELEMENT_TOOLTIP_ICON
  {
   CANV_ELEMENT_TOOLTIP_ICON_NONE,                    // None
   CANV_ELEMENT_TOOLTIP_ICON_INFO,                    // Info
   CANV_ELEMENT_TOOLTIP_ICON_WARNING,                 // Warning
   CANV_ELEMENT_TOOLTIP_ICON_ERROR,                   // Error
   CANV_ELEMENT_TOOLTIP_ICON_USER,                    // User
  };
//+------------------------------------------------+
//| List of control display states                 |
//+------------------------------------------------+
enum ENUM_CANV_ELEMENT_DISPLAY_STATE
  {
   CANV_ELEMENT_DISPLAY_STATE_NORMAL,                 // Normal
   CANV_ELEMENT_DISPLAY_STATE_WAITING_FADE_IN,        // Wait for fading in
   CANV_ELEMENT_DISPLAY_STATE_PROCESS_FADE_IN,        // Fading in
   CANV_ELEMENT_DISPLAY_STATE_COMPLETED_FADE_IN,      // Fading in end
   CANV_ELEMENT_DISPLAY_STATE_WAITING_FADE_OUT,       // Wait for fading out
   CANV_ELEMENT_DISPLAY_STATE_PROCESS_FADE_OUT,       // Fading out
   CANV_ELEMENT_DISPLAY_STATE_COMPLETED_FADE_OUT,     // Fading out end
   CANV_ELEMENT_DISPLAY_STATE_COMPLETED,              // Complete processing
  };
//+------------------------------------------------------------------+

このような状態は、他のコントロールにも適用できます。アニメーションは後で作成できます。また、オブジェクトはフェードイン/アウトする必要はありません。オブジェクトがフェードインしていく描写はドロップダウンリストの拡張に、徐々にフェードアウト(減衰)していく状態は崩壊の状態に相当することができます。ただし、このリストは後でいつでも拡張することができます。

ProgressBarは3つのプログレスバー描画スタイルを持つことができます。列挙してみましょう

//+------------------------------------------------+
//| List of ProgressBar element styles             |
//+------------------------------------------------+
enum ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE
  {
   CANV_ELEMENT_PROGRESS_BAR_STYLE_BLOCKS,            // Segmented blocks
   CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS,        // Continuous bar
   CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE,           // Continuous scrolling
  };
//+------------------------------------------------------------------+
//| Integer properties of the graphical element on the canvas        |
//+------------------------------------------------------------------+

ここでは連続バーだけを実装することにします。


オブジェクトにアニメーション表示が実装されている場合、その状態を保存し、プロパティから取得する必要があります。
新しいグラフィック要素のプロパティを、canvas上のグラフィック要素の整数プロパティの列挙に追加して、整数プロパティの総数を129から138に増やしてみましょう。

//+------------------------------------------------------------------+
//| Integer properties of the graphical element on the canvas        |
//+------------------------------------------------------------------+
enum ENUM_CANV_ELEMENT_PROP_INTEGER
  {
   CANV_ELEMENT_PROP_ID = 0,                          // Element ID
   CANV_ELEMENT_PROP_TYPE,                            // Graphical element type

   //---...
   //---...

   CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH,           // Upper edge area width
   CANV_ELEMENT_PROP_DISPLAYED,                       // Non-hidden control display flag
   CANV_ELEMENT_PROP_DISPLAY_STATE,                   // Control display state
   CANV_ELEMENT_PROP_DISPLAY_DURATION,                // Control display duration
   CANV_ELEMENT_PROP_GROUP,                           // Group the graphical element belongs to
   CANV_ELEMENT_PROP_ZORDER,                          // Priority of a graphical object for receiving the event of clicking on a chart

   //---...
   //---...

   CANV_ELEMENT_PROP_TOOLTIP_IS_BALLOON,              // Tooltip in the form of a "cloud"
   CANV_ELEMENT_PROP_TOOLTIP_USE_FADING,              // Fade when showing/hiding a tooltip
   CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM,            // The upper bound of the range ProgressBar operates in
   CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM,            // The lower bound of the range ProgressBar operates in
   CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,               // ProgressBar increment needed to redraw it
   CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,              // ProgressBar style
   CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,              // Current ProgressBar value from Min to Max
   CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED, // Progress bar animation speed in case of Marquee style
  };
#define CANV_ELEMENT_PROP_INTEGER_TOTAL (138)         // Total number of integer properties
#define CANV_ELEMENT_PROP_INTEGER_SKIP  (0)           // Number of integer properties not used in sorting
//+------------------------------------------------------------------+


キャンバス上のグラフィック要素を並べ替えるための基準の列挙に新しいプロパティによる並べ替えを追加します

//+------------------------------------------------------------------+
//| Possible sorting criteria of graphical elements on the canvas    |
//+------------------------------------------------------------------+
#define FIRST_CANV_ELEMENT_DBL_PROP  (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP)
#define FIRST_CANV_ELEMENT_STR_PROP  (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP+CANV_ELEMENT_PROP_DOUBLE_TOTAL-CANV_ELEMENT_PROP_DOUBLE_SKIP)
enum ENUM_SORT_CANV_ELEMENT_MODE
  {
//--- Sort by integer properties
   SORT_BY_CANV_ELEMENT_ID = 0,                       // Sort by element ID
   SORT_BY_CANV_ELEMENT_TYPE,                         // Sort by graphical element type

   //---...
   //---...

   SORT_BY_CANV_ELEMENT_BORDER_TOP_AREA_WIDTH,        // Sort by upper edge area width
   SORT_BY_CANV_ELEMENT_DISPLAYED,                    // Sort by non-hidden control display flag
   SORT_BY_CANV_ELEMENT_DISPLAY_STATE,                // Sort by control display state
   SORT_BY_CANV_ELEMENT_DISPLAY_DURATION,             // Sort by control display duration
   SORT_BY_CANV_ELEMENT_GROUP,                        // Sort by a group the graphical element belongs to
   SORT_BY_CANV_ELEMENT_ZORDER,                       // Sort by the priority of a graphical object for receiving the event of clicking on a chart

   //---...
   //---...

   SORT_BY_CANV_ELEMENT_TOOLTIP_IS_BALLOON,           // Sort by a cloud tooltip flag
   SORT_BY_CANV_ELEMENT_TOOLTIP_USE_FADING,           // Sort by the flag of fading when showing/hiding a tooltip
   SORT_BY_CANV_ELEMENT_PROGRESS_BAR_MAXIMUM,         // Sort by the upper bound of the range ProgressBar operates in
   SORT_BY_CANV_ELEMENT_PROGRESS_BAR_MINIMUM,         // Sort by the lower bound of the range ProgressBar operates in
   SORT_BY_CANV_ELEMENT_PROGRESS_BAR_STEP,            // Sort by ProgressBar increment needed to redraw it
   SORT_BY_CANV_ELEMENT_PROGRESS_BAR_STYLE,           // Sort by ProgressBar style
   SORT_BY_CANV_ELEMENT_PROGRESS_BAR_VALUE,           // Sort by the current ProgressBar value from Min to Max
   SORT_BY_CANV_ELEMENT_PROGRESS_BAR_MARQUEE_ANIM_SPEED, // Sort by progress bar animation speed in case of Marquee style
//--- 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
   SORT_BY_CANV_ELEMENT_TEXT,                         // Sort by graphical element text
   SORT_BY_CANV_ELEMENT_DESCRIPTION,                  // Sort by graphical element description
   SORT_BY_CANV_ELEMENT_TOOLTIP_HEADER,               // Sort by Tooltip element header
   SORT_BY_CANV_ELEMENT_TOOLTIP_TEXT,                 // Sort by Tooltip element text
  };
//+------------------------------------------------------------------+

これで、すべてのグラフィック要素を新しいプロパティで選択して並べ替えることができるようになります。


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

   MSG_LIB_TEXT_CHEK_STATE_UNCHECKED,                 // Unchecked
   MSG_LIB_TEXT_CHEK_STATE_CHECKED,                   // Checked
   MSG_LIB_TEXT_CHEK_STATE_INDETERMINATE,             // Undefined
   
   MSG_LIB_TEXT_ICON_NONE,                            // None
   MSG_LIB_TEXT_ICON_INFO,                            // Info
   MSG_LIB_TEXT_ICON_WARNING,                         // Warning
   MSG_LIB_TEXT_ICON_ERROR,                           // Error
   MSG_LIB_TEXT_ICON_USER,                            // User
   MSG_LIB_TEXT_STYLE_BLOCKS,                         // Segmented blocks
   MSG_LIB_TEXT_STYLE_CONTINUOUS,                     // Continuous bar
   MSG_LIB_TEXT_STYLE_MARQUEE,                        // Continuous scrolling
   
   MSG_LIB_TEXT_SUNDAY,                               // Sunday
   MSG_LIB_TEXT_MONDAY,                               // Monday

...

   MSG_GRAPH_ELEMENT_TYPE_ELEMENT,                    // Element
   MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                 // Shadow object
   MSG_GRAPH_ELEMENT_TYPE_GLARE_OBJ,                  // Glare object
   MSG_GRAPH_ELEMENT_TYPE_FORM,                       // Form
   MSG_GRAPH_ELEMENT_TYPE_WINDOW,                     // Window

...

   MSG_GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN,          // HintMoveLeft control
   MSG_GRAPH_ELEMENT_TYPE_WF_TOOLTIP,                 // ToolTip control
   MSG_GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,        // BarProgressBar control
   MSG_GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,            // ProgressBar control
//---
   MSG_GRAPH_ELEMENT_TYPE_WF_WRONG_TYPE_PASSED,       // Incorrect control type
   MSG_GRAPH_ELEMENT_TYPE_WF_CANT_ADD_2_TOOLTIP,      // Unable to add two or more ToolTips to the same control
   MSG_GRAPH_OBJ_BELONG_PROGRAM,                      // Graphical object belongs to a program
   MSG_GRAPH_OBJ_BELONG_NO_PROGRAM,                   // Graphical object does not belong to a program

...

//--- CGraphElementsCollection
   MSG_GRAPH_OBJ_FAILED_GET_ADDED_OBJ_LIST,           // Failed to get the list of newly added objects
   MSG_GRAPH_OBJ_FAILED_GET_ACTIVE_OBJ_LIST,          // Failed to get the list of active elements
   MSG_GRAPH_OBJ_FAILED_GET_OBJECT_NAMES,             // Failed to get object names
   MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST,         // Failed to remove a graphical object from the list

...

   MSG_CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH,       // Upper edge area width
   MSG_CANV_ELEMENT_PROP_DISPLAYED,                   // Non-hidden control display flag
   MSG_CANV_ELEMENT_PROP_DISPLAY_STATE,               // Control display state
   MSG_CANV_ELEMENT_PROP_DISPLAY_DURATION,            // Control display duration
   MSG_CANV_ELEMENT_PROP_ENABLED,                     // Element availability flag
   MSG_CANV_ELEMENT_PROP_FORE_COLOR,                  // Default text color for all control objects

...

   MSG_CANV_ELEMENT_PROP_TOOLTIP_IS_BALLOON,          // Tooltip in the form of a "cloud"
   MSG_CANV_ELEMENT_PROP_TOOLTIP_USE_FADING,          // Fade when showing/hiding a tooltip
   MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM,        // The upper bound of the range ProgressBar operates in
   MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM,        // The lower bound of the range ProgressBar operates in
   MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,           // ProgressBar increment needed to redraw it
   MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,          // ProgressBar style
   MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,          // Current ProgressBar value from Min to Max
   MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,// Progress bar animation speed in case of Marquee style
   
//--- Real properties of graphical elements

//--- String properties of graphical elements
   MSG_CANV_ELEMENT_PROP_NAME_OBJ,                    // Graphical element object name
   MSG_CANV_ELEMENT_PROP_NAME_RES,                    // Graphical resource name
   MSG_CANV_ELEMENT_PROP_TEXT,                        // Graphical element text
   MSG_CANV_ELEMENT_PROP_DESCRIPTION,                 // Graphical element description
   MSG_CANV_ELEMENT_PROP_TOOLTIP_TITLE,               // Element tooltip title
   MSG_CANV_ELEMENT_PROP_TOOLTIP_TEXT,                // Element tooltip text
  };
//+------------------------------------------------------------------+

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

   {"Не установлен","Unchecked"},
   {"Установлен","Checked"},
   {"Неопределённый","Indeterminate"},
   
   {"None","None"},
   {"Info","Info"},
   {"Warning","Warning"},
   {"Error","Error"},
   {"Пользовательский","User"},
   {"Сегментированные блоки","Blocks"},
   {"Непрерывная полоса","Continuous"},
   {"Непрерывная прокрутка","Marquee"},
   
   {"Воскресение","Sunday"},
   {"Понедельник","Monday"},

...

   {"Элемент","Element"},
   {"Объект тени","Shadow object"},
   {"Объект блика","Glare object"},
   {"Форма","Form"},
   {"Окно","Window"},

...

   {"Элемент управления \"HintMoveDown\"","Control element \"HintMoveDown\""},
   {"Элемент управления \"ToolTip\"","Control element \"ToolTip\""},
   {"Элемент управления BarProgressBar","Control element \"BarProgressBar\""},
   {"Элемент управления ProgressBar","Control element \"ProgressBar\""},
   
   {"Передан не правильный тип элемента управления","Wrong control type passed"},
   {"Нельзя к одному элементу управления добавить два и более ToolTip","Can't add two or more ToolTips to one control"},
   {"Графический объект принадлежит программе","The graphic object belongs to the program"},
   {"Графический объект не принадлежит программе","The graphic object does not belong to the program"},

...

//--- CGraphElementsCollection
   {"Не удалось получить список вновь добавленных объектов","Failed to get the list of newly added objects"},
   {"Не удалось получить список активных элементов","Failed to get list of active elements"},
   {"Не удалось получить имена объектов","Failed to get object names"},
   {"Не удалось изъять графический объект из списка","Failed to detach graphic object from the list"},

...

   {"Ширина области верхней грани","Width of the top border area"},
   {"Флаг отображения не скрытого элемента управления","Flag that sets the display of a non-hidden control"},
   {"Состояние отображения элемента управления","Display state of the control"},
   {"Продолжительность процесса отображения элемента управления","Duration of the process of displaying the control"},
   {"Флаг доступности элемента","Element Availability Flag"},
   {"Цвет текста по умолчанию для всех объектов элемента управления","Default text color for all objects in the control"},

...

   {"Подсказка в форме \"облачка\"","Tooltip as \"Balloon\""},
   {"Угасание при отображении и скрытии подсказки","Tooltip uses fading"},
   {"Верхняя граница диапазона, в котором действует ProgressBar","Upper bound of the range in which the ProgressBar operates"},
   {"Нижняя граница диапазона, в котором действует ProgressBar","Lower bound of the range in which the ProgressBar operates"},
   {"Величина приращения значения ProgressBar для его перерисовки","Increment value of the ProgressBar to redraw it"},
   {"Стиль элемента ProgressBar","Progress Bar element style"},
   {"Текущее начение элемента ProgressBar в диапазоне от Min до Max","Current value of the ProgressBar in the range from Min to Max"},
   {"Скорость анимации полосы прогресса при стиле Marquee","Marquee style progress bar animation speed"},
   
//--- String properties of graphical elements
   {"Имя объекта-графического элемента","The name of the graphic element object"},
   {"Имя графического ресурса","Image resource name"},
   {"Текст графического элемента","Text of the graphic element"},
   {"Описание графического элемента","Description of the graphic element"},
   {"Заголовок подсказки элемента","Element tooltip header"},
   {"Текст подсказки элемента","Element tooltip title"},
  };
//+---------------------------------------------------------------------+


オブジェクトコレクションを作成する場合、CObjectクラスインスタンスとその子孫へのポインタの動的配列のクラスから派生したリストのクラスを使用します。CArrayObjクラスは、リストからポインタを取得し、取得したポインタを返すDetach()メソッドを備えています。リストからポインタを抽出しても、常にそのポインタを使用する必要はありません。
そのため、
\MQL5\Include\DoEasy\Collections\ListObj.mqhにある派生クラスで、ポインタを返さずリストから削除するメソッドを作成します

//+------------------------------------------------------------------+
//|                                                      ListObj.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------+
//| Include files                                  |
//+------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------+
//| Class of collection lists                      |
//+------------------------------------------------+
class CListObj : public CArrayObj
  {
private:
   int               m_type;                    // List type
public:
   bool              DetachElement(const int index)
                       {
                        CObject *obj=CArrayObj::Detach(index);
                        if(obj==NULL)
                           return false;
                        obj=NULL;
                        return true;
                       }
   void              Type(const int type)       { this.m_type=type;     }
   virtual int       Type(void)           const { return(this.m_type);  }
                     CListObj()                 { this.m_type=0x7778;   }
  };
//+------------------------------------------------------------------+

ここでは、単にリストからポインタを取得します失敗した場合はfalseを返します
抽出に成功したら、結果のポインタをリセットし、trueを返します


\MQL5\Include\DoEasy\Services\Pause.mqhの一時停止オブジェクトクラスを少し変更しましょう。

システム起動からの経過ミリ秒数で一時停止カウントダウンの開始を返すpublicメソッドを追加します。

//--- Return (1) the time passed from the countdown start in milliseconds, (2) waiting completion flag,
//--- (3) pause countdown start time, (4) pause in milliseconds, (5) countdown start
   ulong             Passed(void)                     const { return this.TickCount()-this.m_start;                     }
   bool              IsCompleted(void)                const { return this.Passed()>this.m_wait_msc;                     }
   ulong             TimeBegin(void)                  const { return this.m_time_begin;                                 }
   ulong             TimeWait(void)                   const { return this.m_wait_msc;                                   }
   ulong             CountdownStart(void)             const { return this.m_start;                                      }

このメソッドは、タイマーでコントロールを処理する際に必要になります。


グラフィック要素の新しい整数プロパティを追加したので、それらをグラフィック要素の基本オブジェクトで初期化し、オブジェクト構造の新しいフィールドを追加する必要があります。

\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            visible_area_h;                           // Visibility scope height
      bool           displayed;                                // Non-hidden control display flag
      int            display_state;                            // Control display state
      long           display_duration;                         // Control display duration
      int            split_container_fixed_panel;              // Panel that retains its size when the container is resized
      bool           split_container_splitter_fixed;           // Separator moveability flag

      //---...
      //---...

      //---...
      //---...

      int            border_right_area_width;                  // Right edge area width
      int            border_top_area_width;                    // Upper edge area width
      //--- Object real properties

      //--- Object string properties
      uchar          name_obj[64];                             // Graphical element object name
      uchar          name_res[64];                             // Graphical resource name
      uchar          text[256];                                // Graphical element text
      uchar          descript[256];                            // Graphical element description
     };
   SData             m_struct_obj;                             // Object structure
   uchar             m_uchar_array[];                          // uchar array of the object structure

オブジェクトをファイルに正しく保存し、その後に復元するためには、オブジェクトの構造が必要です。


オブジェクトプロパティへのアクセスを簡略化するメソッドのブロックに、これらの新しいプロパティを処理するメソッドを設定します

//--- (1) Set and (2) return the flag for displaying a non-hidden control
   virtual void      SetDisplayed(const bool flag)             { this.SetProperty(CANV_ELEMENT_PROP_DISPLAYED,flag);                   }
   bool              Displayed(void)                     const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_DISPLAYED);           }
   
//--- (1) Set and (2) return the control display status
   void              SetDisplayState(const ENUM_CANV_ELEMENT_DISPLAY_STATE state)
                       { this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE,state);                                                      }
   ENUM_CANV_ELEMENT_DISPLAY_STATE DisplayState(void)    const
                       { return (ENUM_CANV_ELEMENT_DISPLAY_STATE)this.GetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE);                    }
   
//--- (1) Set and (2) return the control display duration
   void              SetDisplayDuration(const long value)      { this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION,value);           }
   long              DisplayDuration(void)               const { return this.GetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION);          }
   
//--- (1) Set and (2) return the graphical element type
   void              SetTypeElement(const ENUM_GRAPH_ELEMENT_TYPE type)
                       {
                        CGBaseObj::SetTypeElement(type);
                        this.SetProperty(CANV_ELEMENT_PROP_TYPE,type);
                       }
   ENUM_GRAPH_ELEMENT_TYPE TypeGraphElement(void)  const { return (ENUM_GRAPH_ELEMENT_TYPE)this.GetProperty(CANV_ELEMENT_PROP_TYPE);   }

プロパティセッターメソッドは、渡された値をオブジェクトのプロパティに設定し、リターンメソッドは、オブジェクトのプロパティから以前に設定された値を返します。

両方のコンストラクタに新しいプロパティのデフォルト値を設定します

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const int      element_id,
                           const int      element_num,
                           const long     chart_id,
                           const int      wnd_num,
                           const string   descript,
                           const int      x,
                           const int      y,
                           const int      w,
                           const int      h,
                           const color    colour,
                           const uchar    opacity,
                           const bool     movable=true,
                           const bool     activity=true,
                           const bool     redraw=false) : m_shadow(false)
  {
   this.SetTypeElement(element_type);
   this.m_type=OBJECT_DE_TYPE_GELEMENT; 
   this.m_element_main=main_obj;
   this.m_element_base=base_obj;
   this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
   this.m_name=this.CreateNameGraphElement(element_type);
   this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id);
   this.m_subwindow=wnd_num;
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.m_text_anchor=0;
   this.m_text_x=0;
   this.m_text_y=0;
   this.SetBackgroundColor(colour,true);
   this.SetOpacity(opacity);
   this.m_shift_coord_x=0;
   this.m_shift_coord_y=0;
   if(::ArrayResize(this.m_array_colors_bg,1)==1)
      this.m_array_colors_bg[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1)
      this.m_array_colors_bg_dwn[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1)
      this.m_array_colors_bg_ovr[0]=this.BackgroundColor();
   if(this.Create(chart_id,wnd_num,x,y,w,h,redraw))
     {
      this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,this.m_canvas.ResourceName()); // Graphical resource name
      this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,CGBaseObj::ChartID());         // Chart ID

      //---...
      //---...

      this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,h);                 // Visibility scope height
      this.SetProperty(CANV_ELEMENT_PROP_DISPLAYED,true);                        // Non-hidden control display flag
      this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE,CANV_ELEMENT_DISPLAY_STATE_NORMAL);// Control display state
      this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION,DEF_CONTROL_PROCESS_DURATION);  // Control display duration
      this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_X,0);                      // Control area X coordinate
      this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_Y,0);                      // Control area Y coordinate

      //---...
      //---...

      this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_HEIGHT,0);                 // Control area height
      this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_RIGHT,0);                 // Right scroll area X coordinate

      this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT,"");                                            // Tooltip text for the element
      this.SetVisibleFlag(false,false);
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
     }
  }
//+------------------------------------------------+
//| Protected constructor                          |
//+------------------------------------------------+
CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const long    chart_id,
                           const int     wnd_num,
                           const string  descript,
                           const int     x,
                           const int     y,
                           const int     w,
                           const int     h) : m_shadow(false)
  {
   this.m_type=OBJECT_DE_TYPE_GELEMENT; 
   this.m_element_main=main_obj;
   this.m_element_base=base_obj;
   this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
   this.m_name=this.CreateNameGraphElement(element_type);
   this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id);
   this.m_subwindow=wnd_num;
   this.m_type_element=element_type;
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.m_text_anchor=0;
   this.m_text_x=0;
   this.m_text_y=0;
   this.SetBackgroundColor(CLR_CANV_NULL,true);
   this.SetOpacity(0);
   this.m_shift_coord_x=0;
   this.m_shift_coord_y=0;
   if(::ArrayResize(this.m_array_colors_bg,1)==1)
      this.m_array_colors_bg[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1)
      this.m_array_colors_bg_dwn[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1)
      this.m_array_colors_bg_ovr[0]=this.BackgroundColor();
   if(this.Create(chart_id,wnd_num,x,y,w,h,false))
     {
      this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,this.m_canvas.ResourceName()); // Graphical resource name
      this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,CGBaseObj::ChartID());         // Chart ID

      //---...
      //---...

      this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,h);                 // Visibility scope height
      this.SetProperty(CANV_ELEMENT_PROP_DISPLAYED,true);                        // Non-hidden control display flag
      this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE,CANV_ELEMENT_DISPLAY_STATE_NORMAL);// Control display state
      this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION,DEF_CONTROL_PROCESS_DURATION);  // Control display duration
      this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_X,0);                      // Control area X coordinate
      this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_Y,0);                      // Control area Y coordinate

      //---...
      //---...
 
      this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_HEIGHT,0);                 // Control area height
      this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_RIGHT,0);                 // Right scroll area X coordinate

      this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TITLE,"");                                           // Tooltip title for the element
      this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT,"");                                            // Tooltip text for the element
      this.SetVisibleFlag(false,false);
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
     }
  }
//+------------------------------------------------------------------+


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

//+------------------------------------------------+
//| Create the object structure                    |
//+------------------------------------------------+
bool CGCnvElement::ObjectToStruct(void)
  {
//--- Save integer properties
   this.m_struct_obj.id=(int)this.GetProperty(CANV_ELEMENT_PROP_ID);                               // Element ID
   this.m_struct_obj.type=(int)this.GetProperty(CANV_ELEMENT_PROP_TYPE);                           // Graphical element type

   //---...
   //---...

   this.m_struct_obj.visible_area_h=(int)this.GetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT);  // Visibility scope height
   this.m_struct_obj.displayed=(bool)this.GetProperty(CANV_ELEMENT_PROP_DISPLAYED);                // Flag for displaying a non-hidden control
   this.m_struct_obj.display_state=(int)this.GetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE);         // Control display state
   this.m_struct_obj.display_duration=this.GetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION);        // Control display duration
   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.enabled=(bool)this.GetProperty(CANV_ELEMENT_PROP_ENABLED);                    // Element availability flag

   //---...
   //---...

   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.fore_color_opacity=(uchar)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY); // Opacity of the default text color for all control objects

   //---...
   //---...

   this.m_struct_obj.border_right_area_width=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH);    // Right edge area width
   this.m_struct_obj.border_top_area_width=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH);        // Top edge area width
//--- Save real properties

//--- Save string properties
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_OBJ),this.m_struct_obj.name_obj);   // Graphical element object name
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_RES),this.m_struct_obj.name_res);   // Graphical resource name
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TEXT),this.m_struct_obj.text);           // Graphical element text
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_DESCRIPTION),this.m_struct_obj.descript);// Graphical element description
   //--- Save the structure to the uchar array
   ::ResetLastError();
   if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array))
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY,true);
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+


構造体からオブジェクトを生成するメソッドにおいて、構造体フィールドからオブジェクトプロパティに値を設定することを実装します。

//+------------------------------------------------+
//| Create the object from the structure           |
//+------------------------------------------------+
void CGCnvElement::StructToObject(void)
  {
//--- Save integer properties
   this.SetProperty(CANV_ELEMENT_PROP_ID,this.m_struct_obj.id);                                    // Element ID
   this.SetProperty(CANV_ELEMENT_PROP_TYPE,this.m_struct_obj.type);                                // Graphical element type

   //---...
   //---...

   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,this.m_struct_obj.visible_area_h);       // Visibility scope height
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAYED,this.m_struct_obj.displayed);                      // Non-hidden control display flag
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE,this.m_struct_obj.display_state);              // Control display state
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION,this.m_struct_obj.display_duration);        // Control display duration
   this.SetProperty(CANV_ELEMENT_PROP_ZORDER,this.m_struct_obj.zorder);                            // Priority of a graphical object for receiving the event of clicking on a chart
   this.SetProperty(CANV_ELEMENT_PROP_ENABLED,this.m_struct_obj.enabled);                          // Element availability flag

   //---...
   //---...

   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY,this.m_struct_obj.background_color_opacity);       // Element opacity
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN,this.m_struct_obj.background_color_mouse_down); // Control background color when clicking on the control
   
   //---...
   //---...

   this.SetProperty(CANV_ELEMENT_PROP_BORDER_BOTTOM_AREA_WIDTH,this.m_struct_obj.border_bottom_area_width);    // Bottom edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH,this.m_struct_obj.border_right_area_width);      // Right edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH,this.m_struct_obj.border_top_area_width);          // Top edge area width
//--- Save real properties

//--- Save string properties
   this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,::CharArrayToString(this.m_struct_obj.name_obj));   // Graphical element object name
   this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,::CharArrayToString(this.m_struct_obj.name_res));   // Graphical resource name
   this.SetProperty(CANV_ELEMENT_PROP_TEXT,::CharArrayToString(this.m_struct_obj.text));           // Graphical element text
   this.SetProperty(CANV_ELEMENT_PROP_DESCRIPTION,::CharArrayToString(this.m_struct_obj.descript));// Graphical element description
  }
//+------------------------------------------------------------------+


すべてのライブラリグラフィックオブジェクトの基本オブジェクトクラスの\MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqhで、グラフィック要素タイプの説明を返すメソッドに新しい オブジェクトタイプの説明を返すようにします

//+------------------------------------------------------------------+
//| Return the description of the graphical element type             |
//+------------------------------------------------------------------+
string CGBaseObj::TypeElementDescription(const ENUM_GRAPH_ELEMENT_TYPE type)
  {
   return
     (
      type==GRAPH_ELEMENT_TYPE_STANDARD                  ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD)                 :
      type==GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED         ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED)        :
      type==GRAPH_ELEMENT_TYPE_ELEMENT                   ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_ELEMENT)                  :
      type==GRAPH_ELEMENT_TYPE_SHADOW_OBJ                ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ)               :
      type==GRAPH_ELEMENT_TYPE_GLARE_OBJ                 ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_GLARE_OBJ)                :
      type==GRAPH_ELEMENT_TYPE_FORM                      ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_FORM)                     :
      type==GRAPH_ELEMENT_TYPE_WINDOW                    ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WINDOW)                   :
      //--- WinForms
      type==GRAPH_ELEMENT_TYPE_WF_UNDERLAY               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_UNDERLAY)              :
      type==GRAPH_ELEMENT_TYPE_WF_BASE                   ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BASE)                  :
      //--- Containers
      type==GRAPH_ELEMENT_TYPE_WF_CONTAINER              ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CONTAINER)             :
      type==GRAPH_ELEMENT_TYPE_WF_GROUPBOX               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_GROUPBOX)              :
      type==GRAPH_ELEMENT_TYPE_WF_PANEL                  ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_PANEL)                 :
      type==GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL            ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL)           :
      type==GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER        ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER)       :
      //--- Standard controls
      type==GRAPH_ELEMENT_TYPE_WF_COMMON_BASE            ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_COMMON_BASE)           :
      type==GRAPH_ELEMENT_TYPE_WF_LABEL                  ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LABEL)                 :
      type==GRAPH_ELEMENT_TYPE_WF_CHECKBOX               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CHECKBOX)              :
      type==GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON            ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON)           :
      type==GRAPH_ELEMENT_TYPE_WF_BUTTON                 ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BUTTON)                :
      type==GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX      ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX)     :
      type==GRAPH_ELEMENT_TYPE_WF_LIST_BOX               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LIST_BOX)              :
      type==GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM          ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM)         :
      type==GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX       ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX)      :
      type==GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX        ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX)       :
      type==GRAPH_ELEMENT_TYPE_WF_TOOLTIP                ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TOOLTIP)               :
      type==GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR           ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR)          :
      //--- Auxiliary control objects
      type==GRAPH_ELEMENT_TYPE_WF_TAB_HEADER             ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TAB_HEADER)            :
      type==GRAPH_ELEMENT_TYPE_WF_TAB_FIELD              ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TAB_FIELD)             :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON           ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON)          :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP        ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP)       :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN      ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN)     :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT      ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT)     :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT     ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT)    :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX   ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX)  :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX   ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX)  :
      type==GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER_PANEL  ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER_PANEL) :
      type==GRAPH_ELEMENT_TYPE_WF_SPLITTER               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SPLITTER)              :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_BASE              ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_BASE)             :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT         ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT)        :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT        ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT)       :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP           ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP)          :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN         ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN)        :
      type==GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR       ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR)      :
      "Unknown"
     );
  }  
//+------------------------------------------------------------------+

これらのオブジェクトはすでに宣言されていますが、もう少し後にツールチップオブジェクトクラスを確定した後で、作成することにします。


グラフィカル要素を扱うには、タイマーのイベントハンドラを作成する必要があります。すべてのグラフィック要素はフォームオブジェクトクラスから継承されているので、このクラスで仮想タイマーハンドラを宣言することにします。

゙MQL5゙Include゙Objects゙Form.mqhのpublicセクションにvirtual timer event handlerを記述します。

//--- Event handler
   virtual void      OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- Mouse event handler
   virtual void      OnMouseEvent(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- Last mouse event handler
   virtual void      OnMouseEventPostProcessing(void);

//--- Timer
   virtual void      OnTimer(void)  { return; }

ハンドラは何もしません。タイマーのイベントを処理するクラスで再定義する必要があります。


要素に接続されているツールチップオブジェクトの数を返すメソッドを宣言します

//--- Add a new attached element
   bool              AddNewElement(CGCnvElement *obj,const int x,const int y);

//--- (1) Bind the ToolTip object to the element
   bool              AddTooltip(CForm *tooltip);
//--- Return (1) the number of ToolTip objects, (2) bound ToolTip object, (3) by description
   int               ToolTipTotal(void);
   CForm            *GetTooltip(void);
   CForm            *GetTooltipByDescription(const string descript);
//--- Set the text for Tooltip
   virtual void      SetTooltipText(const string text);

1つのグラフィカルオブジェクトに割り当てられるツールチップオブジェクトは1つだけです。しかし、1つのオブジェクトに複数のツールチップを接続し、作成したツールチップを接続した他のオブジェクトに割り当てることができます。これをおこなうのは、すべてのライブラリオブジェクトがツールチップオブジェクトを自らに接続できるわけではないからです。ただし、オブジェクトが接続されているコンテナにツールチップを作成し、これらのオブジェクトにツールチップを割り当てることはいつでも可能です。このメソッドにより、作成されコンテナに取り付けられたツールチップオブジェクトの数を知ることができます。

指定されたツールチップオブジェクトをオブジェクトにバインドするメソッドを改良してみましょう。

無効なタイプ接続されたツールチップの数が0より大きいかどうかに対する確認を追加しました。

//+------------------------------------------------------------------+
//| Assign the specified ToolTip object to an object                 |
//+------------------------------------------------------------------+
bool CForm::AddTooltip(CForm *tooltip)
  {
//--- If the pointer to an empty object is passed or the object type is not equal to Tooltip, report an error and return 'false'
   if(tooltip==NULL)
     {
      CMessage::ToLog(DFUN,MSG_GRAPH_ELM_COLLECTION_ERR_EMPTY_OBJECT);
      return false;
     }
//--- If a pointer to an object whose type is not equal to Tooltip is passed, report an error and return 'false'
   if(tooltip.TypeGraphElement()!=GRAPH_ELEMENT_TYPE_WF_TOOLTIP)
     {
      CMessage::ToLog(DFUN,MSG_GRAPH_ELEMENT_TYPE_WF_WRONG_TYPE_PASSED);
      return false;
     }
//--- If the list of attached objects already contains the Tooltip object with the same description as the object passed to the method - 
//--- inform of that in the journal and return 'false'
   if(this.GetTooltipByDescription(tooltip.Description())!=NULL)
     {
      ::Print(DFUN,this.TypeElementDescription()+": ",CMessage::Text(MSG_FORM_TOOLTIP_OBJ_ALREADY_EXISTS),": ",tooltip.Name(),", Description: \"",tooltip.Description(),"\"");
      return false;
     }
//--- If the list of attached objects already contains the Tooltip object, report this to the log and return 'false'
   if(this.ToolTipTotal()>0)
     {
      ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CANT_ADD_2_TOOLTIP));
      return false;
     }
//--- If it was not possible to add the Tooltip object to the list of attached objects, report an error and return 'false'
   if(!this.m_list_elements.Add(tooltip))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST),": ",tooltip.NameObj());
      return false;
     }
//--- If the coordinates of the object added to the list are changed, set the Tooltip relative coordinates
   if(tooltip.Move(this.CoordX(),this.CoordY()))
     {
      tooltip.SetCoordXRelative(tooltip.CoordX()-this.CoordX());
      tooltip.SetCoordYRelative(tooltip.CoordY()-this.CoordY());
     }
//--- Set this object as the base object for the Tooltip object and return 'true'
   tooltip.SetBase(this.GetObject());
   return true;
  }
//+------------------------------------------------------------------+

もし、間違ってツールチップオブジェクトではなく、別の型のオブジェクトを接続しようとすると、このメソッドはエラーを報告します。ツールチップが既にオブジェクトに接続されている場合は、エラーメッセージも表示され、メソッドはfalseを返します。


以下は、ツールチップオブジェクトの数を返すメソッドです。

//+------------------------------------------------+
//| Return the number of ToolTip objects           |
//+------------------------------------------------+
int CForm::ToolTipTotal(void)
  {
   int res=0;
   for(int i=this.ElementsTotal()-1;i>WRONG_VALUE;i--)
     {
      CGCnvElement *obj=this.GetElement(i);
      if(obj!=NULL && obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_TOOLTIP)
         res++;
     }
   return res;
  }
//+------------------------------------------------------------------+

このオブジェクトがコンテナである場合、任意の数のツールチップオブジェクトが接続されていることがあります。このメソッドは、その数を返します。ループ内の次のオブジェクトを、接続されているオブジェクトの総数で取得します。オブジェクトタイプがツールチップの場合、オブジェクトカウンタ(res変数)を増加させます。ループの最後で、resに設定された計算結果を返します。


グラフィック要素コレクションタイマーは、16ミリ秒ごとに更新されます。例えば1秒以内にツールチップをフェードイン/アウトさせるには、1000ミリ秒をタイマーの更新周期で割る必要があります。その結果、約1000/16=62.5ミリ秒ごとにオブジェクトの不透明度を変更する必要があります。

\MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ToolTip.mqhで、透明度変更ステップを格納する変数を宣言します

//+------------------------------------------------------------------+
//| Class of the base Hint object of the WForms controls             |
//+------------------------------------------------------------------+
class CToolTip : public CHintBase
  {
private:
   int               m_step;                             // Transparency change step
//--- Adjust a tooltip size according to a text size
   void              CorrectSizeByTexts(void);
protected:


クラスのpublicセクションで、仮想イベントハンドラを宣言します

//--- Display the element
   virtual void      Show(void);
//--- Redraw the object
   virtual void      Redraw(bool redraw);
//--- Clear the element filling it with color and opacity
   virtual void      Erase(const color colour,const uchar opacity,const bool redraw=false);
//--- Clear the element with a gradient fill
   virtual void      Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false);
//--- Draw the hint frame
   virtual void      DrawFrame(void);
//--- Initialize the variables
   virtual void      Initialize(void);
//--- Timer
   virtual void      OnTimer(void);
  };
//+------------------------------------------------------------------+


各コンストラクタにおいて、フェードイン/アウトの継続時間グラフィック要素収集タイマカウンタのステップのデフォルト値に基づいて透明度の変更ステップを格納する変数の値を計算します

//+------------------------------------------------+
//| Protected constructor with an object type,     |
//| chart ID and subwindow                         |
//+------------------------------------------------+
CToolTip::CToolTip(const ENUM_GRAPH_ELEMENT_TYPE type,
                   CGCnvElement *main_obj,CGCnvElement *base_obj,
                   const long chart_id,
                   const int subwindow,
                   const string descript,
                   const int x,
                   const int y,
                   const int w,
                   const int h) : CHintBase(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and assign the library object type to the current object
   this.SetTypeElement(type);
   this.m_type=OBJECT_DE_TYPE_GWF_COMMON;
   this.Initialize();
   this.m_step=(int)::floor(DEF_CONTROL_PROCESS_DURATION/COLLECTION_GRAPH_ELM_COUNTER_STEP);
  }
//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CToolTip::CToolTip(CGCnvElement *main_obj,CGCnvElement *base_obj,
                   const long chart_id,
                   const int subwindow,
                   const string descript,
                   const int x,
                   const int y,
                   const int w,
                   const int h) : CHintBase(GRAPH_ELEMENT_TYPE_WF_TOOLTIP,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_TOOLTIP);
   this.m_type=OBJECT_DE_TYPE_GWF_COMMON;
   this.Initialize();
   this.m_step=(int)::floor(DEF_CONTROL_PROCESS_DURATION/COLLECTION_GRAPH_ELM_COUNTER_STEP);
  }
//+------------------------------------------------------------------+


変数の初期化メソッドに、ツールチップオブジェクトの状態を変更する際の遅延のデフォルト値を入力します。

//+------------------------------------------------+
//| Initialize the variables                       |
//+------------------------------------------------+
void CToolTip::Initialize(void)
  {
   this.SetBackgroundColor(CLR_DEF_CONTROL_HINT_BACK_COLOR,true);
   this.SetBorderColor(CLR_DEF_CONTROL_HINT_BORDER_COLOR,true);
   this.SetForeColor(CLR_DEF_CONTROL_HINT_FORE_COLOR,true);
   this.SetDisplayed(false);
   this.SetBorderSizeAll(1);
   this.SetBorderStyle(FRAME_STYLE_SIMPLE);
   this.SetShadow(true);
   this.DrawShadow(2,2,CLR_DEF_SHADOW_COLOR,CLR_DEF_SHADOW_OPACITY,DEF_SHADOW_BLUR);
   this.SetOpacity(255,false);
   this.SetTitle("");
   this.SetTooltipText("");
   this.SetInitialDelay(DEF_CONTROL_TOOLTIP_INITIAL_DELAY);
   this.SetAutoPopDelay(DEF_CONTROL_TOOLTIP_AUTO_POP_DELAY);
   this.SetReshowDelay(DEF_CONTROL_TOOLTIP_RESHOW_DELAY);
   this.SetShowAlways(false);
   this.SetIcon(CANV_ELEMENT_TOOLTIP_ICON_NONE);
   this.SetBalloon(false);
   this.SetUseFading(true);
   this.SetTextAlign(ANCHOR_LEFT_UPPER);
   this.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP);
   this.SetFont(DEF_FONT,DEF_FONT_SIZE,FW_NORMAL);
   this.SetDisplayed(false);
   this.Hide();
  }
//+------------------------------------------------------------------+


ツールチップを表示するメソッドで、オブジェクト表示コマンドを一番最後に移動し、オブジェクト全体の完全な再描画を削除します

//+------------------------------------------------+
//| Show the element                               |
//+------------------------------------------------+
void CToolTip::Show(void)
  {
//--- If the element should not be displayed (hidden inside another control), leave
   if(!this.Displayed() || this.TooltipText()=="")
      return;
//--- Display the object
   CGCnvElement::Show();
//--- Get the "Shadow" object
   CShadowObj *shadow=this.GetShadowObj();
//--- If the object has a shadow and the "Shadow" object exists, display the shadow
   if(this.IsShadow() && shadow!=NULL)
     {
      shadow.Show();
      this.BringToTop();
     }
//--- Redraw the object
   this.Redraw(true);
  }
//+------------------------------------------------------------------+

メソッドは次のようになります。

//+------------------------------------------------+
//| Show the element                               |
//+------------------------------------------------+
void CToolTip::Show(void)
  {
//--- If the element should not be displayed (hidden inside another control), leave
   if(!this.Displayed() || this.TooltipText()=="")
      return;
//--- Get the "Shadow" object
   CShadowObj *shadow=this.GetShadowObj();
//--- If the object has a shadow and the "Shadow" object exists, display the shadow
   if(this.IsShadow() && shadow!=NULL)
     {
      shadow.Show();
      this.BringToTop();
     }
//--- Display the object
   CGCnvElement::Show();
  }
//+------------------------------------------------------------------+

この改良により、要素の不透明度を徐々に変化させたときに発生する不快な「点滅」が若干軽減されまず。


ツールチップメソッドの中で、一番最後に、変更したcanvasの更新を追加します

//+------------------------------------------------+
//| Draw a hint                                    |
//+------------------------------------------------+
void CToolTip::DrawHint(const int shift)
  {
   int y=3;
   int x=6+(this.Icon()>CANV_ELEMENT_TOOLTIP_ICON_NONE ? 16 : 0);
   this.DrawIcon();
   if(this.Title()!="" && this.Title()!=NULL)
     {
      this.SetFont(DEF_FONT,DEF_FONT_SIZE,FW_BLACK);
      this.Text(x,y,this.Title(),this.ForeColor(),this.Opacity(),this.TextAnchor());
      this.SetFont(DEF_FONT,DEF_FONT_SIZE,FW_NORMAL);
      y+=this.TextHeight(this.Title())+4;
     }
   this.Text(x,y,this.Text(),this.ForeColor(),this.Opacity(),this.TextAnchor());
   this.Update();
  }
//+------------------------------------------------------------------+

不透明度をゼロにすると(オブジェクトが完全に透明になる)、アンチエイリアシングでプリミティブを描画するメソッドの挙動がおかしくなることに気づきました。透明度の値に対して反応が悪くなります。不透明度が非常に低い場合、まったく同じ不透明度のオブジェクトの背景に対して、このメソッドで描かれた線が目立ちすぎてしまいます。キャンバスの更新ラインを追加することは、この厄介な効果を軽減する試みの1つです。ただし、まだ動作していません。


以下は、タイマーのイベントハンドラです。

//+------------------------------------------------+
//| Timer                                          |
//+------------------------------------------------+
void CToolTip::OnTimer(void)
  {
//--- If the object is in the normal state (hidden)
   if(this.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_NORMAL)
     {
      //--- set the state of waiting for the object to fade in
      //--- set the waiting duration and set the countdown time
      this.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_WAITING_FADE_IN);
      this.m_pause.SetWaitingMSC(this.InitialDelay());
      this.m_pause.SetTimeBegin();
      return;
     }
//--- If the object is in the state of waiting for fading in
   if(this.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_WAITING_FADE_IN)
     {
      //--- If the waiting time has not yet passed, leave
      if(this.m_pause.Passed()<this.InitialDelay())
         return;
      //--- Set the state of the object fading in and
      //---  the process start countdown time
      this.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_PROCESS_FADE_IN);
      this.m_pause.SetTimeBegin();
      return;
     }
//--- If the object is in the state of fading in
   if(this.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_PROCESS_FADE_IN)
     {
      //--- If the object is not completely opaque yet
      if(this.Opacity()<255)
        {
         //--- set the display flag and show the object,
         //--- calculate the required opacity value at this timer step,
         //--- set the calculated opacity to the properties and redraw the object
         this.SetDisplayed(true);
         if(this.Opacity()==0)
            this.Show();
         uchar value=(this.Opacity()+(uchar)this.m_step<255 ? this.Opacity()+(uchar)this.m_step : 255);
         this.SetOpacity(value);
         this.Redraw(true);
         return;
        }
      //--- Set the end state of fading in
      this.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_COMPLETED_FADE_IN);
     }
//--- If the object is in the state of completion of fading in
   if(this.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_COMPLETED_FADE_IN)
     {
      //--- set the state of waiting for object fading out,
      //--- set the waiting duration and set the countdown time
      this.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_WAITING_FADE_OUT);
      this.m_pause.SetWaitingMSC(this.AutoPopDelay());
      this.m_pause.SetTimeBegin();
      return;
     }
//--- If the object is in the state of waiting for fading out
   if(this.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_WAITING_FADE_OUT)
     {
      //--- If the waiting time has not yet passed, leave
      if(this.m_pause.Passed()<this.AutoPopDelay())
         return;
      //--- Set the state of the object fading out and
      //---  the process start countdown time
      this.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_PROCESS_FADE_OUT);
      this.m_pause.SetTimeBegin();
      return;
     }
//--- If the object is in the state of fading out
   if(this.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_PROCESS_FADE_OUT)
     {
      //--- If the object is not completely transparent yet
      if(this.Opacity()>0)
        {
         //--- set the display flag,
         //--- calculate the required opacity value at this timer step,
         //--- set the calculated opacity to the properties and redraw the object
         //this.SetDisplayed(true);
         uchar value=(this.Opacity()-(uchar)this.m_step>0 ? this.Opacity()-(uchar)this.m_step : 0);
         this.SetOpacity(value);
         this.Redraw(true);
         return;
        }
      //--- Set the end state of fading out,
      //--- set the properties to full transparency and redraw the object
      this.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_COMPLETED_FADE_OUT);
      this.SetOpacity(0);
      this.Redraw(true);
     }
//--- If the object is in the state of completion of fading out
   if(this.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_COMPLETED_FADE_OUT)
     {
      //--- Set the flag for not displaying, set the full transparency,
      //--- hide the object and set the state of the completion of the entire cycle of changes
      this.SetDisplayed(false);
      this.SetOpacity(0);
      this.Hide();
      this.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_COMPLETED);
     }
  }
//+------------------------------------------------------------------+

メソッドのロジックはコードのコメントで完全に説明されています。このハンドラは、オブジェクトのタイマーが切れるたびに呼び出されます。タイマーの反復ごとに、オブジェクトの状態とその待機/状態変化カウンタを確認する必要があります。

まず、オブジェクトは通常の状態が保存されています。この状態では、ツールチップは完全に非表示です。オブジェクトがこの状態にある場合、まず、フェードインを開始する前にしばらく待機する必要があります。そこで、オブジェクトの正常な状態を見て、フェードイン待ちの状態を規定し、待ち時間のカウントダウンを開始し、メソッドから離脱します。

次の反復で、新しい状態(フェードイン待ち)を見て、それに応じて、カウンタを確認します。待ち時間が発生した場合は、オブジェクトをフェードイン状態にし、次のメソッド呼び出しまで放置します。次の実行では、すでにオブジェクトがフェードインしていく過程に入っています。ここで、オブジェクトの不透明度を確認し、変更ステップで増加させる必要があります。これは、タイマー操作の各反復で発生します。オブジェクトが完全に不透明になったら、すぐに新しい状態を設定し、スムーズなフェードプロセスを待ちます。結局、5秒程度で現れるオブジェクトは、スムーズに消えてくれるはずです。

フェードアウトのプロセスは、フェードインのプロセスと同一です。フルサイクルの終了時に、変更サイクル終了の状態がオブジェクトに設定されます。すぐに正常な状態を設定すれば、そのオブジェクトの正常な状態がこのサイクルを開始するための条件となるので、すべてのサイクルが新たに開始されることになります。タイマーで処理するオブジェクトのリストから、そのオブジェクトへのポインタが削除されたときのみ、そのオブジェクトに書き込む必要があります。これは、グラフィック要素のコレクションクラスでおこなわれます。オブジェクトのフルサイクル完了状態を見て、メソッドはオブジェクトへのポインタを処理リストから削除し、オブジェクト自体を通常の状態に設定します。次にカーソルを合わせると、そのオブジェクトは再びタイマーで処理するためのリストに置かれます。同様に、オブジェクトの処理サイクルの準備ができた領域からカーソルが移動した場合、あるいはサイクル中であっても、オブジェクトポインタはリストから削除されます。


徐々に、新しいProgressBar WinFormsオブジェクトの作成に近づいています。このコントロールのために、Glare補助オブジェクトを作成する必要があります。このタイプのオブジェクトは、いくつかのGUI要素を視覚的に装飾する役割を果たします。一方、ProgressBarオブジェクトでは、グレアがプログレスバーに沿って走るようにする必要があります。概念的には、必要な形と大きさの白い点を描き、中心から端までぼかすことになります。グレアオブジェクトは、影オブジェクトと同様に半透明になります。ここで、カスタムレンダリングを維持したまま、影オブジェクトのブラーメソッドを使用するためには、このようなオブジェクトを継承する必要があることに気づきます。影オブジェクトを正常に継承するためには、protectedコンストラクタを追加して、その中で生成されるオブジェクトのタイプを指定する必要があります。

\MQL5\Include\DoEasy\Objects\Graph\ShadowObj.mqhで影オブジェクトのクラスを変更しましょう。

ガウスぼかしメソッドと重み係数の配列を、クラスのprivateセクションからprotectedセクションに移動しますprotectedコンストラクタもそこで宣言されています。クラスのpublicセクションに、オブジェクトによる実数プロパティの保持のためのフラグを返す仮想メソッドを記述します

//+------------------------------------------------+
//| Shadows object class                           |
//+------------------------------------------------+
class CShadowObj : public CGCnvElement
  {
private:
   color             m_color;                         // Shadow color
   uchar             m_opacity;                       // Shadow opacity
   uchar             m_blur;                          // Blur
//--- Draw the object shadow form
   void              DrawShadowFigureRect(const int w,const int h);
protected:
//--- Gaussian blur
   bool              GaussianBlur(const uint radius);
//--- Return the array of weight ratios
   bool              GetQuadratureWeights(const double mu0,const int n,double &weights[]);
//--- Protected constructor with object type, chart ID and subwindow
                     CShadowObj(const ENUM_GRAPH_ELEMENT_TYPE type,
                                CGCnvElement *main_obj,CGCnvElement *base_obj,
                                const long chart_id,
                                const int subwindow,
                                const string descript,
                                const int x,
                                const int y,
                                const int w,
                                const int h);
public:
//--- Constructor indicating the main and base objects, chart ID and subwindow
                     CShadowObj(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                const long chart_id,
                                const int subwindow,
                                const string descript,
                                const int x,
                                const int y,
                                const int w,
                                const int h);

//--- Supported object properties (1) integer, (2) real and (3) string ones
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)  { return true; }
   
//--- Draw an object shadow

オブジェクトによるプロパティの維持のためのフラグを返すメソッドは、今後必要となるライブラリの標準メソッドなので、徐々にすべてのグラフィック要素に追加していく予定です。ここでは、このクラスでこの問題に立ち戻ることを避けるために、このようなメソッドを追加しただけです。


以下は、Protectedコンストラクタです。

//+------------------------------------------------+
//| Protected constructor with an object type,     |
//| chart ID and subwindow                         |
//+------------------------------------------------+
CShadowObj::CShadowObj(const ENUM_GRAPH_ELEMENT_TYPE type,
                       CGCnvElement *main_obj,CGCnvElement *base_obj,
                       const long chart_id,
                       const int subwindow,
                       const string descript,
                       const int x,
                       const int y,
                       const int w,
                       const int h) : CGCnvElement(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and assign the library object type to the current object
   this.SetTypeElement(type);
   this.m_type=OBJECT_DE_TYPE_GSHADOW; 
   CGCnvElement::SetBackgroundColor(clrNONE,true);
   CGCnvElement::SetOpacity(0);
   CGCnvElement::SetActive(false);
   this.SetOpacityDraw(CLR_DEF_SHADOW_OPACITY);
   this.SetBlur(DEF_SHADOW_BLUR);
   color gray=CGCnvElement::ChangeColorSaturation(this.ChartBackgroundColor(),-100);
   this.m_color=CGCnvElement::ChangeColorLightness(gray,-50);
   this.m_shadow=false;
   this.SetVisibleFlag(false,false);
  }
//+------------------------------------------------------------------+

コンストラクタの仮パラメータで、初期化文字列で親クラスのコンストラクタに渡される、作成されたオブジェクトのタイプを渡します。これは、ライブラリのすべてのオブジェクトでおこなわれます。ここでの他のすべては、パラメトリックコンストラクタとまったく同じようにおこなわれます。

パラメトリックコンストラクタで、末尾にある、作成直後に影を描画する文字列を削除します

//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CShadowObj::CShadowObj(CGCnvElement *main_obj,CGCnvElement *base_obj,
                       const long chart_id,
                       const int subwindow,
                       const string descript,
                       const int x,
                       const int y,
                       const int w,
                       const int h) : CGCnvElement(GRAPH_ELEMENT_TYPE_SHADOW_OBJ,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.m_type=OBJECT_DE_TYPE_GSHADOW; 
   CGCnvElement::SetBackgroundColor(clrNONE,true);
   CGCnvElement::SetOpacity(0);
   CGCnvElement::SetActive(false);
   this.SetOpacityDraw(CLR_DEF_SHADOW_OPACITY);
   this.SetBlur(DEF_SHADOW_BLUR);
   color gray=CGCnvElement::ChangeColorSaturation(this.ChartBackgroundColor(),-100);
   this.m_color=CGCnvElement::ChangeColorLightness(gray,-50);
   this.m_shadow=false;
   this.SetVisibleFlag(false,false);
   CGCnvElement::Erase();
  }
//+------------------------------------------------------------------+

GUI要素作成時の影オブジェクトの動作が不正になる文字列がありました。まず、空のチャートに影を表示し、GUIの外観を構築した。これで、影が先に表示されることはありません。


ProgressBarコントロール

まず、\MQL5\Include\DoEasy\Objects\Graph\WForms\GlareObj.mqhファイルに補助グレアオブジェクトを作成しましょう。現在、このオブジェクトは必要ないので、検討しないことにします。描画されたグレアの色が白に設定される以外は、影オブジェクトクラスと完全に類似しています。

//+------------------------------------------------------------------+
//|                                                     GlareObj.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------+
//| Include files                                  |
//+------------------------------------------------+
#include "..\ShadowObj.mqh"
//+------------------------------------------------+
//| Glare object class                             |
//+------------------------------------------------+
class CGlareObj : public CShadowObj
  {
private:
   color             m_color;                         // Glare color
   uchar             m_opacity;                       // Glare opacity
   uchar             m_blur;                          // Blur
//--- Draw the object glare form
   void              DrawGlareFigure(const int w,const int h);
   void              DrawGlareFigureRect(const int w,const int h);
protected:
//--- Protected constructor with object type, chart ID and subwindow
                     CGlareObj(const ENUM_GRAPH_ELEMENT_TYPE type,
                               CGCnvElement *main_obj,CGCnvElement *base_obj,
                               const long chart_id,
                               const int subwindow,
                               const string descript,
                               const int x,
                               const int y,
                               const int w,
                               const int h);
public:
//--- Constructor indicating the main and base objects, chart ID and subwindow
                     CGlareObj(CGCnvElement *main_obj,CGCnvElement *base_obj,
                               const long chart_id,
                               const int subwindow,
                               const string descript,
                               const int x,
                               const int y,
                               const int w,
                               const int h);

//--- Supported object properties (1) integer, (2) real and (3) string ones
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)  { return true; }
   
//--- Draw the object glare
   void              Draw(const int shift_x,const int shift_y,const uchar blur_value,const bool redraw);
  };
//+------------------------------------------------+
//| Protected constructor with an object type,     |
//| chart ID and subwindow                         |
//+------------------------------------------------+
CGlareObj::CGlareObj(const ENUM_GRAPH_ELEMENT_TYPE type,
                     CGCnvElement *main_obj,CGCnvElement *base_obj,
                     const long chart_id,
                     const int subwindow,
                     const string descript,
                     const int x,
                     const int y,
                     const int w,
                     const int h) : CShadowObj(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and assign the library object type to the current object
   this.SetTypeElement(type);
   this.m_type=OBJECT_DE_TYPE_GGLARE; 
   CGCnvElement::SetBackgroundColor(clrNONE,true);
   CGCnvElement::SetOpacity(0);
   CGCnvElement::SetActive(false);
   this.SetOpacityDraw(CLR_DEF_SHADOW_OPACITY);
   this.SetBlur(DEF_SHADOW_BLUR);
   this.m_color=clrWhite;
   this.m_shadow=false;
   this.SetVisibleFlag(false,false);
  }
//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CGlareObj::CGlareObj(CGCnvElement *main_obj,CGCnvElement *base_obj,
                     const long chart_id,
                     const int subwindow,
                     const string descript,
                     const int x,
                     const int y,
                     const int w,
                     const int h) : CShadowObj(GRAPH_ELEMENT_TYPE_GLARE_OBJ,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.m_type=OBJECT_DE_TYPE_GGLARE; 
   CGCnvElement::SetBackgroundColor(clrNONE,true);
   CGCnvElement::SetOpacity(0);
   CGCnvElement::SetActive(false);
   this.SetOpacityDraw(CLR_DEF_SHADOW_OPACITY);
   this.SetBlur(DEF_SHADOW_BLUR);
   this.m_color=clrWhite;
   this.m_shadow=false;
   this.SetVisibleFlag(false,false);
  }
//+------------------------------------------------+
//| Draw the object glare                          |
//+------------------------------------------------+
void CGlareObj::Draw(const int shift_x,const int shift_y,const uchar blur_value,const bool redraw)
  {
   if(!this.IsVisible())
      return;
//--- Set the glare offset values along the X and Y axes to variables
   this.SetCoordXRelative(shift_x);
   this.SetCoordYRelative(shift_y);
//--- Calculate the height and width of the drawn rectangle
   int w=this.Width()-OUTER_AREA_SIZE*2;
   int h=this.Height()-OUTER_AREA_SIZE*2;
//--- Draw a filled rectangle with calculated dimensions
   this.DrawGlareFigure(w,h);
//--- Calculate the blur radius, which cannot exceed a quarter of the OUTER_AREA_SIZE constant
   this.m_blur=(blur_value>OUTER_AREA_SIZE/4 ? OUTER_AREA_SIZE/4 : blur_value);
//--- If failed to blur the shape, exit the method (GaussianBlur() displays the error on the journal)
   if(!this.GaussianBlur(this.m_blur))
      return;
//--- Shift the glare object by X/Y offsets specified in the method arguments and update the canvas
   CGCnvElement::Move(this.CoordX()+this.CoordXRelative(),this.CoordY()+this.CoordYRelative(),false);
   CGCnvElement::Update(redraw);
  }
//+------------------------------------------------+
//| Draw the object glare form                     |
//+------------------------------------------------+
void CGlareObj::DrawGlareFigure(const int w,const int h)
  {
   this.DrawGlareFigureRect(w,h);
  }
//+------------------------------------------------+
//| Draw the rectangle object glare form           |
//+------------------------------------------------+
void CGlareObj::DrawGlareFigureRect(const int w,const int h)
  {
   CGCnvElement::DrawRectangleFill(OUTER_AREA_SIZE,OUTER_AREA_SIZE,OUTER_AREA_SIZE+w-1,OUTER_AREA_SIZE+h-1,this.m_color,this.OpacityDraw());
   CGCnvElement::Update();
  }
//+------------------------------------------------------------------+

このクラスで必要な変更はすべて次回おこなう予定です。とりあえず、このままにしておきましょう。


ProgressBarコントロールは、ウォーターマークとプログレスバーの2つのオブジェクトで構成されます。アンダーレイはコントロール要素そのものを表すことになります。今後、追加要素を配置することも可能で、プログレスバーは親オブジェクトからプロパティを変更した別の補助オブジェクトで表現される予定です。

\MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ライブラリフォルダで、CBarProgressBarクラスのBarProgressBar.mqhを新規に作成しますクラスは、すべてのライブラリWinFormsオブジェクトの基本オブジェクトから派生します基本オブジェクトファイルは、作成したクラスファイルにインクルードする必要があります

//+------------------------------------------------------------------+
//|                                               BarProgressBar.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------+
//| Include files                                  |
//+------------------------------------------------+
#include "..\WinFormBase.mqh"
//+------------------------------------------------------------------+
//| BarProgressBar object class of the ProgressBar control           |
//+------------------------------------------------------------------+
class CBarProgressBar : public CWinFormBase
  {
  }


クラスのprotectedセクションで、プログレスバーにグレアオブジェクトを表示するメソッドとprotectedコンストラクタを宣言します。publicセクションに、オブジェクトのプロパティ値を設定するメソッド、オブジェクトのプロパティ値を返すメソッド、プロパティを保持する仮想メソッド、パラメトリックコンストラクタ、クラスタイマーイベントハンドラを記述します。

//+------------------------------------------------+
//| Include files                                  |
//+------------------------------------------------+
#include "..\WinFormBase.mqh"
//+------------------------------------------------------------------+
//| BarProgressBar object class of the ProgressBar control           |
//+------------------------------------------------------------------+
class CBarProgressBar : public CWinFormBase
  {
private:

protected:
   //--- Display the glare
   virtual void      DrawGlare(void);
//--- Protected constructor with object type, chart ID and subwindow
                     CBarProgressBar(const ENUM_GRAPH_ELEMENT_TYPE type,
                                     CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h);
public:
//--- Set the (1) animation speed in case of Marquee style, (2) style, (3) increment value, (4) current value of the ProgressBar control
   void              SetMarqueeAnimationSpeed(const int value)    { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,value);  }
   void              SetStyle(const ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE style) { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,style); }
   void              SetStep(const int value)                     { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,value);                }
   void              SetValue(const int value)                    { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,value);               }

//--- Supported object properties (1) integer, (2) real and (3) string ones
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)  { return true; }
   
//--- Constructor
                     CBarProgressBar(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h);
//--- Timer
   virtual void      OnTimer(void);
  };
//+------------------------------------------------------------------+

宣言されたメソッドを詳しく見てみましょう。


以下は、Protectedコンストラクタです。

//+------------------------------------------------+
//| Protected constructor with an object type,     |
//| chart ID and subwindow                         |
//+------------------------------------------------+
CBarProgressBar::CBarProgressBar(const ENUM_GRAPH_ELEMENT_TYPE type,
                                 CGCnvElement *main_obj,CGCnvElement *base_obj,
                                 const long chart_id,
                                 const int subwindow,
                                 const string descript,
                                 const int x,
                                 const int y,
                                 const int w,
                                 const int h) : CWinFormBase(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and assign the library object type to the current object
   this.SetTypeElement(type);
   this.m_type=OBJECT_DE_TYPE_GWF_HELPER;
   this.SetPaddingAll(0);
   this.SetMarginAll(0);
   this.SetBorderSizeAll(0);
   this.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
   this.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
   this.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
  }
//+------------------------------------------------------------------+

コンストラクタは、初期化文字列で親クラスに渡された作成されたグラフィック要素の型を受け取りますライブラリグラフィカルオブジェクトのタイプは「補助」に設定され、オブジェクトには境界がなく、デフォルトの色が設定されています。


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

//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CBarProgressBar::CBarProgressBar(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                 const long chart_id,
                                 const int subwindow,
                                 const string descript,
                                 const int x,
                                 const int y,
                                 const int w,
                                 const int h) : CWinFormBase(GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR);
   this.m_type=OBJECT_DE_TYPE_GWF_HELPER;
   this.SetPaddingAll(0);
   this.SetMarginAll(0);
   this.SetBorderSizeAll(0);
   this.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
   this.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
   this.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
  }
//+------------------------------------------------------------------+

ここでのすべてはprotectedコンストラクタとまったく同じですが、オブジェクトタイプは仮パラメータでは渡されません。代わりに初期化文字列にハードコードされています

グレアオブジェクトがまだ準備されていないため、グレアを描画するメソッドは今のところ空になります。その作成とデバッグは次回おこなう予定です。

//+------------------------------------------------+
//| Draw a glare                                   |
//+------------------------------------------------+
void CBarProgressBar::DrawGlare(void)
  {
   
  }
//+------------------------------------------------------------------+


タイマーのイベントハンドラでGetTickCount()関数から返される値を一時的に設定し、ライブラリタイマーで処理するために割り当てられたアクティブオブジェクトのリストにオブジェクトが含まれるようにします。

//+------------------------------------------------+
//| Timer                                          |
//+------------------------------------------------+
void CBarProgressBar::OnTimer(void)
  {
   Comment(DFUN,GetTickCount());
  }
//+------------------------------------------------------------------+


ProgressBarコントロールの作成を始める前に、グラフィック要素オブジェクトがライブラリタイマーで独立して処理できることを確認する必要があります。

概念的には、タイマーの中で独立して処理されるグラフィック要素をそれぞれアクティブな要素とします。アクティブな要素を扱うために、そのようなオブジェクトへのポインタを格納するリストを作成しましょう。このリストは常にメインオブジェクトに作成され、それに応じて、グラフィック要素のコレクションクラスで可視化されます。コレクションクラスのタイマーでは、すべてのメインフォームオブジェクトをループして、アクティブな要素へのポインタを取得し、そのタイマーのイベントハンドラを呼び出します。このように、メインオブジェクトの中からグラフィカル要素を一つ一つ探すのではなく、すぐにメインオブジェクトの要素一覧を作成し、その要素のみを処理するようにします。

すべてのWinFormsライブラリオブジェクトの基本オブジェクトクラスの\MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqhファイルに、グレアオブジェクトクラスのファイルをインクルードし、protectedセクションでアクティブな要素のリストへのポインタの宣言を追加します

//+------------------------------------------------------------------+
//|                                                  WinFormBase.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------+
//| Include files                                  |
//+------------------------------------------------+
#include "GlareObj.mqh"
#include "..\Form.mqh"
#include "..\..\..\Services\Select.mqh"
//+------------------------------------------------+
//| Form object class                              |
//+------------------------------------------------+
class CWinFormBase : public CForm
  {
protected:
   CArrayObj        *m_list_active_elements;                   // Pointer to the list of active elements
   color             m_fore_color_init;                        // Initial color of the control text
   color             m_fore_state_on_color_init;               // Initial color of the control text when the control is "ON"
private:
//--- Return the font flags
   uint              GetFontFlags(void);
public:

ここにグレアオブジェクトファイルを含めることで、ライブラリの多くのグラフィック要素でグレアオブジェクトを作成し、使用することができるようになります。

クラスのpublicセクションで、アクティブな要素のリストを操作するためのメソッドを宣言します

public:
//--- Draw a frame
   virtual void      DrawFrame(void){}
//--- Return by type the (1) list, (2) the number of bound controls, the bound control (3) by index in the list, (4) by name
   CArrayObj        *GetListElementsByType(const ENUM_GRAPH_ELEMENT_TYPE type);
   int               ElementsTotalByType(const ENUM_GRAPH_ELEMENT_TYPE type);
   CGCnvElement     *GetElementByType(const ENUM_GRAPH_ELEMENT_TYPE type,const int index);
   CGCnvElement     *GetElementByName(const string name);
//--- Return the list of active elements of (1) the current, (2) main object
   CArrayObj        *GetListActiveElements(void)      { return this.m_list_active_elements; }
   CArrayObj        *GetListMainActiveElements(void);
//--- Return the number of active elements of the main object
   int               ListMainActiveElementsTotal(void);
//--- Return the element from the list of active elements of the main object by index
   CWinFormBase     *GetActiveElement(const int index);
//--- Return the index of the specified object in the list of active elements of the main object
   int               IndexActiveElements(CWinFormBase *obj);
//--- Return the flag of the object presence by name in the list of active elements
   bool              IsPresentObjInListActiveElements(string name_obj);
//--- Add (1) the specified and (2) the current object to the list of active elements
   bool              AddObjToListActiveElements(CWinFormBase *obj);
   bool              AddObjToListActiveElements(void);
//--- Remove (1) the specified and (2) the current object from the list of active elements
   bool              DetachObjFromListActiveElements(CWinFormBase *obj);
   bool              DetachObjFromListActiveElements(void);
//--- Clear the element filling it with color and opacity
   virtual void      Erase(const color colour,const uchar opacity,const bool redraw=false);


クラスデストラクタ:を追加します。

public:
//--- Constructor
                     CWinFormBase(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                  const long chart_id,
                                  const int subwindow,
                                  const string descript,
                                  const int x,
                                  const int y,
                                  const int w,
                                  const int h);
//--- Destructor
                    ~CWinFormBase(void)
                      {
                       if(this.m_list_active_elements!=NULL)
                         {
                           this.m_list_active_elements.Clear();
                           delete this.m_list_active_elements;
                         }
                      }
//--- (1) Set and (2) return the default text color of all panel objects

アクティブな要素のリストが作成されている場合は、それをクリアし、作成されたリストオブジェクトを削除します。


クラスのコンストラクタに、アクティブな要素のリストオブジェクトの生成を記述します

//+------------------------------------------------+
//| Protected constructor with an object type,     |
//| chart ID and subwindow                         |
//+------------------------------------------------+
CWinFormBase::CWinFormBase(const ENUM_GRAPH_ELEMENT_TYPE type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const long chart_id,
                           const int subwindow,
                           const string descript,
                           const int x,
                           const int y,
                           const int w,
                           const int h) : CForm(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and assign the library object type to the current object
   this.SetTypeElement(type);
   this.m_type=OBJECT_DE_TYPE_GWF_BASE; 
//--- Initialize all variables
   this.SetText("");
   this.SetForeColor(CLR_DEF_FORE_COLOR,true);
   this.SetForeStateOnColor(this.ForeColor(),true);
   this.SetForeStateOnColorMouseDown(this.ForeColor());
   this.SetForeStateOnColorMouseOver(this.ForeColor());
   this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY);
   this.SetFontBoldType(FW_TYPE_NORMAL);
   this.SetMarginAll(0);
   this.SetPaddingAll(0);
   this.SetBorderSizeAll(0);
   this.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false);
   this.SetBorderStyle(FRAME_STYLE_NONE);
   this.SetAutoSize(false,false);
   CForm::SetCoordXInit(x);
   CForm::SetCoordYInit(y);
   CForm::SetWidthInit(w);
   CForm::SetHeightInit(h);
   this.m_shadow=false;
   this.m_gradient_v=true;
   this.m_gradient_c=false;
   this.m_list_active_elements=new CArrayObj();
  }
//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CWinFormBase::CWinFormBase(CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const long chart_id,
                           const int subwindow,
                           const string descript,
                           const int x,
                           const int y,
                           const int w,
                           const int h) : CForm(GRAPH_ELEMENT_TYPE_WF_BASE,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the graphical element and library object types as a base WinForms object
   this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_BASE);
   this.m_type=OBJECT_DE_TYPE_GWF_BASE; 
//--- Initialize all variables
   this.SetText("");
   this.SetForeColor(CLR_DEF_FORE_COLOR,true);
   this.SetForeStateOnColor(this.ForeColor(),true);
   this.SetForeStateOnColorMouseDown(this.ForeColor());
   this.SetForeStateOnColorMouseOver(this.ForeColor());
   this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY);
   this.SetFontBoldType(FW_TYPE_NORMAL);
   this.SetMarginAll(0);
   this.SetPaddingAll(0);
   this.SetBorderSizeAll(0);
   this.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false);
   this.SetBorderStyle(FRAME_STYLE_NONE);
   this.SetAutoSize(false,false);
   CForm::SetCoordXInit(x);
   CForm::SetCoordYInit(y);
   CForm::SetWidthInit(w);
   CForm::SetHeightInit(h);
   this.m_shadow=false;
   this.m_gradient_v=true;
   this.m_gradient_c=false;
   this.m_list_active_elements=new CArrayObj();
  }
//+------------------------------------------------------------------+


要素の整数プロパティの説明を返すメソッドに、新しいオブジェクトのプロパティの説明を返すコードブロックを記述します。

//+------------------------------------------------------------------+
//| Return the description of the control integer property           |
//+------------------------------------------------------------------+
string CWinFormBase::GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_INTEGER property,bool only_prop=false)
  {
   return
     (
      property==CANV_ELEMENT_PROP_ID                           ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_ID)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :

      //---...
      //---...

      property==CANV_ELEMENT_PROP_DISPLAYED                    ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_DISPLAYED)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_DISPLAY_STATE                ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_DISPLAY_STATE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_DISPLAY_DURATION             ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_DISPLAY_DURATION)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_GROUP                        ?  CMessage::Text(MSG_GRAPH_OBJ_PROP_GROUP)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :

      //---...
      //---...


      property==CANV_ELEMENT_PROP_TOOLTIP_USE_FADING           ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_TOOLTIP_USE_FADING)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
         
      property==CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM         ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM         ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_PROGRESS_BAR_STEP            ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_STEP)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE           ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE           ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+


以下は、メインオブジェクトのアクティブな要素のリストを返すメソッドです。

//+------------------------------------------------------------------+
//| Return the list of active elements of the main object            |
//+------------------------------------------------------------------+
CArrayObj *CWinFormBase::GetListMainActiveElements(void)
  {
   CWinFormBase *main=this.GetMain();
   if(main==NULL)
      main=this.GetObject();
   CArrayObj *list=main.GetListActiveElements();
   if(list==NULL)
     {
      CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_GET_ACTIVE_OBJ_LIST);
      .return NULL;
     }
   return list;
  }
//+------------------------------------------------------------------+

ここでは、メインオブジェクトへのポインタを取得しますNULLが返された場合、このオブジェクトがメインとなりますメインオブジェクトからアクティブな要素のリストを取得しますポインタの取得に失敗した場合は、その旨を通知してNULLを返しますそれ以外の場合は、リストへのポインタを返します


以下は、メインオブジェクトのアクティブな要素数を返すメソッドです。

//+------------------------------------------------------------------+
//| Return the number of active elements of the main object          |
//+------------------------------------------------------------------+
int CWinFormBase::ListMainActiveElementsTotal(void)
  {
   return(this.GetListMainActiveElements()!=NULL ? this.GetListMainActiveElements().Total() : 0);
  }
//+------------------------------------------------------------------+

メインオブジェクトのリストへのポインタが取得された場合リストの要素数を返しますそれ以外の場合は0を返します


以下は、メインオブジェクトのアクティブな要素のリストにおける、指定されたオブジェクトのインデックスを返すメソッドです。

//+------------------------------------------------------------------+
//| Return the specified object index                                |
//| in the list of active elements of the main object                |
//+------------------------------------------------------------------+
int CWinFormBase::IndexActiveElements(CWinFormBase *obj)
  {
   CArrayObj *list=this.GetListMainActiveElements();
   if(list==NULL)
      return WRONG_VALUE;
   for(int i=0;i<this.ListMainActiveElementsTotal();i++)
     {
      CWinFormBase *elm=list.At(i);
      if(elm!=NULL && elm.Name()==obj.Name())
         return i;
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+

このメソッドは、インデックスを求めるオブジェクトへのポインタを受け取ります。メインオブジェクトからアクティブな要素のリストを取得します。ループ内で、受け取ったリストに従って、次のオブジェクトを取得します。その名前がメソッドに渡されたオブジェクトの名前と等しい場合、ループインデックスを返します。ループの終わりでは、オブジェクトが見つからなかったことを意味する-1を返します。


以下は、メインオブジェクトのアクティブな要素のリストからインデックスで要素を返すメソッドです。

//+------------------------------------------------+
//| Return an element from the list of active      |
//| elements of the main object by index           |
//+------------------------------------------------+
CWinFormBase *CWinFormBase::GetActiveElement(const int index)
  {
   CArrayObj *list=this.GetListMainActiveElements();
   return(list!=NULL ? list.At(index) : NULL);
  }
//+------------------------------------------------------------------+

このメソッドは、リストから返されるオブジェクトのインデックスを受け取ります。メインオブジェクトからアクティブな要素のリストを取得し、インデックスでオブジェクトへのポインタを返します。リストを取得できなかった場合、このメソッドはNULLを返します。


以下は、メインオブジェクトのアクティブな要素のリストに、名前でオブジェクトが存在するフラグを返すメソッドです。

//+------------------------------------------------------------------+
//|  Return the flag of an object presence by name                   |
//| in the list of active elements of the main object                |
//+------------------------------------------------------------------+
bool CWinFormBase::IsPresentObjInListActiveElements(string name_obj)
  {
   CArrayObj *list=this.GetListMainActiveElements();
   if(list==NULL)
      return false;
   for(int i=list.Total()-1;i>WRONG_VALUE;i--)
     {
      CWinFormBase *obj=list.At(i);
      if(obj!=NULL && obj.Name()==name_obj)
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

このメソッドは、リスト内の存在を確認する必要があるオブジェクトの名前を受け取ります。メインオブジェクトからアクティブな要素のリストを取得します。取得したリストによるループで、次のオブジェクトを取得します。その名前がメソッドに渡された名前と一致する場合、trueを返す。ループが完了したら、falseを返します。オブジェクトはリストにありません。


以下は、指定されたオブジェクトを、メインオブジェクトのアクティブな要素のリストに追加するメソッドです。

//+------------------------------------------------------------------+
//| Add the specified object to the list                             |
//| of active elements of the main object                            |
//+------------------------------------------------------------------+
bool CWinFormBase::AddObjToListActiveElements(CWinFormBase *obj)
  {
   CArrayObj *list=this.GetListMainActiveElements();
   if(list==NULL)
      return false;
   if(obj==NULL || this.IsPresentObjInListActiveElements(obj.Name()))
      return false;
   return list.Add(obj);
  }
//+------------------------------------------------------------------+

メインオブジェクトのアクティブな要素のリストを取得します同じ名前のオブジェクトがリストに既に存在する場合、falseを返します。それ以外の場合は、リストにオブジェクトを追加した結果を返します


以下は、メインオブジェクトのアクティブな要素のリストに現在のオブジェクトを追加するメソッドです。

//+------------------------------------------------+
//| Add the current object to the list of          |
//| active elements of the main object             |
//+------------------------------------------------+
bool CWinFormBase::AddObjToListActiveElements(void)
  {
   return this.AddObjToListActiveElements(this.GetObject());
  }
//+------------------------------------------------------------------+

上記のメソッドを呼び出した結果を返します。リストに追加するオブジェクトとして、現在のオブジェクトを指定します


以下は、指定されたオブジェクトを、メインオブジェクトのアクティブな要素のリストから削除するメソッドです。

//+------------------------------------------------+
//| Remove the specified object from the list of   |
//| active elements of the main object             |
//+------------------------------------------------+
bool CWinFormBase::DetachObjFromListActiveElements(CWinFormBase *obj)
  {
   CArrayObj *list=this.GetListMainActiveElements();
   if(list==NULL)
      return false;
   int index=this.IndexActiveElements(obj);
   if(index==WRONG_VALUE)
      return false;
   CWinFormBase *elm=list.Detach(index);
   if(elm==NULL)
      return false;
   elm=NULL;
   return true;
  }
//+------------------------------------------------------------------+

メインオブジェクトのアクティブな要素のリストへのポインタを取得します。リスト内のオブジェクトのインデックスを取得し、そのポインタはメソッドに渡されます。リストから削除されたオブジェクトへのポインタを取得しますオブジェクトの削除に失敗した場合、falseを返します。そうでない場合は、ポインタをリセットして trueを返します


以下は、メインオブジェクトのアクティブな要素のリストから現在のオブジェクトを削除するメソッドです。

//+------------------------------------------------+
//| Remove the current object from the list of     |
//| active elements of the main object             |
//+------------------------------------------------+
bool CWinFormBase::DetachObjFromListActiveElements(void)
  {
   return this.DetachObjFromListActiveElements(this.GetObject());
  }
//+------------------------------------------------------------------+

上記のメソッドを呼び出した結果を返します。削除するオブジェクトとして、現在のオブジェクトを指定します


ProgressBarコントロールを作成しましょう。

MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\で、CProgressBarlクラスの新しいファイル(ProgressBar.mqh)を作成します。オブジェクトの機能を拡張するために、他のコントロールを接続できるようにする予定なので、コンテナオブジェクトクラスから派生させる必要があります。コンテナクラスファイルは、作成されたオブジェクトのファイルに、プログレスバークラスファイルと一緒にインクルードする必要があります。

//+------------------------------------------------------------------+
//|                                                  ProgressBar.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------+
//| Include files                                  |
//+------------------------------------------------+
#include "..\Containers\Container.mqh"
#include "..\Helpers\BarProgressBar.mqh"
//+------------------------------------------------------------------+
//| ArrowLeftRightBox object class of WForms controls                |
//+------------------------------------------------------------------+
class CProgressBar : public CContainer
  {
  }


クラスのprivateセクションで、新しいグラフィカルオブジェクトとプログレスバーを作成するメソッドと、クラスの初期化メソッドを宣言します。

//+------------------------------------------------------------------+
//| ArrowLeftRightBox object class of WForms controls                |
//+------------------------------------------------------------------+
class CProgressBar : public CContainer
  {
private:
//--- Create a new graphical object
   virtual CGCnvElement *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                          const int element_num,
                                          const string descript,
                                          const int x,
                                          const int y,
                                          const int w,
                                          const int h,
                                          const color colour,
                                          const uchar opacity,
                                          const bool movable,
                                          const bool activity);
//--- Create the progress bar object
   void              CreateProgressBar(void);

//--- Initialize the element properties
   void              Initialize(void);

protected:


クラスのprotectedセクションで、protectedコンストラクタを宣言します。

protected:
//--- Protected constructor with object type, chart ID and subwindow
                     CProgressBar(const ENUM_GRAPH_ELEMENT_TYPE type,
                                  CGCnvElement *main_obj,CGCnvElement *base_obj,
                                  const long chart_id,
                                  const int subwindow,
                                  const string descript,
                                  const int x,
                                  const int y,
                                  const int w,
                                  const int h);
public:


クラスのpublicセクションで、オブジェクトのプロパティを設定取得するメソッド、プログレスバーオブジェクトへのポインタを取得するメソッド、オブジェクトのプロパティを保持するフラグを返すメソッド、パラメトリックコンストラクタ、タイマーのイベントハンドラを宣言します。

public:
//--- (1) Set and (2) return the animation speed of the progress bar in case of the Marquee style
   void              SetMarqueeAnimationSpeed(const int value)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,value);
                        CBarProgressBar *bar=this.GetProgressBar();
                        if(bar!=NULL)
                           bar.SetMarqueeAnimationSpeed(value);
                       }
   int               MarqueeAnimationSpeed(void)   const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED);  }

//--- (1) Set and (2) return the progress bar style
   void              SetStyle(const ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE style)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,style);
                        CBarProgressBar *bar=this.GetProgressBar();
                        if(bar!=NULL)
                           bar.SetStyle(style);
                       }
   ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE Style(void) const
                       { return (ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE);          }

//--- (1) Set and (2) return the progress bar increment to redraw it
   void              SetStep(const int value)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,value);
                        CBarProgressBar *bar=this.GetProgressBar();
                        if(bar!=NULL)
                           bar.SetStep(value);
                       }
   int               Step(void)                          const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP);    }
   
//--- (1) Set and (2) return the current value of the progress bar in the range from Min to Max
   void              SetValue(const int value)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,value);
                        CBarProgressBar *bar=this.GetProgressBar();
                        if(bar!=NULL)
                           bar.SetValue(value);
                       }
   int               Value(void)                         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE);   }
   
//--- (1) Set and (2) return the upper bound of the ProgressBar operating range
   void              SetMaximum(const int value)               { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM,value);       }
   int               Maximum(void)                       const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM); }
   
//--- (1) Set and (2) return the lower bound of the ProgressBar operating range
   void              SetMinimum(const int value)               { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM,value);       }
   int               Minimum(void)                       const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM); }
   
//--- Return the pointer to the progress bar object
   CBarProgressBar  *GetProgressBar(void)                { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,0);     }

//--- Supported object properties (1) integer, (2) real and (3) string ones
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)  { return true; }
   
//--- Constructor
                     CProgressBar(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                  const long chart_id,
                                  const int subwindow,
                                  const string descript,
                                  const int x,
                                  const int y,
                                  const int w,
                                  const int h);
//--- Timer
   virtual void      OnTimer(void);
  };
//+------------------------------------------------------------------+

プロパティを設定した後、オブジェクトのプロパティを設定するいくつかのメソッドは、プログレスバーオブジェクトの対応するプロパティにプロパティを設定します。

宣言されたメソッドを詳しく見てみましょう。


以下は、Protectedコンストラクタです。

//+------------------------------------------------+
//| Protected constructor with an object type,     |
//| chart ID and subwindow                         |
//+------------------------------------------------+
CProgressBar::CProgressBar(const ENUM_GRAPH_ELEMENT_TYPE type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const long chart_id,
                           const int subwindow,
                           const string descript,
                           const int x,
                           const int y,
                           const int w,
                           const int h) : CContainer(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and assign the library object type to the current object
   this.SetTypeElement(type);
   this.m_type=OBJECT_DE_TYPE_GWF_COMMON;
   this.Initialize();
   this.CreateProgressBar();
  }
//+------------------------------------------------------------------+

このメソッドは、生成されたオブジェクトのタイプを受け取ります。このタイプは、初期化文字列の親クラスに設定されていますライブラリグラフィックオブジェクトの種類は「標準コントロール」に設定されています。そして、オブジェクトのプロパティの初期化メソッドとプログレスバーオブジェクトを作成するメソッドが呼び出されます。


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

//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CProgressBar::CProgressBar(CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const long chart_id,
                           const int subwindow,
                           const string descript,
                           const int x,
                           const int y,
                           const int w,
                           const int h) : CContainer(GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR);
   this.m_type=OBJECT_DE_TYPE_GWF_COMMON;
   this.Initialize();
   this.CreateProgressBar();
  }
//+------------------------------------------------------------------+

ここでは、コントロールのタイプは初期化文字列にハードコードされています


以下は、要素プロパティの初期化メソッドです。

//+------------------------------------------------+
//| Initialize the element properties              |
//+------------------------------------------------+
void CProgressBar::Initialize(void)
  {
   this.SetBorderSizeAll(1);
   this.SetBorderStyle(FRAME_STYLE_SIMPLE);
   this.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BACK_COLOR,true);
   this.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BORDER_COLOR,true);
   this.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
   this.SetMarqueeAnimationSpeed(10);
   this.SetMaximum(100);
   this.SetMinimum(0);
   this.SetStep(10);
   this.SetStyle(CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS);
   this.SetValue(this.Width()/2);
  }
//+------------------------------------------------------------------+

オブジェクトのフレームは一辺が1ピクセルに設定され、フレームタイプはシンプルで、オブジェクトの色やその他のデフォルトのプロパティも設定されています。プログレスバーの長さは、オブジェクトの幅の半分に設定されています


以下は、プログレスバーオブジェクトを生成するメソッドです。

//+------------------------------------------------+
//| Create the progress bar object                 |
//+------------------------------------------------+
void CProgressBar::CreateProgressBar(void)
  {
//--- Set the length of the progress bar equal to the object Value()
//--- The height of the progress bar is equal to the height of the object minus the top and bottom frame sizes
   int w=this.Value();
   int h=this.Height()-this.BorderSizeTop()-this.BorderSizeBottom();
//--- Create the progress bar object
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,0,0,w,h,clrNONE,255,false,false);
//--- Add the created CProgressBar object to the list of active elements of the collection
   if(this.AddObjToListActiveElements())
     {
      //--- To perform the check, get this element from the list, display its description and the number of active elements in the list
      CProgressBar *progress_bar=this.GetActiveElement(this.IndexActiveElements(this.GetObject()));
      if(progress_bar!=NULL)
         Print(DFUN_ERR_LINE,"CProgressBar: ",progress_bar.TypeElementDescription(),", ListMainActiveElementsTotal=",this.ListMainActiveElementsTotal());
     }
  }
//+------------------------------------------------------------------+

メソッドロジックはコードでコメントされています。プログレスバーの高さは、オブジェクトがコンテナに完全に収まると同時に、コンテナのフレームがそれに重ならないように設定されています。プログレスバーを作成した後、オブジェクト全体をアクティブな要素のリストに追加します。この場合、ライブラリグラフィック要素のタイマーのイベントハンドラに入り、その中で処理されることになります。したがって、オブジェクトタイマーでは、ユーザーと独立して動作する機能を作ることができます。このオブジェクトでは、これが次回以降に扱う視覚効果になります。


以下は、新しいグラフィカルオブジェクトを作成する仮想メソッドです。

//+------------------------------------------------+
//| Create a new graphical object                  |
//+------------------------------------------------+
CGCnvElement *CProgressBar::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                             const int obj_num,
                                             const string descript,
                                             const int x,
                                             const int y,
                                             const int w,
                                             const int h,
                                             const color colour,
                                             const uchar opacity,
                                             const bool movable,
                                             const bool activity)
  {
   CGCnvElement *element=NULL;
   switch(type)
     {
      case GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR  :
         element=new CBarProgressBar(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_GLARE_OBJ            :
         element=new CGlareObj(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      default:
        break;
     }
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type));
   return element;
  }
//+------------------------------------------------------------------+

コンテナオブジェクトが自らの内部に接続されたオブジェクトを作成するために、これらのオブジェクトを作成する仮想メソッドが存在します。各コントロールについて、その中に作成されるオブジェクトのリストは異なる場合があります。このオブジェクトは、プログレスバーオブジェクトとグレアオブジェクトを作成する機能を提供します。今のところ、ここでオブジェクトを作成する必要はありません。


以下は、タイマーのイベントハンドラです。

//+------------------------------------------------+
//| Timer                                          |
//+------------------------------------------------+
void CProgressBar::OnTimer(void)
  {
   CBarProgressBar *bar=this.GetProgressBar();
   if(bar!=NULL)
      bar.OnTimer();
  }
//+------------------------------------------------------------------+

ここでは、プログレスバーオブジェクトへのポインタを取得し、そのタイマーイベントハンドラを呼び出します。グレアはプログレスバーにぴったり沿って走るはずなので、その動作をCBarProgressBarクラスのオブジェクトのタイマーに実装してみます。そのため、ここでは、チャート上のGetTickCount()の値の出力がコメントとして書かれていることを特徴として、そのタイマーが呼び出されます。


コンテナオブジェクトクラスの\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Container.mqhファイルにある、バインドされたオブジェクトのパラメータを設定するメソッドで、新しい作成された区切りオブジェクトのパラメータを設定する新しいコードブロックを追加します

//+------------------------------------------------+
//| Set parameters for the attached object         |
//+------------------------------------------------+
void CContainer::SetObjParams(CWinFormBase *obj,const color colour)
  {
//--- Set the text color of the object to be the same as that of the base container
   obj.SetForeColor(this.ForeColor(),true);
//--- If the created object is not a container, set the same group for it as the one for its base object
   if(obj.TypeGraphElement()<GRAPH_ELEMENT_TYPE_WF_CONTAINER || obj.TypeGraphElement()>GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER)
      obj.SetGroup(this.Group());
//--- Depending on the object type
   switch(obj.TypeGraphElement())
     {
      //--- For the Container, Panel and GroupBox WinForms objects
      case GRAPH_ELEMENT_TYPE_WF_CONTAINER            :
      case GRAPH_ELEMENT_TYPE_WF_PANEL                :
      case GRAPH_ELEMENT_TYPE_WF_GROUPBOX             :
        obj.SetBorderColor(obj.BackgroundColor(),true);
        break;
      //--- For "Label", "CheckBox" and "RadioButton" WinForms objects

      //---...
      //---...

      //--- For ToolTip WinForms object
      case GRAPH_ELEMENT_TYPE_WF_TOOLTIP              :
        obj.SetBackgroundColor(CLR_DEF_CONTROL_HINT_BACK_COLOR,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_HINT_BORDER_COLOR,true);
        obj.SetForeColor(CLR_DEF_CONTROL_HINT_FORE_COLOR,true);
        obj.SetBorderStyle(FRAME_STYLE_SIMPLE);
        obj.SetOpacity(0,false);
        obj.SetDisplayed(false);
        obj.Hide();
        break;
      //--- For BarProgressBar WinForms object
      case GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR     :
        obj.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
        obj.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
        obj.SetBorderStyle(FRAME_STYLE_NONE);
        break;
      //--- For ProgressBar WinForms object
      case GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR         :
        obj.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BACK_COLOR,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BORDER_COLOR,true);
        obj.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
        obj.SetBorderStyle(FRAME_STYLE_SIMPLE);
        break;
      default:
        break;
     }
   obj.Crop();
  }
//+------------------------------------------------------------------+

これらのクラスのコンストラクタで設定されるデフォルト値を設定するだけです。


あとは、各コンテナオブジェクトに、ツールチップオブジェクトをカレントと指定された要素に素早く接続する機能を作る必要があります。これにより、コンテナに接続されている目的のオブジェクトにツールチップを付けることが容易になります。

\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Panel.mqhで、ProgressBarコントロールファイルのインクルードを追加します

//+------------------------------------------------------------------+
//|                                                        Panel.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------+
//| Include files                                  |
//+------------------------------------------------+
#include "Container.mqh"
#include "..\Helpers\TabField.mqh"
#include "..\Helpers\ArrowUpButton.mqh"
#include "..\Helpers\ArrowDownButton.mqh"
#include "..\Helpers\ArrowLeftButton.mqh"
#include "..\Helpers\ArrowRightButton.mqh"
#include "..\Helpers\ArrowUpDownBox.mqh"
#include "..\Helpers\ArrowLeftRightBox.mqh"
#include "..\Helpers\HintMoveLeft.mqh"
#include "..\Helpers\HintMoveRight.mqh"
#include "..\Helpers\HintMoveUp.mqh"
#include "..\Helpers\HintMoveDown.mqh"
#include "GroupBox.mqh"
#include "TabControl.mqh"
#include "SplitContainer.mqh"
#include "..\..\WForms\Common Controls\ListBox.mqh"
#include "..\..\WForms\Common Controls\CheckedListBox.mqh"
#include "..\..\WForms\Common Controls\ButtonListBox.mqh"
#include "..\..\WForms\Common Controls\ToolTip.mqh"
#include "..\..\WForms\Common Controls\ProgressBar.mqh"
//+------------------------------------------------------------------+


publicセクションで、ツールチップオブジェクトの作成と接続のための2つのメソッドを宣言します

   virtual void      SetPaddingAll(const uint value)
                       {
                        this.SetPaddingLeft(value); this.SetPaddingTop(value); this.SetPaddingRight(value); this.SetPaddingBottom(value);
                       }
//--- Create and attach the ToolTip object (1) to the current and (2) to the specified control
   CToolTip         *SetToolTip(const string tooltip_description,const string tooltip_title,const string tooltip_text,ENUM_CANV_ELEMENT_TOOLTIP_ICON tooltip_ico);
   CToolTip         *SetToolTipTo(CForm *element,const string tooltip_description,const string tooltip_title,const string tooltip_text,ENUM_CANV_ELEMENT_TOOLTIP_ICON tooltip_ico);


新しいグラフィカルオブジェクトを作成するメソッドで、新しいコントロールを作成するための文字列を追加します

//+------------------------------------------------+
//| Create a new graphical object                  |
//+------------------------------------------------+
CGCnvElement *CPanel::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                       const int obj_num,
                                       const string descript,
                                       const int x,
                                       const int y,
                                       const int w,
                                       const int h,
                                       const color colour,
                                       const uchar opacity,
                                       const bool movable,
                                       const bool activity)
  {
   CGCnvElement *element=NULL;
   switch(type)
     {
      case GRAPH_ELEMENT_TYPE_ELEMENT                 : element=new CGCnvElement(type,this.GetMain(),this.GetObject(),this.ID(),obj_num,this.ChartID(),this.SubWindow(),descript,x,y,w,h,colour,opacity,movable,activity); break;
      case GRAPH_ELEMENT_TYPE_FORM                    : element=new CForm(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);               break;
      case GRAPH_ELEMENT_TYPE_WF_CONTAINER            : element=new CContainer(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);          break;
      case GRAPH_ELEMENT_TYPE_WF_GROUPBOX             : element=new CGroupBox(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);           break;
      case GRAPH_ELEMENT_TYPE_WF_PANEL                : element=new CPanel(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);              break;
      case GRAPH_ELEMENT_TYPE_WF_LABEL                : element=new CLabel(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);              break;
      case GRAPH_ELEMENT_TYPE_WF_CHECKBOX             : element=new CCheckBox(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);           break;
      case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON          : element=new CRadioButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);        break;
      case GRAPH_ELEMENT_TYPE_WF_BUTTON               : element=new CButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);             break;
      case GRAPH_ELEMENT_TYPE_WF_LIST_BOX             : element=new CListBox(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);            break;
      case GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM        : element=new CListBoxItem(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);        break;
      case GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX     : element=new CCheckedListBox(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);     break;
      case GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX      : element=new CButtonListBox(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);      break;
      case GRAPH_ELEMENT_TYPE_WF_TAB_HEADER           : element=new CTabHeader(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);          break;
      case GRAPH_ELEMENT_TYPE_WF_TAB_FIELD            : element=new CTabField(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);           break;
      case GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL          : element=new CTabControl(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);         break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON         : element=new CArrowButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);        break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP      : element=new CArrowUpButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);      break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN    : element=new CArrowDownButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);    break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT    : element=new CArrowLeftButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);    break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT   : element=new CArrowRightButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);   break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX : element=new CArrowUpDownBox(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);     break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX : element=new CArrowLeftRightBox(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);  break;
      case GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER      : element=new CSplitContainer(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);     break;
      case GRAPH_ELEMENT_TYPE_WF_SPLITTER             : element=new CSplitter(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);           break;
      case GRAPH_ELEMENT_TYPE_WF_HINT_BASE            : element=new CHintBase(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);           break;
      case GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT       : element=new CHintMoveLeft(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);       break;
      case GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT      : element=new CHintMoveRight(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);      break;
      case GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP         : element=new CHintMoveUp(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);         break;
      case GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN       : element=new CHintMoveDown(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);       break;
      case GRAPH_ELEMENT_TYPE_WF_TOOLTIP              : element=new CToolTip(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);            break;
      case GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR         : element=new CProgressBar(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);        break;
      default  : break;
     }
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type));
   return element;
  }
//+------------------------------------------------------------------+


以下は、ツールチップオブジェクトを生成し、現在の要素に接続するメソッドです

//+------------------------------------------------------------------+
//| Create and attach the ToolTip object to the current element      |
//+------------------------------------------------------------------+
CToolTip *CPanel::SetToolTip(const string tooltip_description,const string tooltip_title,const string tooltip_text,ENUM_CANV_ELEMENT_TOOLTIP_ICON tooltip_ico)
  {
//--- Create a new tooltip object
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_TOOLTIP,0,0,10,10,clrNONE,0,false,false);
//--- Get the list of all created ToolTip objects
   CArrayObj *list=this.GetListElementsByType(GRAPH_ELEMENT_TYPE_WF_TOOLTIP);
   if(list==NULL || list.Total()==0)
      .return NULL;
//--- Get the last element in the list of ToolTip objects (the last one created)
   CToolTip *tooltip=list.At(list.Total()-1);
//--- If the object is received
   if(tooltip!=NULL)
     {
      //--- set the description, icon, title and tooltip text for the object
      tooltip.SetDescription(tooltip_description);
      tooltip.SetIcon(tooltip_ico);
      tooltip.SetTitle(tooltip_title);
      tooltip.SetTooltipText(tooltip_text);
     }
//--- Return the ToolTip object
   return tooltip;
  }
//+------------------------------------------------------------------+

メソッドのロジックはコードのコメントで完全に説明されています。必要なデータはすべて、ツールチップオブジェクトを作成するメソッドに渡されます。オブジェクトが作成されると、自動的に現在のオブジェクトに接続されるようになります。次に、ツールチップオブジェクトの一覧から最新のツールチップオブジェクトを取得し、メソッドに渡されたパラメータをそれに設定します。


以下は、指定された要素にツールチップオブジェクトを生成してアタッチするメソッドです。

//+------------------------------------------------------------------+
//| Create and attach the ToolTip object to the specified element    |
//+------------------------------------------------------------------+
CToolTip *CPanel::SetToolTipTo(CForm *element,const string tooltip_description,const string tooltip_title,const string tooltip_text,ENUM_CANV_ELEMENT_TOOLTIP_ICON tooltip_ico)
  {
   CToolTip *tooltip=this.SetToolTip(tooltip_description,tooltip_title,tooltip_text,tooltip_ico);
   if(tooltip==NULL)
      .return NULL;
   if(element.AddTooltip(tooltip))
      return tooltip;
   .return NULL;
  }
//+------------------------------------------------------------------+

ツールチップオブジェクトを作成するために必要なパラメータに加えて、このメソッドは、作成されたツールチップが接続されることになるコントロールを受け取ります。上記のメソッドを使用して、新しいツールチップオブジェクトが作成されメソッドパラメータで指定されたコントロールに接続されますツールチップを接続できた場合、作成したオブジェクトへのポインタを返しますそれ以外の場合は、NULLを返します


ツールチップオブジェクトの接続とProgressBarコントロールの作成について、すべてのコンテナクラスファイルで同様の改良がおこなわれました。

TabControl.mqhTabField.mqhSplitContainer.mqhSplitContainerPanel.mqhGroupBox.mqhです。ここでは、これらの変更点についての考察は省きます。


\MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqhのグラフィック要素のコレクションクラスを改善しましょう。

ツールチップオブジェクトをどのように扱うべきか見てみましょう。これらのオブジェクトはマウスと相互作用し、その結果に応じてグラフィック要素のコレクションのタイマーで処理されます。カーソル下のツールチップオブジェクトがインタラクションオブジェクトのリストに追加されます。このリストは、タイマーで処理する必要があります。この場合、それまでカーソルの下にあった前のオブジェクトも処理する必要があります。しかし、過去のオブジェクトはフェードアウトのアニメーションを必要としないので、コレクションイベントハンドラーから呼び出されるメソッドがその処理をおこないます。オブジェクトは単に非表示にされ、それに対して非表示フラグが設定されるべきです。このようなロジックは、アクティブな要素のリストに最初に配置され、その中のタイマーによって常に処理されるアクティブなオブジェクトのロジックとは異なります。

コレクションクラスのprivateセクションで、処理するオブジェクトのリストを宣言します

   SDataPivotPoint   m_data_pivot_point[];      // Pivot point data structure array
   CArrayObj         m_list_charts_control;     // List of chart management objects
   CListObj          m_list_all_canv_elm_obj;   // List of all graphical elements on canvas
   CListObj          m_list_elm_to_process;     // List of graphical elements on canvas for processing
   CListObj          m_list_all_graph_obj;      // List of all graphical objects
   CArrayObj         m_list_deleted_obj;        // List of removed graphical objects
   CMouseState       m_mouse;                   // "Mouse status" class object


また、カーソル下の現在と過去のオブジェクトを処理するメソッド処理対象オブジェクトのリストを処理するメソッドを宣言します。

//--- Reset all interaction flags for all forms except the specified one
   void              ResetAllInteractionExeptOne(CGCnvElement *form);
//--- Post-processing of the former active form under the cursor
   void              FormPostProcessing(CForm *form,const int id, const long &lparam, const double &dparam, const string &sparam);
//--- Processing (1) the current and (2) previous ToolTip element
   void              TooltipCurrProcessing(CForm *tooltip,CForm *base);
   void              TooltipPrevProcessing(CForm *tooltip);
//--- Add the element (1) to the collection list and (2) to the list for processing
   bool              AddCanvElmToCollection(CGCnvElement *element);
   bool              AddCanvElmToProcessList(CForm *element);
//--- Get an element by name from the list for handling
   CForm            *GetCanvElementFromProcessList(CForm *element);
//--- Return the element index by name in the list for handling
   int               CanvElementIndexInProcessList(CForm *element) const;
//--- Add the element to the collectionl ist or return the existing one
   ENUM_ADD_OBJ_RET_CODE AddOrGetCanvElmToCollection(CGCnvElement *element,int &id);
//--- Return the graphical elemnt index in the collection list
   int               GetIndexGraphElement(const long chart_id,const string name);


publicセクションに、処理するオブジェクトのリストを返すメソッドを記述します

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

コレクションタイマーイベントハンドラを宣言します

//--- (1) Event handlers, (2) timer, (3) deinitialization
   void              OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
   void              OnTimer();
   void              OnDeinit(void);


クラスコンストラクタで、リストをクリアし、並び替えられたリストフラグをそれに設定します

//+------------------------------------------------+
//| Constructor                                    |
//+------------------------------------------------+
CGraphElementsCollection::CGraphElementsCollection()
  {
   this.m_type=COLLECTION_GRAPH_OBJ_ID;
   this.m_name_prefix=this.m_name_program+"_";
   ::ChartSetInteger(::ChartID(),CHART_EVENT_MOUSE_MOVE,true);
   ::ChartSetInteger(::ChartID(),CHART_EVENT_MOUSE_WHEEL,true);
   this.m_list_all_graph_obj.Type(COLLECTION_GRAPH_OBJ_ID);
   this.m_list_all_graph_obj.Sort(SORT_BY_CANV_ELEMENT_ID);
   this.m_list_all_graph_obj.Clear();
   this.m_list_charts_control.Sort();
   this.m_list_charts_control.Clear();
   this.m_total_objects=0;
   this.m_is_graph_obj_event=false;
   this.m_list_deleted_obj.Clear();
   this.m_list_deleted_obj.Sort();
   this.m_list_all_canv_elm_obj.Clear();
   this.m_list_all_canv_elm_obj.Sort();
   this.m_list_elm_to_process.Clear();
   this.m_list_elm_to_process.Sort();
  }
//+------------------------------------------------------------------+


以下は、キャンバス上のグラフィック要素を処理のためにリストに追加するメソッドです。

//+------------------------------------------------------------------+
//| Add a graphical element on canvas to the list for handling       |
//+------------------------------------------------------------------+
bool CGraphElementsCollection::AddCanvElmToProcessList(CForm *element)
  {
   if(this.GetCanvElementFromProcessList(element)!=NULL)
      return false;
   if(!this.m_list_elm_to_process.Add(element))
     {
      CMessage::ToLog(DFUN+element.TypeElementDescription()+element.Name()+": ",MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+

処理対象オブジェクトのリストへのポインタを取得しますメソッドに渡されたオブジェクトの受け渡しに失敗した場合、その旨をログに記録し、falseを返します追加に成功した場合は、trueを返します


以下は、リストから名前を指定して要素を受け取り、処理するメソッドです。

//+------------------------------------------------------------------+
//| Get an element by name from the list for handling                |
//+------------------------------------------------------------------+
CForm *CGraphElementsCollection::GetCanvElementFromProcessList(CForm *element)
  {
   for(int i=this.m_list_elm_to_process.Total()-1;i>WRONG_VALUE;i--)
     {
      CForm *obj=this.m_list_elm_to_process.At(i);
      if(obj==NULL)
         continue;
      if(obj.Name()==element.Name())
         return obj;
     }
   .return NULL;
  }
//+------------------------------------------------------------------+

処理対象オブジェクトのリストによるループの中で、次のオブジェクトを取得します。その名前がメソッドに渡されたオブジェクトの名前と一致する場合、見つかったオブジェクトへのポインタを返します。ループが完了したら、NULLを返します。オブジェクトが見つかりません。


以下は、処理対象リスト内の要素のインデックスを名前付きで返すメソッドです。

//+------------------------------------------------------------------+
//| Return the index of an element by name in the list for handling  |
//+------------------------------------------------------------------+
int CGraphElementsCollection::CanvElementIndexInProcessList(CForm *element) const
  {
   for(int i=this.m_list_elm_to_process.Total()-1;i>WRONG_VALUE;i--)
     {
      CForm *obj=this.m_list_elm_to_process.At(i);
      if(obj==NULL)
         continue;
      if(obj.Name()==element.Name())
         return i;
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+

処理対象オブジェクトのリストによるループの中で、次のオブジェクトを取得します。その名前がメソッドに渡されたオブジェクトの名前と一致する場合、ループインデックスを返します。ループの終わりでは、オブジェクトが見つからなかったことを意味する-1を返します。


以下は、現在のツールチップ要素を処理するメソッドです。

//+------------------------------------------------+
//| Handle the current ToolTip element             |
//+------------------------------------------------+
void CGraphElementsCollection::TooltipCurrProcessing(CForm *tooltip,CForm *base)
  {
//--- If at least one empty object is passed, leave
   if(tooltip==NULL || base==NULL)
      return;
//--- Get the chart width and height
   int w=(int)::ChartGetInteger(tooltip.ChartID(),CHART_WIDTH_IN_PIXELS,tooltip.SubWindow());
   int h=(int)::ChartGetInteger(tooltip.ChartID(),CHART_HEIGHT_IN_PIXELS,tooltip.SubWindow());
//--- Get cursor coordinates
   int x=this.m_mouse.CoordX();
   int y=this.m_mouse.CoordY();
//--- If at the current X coordinate (cursor) the tooltip goes beyond the right edge of the chart, adjust the X coordinate
   if(x+tooltip.Width()>w)
      x=w-tooltip.Width();
//--- If at the current Y coordinate (cursor) the tooltip goes beyond the bottom edge of the chart, adjust the Y coordinate
   if(y+tooltip.Height()>h)
      y=h-tooltip.Height();
//--- If the tooltip object is shifted to the received cursor coordinates
   if(tooltip.Move(x,y))
     {
      //--- Set new relative tooltip coordinates
      tooltip.SetCoordXRelative(tooltip.CoordX()-base.CoordX());
      tooltip.SetCoordYRelative(tooltip.CoordY()-base.CoordY());
     }
  }
//+------------------------------------------------------------------+

メソッドのロジックはコードのコメントで完全に説明されています。このメソッドは、ツールチップオブジェクトをカーソル座標に移動させ、オブジェクトが画面の端からはみ出した場合は、受け取った座標を調整します。


以下は、前のツールチップ要素を処理するメソッドです。

//+------------------------------------------------+
//| Handle the previous ToolTip element            |
//+------------------------------------------------+
void CGraphElementsCollection::TooltipPrevProcessing(CForm *tooltip)
  {
//--- If an empty object is passed, leave
   if(tooltip==NULL)
      return;
//--- Set the object non-display flag, make it completely transparent and hide it
   tooltip.SetDisplayed(false);
   tooltip.SetOpacity(0,false);
   tooltip.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_NORMAL);
   tooltip.Hide();
//--- Get the index of the object in the list
   int index=this.CanvElementIndexInProcessList(tooltip);
//--- If the index is received, remove the object from the list
   if(index>WRONG_VALUE)
      this.m_list_elm_to_process.DetachElement(index);
  }
//+------------------------------------------------------------------+

ここでも、すべてが透明です。もちろん、前のオブジェクトはカーソルの下にはありません。つまり、すぐに非表示にし、そのポインタを処理するオブジェクトのリストから削除する必要があります。

前回の記事でテストしたエキスパートアドバイザー(EA)をチャート上で起動し、チャートの期間を別の期間に変更すると、プログラムはクリティカルエラーで終了します。これは、フォームオブジェクトへのポインタがstaticとして宣言されているために起こる現象です。

      //--- Declare static variables for the active form and status flags
      static CForm *form=NULL;

つまり、チャートの期間を変更しても、データはその中に残り、NULLを確認すると、オブジェクトは有効であるという否定的な結果が得られるということです。

      //--- In case of the mouse movement event
      if(id==CHARTEVENT_MOUSE_MOVE)
        {
         //--- If the cursor is above the form
         if(form!=NULL)
           {
            //--- If the move flag is set

ポインターのデータセットは、このオブジェクトのメモリ領域を参照しなくなります。そのため、メモリ上の間違った場所にアクセスするとプログラムが終了してしまうのです。エラーを修正するのは簡単です。ポインタの値ではなく、ポインタの有効性を確認します

      //--- In case of the mouse movement event
      if(id==CHARTEVENT_MOUSE_MOVE)
        {
         //--- If the cursor is above the form
         if(::CheckPointer(form)!=POINTER_INVALID)
           {
            //--- If the move flag is set
            if(move)
              {


前のツールチップと現在のツールチップの処理は、以下のように実装されました。

            //--- If the move flag is disabled
            else
              {
               //--- Get the ToolTip object assigned to the form and declare the previous ToolTip
               CForm *tooltip=form.GetTooltip();
               static CForm *tooltip_prev=NULL;
               //--- If the ToolTip object is received
               if(tooltip!=NULL && tooltip.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_TOOLTIP)
                 {
                  //--- If the previous ToolTip object exists
                  if(::CheckPointer(tooltip_prev)!=POINTER_INVALID && tooltip_prev.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_TOOLTIP)
                    {
                     //--- If the name of the previous ToolTip is not equal to the name of the current one, hide the previous ToolTip object
                     if(tooltip_prev.Name()!=tooltip.Name())
                        this.TooltipPrevProcessing(tooltip_prev);
                    }
                    
                  //--- Get the base object set in ToolTip
                  CForm *base=tooltip.GetBase();
                  //--- If the base object is received
                  //--- and if the name of the base object is the same as the name of the current form (the ToolTip is bound to the form)
                  if(base!=NULL && base.Name()==form.Name())
                    {
                     //--- Add ToolTip to the handling list, shift it to the cursor coordinates
                     //--- and write the current ToolTip to the variable as the previous one
                     if(this.AddCanvElmToProcessList(tooltip))
                       {
                        this.TooltipCurrProcessing(tooltip,base);
                        tooltip_prev=tooltip;
                       }
                    }
                 }
               //--- If there is no current ToolTip object, but the previous ToolTip exists, hide the previous ToolTip object
               else if(::CheckPointer(tooltip_prev)!=POINTER_INVALID && tooltip_prev.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_TOOLTIP)
                  this.TooltipPrevProcessing(tooltip_prev);
               
               //--- The undefined mouse status in mouse_state means releasing the left button
               //--- Assign the new mouse status to the variable
               if(mouse_state==MOUSE_FORM_STATE_NONE)
                  mouse_state=MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED;
               //--- Handle moving the cursor mouse away from the graphical element
               this.FormPostProcessing(form,id,lparam,dparam,sparam);
              }

すべてのロジックは、コードコメントで十分に詳細に説明されています。つまり、カーソルの下にオブジェクトがあれば、それを処理対象としてリストに追加し、その座標をカーソル座標に移動させます。オブジェクトがカーソルの下にない場合、リストから削除され、非表示になります。


以下は、コレクションタイマーイベントハンドラです。

//+------------------------------------------------+
//| Timer                                          |
//+------------------------------------------------+
void CGraphElementsCollection::OnTimer(void)
  {
//--- Handle the elements under the cursor
//--- In the loop by the list of objects for handling
   for(int i=this.m_list_elm_to_process.Total()-1;i>WRONG_VALUE;i--)
     {
      //--- get the next object from the list
      CForm *obj=this.m_list_elm_to_process.At(i);
      if(obj==NULL)
         continue;
      //--- If the state of the object is the full loop is completed
      if(obj.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_COMPLETED)
        {
         //--- remove the pointer to the object from the list and go to the next iteration
         this.m_list_elm_to_process.DetachElement(i);
         continue;
        }
      //--- Call the object timer event handler
      obj.OnTimer();
     }

//--- Work with active elements of the collection
//--- In the loop by the collection list of graphical elements
   for(int i=0;i<this.m_list_all_canv_elm_obj.Total();i++)
     {
      //--- Get the next object from the list
      CWinFormBase *obj=this.m_list_all_canv_elm_obj.At(i);
      if(obj==NULL)
         continue;
      //--- Get the list of active elements from the object
      CArrayObj *list=obj.GetListMainActiveElements();
      if(list==NULL || list.Total()==0)
         continue;
      //--- In the loop by the list of active elements
      for(int j=0;j<list.Total();j++)
        {
         //--- get the next object and
         CWinFormBase *elm=list.At(j);
         if(elm==NULL)
            continue;
         //--- call the object timer event handler
         elm.OnTimer();
        }
     }
  }
//+------------------------------------------------------------------+

ハンドラのロジックは、コードのコメントで完全に説明されています。処理するオブジェクトのリスト(ToolTip)とアクティブな要素のリスト(視覚的なアニメーション効果を持つオブジェクト)による、2つのループで作業します。


\MQL5\Include\DoEasy\Engine.mqhで、CEngineライブラリのメインオブジェクトに、ライブラリのグラフィック要素のタイマーとタイマーイベントハンドラを作成します。

privateセクションで、ハンドラを宣言します

//--- Handling events of (1) orders, deals and positions, (2) accounts, (3) graphical objects and (4) canvas elements
   void                 TradeEventsControl(void);
   void                 AccountEventsControl(void);
   void                 GraphObjEventsControl(void);
   void                 GraphElmEventsControl(void);
//--- (1) Working with a symbol collection and (2) symbol list events in the market watch window


クラスのコンストラクタで、さらに別のタイマー(グラフィック要素コレクションタイマー)を作成します

//+------------------------------------------------+
//| CEngine constructor                            |
//+------------------------------------------------+
CEngine::CEngine() : m_first_start(true),
                     m_last_trade_event(TRADE_EVENT_NO_EVENT),
                     m_last_account_event(WRONG_VALUE),
                     m_last_symbol_event(WRONG_VALUE),
                     m_global_error(ERR_SUCCESS)
  {
   this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif;
   this.m_is_tester=::MQLInfoInteger(MQL_TESTER);
   this.m_program_type=(ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE);
   this.m_name_program=::MQLInfoString(MQL_PROGRAM_NAME);
   this.m_name_prefix=this.m_name_program+"_";
   
   this.m_list_counters.Sort();
   this.m_list_counters.Clear();
   this.CreateCounter(COLLECTION_ORD_COUNTER_ID,COLLECTION_ORD_COUNTER_STEP,COLLECTION_ORD_PAUSE);
   this.CreateCounter(COLLECTION_ACC_COUNTER_ID,COLLECTION_ACC_COUNTER_STEP,COLLECTION_ACC_PAUSE);
   this.CreateCounter(COLLECTION_SYM_COUNTER_ID1,COLLECTION_SYM_COUNTER_STEP1,COLLECTION_SYM_PAUSE1);
   this.CreateCounter(COLLECTION_SYM_COUNTER_ID2,COLLECTION_SYM_COUNTER_STEP2,COLLECTION_SYM_PAUSE2);
   this.CreateCounter(COLLECTION_REQ_COUNTER_ID,COLLECTION_REQ_COUNTER_STEP,COLLECTION_REQ_PAUSE);
   this.CreateCounter(COLLECTION_TS_COUNTER_ID,COLLECTION_TS_COUNTER_STEP,COLLECTION_TS_PAUSE);
   this.CreateCounter(COLLECTION_IND_TS_COUNTER_ID,COLLECTION_IND_TS_COUNTER_STEP,COLLECTION_IND_TS_PAUSE);
   this.CreateCounter(COLLECTION_TICKS_COUNTER_ID,COLLECTION_TICKS_COUNTER_STEP,COLLECTION_TICKS_PAUSE);
   this.CreateCounter(COLLECTION_CHARTS_COUNTER_ID,COLLECTION_CHARTS_COUNTER_STEP,COLLECTION_CHARTS_PAUSE);
   this.CreateCounter(COLLECTION_GRAPH_OBJ_COUNTER_ID,COLLECTION_GRAPH_OBJ_COUNTER_STEP,COLLECTION_GRAPH_OBJ_PAUSE);
   this.CreateCounter(COLLECTION_GRAPH_ELM_COUNTER_ID,COLLECTION_GRAPH_ELM_COUNTER_STEP,COLLECTION_GRAPH_ELM_PAUSE);
   
   ::ResetLastError();
   #ifdef __MQL5__
      if(!::EventSetMillisecondTimer(TIMER_FREQUENCY))
        {
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TIMER),(string)::GetLastError());
         this.m_global_error=::GetLastError();
        }
   //---__MQL4__
   #else 
      if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY))
        {
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TIMER),(string)::GetLastError());
         this.m_global_error=::GetLastError();
        }
   #endif 
   //---
  }
//+------------------------------------------------------------------+


タイマーイベントハンドラに、グラフィック要素のタイマーを処理するコードブロックを追加します

//+------------------------------------------------+
//| CEngine timer                                  |
//+------------------------------------------------+
void CEngine::OnTimer(SDataCalculate &data_calculate)
  {
//--- If this is not a tester, work with collection events by timer
   if(!this.IsTester())
     {
   //--- Timer of the collections of historical orders and deals, as well as of market orders and positions
      int index=this.CounterIndex(COLLECTION_ORD_COUNTER_ID);
      CTimerCounter* cnt1=this.m_list_counters.At(index);
      if(cnt1!=NULL)
        {
         //--- If unpaused, work with the order, deal and position collections events
         if(cnt1.IsTimeDone())
            this.TradeEventsControl();
        }
   //--- Account collection timer
      index=this.CounterIndex(COLLECTION_ACC_COUNTER_ID);
      CTimerCounter* cnt2=this.m_list_counters.At(index);
      if(cnt2!=NULL)
        {
         //--- If unpaused, work with the account collection events
         if(cnt2.IsTimeDone())
            this.AccountEventsControl();
        }
   //--- Timer 1 of the symbol collection (updating symbol quote data in the collection)
      index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID1);
      CTimerCounter* cnt3=this.m_list_counters.At(index);
      if(cnt3!=NULL)
        {
         //--- If the pause is over, update quote data of all symbols in the collection
         if(cnt3.IsTimeDone())
            this.m_symbols.RefreshRates();
        }
   //--- Timer 2 of the symbol collection (updating all data of all symbols in the collection and tracking symbl and symbol search events in the market watch window)
      index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID2);
      CTimerCounter* cnt4=this.m_list_counters.At(index);
      if(cnt4!=NULL)
        {
         //--- If the pause is over
         if(cnt4.IsTimeDone())
           {
            //--- update data and work with events of all symbols in the collection
            this.SymbolEventsControl();
            //--- When working with the market watch list, check the market watch window events
            if(this.m_symbols.ModeSymbolsList()==SYMBOLS_MODE_MARKET_WATCH)
               this.MarketWatchEventsControl();
           }
        }
   //--- Trading class timer
      index=this.CounterIndex(COLLECTION_REQ_COUNTER_ID);
      CTimerCounter* cnt5=this.m_list_counters.At(index);
      if(cnt5!=NULL)
        {
         //--- If unpaused, work with the list of pending requests
         if(cnt5.IsTimeDone())
            this.m_trading.OnTimer();
        }
   //--- Timeseries collection timer
      index=this.CounterIndex(COLLECTION_TS_COUNTER_ID);
      CTimerCounter* cnt6=this.m_list_counters.At(index);
      if(cnt6!=NULL)
        {
         //--- If the pause is over, work with the timeseries list (update all except the current one)
         if(cnt6.IsTimeDone())
            this.SeriesRefreshAllExceptCurrent(data_calculate);
        }
        
   //--- Timer of timeseries collection of indicator buffer data
      index=this.CounterIndex(COLLECTION_IND_TS_COUNTER_ID);
      CTimerCounter* cnt7=this.m_list_counters.At(index);
      if(cnt7!=NULL)
        {
         //--- If the pause is over, work with the timeseries list of indicator data (update all except for the current one)
         if(cnt7.IsTimeDone()) 
            this.IndicatorSeriesRefreshAll();
        }
   //--- Tick series collection timer
      index=this.CounterIndex(COLLECTION_TICKS_COUNTER_ID);
      CTimerCounter* cnt8=this.m_list_counters.At(index);
      if(cnt8!=NULL)
        {
         //--- If the pause is over, work with the tick series list (update all except the current one)
         if(cnt8.IsTimeDone())
            this.TickSeriesRefreshAllExceptCurrent();
        }
   //--- Chart collection timer
      index=this.CounterIndex(COLLECTION_CHARTS_COUNTER_ID);
      CTimerCounter* cnt9=this.m_list_counters.At(index);
      if(cnt9!=NULL)
        {
         //--- If unpaused, work with the chart list
         if(cnt9.IsTimeDone())
            this.ChartsRefreshAll();
        }
        
   //--- Graphical objects collection timer
      index=this.CounterIndex(COLLECTION_GRAPH_OBJ_COUNTER_ID);
      CTimerCounter* cnt10=this.m_list_counters.At(index);
      if(cnt10!=NULL)
        {
         //--- If unpaused, work with the list of graphical objects
         if(cnt10.IsTimeDone())
            this.GraphObjEventsControl();
        }
        
   //--- The timer for the collection of graphical elements on the canvas
      index=this.CounterIndex(COLLECTION_GRAPH_ELM_COUNTER_ID);
      CTimerCounter* cnt11=this.m_list_counters.At(index);
      if(cnt11!=NULL)
        {
         //--- If the pause is over, work with the list of graphical elements on the canvas
         if(cnt11.IsTimeDone())
            this.GraphElmEventsControl();
        }
        
     }
//--- If this is a tester, work with collection events by tick
   else
     {
      //--- work with events of collections of orders, deals and positions by tick
      this.TradeEventsControl();
      //--- work with events of collections of accounts by tick
      this.AccountEventsControl();
      //--- update quote data of all collection symbols by tick
      this.m_symbols.RefreshRates();
      //--- work with events of all symbols in the collection by tick
      this.SymbolEventsControl();
      //--- work with the list of pending orders by tick
      this.m_trading.OnTimer();
      //--- work with the timeseries list by tick
      this.SeriesRefresh(data_calculate);
      //--- work with the timeseries list of indicator buffers by tick
      this.IndicatorSeriesRefreshAll();
      //--- work with the list of tick series by tick
      this.TickSeriesRefreshAll();
      //--- work with the list of graphical objects by tick
      this.GraphObjEventsControl();
      //--- work with the list of graphical elements on canvas by tick
      this.GraphElmEventsControl();
     }
  }
//+------------------------------------------------------------------+


以下は、canvas上のグラフィック要素のイベントを処理するメソッドです。

//+------------------------------------------------------------------+
//| Event handling method for graphical elements on canvas           |
//+------------------------------------------------------------------+
void CEngine::GraphElmEventsControl(void)
  {
   this.m_graph_objects.OnTimer();
  }
//+------------------------------------------------------------------+

グラフィック要素のコレクションのポーズタイマーが終了すると、このメソッドが呼び出され、次にグラフィック要素のコレクションクラスのタイマーハンドラが呼び出されます。デフォルトでは、16ミリ秒ごとに呼び出しが発生します(タイマーポーズ)。

すべてをテストする準備ができました。


検証

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

OnInit() EAハンドラで、SplitContainerコントロール内のTabControlの最初のタブの2番目のパネルに、ProgressBarコントロールを作成します。

                  //--- On each of the control panels...
                  for(int j=0;j<2;j++)
                    {
                     //--- Get the panel by loop index
                     CSplitContainerPanel *panel=split_container.GetPanel(j);
                     if(panel==NULL)
                        continue;
                     //--- set its description for the panel
                     panel.SetDescription(TextByLanguage("Панель","Panel")+string(j+1));
                     
                     //--- If this is the first tab and the second panel
                     if(n==0 && j==1)
                       {
                        //--- Create the ProgressBar control on it
                        if(split_container.CreateNewElement(j,GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,4,4,100,12,clrNONE,255,false,false))
                          {
                           CProgressBar *progress_bar=split_container.GetPanelElementByType(j,GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,0);
                           if(progress_bar!=NULL)
                             {
                              Print(DFUN,progress_bar.TypeElementDescription()," ",progress_bar.Name());
                             }
                          }
                       }
                     
                     //--- ...create a text label with the panel name
                     if(split_container.CreateNewElement(j,GRAPH_ELEMENT_TYPE_WF_LABEL,4,4,panel.Width()-8,panel.Height()-8,clrDodgerBlue,255,true,false))
                       {
                        CLabel *label=split_container.GetPanelElementByType(j,GRAPH_ELEMENT_TYPE_WF_LABEL,0);
                        if(label==NULL)
                           continue;
                        label.SetTextAlign(ANCHOR_CENTER);
                        label.SetText(panel.Description());
                       }
                    }

オブジェクトが作成されたことを確認するために、そのポインタを取得し、その説明をログに送信します

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


今回の記事で宣言した機能は、うまく作動しています。チャートのコメントで常に変化する数字を見ることができます。これは、ProgressBarコントロールのプログレスバータイマーのデータです。


次の段階

次回は、引き続き、ProgressBarオブジェクトの作成に取り組みます。

現在のライブラリバージョン、テストEA、およびMQL5のチャートイベントコントロール指標のすべてのファイルは以下に添付されています。

目次に戻る

連載のこれまでの記事

 
DoEasy - コントロール(第20部):SplitContainerWinFormsオブジェクト
DoEasy - コントロール(第21部):SplitContainerコントロール。パネル区切り
DoEasy - コントロール(第22部):SplitContainer。作成したオブジェクトのプロパティを変更する
DoEasy - コントロール(第23部):TabControlとSplitContainerのWinFormsオブジェクトの改善
DoEasy - コントロール(第24部):ヒント補助WinFormsオブジェクト
DoEasy - コントロール(第25部):Tooltip WinFormsオブジェクト

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

添付されたファイル |
MQL5.zip (4521.53 KB)
DoEasy - コントロール(第27部):ProgressBar WinFormsオブジェクトの操作 DoEasy - コントロール(第27部):ProgressBar WinFormsオブジェクトの操作
この記事では、ProgressBarコントロールの開発を続けます。特に、プログレスバーと視覚効果を管理するための機能を作成します。
ニューラルネットワークが簡単に(第32部):分散型Q学習 ニューラルネットワークが簡単に(第32部):分散型Q学習
この連載で前回Q学習法を紹介しました。この手法は、各行動の報酬を平均化するものです。2017年には、報酬分布関数を研究する際に、より大きな成果を示す2つの研究が発表されました。そのような技術を使って、私たちの問題を解決する可能性を考えてみましょう。
MQL5を使った線の扱い方 MQL5を使った線の扱い方
今回は、MQL5によるトレンドラインや支持線と抵抗線といった、最も重要な線の扱い方についてご紹介します。
知っておくべきMQL5ウィザードのテクニック(第04回):線形判別分析 知っておくべきMQL5ウィザードのテクニック(第04回):線形判別分析
今日のトレーダーは哲学者であり、ほとんどの場合、新しいアイデアを探して試し、変更するか破棄するかを選択します。これは、かなりの労力を要する探索的プロセスです。この連載では、MQL5ウィザードがこの取り組みにおけるトレーダーの主力であるべきであることを示しています。