
DoEasy - コントロール(第26部):ToolTip WinFormsオブジェクトの最終確認とProgressBarの開発開始
内容
概念
前回の記事で、ツールチップコントロールの開発を開始しました。オブジェクトにカーソルを合わせると、短いポーズの後にツールチップが表示されます。先に表示されていたツールチップは非表示になります。ツールチップが表示された後にカーソルを同じ位置に置いておくと、ツールチップが一定時間後に消えるはずです。前回は、ツールチップを割り当てたオブジェクトにカーソルを合わせるとすぐに表示されるようにしました。今回は、ツールチップの挙動を工夫し、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.mqh、TabField.mqh、SplitContainer.mqh、SplitContainerPanel.mqh、GroupBox.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




- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索