English Русский 中文 Español Deutsch Português
preview
DoEasy - コントロール(第27部):ProgressBar WinFormsオブジェクトの操作

DoEasy - コントロール(第27部):ProgressBar WinFormsオブジェクトの操作

MetaTrader 5 | 20 1月 2023, 10:15
281 0
Artyom Trishkin
Artyom Trishkin

内容


概念

今回の記事では、前回の記事で実装を開始したProgressBarコントロールの開発を続けます。この要素は、アンダーレイとプログレスバーの2つのコンポーネントで構成されます。将来的には、プログレスバーに加えて、アンダーレイに他のデザイン要素(テキスト、画像など)を配置できるようになります。現時点では、このコントロールは静的WinFormsオブジェクトです。今日は、オブジェクトのプログレスバーをプログラムで制御する機能を開発します。したがって、プログラムでこれを使用して、多数の同一のアクションを必要とする操作の進行状況を示すことができるようにします。

Windows環境で同様のプログレスバーに注意を払うと、プログレスバーに沿ってグレアが移動したり、バーが塗りつぶされたときにその他の視覚効果が表示されたりすることがわかります。プログレスバーの視覚効果は、プログラムインターフェイスをより魅力的にアニメーション化するという事実に加えて、プロセスの完了を追加で示す機能も備えています。プログレスバーに表示される操作の数が十分に多い場合、プログレスバーは完了した操作ごとにではなく、特定の数の操作の後に塗りつぶされます。したがって、プログレスバーが塗りつぶされても、操作が続行することがあります。このような状況で、視覚効果がプログレスバーに表示され続ける場合、プロセスはまだ完了していません。プロセスが完了すると、プログレスバーに視覚効果が表示されなくなります。

通常、プロセスが終了すると、ProgressBarコントロールも非表示になるため、上記は表示されません。しかし、プログレスバーが個別のウィンドウで作成され、すべての操作が完了したときに手動で閉じる必要がある場合は、プログレスバーの視覚効果を使用してプロセスの完了/未完了の表示を確認できます。または、1つのプロセスをサブプロセスに分割して表示するプログレスバーが同時に複数ある場合は、プロセス全体が完了するまで、既に完了したプロセスのプログレスバーが表示されます。サブプロセスを表示するProgressBarコントロールでは、二重の表示も確認できます。プログレスバーが完全に塗りつぶされているが視覚効果が引き続き表示されている場合、このサブプロセスはまだ完全には終了していません。

ProgressBarコントロールの視覚効果機能を実装すれば、その概念をライブラリ内の他のコントロールで使用できるようになります。視覚効果を持つ各オブジェクトは、アクティブな要素のリストに配置されます。ライブラリはこのリストを見て、このリストに配置された各オブジェクトのタイマーイベントハンドラをタイマーで順番に呼び出します。必要な機能は、オブジェクト自体、つまりタイマーハンドラに実装されます。

さらに、定義済みアイコンの描画を少し改良します。前回の記事で、アンチエイリアス処理された線を透明に描画するときの奇妙な動作について説明しました。実際、標準ライブラリのスムージングメソッドを使用して描画されたすべてのグラフィカルプリミティブは、透明に設定されていると正常に描画されません。つまり、そのような線を滑らかに表示または非表示にすることはできません。ただし、線の色の不透明度が特定の値(たとえば128から255)に設定されている場合はアンチエイリアス法を使用して描画して、不透明度が127から0に設定されている場合はスムージングせずに通常の方法でそのような線を描画するというトリックを使用することができます。このアプローチで、描画されたグラフィカルプリミティブは滑らかな視覚効果で表示/非表示されるようになり、アンチエイリアスなしで描画された線の「粗さ」で半透明性が隠されるようになります。


ライブラリクラスの改善

前回の記事でグレアオブジェクトを作成するときは、影オブジェクトに基づいて作成されると想定しました。つまり、そのクラスで使用可能なぼかしメソッドを使用するために、影オブジェクトから派生することになります。ただし、実践が示しているように、このアプローチ自体は正当化されていません。オブジェクトへの視覚効果の追加が複雑になるという事実に加えて、影オブジェクトの後継としてグレアを使用すると、その使用がすでに作成された概念のフレームワーク内に制限されます。

したがって、グレアオブジェクトがCWinFormBaseライブラリのすべてのWinFormsオブジェクトの基本オブジェクトクラスから派生し、補助オブジェクトのリストに含まれるようにします。そうすれば、それを使用するクラスに1行のコードで簡単に追加できます。アクティブなオブジェクトのハンドラは既に実装しています。このアプローチにより、影オブジェクト処理の機能と同じ機能を別のライブラリクラスに定期的に追加する必要がなくなります。バインドされたオブジェクトを追加して処理するために、既製のメソッドを使用するだけです。

\MQL5\Include\DoEasy\Defines.mqhで、グレアオブジェクトID文字列をグラフィカルオブジェクトのセクションから補助ライブラリコントロールのセクションに移動します。

//+-----------------------------------------------+
//| 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_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
   GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,                   // Glare object
  };
//+------------------------------------------------------------------+


視覚効果(この場合は強調表示)を描画するには、視覚効果スタイルのリストを設定する必要があります。

//+-----------------------------------------------+
//| List of visual effect styles                  |
//+-----------------------------------------------+
enum ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE
  {
   CANV_ELEMENT_VISUAL_EFF_STYLE_RECTANGLE,           // Rectangle
   CANV_ELEMENT_VISUAL_EFF_STYLE_PARALLELOGRAMM,      // Parallelogram
  };
//+------------------------------------------------------------------+

ここでは、正四角形と平行四辺形の2種類のグレアのみを作成します。次に、定義済みのグレア形状をいくつでも描画し、それらを使用して視覚効果をデザインできます。グラフィカルプリミティブである必要はありません。特にこれらの画像はアニメーション化できるため、効果としてオブジェクトに重ね合わせた任意の画像を使用できます。これについては、後で例として説明します。

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

//--- CForm
   MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT,// No shadow object. Create it using the CreateShadowObj() method
   MSG_FORM_OBJECT_TEXT_NO_GLARE_OBJ_FIRST_CREATE_IT, // No glare object. We must first create it using the CreateGlareObj() method
   MSG_FORM_OBJECT_ERR_FAILED_CREATE_SHADOW_OBJ,      // Failed to create new shadow object
   MSG_FORM_OBJECT_ERR_FAILED_CREATE_GLARE_OBJ,       // Failed to create new glare object
   MSG_FORM_OBJECT_ERR_FAILED_CREATE_PC_OBJ,          // Failed to create new pixel copier object
   MSG_FORM_OBJECT_PC_OBJ_ALREADY_IN_LIST,            // Pixel copier object with ID already present in the list 

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

//--- CForm
   {"Отсутствует объект тени. Необходимо сначала его создать при помощи метода CreateShadowObj()","There is no shadow object. You must first create it using the CreateShadowObj() method"},
   {"Отсутствует объект блика. Необходимо сначала его создать при помощи метода CreateGlareObj()","There is no glare object. You must first create it using the CreateGlareObj() method"},
   {"Не удалось создать новый объект для тени","Failed to create new object for shadow"},
   {"Не удалось создать новый объект для блика","Failed to create new object for glare"},
   {"Не удалось создать новый объект-копировщик пикселей","Failed to create new pixel copier object"},
   {"В списке уже есть объект-копировщик пикселей с идентификатором ","There is already a pixel copier object in the list with ID "},

「Glareオブジェクト」メッセージインデックス標準のWinFormsオブジェクトのグループに移動します。

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

   MSG_GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,        // BarProgressBar control
   MSG_GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,            // ProgressBar control
   MSG_GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,               // Glare object
//---
   MSG_GRAPH_ELEMENT_TYPE_WF_WRONG_TYPE_PASSED,       // Incorrect control type

メッセージテキストを同じ方法で移動します。

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

   {"Элемент управления BarProgressBar","Control element \"BarProgressBar\""},
   {"Элемент управления ProgressBar","Control element \"ProgressBar\""},
   {"Объект блика","Glare object"},
   
   {"Передан не правильный тип элемента управления","Wrong control type passed"},


各種配色のパラメータが設定されている\MQL5\Include\DoEasy\GraphINI.mqhグレアの不透明度値を指定するプロパティを追加しますプロパティの総数を12に増やします

//+-----------------------------------------------+
//| List of form style parameter indices          |
//+-----------------------------------------------+
enum ENUM_FORM_STYLE_PARAMS
  {
   //--- CForm
   FORM_STYLE_FRAME_GLARE_OPACITY,              // Glare opacity
   FORM_STYLE_FRAME_SHADOW_OPACITY,             // Shadow opacity
   FORM_STYLE_FRAME_SHADOW_BLUR,                // Shadow blur
   FORM_STYLE_DARKENING_COLOR_FOR_SHADOW,       // Form shadow color darkening
   FORM_STYLE_FRAME_SHADOW_X_SHIFT,             // Shadow X axis shift
   FORM_STYLE_FRAME_SHADOW_Y_SHIFT,             // Shadow Y axis shift
   FORM_STYLE_GRADIENT_V,                       // Vertical gradient filling flag
   FORM_STYLE_GRADIENT_C,                       // Cyclic gradient filling flag
   //--- CPanel
   FORM_STYLE_FRAME_WIDTH_LEFT,                 // Panel frame width to the left
   FORM_STYLE_FRAME_WIDTH_RIGHT,                // Panel frame width to the right
   FORM_STYLE_FRAME_WIDTH_TOP,                  // Panel frame width on top
   FORM_STYLE_FRAME_WIDTH_BOTTOM,               // Panel frame width below
  };
#define TOTAL_FORM_STYLE_PARAMS        (12)     // Number of form style parameters
//+------------------------------------------------------------------+


グレアの不透明度の既定値を、現在ライブラリにある2つの配色のプロパティの配列に設定します

//+-----------------------------------------------+
//| Array containing form style parameters        |
//+-----------------------------------------------+
int array_form_style[TOTAL_FORM_STYLES][TOTAL_FORM_STYLE_PARAMS]=
  {
//--- "Flat form" style parameters
   {
      //--- CForm
      40,                                       // Glare opacity
      80,                                       // Shadow opacity
      4,                                        // Shadow blur
      80,                                       // Form shadow color darkening
      2,                                        // Shadow X axis shift
      2,                                        // Shadow Y axis shift
      false,                                    // Vertical gradient filling flag
      false,                                    // Cyclic gradient filling flag
      //--- CPanel
      3,                                        // Panel frame width to the left
      3,                                        // Panel frame width to the right
      3,                                        // Panel frame width on top
      3,                                        // Panel frame width below
   },
//--- "Embossed form" style parameters
   {
      //--- CForm
      40,                                       // Glare opacity
      80,                                       // Shadow opacity
      4,                                        // Shadow blur
      80,                                       // Form shadow color darkening
      2,                                        // Shadow X axis shift
      2,                                        // Shadow Y axis shift
      true,                                     // Vertical gradient filling flag
      false,                                    // Cyclic gradient filling flag
      //--- CPanel
      3,                                        // Panel frame width to the left
      3,                                        // Panel frame width to the right
      3,                                        // Panel frame width on top
      3,                                        // Panel frame width below
   },
  };
//+------------------------------------------------------------------+

将来的には、実装を開始するときに、さまざまな配色のこれらのプロパティ値の構成を根本的に変更して補足します。


グレアグラフィカル要素のカテゴリを変更したので、すべてのライブラリグラフィカルオブジェクトの基本オブジェクトクラスの\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_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)      :
      type==GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ              ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ)             :
      "Unknown"
     );
  }  
//+------------------------------------------------------------------+

技術的には、確認する順番に違いはありませんが、順番のために「正しい」ところに移動させましょう。もちろん、アクセス速度には違いがあります。 if-elseによる確認がここにまとめられているため、あるタイプが他のタイプよりも頻繁に確認されるが、チェックリストの最後に近い位置にある場合、少なくとも理論的には、CPUサイクルのフレームワーク内でアクセス時間が増加します。ただし、すべての要素へのアクセスが同じになるようにするには、switch演算子を使用して、ライブラリメソッドでそのようなすべての確認をおこなう必要があります。これは、ライブラリの作成の最後におこなわれます。

強調表示オブジェクトが影オブジェクトから派生することは以前から計画されていました(そして前回の記事で実行されました)。その理由は、影オブジェクトメソッドにガウスぼかしメソッドが存在するためです。ぼかしを使用してグレアを実装する必要がないため、このアイデアは放棄しました。さらに、影オブジェクトをグレアオブジェクトの親として使用すると、オブジェクトの一部として他のグラフィック要素への追加が非常に複雑になります。したがって、グレアオブジェクトは独立した補助的なWinFormsオブジェクトになります。ただし、必要なオブジェクト(影オブジェクトだけでなく)でぼかしを使用できるようにするために、ぼかしメソッドを影オブジェクトからグラフィカル要素オブジェクトに移動します。そこから、ライブラリのすべてのグラフィック要素でこれらのメソッドを使用できるようになります。

\MQL5\Include\DoEasy\Objects\Graph\ShadowObj.mqhファイルからAlgLibライブラリのインクルードを削除し、、blurメソッドの宣言を削除し、これら2つのメソッドの実装コードを削除します。

//+------------------------------------------------------------------+
//|                                                    ShadowObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+-----------------------------------------------+
//| Include files                                 |
//+-----------------------------------------------+
#include "GCnvElement.mqh"
#include <Math\Alglib\alglib.mqh>
//+-----------------------------------------------+
//| 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:


\MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqhで、AlgLibライブラリのインクルードを設定し、protectedセクションでぼかし実装のメソッドを宣言します

//+------------------------------------------------------------------+
//|                                                  GCnvElement.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+-----------------------------------------------+
//| Include files                                 |
//+-----------------------------------------------+
#include "GBaseObj.mqh"
#include <Math\Alglib\alglib.mqh>
//+-----------------------------------------------+
//| Class of the graphical element object         |
//+-----------------------------------------------+
class CGCnvElement : public CGBaseObj
  {
protected:
   CGCnvElement     *m_element_main;                           // Pointer to the initial parent element within all the groups of bound objects
   CGCnvElement     *m_element_base;                           // Pointer to the parent element within related objects of the current group
   CCanvas           m_canvas;                                 // CCanvas class object
   CPause            m_pause;                                  // Pause class object
   bool              m_shadow;                                 // Shadow presence
   color             m_chart_color_bg;                         // Chart background color
   uint              m_duplicate_res[];                        // Array for storing resource data copy
   color             m_array_colors_bg[];                      // Array of element background colors
   color             m_array_colors_bg_dwn[];                  // Array of control background colors when clicking on the control
   color             m_array_colors_bg_ovr[];                  // Array of control background colors when hovering the mouse over the control
   bool              m_gradient_v;                             // Vertical gradient filling flag
   bool              m_gradient_c;                             // Cyclic gradient filling flag
   int               m_init_relative_x;                        // Initial relative X coordinate
   int               m_init_relative_y;                        // Initial relative Y coordinate
   color             m_array_colors_bg_init[];                 // Array of element background colors (initial color)

//--- Create (1) the object structure and (2) the object from the structure
   virtual bool      ObjectToStruct(void);
   virtual void      StructToObject(void);
//--- Copy the color array to the specified background color array
   void              CopyArraysColors(color &array_dst[],const color &array_src[],const string source);
   
//--- Return the number of graphical elements (1) by type, (2) by name and type
   int               GetNumGraphElements(const ENUM_GRAPH_ELEMENT_TYPE type) const;
   int               GetNumGraphElements(const string name,const ENUM_GRAPH_ELEMENT_TYPE type) const;
//--- Create and return the graphical element name by its type
   string            CreateNameGraphElement(const ENUM_GRAPH_ELEMENT_TYPE type);
   
//--- Gaussian blur
   bool              GaussianBlur(const uint radius);
//--- Return the array of weight ratios
   bool              GetQuadratureWeights(const double mu0,const int n,double &weights[]);

private:


クラス本体の外に、CShadowObjクラスから削除されたぼかしメソッドの実装を追加します。

//+-----------------------------------------------+
//| Gaussian blur                                 |
//| https://www.mql5.com/ja/articles/1612#chapter4|
//+-----------------------------------------------+
bool CGCnvElement::GaussianBlur(const uint radius)
  {
//---
   int n_nodes=(int)radius*2+1;
//--- Read graphical resource data. If failed, return false
   if(!CGCnvElement::ResourceStamp(DFUN))
      return false;
//--- Check the blur amount. If the blur radius exceeds half of the width or height, return 'false'
   if((int)radius>=this.Width()/2 || (int)radius>=this.Height()/2)
     {
      ::Print(DFUN,CMessage::Text(MSG_SHADOW_OBJ_IMG_SMALL_BLUR_LARGE));
      return false;
     }
     
//--- Decompose image data from the resource into a, r, g, b color components
   int  size=::ArraySize(this.m_duplicate_res);
//--- arrays for storing A, R, G and B color components
//--- for horizontal and vertical blur
   uchar a_h_data[],r_h_data[],g_h_data[],b_h_data[];
   uchar a_v_data[],r_v_data[],g_v_data[],b_v_data[];
   
//--- Change the size of component arrays according to the array size of the graphical resource data
   if(::ArrayResize(a_h_data,size)==-1)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE);
      ::Print(DFUN_ERR_LINE,": \"a_h_data\"");
      return false;
     }
   if(::ArrayResize(r_h_data,size)==-1)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE);
      ::Print(DFUN_ERR_LINE,": \"r_h_data\"");
      return false;
     }
   if(::ArrayResize(g_h_data,size)==-1)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE);
      ::Print(DFUN_ERR_LINE,": \"g_h_data\"");
      return false;
     }
   if(ArrayResize(b_h_data,size)==-1)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE);
      ::Print(DFUN_ERR_LINE,": \"b_h_data\"");
      return false;
     }
   if(::ArrayResize(a_v_data,size)==-1)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE);
      ::Print(DFUN_ERR_LINE,": \"a_v_data\"");
      return false;
     }
   if(::ArrayResize(r_v_data,size)==-1)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE);
      ::Print(DFUN_ERR_LINE,": \"r_v_data\"");
      return false;
     }
   if(::ArrayResize(g_v_data,size)==-1)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE);
      ::Print(DFUN_ERR_LINE,": \"g_v_data\"");
      return false;
     }
   if(::ArrayResize(b_v_data,size)==-1)
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE);
      ::Print(DFUN_ERR_LINE,": \"b_v_data\"");
      return false;
     }
//--- Declare the array for storing blur weight ratios and,
//--- if failed to get the array of weight ratios, return 'false'
   double weights[];
   if(!this.GetQuadratureWeights(1,n_nodes,weights))
      return false;
      
//--- Set components of each image pixel to the color component arrays
   for(int i=0;i<size;i++)
     {
      a_h_data[i]=GETRGBA(this.m_duplicate_res[i]);
      r_h_data[i]=GETRGBR(this.m_duplicate_res[i]);
      g_h_data[i]=GETRGBG(this.m_duplicate_res[i]);
      b_h_data[i]=GETRGBB(this.m_duplicate_res[i]);
     }

//--- Blur the image horizontally (along the X axis)
   uint XY; // Pixel coordinate in the array
   double a_temp=0.0,r_temp=0.0,g_temp=0.0,b_temp=0.0;
   int coef=0;
   int j=(int)radius;
   //--- Loop by the image width
   for(int Y=0;Y<this.Height();Y++)
     {
      //--- Loop by the image height
      for(uint X=radius;X<this.Width()-radius;X++)
        {
         XY=Y*this.Width()+X;
         a_temp=0.0; r_temp=0.0; g_temp=0.0; b_temp=0.0;
         coef=0;
         //--- Multiply each color component by the weight ratio corresponding to the current image pixel
         for(int i=-1*j;i<j+1;i=i+1)
           {
            a_temp+=a_h_data[XY+i]*weights[coef];
            r_temp+=r_h_data[XY+i]*weights[coef];
            g_temp+=g_h_data[XY+i]*weights[coef];
            b_temp+=b_h_data[XY+i]*weights[coef];
            coef++;
           }
         //--- Save each rounded color component calculated according to the ratios to the component arrays
         a_h_data[XY]=(uchar)::round(a_temp);
         r_h_data[XY]=(uchar)::round(r_temp);
         g_h_data[XY]=(uchar)::round(g_temp);
         b_h_data[XY]=(uchar)::round(b_temp);
        }
      //--- Remove blur artifacts to the left by copying adjacent pixels
      for(uint x=0;x<radius;x++)
        {
         XY=Y*this.Width()+x;
         a_h_data[XY]=a_h_data[Y*this.Width()+radius];
         r_h_data[XY]=r_h_data[Y*this.Width()+radius];
         g_h_data[XY]=g_h_data[Y*this.Width()+radius];
         b_h_data[XY]=b_h_data[Y*this.Width()+radius];
        }
      //--- Remove blur artifacts to the right by copying adjacent pixels
      for(int x=int(this.Width()-radius);x<this.Width();x++)
        {
         XY=Y*this.Width()+x;
         a_h_data[XY]=a_h_data[(Y+1)*this.Width()-radius-1];
         r_h_data[XY]=r_h_data[(Y+1)*this.Width()-radius-1];
         g_h_data[XY]=g_h_data[(Y+1)*this.Width()-radius-1];
         b_h_data[XY]=b_h_data[(Y+1)*this.Width()-radius-1];
        }
     }

//--- Blur vertically (along the Y axis) the image already blurred horizontally
   int dxdy=0;
   //--- Loop by the image height
   for(int X=0;X<this.Width();X++)
     {
      //--- Loop by the image width
      for(uint Y=radius;Y<this.Height()-radius;Y++)
        {
         XY=Y*this.Width()+X;
         a_temp=0.0; r_temp=0.0; g_temp=0.0; b_temp=0.0;
         coef=0;
         //--- Multiply each color component by the weight ratio corresponding to the current image pixel
         for(int i=-1*j;i<j+1;i=i+1)
           {
            dxdy=i*(int)this.Width();
            a_temp+=a_h_data[XY+dxdy]*weights[coef];
            r_temp+=r_h_data[XY+dxdy]*weights[coef];
            g_temp+=g_h_data[XY+dxdy]*weights[coef];
            b_temp+=b_h_data[XY+dxdy]*weights[coef];
            coef++;
           }
         //--- Save each rounded color component calculated according to the ratios to the component arrays
         a_v_data[XY]=(uchar)::round(a_temp);
         r_v_data[XY]=(uchar)::round(r_temp);
         g_v_data[XY]=(uchar)::round(g_temp);
         b_v_data[XY]=(uchar)::round(b_temp);
        }
      //--- Remove blur artifacts at the top by copying adjacent pixels
      for(uint y=0;y<radius;y++)
        {
         XY=y*this.Width()+X;
         a_v_data[XY]=a_v_data[X+radius*this.Width()];
         r_v_data[XY]=r_v_data[X+radius*this.Width()];
         g_v_data[XY]=g_v_data[X+radius*this.Width()];
         b_v_data[XY]=b_v_data[X+radius*this.Width()];
        }
      //--- Remove blur artifacts at the bottom by copying adjacent pixels
      for(int y=int(this.Height()-radius);y<this.Height();y++)
        {
         XY=y*this.Width()+X;
         a_v_data[XY]=a_v_data[X+(this.Height()-1-radius)*this.Width()];
         r_v_data[XY]=r_v_data[X+(this.Height()-1-radius)*this.Width()];
         g_v_data[XY]=g_v_data[X+(this.Height()-1-radius)*this.Width()];
         b_v_data[XY]=b_v_data[X+(this.Height()-1-radius)*this.Width()];
        }
     }
     
//--- Set the twice blurred (horizontally and vertically) image pixels to the graphical resource data array
   for(int i=0;i<size;i++)
      this.m_duplicate_res[i]=ARGB(a_v_data[i],r_v_data[i],g_v_data[i],b_v_data[i]);
//--- Display the image pixels on the canvas in a loop by the image height and width from the graphical resource data array
   for(int X=0;X<this.Width();X++)
     {
      for(uint Y=radius;Y<this.Height()-radius;Y++)
        {
         XY=Y*this.Width()+X;
         this.m_canvas.PixelSet(X,Y,this.m_duplicate_res[XY]);
        }
     }
//--- Done
   return true;
  }
//+------------------------------------------------------------------+
//| Return the array of weight ratios                                |
//| https://www.mql5.com/ja/articles/1612#chapter3_2                 |
//+------------------------------------------------------------------+
bool CGCnvElement::GetQuadratureWeights(const double mu0,const int n,double &weights[])
  {
   CAlglib alglib;
   double  alp[];
   double  bet[];
   ::ArrayResize(alp,n);
   ::ArrayResize(bet,n);
   ::ArrayInitialize(alp,1.0);
   ::ArrayInitialize(bet,1.0);
//---
   double out_x[];
   int    info=0;
   alglib.GQGenerateRec(alp,bet,mu0,n,info,out_x,weights);
   if(info!=1)
     {
      string txt=(info==-3 ? "internal eigenproblem solver hasn't converged" : info==-2 ? "Beta[i]<=0" : "incorrect N was passed");
      ::Print("Call error in CGaussQ::GQGenerateRec: ",txt);
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+

メソッドは、クラス間で移動されただけです。


事前定義されたグラフィカルプリミティブと画像を描画するメソッドを改良する必要があることは既に述べました。半透明の線を描画する場合、アンチエイリアシングを使用してプリミティブを描画するメソッドはうまく機能しないため、線の透明度が設定されたしきい値(完全の半分)を超えた場合は、平滑化されたプリミティブの描画を平滑化されていないものに置き換える必要があります。

改善されたメソッドを見てみましょう。描画されたグラフィカルプリミティブの不透明度の値が127を超える場合、プリミティブはアンチエイリアシングを使用するメソッドによって描画されます。それ以外の場合は、アンチエイリアシングなしのメソッドを使用して描画します

//+-----------------------------------------------+
//| Draw the Info icon                            |
//+-----------------------------------------------+
void CGCnvElement::DrawIconInfo(const int coord_x,const int coord_y,const uchar opacity)
  {
   int x=coord_x+8;
   int y=coord_y+8;
   this.DrawCircleFill(x,y,7,C'0x00,0x77,0xD7',opacity);
   if(opacity>127)
      this.DrawCircleWu(x,y,7.5,C'0x00,0x3D,0x8C',opacity);
   else
      this.DrawCircle(x,y,8,C'0x00,0x3D,0x8C',opacity);
   this.DrawRectangle(x,y-5,x+1,y-4, C'0xFF,0xFF,0xFF',opacity);
   this.DrawRectangle(x,y-2,x+1,y+4,C'0xFF,0xFF,0xFF',opacity);
  }
//+-----------------------------------------------+
//| Draw the Warning icon                         |
//+-----------------------------------------------+
void CGCnvElement::DrawIconWarning(const int coord_x,const int coord_y,const uchar opacity)
  {
   int x=coord_x+8;
   int y=coord_y+1;
   this.DrawTriangleFill(x,y,x+8,y+14,x-8,y+14,C'0xFC,0xE1,0x00',opacity);
   if(opacity>127)
      this.DrawTriangleWu(x,y,x+8,y+14,x-7,y+14,C'0xFF,0xB9,0x00',opacity);
   else
      this.DrawTriangle(x,y,x+8,y+14,x-7,y+14,C'0xFF,0xB9,0x00',opacity);
   this.DrawRectangle(x,y+5,x+1,y+9,  C'0x00,0x00,0x00',opacity);
   this.DrawRectangle(x,y+11,x+1,y+12,C'0x00,0x00,0x00',opacity);
  }
//+-----------------------------------------------+
//| Draw the Error icon                           |
//+-----------------------------------------------+
void CGCnvElement::DrawIconError(const int coord_x,const int coord_y,const uchar opacity)
  {
   int x=coord_x+8;
   int y=coord_y+8;
   this.DrawCircleFill(x,y,7,C'0xF0,0x39,0x16',opacity);
   if(opacity>127)
     {
      this.DrawCircleWu(x,y,7.5,C'0xA5,0x25,0x12',opacity);
      this.DrawLineWu(x-3,y-3,x+3,y+3,C'0xFF,0xFF,0xFF',opacity);
      this.DrawLineWu(x+3,y-3,x-3,y+3,C'0xFF,0xFF,0xFF',opacity);
     }
   else
     {
      this.DrawCircle(x,y,8,C'0xA5,0x25,0x12',opacity);
      this.DrawLine(x-3,y-3,x+3,y+3,C'0xFF,0xFF,0xFF',opacity);
      this.DrawLine(x+3,y-3,x-3,y+3,C'0xFF,0xFF,0xFF',opacity);
     }
  }
//+------------------------------------------------------------------+

もちろん、単に問題を隠しているのですが、ここではそれが正当化されています。不透明度が255から128に減少すると、平滑化された線は多かれ少なかれ正常に見えます。線の描画をアンチエイリアシングなしの描画に置き換えると、ここでは完全に見えなくなります。線はすでに半透明であり、この状態ではピクセル化された外観は目立ちません。これは、平滑化されていない線を完全に不透明に描画した場合には当てはまりません。

このクラスの定義済み形状描画メソッドの残りの部分も、アンチエイリアス描画メソッドを使用します。ただし、透明度を変更したときにどのように見えるかはまだテストしていません。これらのメソッドにも視覚的なアーティファクトがある場合は、まったく同じ方法で改良します。


グレアオブジェクトは別個の分離したタイプ(影オブジェクトのような)ではなく、補助的なWinFormsオブジェクトのリストに属しているため、このオブジェクトのクラスファイルをパネルオブジェクトのクラスファイルにインクルードする必要があります。.このオブジェクトは、すべてのWinFormsライブラリオブジェクトのファイルが接続されるコンテナオブジェクトです。
\MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqhファイルから、グレアオブジェクトクラスの接続文字列を削除します

//+------------------------------------------------------------------+
//|                                                  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"
//+------------------------------------------------------------------+

パネルオブジェクトクラスの\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Panel.mqhグレアオブジェクトクラスファイルをインクルードします

//+------------------------------------------------------------------+
//|                                                        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"
#include "..\..\WForms\GlareObj.mqh"
//+-----------------------------------------------+
//| Panel object class of WForms controls         |
//+-----------------------------------------------+
class CPanel : public CContainer

これで、すべてのコンテナオブジェクトでグレアオブジェクトを使用できるようになり、そこから作成して、ライブラリの他のグラフィカル要素にある接続されたオブジェクトのリストに含めることができます。独立したGUIウィンドウはアプリオリにコンテナであるため、このウィンドウに接続された任意のコントロールにグレアオブジェクト(および視覚効果オブジェクト)を追加できます。


コンテナオブジェクトクラスの\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 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;
      //--- For "GlareObj" WinForms object
      case GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ            :
        obj.SetBackgroundColor(CLR_CANV_NULL,true);
        obj.SetBorderColor(CLR_CANV_NULL,true);
        obj.SetForeColor(CLR_CANV_NULL,true);
        obj.SetBorderStyle(FRAME_STYLE_NONE);
        break;
      default:
        break;
     }
   obj.Crop();
  }
//+------------------------------------------------------------------+

コンテナに接続されたグラフィカルコントロールを作成した後、このメソッドが呼び出され、オブジェクトが適切に機能するための最小限のプロパティが設定されます。


\MQL5\Include\DoEasy\Objects\Graph\WForms\GlareObj.mqhでグレアオブジェクトクラスを完成させましょう。

これで、クラスは基本WinFormsオブジェクトのクラスを派生させますそのファイルをグレアオブジェクトクラスファイルにインクルードしして、親クラスを変更します

//+------------------------------------------------------------------+
//|                                                     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 "WinFormBase.mqh"
//+-----------------------------------------------+
//| Glare object class                            |
//+-----------------------------------------------+
class CGlareObj : public CWinFormBase
  {
   //---...


privateセクションでグレアスタイルを格納するための変数を宣言し、さらに別のものを宣言してグレア描画メソッドを変更します

class CGlareObj : public CWinFormBase
  {
private:
   ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE m_style;        // Glare style
   color             m_color;                         // Glare color
   uchar             m_opacity;                       // Glare opacity
   uchar             m_blur;                          // Blur
//--- Draw the object glare form
   void              DrawGlareFigure(void);
   void              DrawFigureRectangle(void);
   void              DrawFigureParallelogram(void);
protected:

グレアスタイルは、それを描画するためにどのメソッドを呼び出す必要があるかを決定します。DrawGlareFigure()メソッドは、指定されたスタイルに対応する描画メソッドを呼び出します。グレア描画メソッドには仮パラメータはありません。事前定義されたサイズのグラフィック要素で画像を正しくレンダリングするために指定するものはまだありません。描画されるグレアの色と不透明度は、適切なメソッドによって事前に設定されます。ぼかしはまだ使用されません。

クラスのpublicセクションで、グレアの描画、再描画、不透明度の設定、プロパティの初期化のメソッドを宣言し、いくつかのオブジェクトプロパティの設定と取得のメソッドを実装します

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(void);
//--- Redraw the object
   virtual void      Redraw(bool redraw);
//--- Set the element opacity
   virtual void      SetOpacity(const uchar value,const bool redraw=false);
//--- Initialize the properties
   void              Initialize(void);

//+------------------------------------------------------------------+
//| Methods of simplified access to object properties                |
//+------------------------------------------------------------------+
//--- (1) Set and (2) return the glare color
   void              SetColor(const color colour)                             { this.m_color=colour;     }
   color             Color(void)                                        const { return this.m_color;     }
//--- (1) Set and (2) return the opacity of the drawn glare
   void              SetOpacityDraw(const uchar opacity)                      { this.m_opacity=opacity;  }
   uchar             OpacityDraw(void)                                  const { return this.m_opacity;   }
//--- (1) Set and (2) return the glare blur
   void              SetBlur(const uchar blur)                                { this.m_blur=blur;        }
   uchar             Blur(void)                                         const { return this.m_blur;      }
//--- (1) Set and (2) return the glare visual effect
   void              SetVisualEffectStyle(const ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE style)
                       { this.m_style=style;                                                             }
   ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE VisualEffectStyle(void)           const { return this.m_style;     }
//--- Set the glare visual effect style as (1) rectangle and (2) parallelogram
   void              SetStyleRectangle(void)
                       { this.SetVisualEffectStyle(CANV_ELEMENT_VISUAL_EFF_STYLE_RECTANGLE);             }
   void              SetStyleParallelogramm(void)
                       { this.SetVisualEffectStyle(CANV_ELEMENT_VISUAL_EFF_STYLE_PARALLELOGRAMM);        }
  };
//+------------------------------------------------------------------+

オブジェクトプロパティへのアクセスを簡素化するためのメソッドのブロックは、メソッドに渡される値がprivate変数に設定され、これらの変数からの値が返されるメソッドを備えています。

クラスコンストラクタで、CShadowObj親クラスの初期化をCWinFormBaseに置き換え、変数初期化メソッドの呼び出しを追加します

//+-----------------------------------------------+
//| 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) : CWinFormBase(type,main_obj,base_obj,chart_id,subwindow,descript,x-OUTER_AREA_SIZE,y-OUTER_AREA_SIZE,w+OUTER_AREA_SIZE*2,h+OUTER_AREA_SIZE*2)
  {
//--- 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;
   this.Initialize();
  }
//+------------------------------------------------------------------+
//| 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) : CWinFormBase(GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.m_type=OBJECT_DE_TYPE_GGLARE; 
   this.Initialize();
  }
//+------------------------------------------------------------------+

ここで、各コンストラクタに各変数の初期化文字列を書き込む代わりに(両方のコンストラクタで同じ)、オブジェクトプロパティの初期化メソッドを呼び出すだけです。

//+-----------------------------------------------+
//| Initialize the properties                     |
//+-----------------------------------------------+
void CGlareObj::Initialize(void)
  {
   CGCnvElement::SetBackgroundColor(CLR_CANV_NULL,true);
   CGCnvElement::SetActive(false);
   this.SetBlur(4);
   this.SetColor(clrWhite);
   this.SetOpacity(127);
   this.m_shadow=false;
   this.SetVisibleFlag(false,false);
   this.SetVisualEffectStyle(CANV_ELEMENT_VISUAL_EFF_STYLE_RECTANGLE);
   this.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_NORMAL);
   this.SetDisplayed(false);
  }
//+------------------------------------------------------------------+

このメソッドは、オブジェクトプロパティのデフォルト値を設定します。ぼかしは4に設定され、ぼかしの色は白です。不透明度は127に設定されています。これは半透明のオブジェクトで、影はありません。オブジェクトの非表示フラグを設定します。視覚効果のタイプは長方形のグレアです。表示フラグがリセットされている間、表示状態は通常(オブジェクトは非表示)です。オブジェクトは、表示された親オブジェクトに表示されるべきではありません。


以下は、要素の不透明度を設定するメソッドです。

//+-----------------------------------------------+
//| Set the element opacity                       |
//+-----------------------------------------------+
void CGlareObj::SetOpacity(const uchar value,const bool redraw=false)
  {
   CGCnvElement::SetOpacity(0,false);
   this.SetOpacityDraw(value>(uchar)CLR_DEF_SHADOW_OPACITY ? (uchar)CLR_DEF_SHADOW_OPACITY : value);
   this.m_canvas.Update(redraw);
  }
//+------------------------------------------------------------------+

このメソッドは、同名の影オブジェクトメソッドと同じです。ここでは、グレアが描画されるアンダーレイに完全な透明度が設定され、メソッドに渡される値はグレアの色に設定されます。メソッドに渡された不透明度の値がデフォルトの影の不透明度の値より大きい場合は、デフォルト値が使用されます。それ以外の場合は、メソッドに渡された値が適用されます。これは、オブジェクトが完全に不透明にならないようにするためです。これらの目的には非常に適しているため、影にはデフォルト値を使用します。

以下はグレア描画メソッドです。

//+-----------------------------------------------+
//| Draw the object glare                         |
//+-----------------------------------------------+
void CGlareObj::Draw(void)
  {
   if(!this.IsVisible())
      return;
//--- Draw the glare
   this.DrawGlareFigure();
  }
//+------------------------------------------------------------------+

オブジェクトが非表示の場合、何も描画されません。メソッドを終了します。
次に、描画メソッドが設定されているメソッドを呼び出します。

//+-----------------------------------------------+
//| Draw the object glare form                    |
//+-----------------------------------------------+
void CGlareObj::DrawGlareFigure()
  {
   switch(this.VisualEffectStyle())
     {
      case CANV_ELEMENT_VISUAL_EFF_STYLE_RECTANGLE       : this.DrawFigureRectangle();       break;
      case CANV_ELEMENT_VISUAL_EFF_STYLE_PARALLELOGRAMM  : this.DrawFigureParallelogram();   break;
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

描画されるグレアのタイプに応じて、適切なメソッドを呼び出し、実際にグレアの形状を描画します。


以下は、オブジェクトのグレアの長方形を描画するメソッドです。

//+-----------------------------------------------+
//| Draw the rectangle object glare form          |
//+-----------------------------------------------+
void CGlareObj::DrawFigureRectangle(void)
  {
   CGCnvElement::DrawRectangleFill(0,0,this.Width()-1,this.Height()-1,this.m_color,this.OpacityDraw());
   CGCnvElement::Update();
  }
//+------------------------------------------------------------------+

ここでは、オブジェクトの色と描画の不透明度が設定されたオブジェクトのサイズ全体に塗りつぶされた四角形が描画されます。


以下は、オブジェクトのグレアの形状を平行四辺形の形で描画するメソッドです。

//+------------------------------------------------------------------+
//| Draw the shape of the object glare as a parallelogram            |
//+------------------------------------------------------------------+
void CGlareObj::DrawFigureParallelogram(void)
  {
   int array_x[]={6,this.Width()-1,this.Width()-1-6,0};
   int array_y[]={0,0,this.Height()-1,this.Height()-1};
   CGCnvElement::DrawPolygonFill(array_x,array_y,this.m_color,this.OpacityDraw());
   CGCnvElement::Update();
  }
//+------------------------------------------------------------------+

ここには「歪んだ」三角形が描かれます。最初に、多角形の頂点のX座標とY座標の配列を宣言し、配列で指定された頂点を使用して、歪んだ長方形(オブジェクトに設定された色と描画不透明度を持つ平行四辺形)の形で塗りつぶされた多角形を描画します。


オブジェクトを一度描画してから移動すると、移動したオブジェクトがプログレスバーの境界を超えても、グレアオブジェクトは表示されたままになります(つまり、この場合、オブジェクトはそれに沿って移動します)。視覚的には、グレアがプログレスバーから「ジャンプ」して、ProgressBarコントロールが接続されているパネルに描画されているように見えます。これを回避するには、コンテナを超える部分をトリミングしながら、オブジェクトを再描画する必要があります。これには、オブジェクトの再描画メソッドが必要です。

以下は、オブジェクトを再描画するメソッドです。

//+-----------------------------------------------+
//| Redraw the object                             |
//+-----------------------------------------------+
void CGlareObj::Redraw(bool redraw)
  {
   CGCnvElement::Erase(false);
   this.Draw();
   this.Crop();
   this.Update(redraw);
  }
//+------------------------------------------------------------------+

ここではまず、色と不透明度で塗りつぶされたオブジェクトを完全にクリアします。透明色が背景色として設定されているため、不透明度がゼロの間、オブジェクトは完全に透明になります。次に、インストールされたグレアシェイプを描画する前述のメソッドを呼び出し、オブジェクト領域コンテナの外側にはみ出した領域をトリミングして、キャンバスを更新します

これで、プログレスバーに沿ってオブジェクトを移動するときにメソッドを呼び出すだけで済み、グレアはコンテナを超えません。


ProgressBarオブジェクトの機能を開発しましょう。

特定のプロセスの進行状況を表示するには、プログレスバーの増加ステップの量だけBarProgressBarオブジェクトの幅を増やす必要があります。一般に、プログレスバーの幅の値はすべて相対的になり、ProgressBarオブジェクトの幅の割合およびプログレスバーのValueパラメータの最大値の割合です。プログレスバーは、MinimumおよびMaximumパラメータで設定された制限内で値を変更できます。ただし、これらの値はピクセル単位ではなく、オブジェクト幅の割合として設定する必要があります。100の値は、ProgressBarが同じ幅の場合は100ピクセル幅になり、ProgressBarが200ピクセル幅の場合は200になります。この場合、値が50で、上記のオブジェクト幅の値の50および100ピクセルの値に対応します。

プログレスバーの値を簡単に制御するために、プロセスを表示する必要があるサイクルの開始前にオブジェクトを使用する前に、制限の最小値と最大値を設定して、プログレスバーの幅の値を増やすステップを設定するようにしましょう。追跡されたサイクルの次のアクションが完了したら、ProgressBarオブジェクトのPerformStep()メソッドを呼び出すだけで、指定された増加ステップに従ってプログレスバーの幅が増加します。したがって、常に次のようにする必要があります。追跡されたループの反復回数を把握して、必要な値をProgressBarオブジェクトに設定し、ループ内で次の反復が完了したら、PerformStep()メソッドを呼び出します。プログレスバーが1ステップずつ変化します。

\MQL5\Include\DoEasy\Objects\Graph\WForms\CommonControls\ProgressBar.mqhのprivateセクションで、プログレスバーの値を格納するための変数プログレスバーの幅を計算するためのメソッドを宣言します。

//+------------------------------------------------------------------+
//| ArrowLeftRightBox object class of WForms controls                |
//+------------------------------------------------------------------+
class CProgressBar : public CContainer
  {
private:
   int               m_progress_bar_max;  // Maximum progress bar width
   int               m_value_by_max;      // Value relative to Maximum
   int               m_steps_skipped;     // Number of skipped steps of increasing the width of the progress bar
//--- 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);
//--- Calculate the progress bar width
   int               CalculateProgressBarWidth(void);
//--- Initialize the element properties
   void              Initialize(void);

protected:


SetValue()publicメソッドの実装をクラス本体の外に移動し、本体にその宣言のみを残します

//--- (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);
   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); }


メソッドを他にも宣言します

//--- Return the pointer to the progress bar object
   CBarProgressBar  *GetProgressBar(void)                { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,0);     }

//--- Resets the progress bar values to the set minimum
   void              ResetProgressBar(void)              { this.SetValue(this.Minimum());    }
//--- Set the element width
   virtual bool      SetWidth(const int width);
//--- Initialize values for handling in PerformStep
   void              SetValuesForProcessing(const int minimum,const int maximum,const int step,const int steps_skipped);
//--- Increase the current position of the progress bar by the step value
   void              PerformStep();

//--- 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; }

ResetProgressBar()メソッドは、クラスの本体に直接実装され、プログレスバーのValueをMinimumプロパティで設定された値に設定します。これにより、プログレスバーを元の状態に戻すことができます。

デフォルト値の初期化メソッドで、プログレスバーの値をオブジェクト幅の50%に設定し、BarProgressBarオブジェクトの最大幅をピクセル単位で計算しオブジェクト幅の%単位で値を計算します

//+-----------------------------------------------+
//| 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.SetValue(50);
   this.SetStep(10);
   this.SetStyle(CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS);
   this.m_progress_bar_max=this.Width()-this.BorderSizeLeft()-this.BorderSizeRight();
   this.m_value_by_max=this.Value()*100/this.Maximum();
   this.m_steps_skipped=0;
  }
//+------------------------------------------------------------------+

プログレスバーオブジェクトの最大幅は、背景の幅から左右のフレームのサイズを引いた値以下にする必要がありますこうすればプログレスバーは背景に描画されたフレーム内に収まり、それを超えることはありません。


プログレスバーオブジェクトを作成するメソッドで、CalculateProgressBarWidth()メソッドによって計算されたから作成されたオブジェクトの幅を設定しグレアオブジェクトの作成を追加します

//+-----------------------------------------------+
//| 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.CalculateProgressBarWidth();
   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);
//--- Create the glare object
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,0,0,w,h,CLR_CANV_NULL,0,true,false);
//--- Add the current CProgressBar object to the list of active elements of the collection
   this.AddObjToListActiveElements();
  }
//+------------------------------------------------------------------+

メソッドのロジックは、コードのコメントで説明されています。ここではすべて簡単です。プログレスバーの幅を計算し、計算された幅でオブジェクトを作成します。デフォルトは、ProgressBarオブジェクトの幅の50%です。次に、グレアオブジェクトを作成し、現在のオブジェクトをアクティブなオブジェクトのリストに追加します。アクティブな要素のリスト内のすべてのオブジェクトは、ライブラリタイマーで処理され、これらのオブジェクトのタイマーハンドラに実装されているいくつかの独立したアクションを実行できます。このコントロールでは、タイマーがプログレスバーのグレアの外観を処理します。


以下は、PerformStepで処理する値を初期化するメソッドです。

//+-----------------------------------------------+
//| Initialize values for handling in PerformStep |
//+-----------------------------------------------+
void CProgressBar::SetValuesForProcessing(const int minimum,const int maximum,const int step,const int steps_skipped)
  {
   this.SetMinimum(minimum<0 ? 0 : minimum);
   this.SetMaximum(maximum<this.Minimum() ? this.Minimum() : maximum);
   this.SetStep(step<0 ? 0 : step);
   this.m_steps_skipped=steps_skipped;
  }
//+------------------------------------------------------------------+

ここでは、最小値と最大値の値がメソッドに渡され、値、変更のステップ、およびスキップされたステップの数が変更される可能性があります。次に、最小値、最大値、およびステップの値が正しいかどうかが確認され、スキップされたステップの値が変数に設定されます。プログレスバーの値はProgressBarオブジェクトの幅の割合として計算されるため、スキップされたステップの値は使用されない可能性が高くなります。これは、準備が整った後の一連のオブジェクトテストから明らかです。.現在の実装では、この値はどこにも使用されていません。

以下は、プログレスバーの現在値を設定するメソッドです。

//+-----------------------------------------------+
//| Set the current value of the progress bar     |
//+-----------------------------------------------+
void CProgressBar::SetValue(const int value)
  {
//--- Correct the value passed to the method and set it to the object property
   int v=(value<this.Minimum() ? this.Minimum() : value>this.Maximum() ? this.Maximum() : value);
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,v);
//--- Get the progress bar object
   CBarProgressBar *bar=this.GetProgressBar();
   if(bar!=NULL)
     {
      //--- Set 'value' for the progress bar
      bar.SetValue(v);
      //--- Calculate the width of the progress bar object
      int w=this.CalculateProgressBarWidth();
      //--- If the calculated width is greater than the maximum possible value, set the maximum width
      if(w>this.m_progress_bar_max)
         w=this.m_progress_bar_max;
      //--- If the width is less than 1, then
      if(w<1)
        {
         //--- hide the progress bar and redraw the chart to display changes immediately
         bar.Hide();
         ::ChartRedraw(bar.ChartID());
        }
      //--- If the width value is not less than 1
      else
        {
         //--- If the progress bar is hidden, display it and
         if(!bar.IsVisible())
            bar.Show();
         //--- change its size according to the received width
         bar.Resize(w,bar.Height(),true);
        }
     }
  }
//+------------------------------------------------------------------+

メソッドのロジックはコードのコメントで完全に説明されています。オブジェクトの幅を計算するときに、その幅が1ピクセル未満であることが判明した場合、そのような値はオブジェクトに設定できません。したがって、1ピクセルの幅が与えられ、オブジェクトが非表示になるため、幅がゼロのプログレスバーがシミュレートされます。


以下は、プログレスバーの現在の位置をステップ値だけ増やすメソッドです。

//+----------------------------------------------------------------------+
//| Increase the current position of the progress bar by the step value  |
//+----------------------------------------------------------------------+
void CProgressBar::PerformStep(void)
  {
   this.SetValue(this.Value()+this.Step());
  }
//+------------------------------------------------------------------+

ここでは、オブジェクトのValueプロパティを、その過去の値に加えて、この値の増分として以前に指定した値に設定するだけです。したがって、このメソッドが呼び出されるたびに、Valueの値はStepに記録された増分だけ増加します。


以下は、プログレスバーの幅を計算するメソッドです。

//+-----------------------------------------------+
//| Calculate the width of the progress bar       |
//+-----------------------------------------------+
int CProgressBar::CalculateProgressBarWidth(void)   

  {
   this.m_value_by_max=this.Value()*100/this.Maximum();
   return this.m_progress_bar_max*this.m_value_by_max/100;
  }
//+------------------------------------------------------------------+

ここでは、まず値を可能な最大値の割合として計算してから、プログレスバーの最大幅の相対的な幅を上で計算した値の割合として返します。


以下は、新しいオブジェクトの幅を設定するメソッドです。

//+-----------------------------------------------+
//| Set a new width                               |
//+-----------------------------------------------+
bool CProgressBar::SetWidth(const int width)
  {
   if(!CGCnvElement::SetWidth(width))
      return false;
   this.m_progress_bar_max=this.Width()-this.BorderSizeLeft()-this.BorderSizeRight();
   CBarProgressBar *bar=this.GetProgressBar();
   if(bar==NULL)
      return false;
   int w=this.CalculateProgressBarWidth();
   bar.SetWidth(w);
   return true;
  }
//+------------------------------------------------------------------+

ここでは、まず新しいアンダーレイの幅を設定してから、プログレスバーの最大幅をピクセル単位で計算します
次に、プログレスバーの相対的な幅を%で取得しそれをCBarProgressBarオブジェクトに設定します


プログレスバーに表示されるすべての視覚効果は、BarProgressBarオブジェクトのタイマーで処理する必要があります。グレアは、一時停止した後、プログレスバーに沿って実行する必要があります(一時停止 - グレア - 一時停止 - グレア、など)。この動作を実装するには、オブジェクトが既に持っているプロパティにいくつかの値を設定する必要があります。このようなプロパティを設定して、以前の記事でツールチップを滑らかに表示/非表示するような実装をおこないました。これらのプロパティは、グレアオブジェクトにも適しています。

プログレスバーオブジェクトクラスの\MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\BarProgressBar.mqhファイルにグレアオブジェクトファイルをインクルードします。privateセクションで、遅延を設定するメソッドと返すメソッドを記述、オブジェクトプロパティを初期化するメソッドを宣言します

//+------------------------------------------------------------------+
//|                                               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"
#include "..\GlareObj.mqh"
//+------------------------------------------------------------------+
//| BarProgressBar object class of the ProgressBar control           |
//+------------------------------------------------------------------+
class CBarProgressBar : public CWinFormBase
  {
private:
//--- (1) Set and (2) return a pause before displaying the effect
   void              SetShowDelay(const long delay)               { this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY,delay);             }
   ulong             ShowDelay(void)                              { return this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY);            }
//--- Initialize the properties
   void              Initialize(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.Initialize();
  }
//+------------------------------------------------------------------+
//| 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.Initialize();
  }
//+------------------------------------------------------------------+


コンストラクタから削除されたプロパティ初期化文字列を初期化メソッドに移動します。

//+-----------------------------------------------+
//| Initialize the properties                     |
//+-----------------------------------------------+
void CBarProgressBar::Initialize(void)
  {
   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);
   this.SetShowDelay(2000);
  }
//+------------------------------------------------------------------+

移動された文字列に加えて、ここではプログレスバーのグレアの間に2秒間の一時停止を実装しました

以前は、オブジェクトタイマーで、GetTickCount()関数からの値をコメントでチャートに単純に送信していました。
それでは、本格的なハンドラを書きましょう。

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

//+-----------------------------------------------+
//| Timer                                         |
//+-----------------------------------------------+
void CBarProgressBar::OnTimer(void)
  {
   CWinFormBase *base=this.GetBase();
   if(base==NULL)
      return;
   CWinFormBase *glare=base.GetElementByType(GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,0);
   if(glare==NULL)
      return;
      
//--- If the object is in the normal state (hidden)
   if(glare.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_NORMAL)
     {
      //--- set the state of waiting for fading in to the object (in our case, waiting for a shift along the progress bar),
      //--- set the waiting duration and set the countdown time
      glare.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_WAITING_FADE_IN);
      this.m_pause.SetWaitingMSC(this.ShowDelay());
      this.m_pause.SetTimeBegin();
      //--- If the right edge of the glare object is to the right of the left edge of the progress bar object
      if(glare.RightEdge()>=this.CoordX())
        {
         //--- Hide the glare object and move it beyond the right edge of the progress bar
         glare.Hide();
         if(glare.Move(this.CoordX()-glare.Width(),this.CoordY()))
           {
            //--- Set the relative coordinates of the glare object
            glare.SetCoordXRelative(glare.CoordX()-this.CoordX());
            glare.SetCoordYRelative(glare.CoordY()-this.CoordY());
            //--- and its visibility scope equal to the entire object
            glare.SetVisibleArea(0,0,glare.Width(),glare.Height());
           }
        }
      return;
     }
//--- If the object is in the state of waiting for fading in (in our case, waiting for a shift along the progress bar)
   if(glare.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_WAITING_FADE_IN)
     {
      //--- If the waiting time has not yet passed, leave
      if(this.m_pause.Passed()<this.ShowDelay())
         return;
      //--- Set the state of the object being in the process of shifting along the progress bar and
      //---  set the process start countdown time
      glare.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_PROCESS_FADE_IN);
      this.m_pause.SetTimeBegin();
      return;
     }
//--- If the object is in the state of a shift along the progress bar
   if(glare.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_PROCESS_FADE_IN)
     {
      //--- If the glare object X coordinate still has not gone beyond the right edge of the progress bar
      if(glare.CoordX()<=this.RightEdge())
        {
         //--- set the display flag and show the object
         if(!glare.Displayed())
            glare.SetDisplayed(true);
         if(!glare.IsVisible())
            glare.Show();
         //--- bring the highlight object to the foreground
         glare.BringToTop();
         //--- Shift the highlight by 16 pixels to the right
         if(glare.Move(glare.CoordX()+16,this.CoordY()))
           {
            //--- Set the relative coordinates of the highlight object and redraw it
            glare.SetCoordXRelative(glare.CoordX()-this.CoordX());
            glare.SetCoordYRelative(glare.CoordY()-this.CoordY());
            glare.Redraw(true);
           }
         return;
        }
      //--- Set the completion state of the shift along the progress bar
      glare.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_COMPLETED_FADE_IN);
     }
//--- If the object is in the state of completion of shifting along the progress bar
   if(glare.DisplayState()==CANV_ELEMENT_DISPLAY_STATE_COMPLETED_FADE_IN)
     {
      //--- set the object to its normal state (invisible),
      //--- hide the object and set its invisibility flag
      glare.SetDisplayState(CANV_ELEMENT_DISPLAY_STATE_NORMAL);
      glare.Hide();
      glare.SetDisplayed(false);
      return;
     }
  }
//+------------------------------------------------------------------+

メソッドのロジックは、コードのコメントで詳しく説明されており、前回の記事でツールチップオブジェクト用に実装したタイマーイベントハンドラと同じです。これは、よりトリミングされたバージョンです。ツールチップオブジェクトでは、オブジェクトが表示されるのを待ち(ここでも)、次にオブジェクトがフェードインし(ここではプログレスバーに沿って実行)、フェードアウトしてフェードアウトするのを待ちます(現在のケースではおこないません)。それが全体の違いです。しかし、まぶしさを表示してプログレスバーに沿って実行するには、ツールチップオブジェクトと同じENUM_CANV_ELEMENT_DISPLAY_STATE列挙値を使用します。

//+-----------------------------------------------+
//| 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
  };
//+------------------------------------------------------------------+

この列挙型の定数は、さまざまなオブジェクトのさまざまなイベントを処理するために使用できるほど普遍的です。必要に応じて、さらに発生する可能性のあるイベントを記述した定数をこのリストに追加できます。

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


検証

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

TabControlの最初のタブにあるSplitContainerコントロールの2番目のバーに静的なProgressBarオブジェクトを作成しました。ここで、ProgressBarオブジェクトへのポインタを取得し、まずループ内でそのサイズを大きくして、ProgressBar幅の50%に設定されたプログレスバーの相対的なサイズがどのように変化するかを視覚的に確認する必要があります。次に、ループ内で、PerformStepメソッドを使用してプログレスバーの値を増やします。メソッドを機能させるには、事前に必要なパラメータを設定します(minimum = 0、maximum = 350,、step = 1.)。両方のループが完了したら、グレアオブジェクトへのポインタを取得し、その表示パラメータを設定します。

これらすべてを実装するには、OnInit()ハンドラの最後に次のコードブロックを設定します。:

//--- Display and redraw all created panels
   for(int i=0;i<FORMS_TOTAL;i++)
     {
      //--- Get the panel object
      pnl=engine.GetWFPanel("WinForms Panel"+(string)i);
      if(pnl!=NULL)
        {
         //--- display and redraw the panel
         pnl.Show();
         pnl.Redraw(true);
         //--- Get the TabControl object from the panel
         CTabControl *tc=pnl.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,0);
         //--- Get the SplitContainer object from the first tab of the TabControl object
         CSplitContainer *sc=tc.GetTabElementByType(0,GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,0);
         //--- Get the second panel from the SplitContainer object
         CSplitContainerPanel *scp=sc.GetPanel(1);
         //--- Get the ProgressBar object from the received panel
         CProgressBar *pb=scp.GetElementByType(GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,0);
         //--- Wait for 1/10 of a second
         Sleep(100);
         //--- Get the width of the ProgressBar object
         int w=pb.Width();
         //--- In the loop, increase the width of the ProgressBar by 180 pixels with a delay of 1/50
         for(int n=0;n<180;n++)
           {
            Sleep(20);
            pb.Resize(w+n,pb.Height(),true);
           }
         //--- Set the values for PerformStep of the ProgressBar object
         pb.SetValuesForProcessing(0,350,1,0);
         //--- Reset ProgressBar to minimum
         pb.ResetProgressBar();
         //--- Wait for 1/5 second
         Sleep(200);
         //--- In the loop from the minimum to the maximum value of ProgressBar
         for(int n=0;n<=pb.Maximum();n++)
           {
            //--- call the method for increasing the progress bar by a given step with a wait of 1/5 second
            pb.PerformStep();
            Sleep(20);
           }
         //--- Get the glare object
         CGlareObj *gl=pb.GetElementByType(GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,0);
         if(gl!=NULL)
           {
            //--- Set the glare type - rectangle, opacity 40, color - white
            gl.SetStyleRectangle();
            gl.SetOpacity(40);
            gl.SetColor(clrWhite);
           }
        }
     }
        
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+


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


最初のループでは、ProgressBarオブジェクトの幅がどのように増加するかを確認し、プログレスバーの幅もそれに比例して増加します。同時に、Valueは最初は50に設定されており、プログレスバーの幅が相対値で設定されているため、そのままです。

2番目のループでは、PerformStepメソッドを毎回呼び出します。このメソッドは、各ステップで(相対)Valueを増加ステップの値だけ増加します。350の増分がありますが、プログレスバーが一度に1ピクセル以上増加していることがわかります。これは、すべての値が相対的であり、ProgressBarの幅の割合として計算されるためです。各ステップで1ピクセル増加することは不可能であるため、これは正しいことです。ProgressBarの幅が100ピクセルで、ステップ数が1000の場合、1ピクセルあたり10の増加ステップがあります。相対値を計算するときはスキップされます。

プログレスバーの増加ループが完了すると、2秒ごとにグレアが発生します。デモにはこれで十分です。しかし、これは通常の外観には不十分です。まず、グレアは、完了したものではなく、移動するプログレスバーに沿って実行する必要があります。次に、「効果」が単純すぎることが判明しました。これらすべては徐々に改善していきます。

ツールチップオブジェクトのアイコンが正常にフェードアウトするようになりました。


次の段階

次回の記事では、引き続きWinFormsライブラリオブジェクトとProgressBarオブジェクトに取り組みます。

目次に戻る

連載のこれまでの記事

 
DoEasy-コントロール(第20部):SplitContainerWinFormsオブジェクト
DoEasy-コントロール(第21部):SplitContainerコントロール。パネル区切り
DoEasy-コントロール(第22部):SplitContainer。作成したオブジェクトのプロパティを変更する
DoEasy-コントロール(第23部):TabControlとSplitContainerのWinFormsオブジェクトの改善
DoEasy-コントロール(第24部):ヒント補助WinFormsオブジェクト
DoEasy-コントロール(第25部):TooltipWinFormsオブジェクト
DoEasy - コントロール(第26部):ToolTipWinFormsオブジェクトの最終確認とProgressBarの開発開始スムーズ

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

添付されたファイル |
MQL5.zip (4524.46 KB)
MQL5を使った線の扱い方 MQL5を使った線の扱い方
今回は、MQL5によるトレンドラインや支持線と抵抗線といった、最も重要な線の扱い方についてご紹介します。
DoEasy - コントロール(第26部):ToolTip WinFormsオブジェクトの最終確認とProgressBarの開発開始 DoEasy - コントロール(第26部):ToolTip WinFormsオブジェクトの最終確認とProgressBarの開発開始
今回は、ツールチップコントロールの開発を完了し、ProgressBar WinFormsオブジェクトの開発を開始します。オブジェクトで作業しながら、コントロールやそのコンポーネントをアニメーション化するための普遍的な機能を開発する予定です。
非線形指標 非線形指標
今回は、非線形指標を構築する方法と取引での使用について、いくつか考えてみたいと思います。MetaTraderの取引プラットフォームには、非線形なアプローチを使用する指標がかなりあります。
ニューラルネットワークが簡単に(第32部):分散型Q学習 ニューラルネットワークが簡単に(第32部):分散型Q学習
この連載で前回Q学習法を紹介しました。この手法は、各行動の報酬を平均化するものです。2017年には、報酬分布関数を研究する際に、より大きな成果を示す2つの研究が発表されました。そのような技術を使って、私たちの問題を解決する可能性を考えてみましょう。