English Русский 中文 Español Deutsch Português
preview
DoEasy - コントロール(第8部):カテゴリ(GroupBoxおよびCheckBoxのコントロール)による基本WinFormsオブジェクト

DoEasy - コントロール(第8部):カテゴリ(GroupBoxおよびCheckBoxのコントロール)による基本WinFormsオブジェクト

MetaTrader 5 | 22 9月 2022, 09:28
349 0
Artyom Trishkin
Artyom Trishkin

内容


概念

作成するWinFormsオブジェクトは、MS Visual Studiod同様次のように分類されます。

  • 標準コントロール
  • コンテナ
  • メニューとツールバー
  • データ
  • コンポーネント
  • 印刷
  • ダイアログウィンドウ

すべてのカテゴリのオブジェクトは、共通のCWinFormBase基本オブジェクトから継承されます。また、同じカテゴリに属するオブジェクトの機能は、そのカテゴリ内で重複しています。したがって、1つのカテゴリに属するオブジェクトの同様のプロパティとメソッドをすべて、同じカテゴリの共通クラスに結合する価値があります。つまり、すべてのWinFormsオブジェクトの基本クラスから継承されたWinFormsオブジェクトのカテゴリごとに個別の基本クラスを作成する必要があります。これにより、各カテゴリの新しいオブジェクトのコードを簡単に記述できるようになります。

この記事では、コンテナオブジェクトと標準コントロールオブジェクトの2つのオブジェクトを作成します。一般に、1つのカテゴリのオブジェクトに共通するプロパティとメソッドを理解するには、このカテゴリに少なくとも2つのオブジェクトを作成する必要があります。

コンテナカテゴリにGroupBoxオブジェクトクラスを作成しましょう。これは、コンテナ内で複数のオブジェクトを視覚的に組み合わせたコンテナです。
コンテナでもあるPanelオブジェクトとは異なり、GroupBoxは機能が少なく、オブジェクトを共通のグループに視覚的に結合するための単なるコンテナです。

標準コントロールカテゴリで、CheckBoxオブジェクトを作成します。これは、確認済み、未確認、未定義の3つの状態を持つことができるラベル付きのチェックボックスです。このオブジェクトにはテキストラベルがあるため、Labelオブジェクトから継承されます。ただし、さまざまな状態のチェックボックス(検証フラグ)を描画する機能が追加されます。

作成されたすべてのオブジェクトはまだ静的で、マウスと対話することはできません。開発予定のほとんどのWinFormsオブジェクトを作成した後、必要な機能を実装します。


ライブラリクラスの改善

作成されたオブジェクトの場合、作成時にデフォルトで割り当てられたいくつかのプロパティの値を追加する必要があります。

\MQL5\Include\DoEasy\Defines.mqhで、これらの値の新しいマクロ置換を追加します。

//--- Canvas parameters
#define PAUSE_FOR_CANV_UPDATE          (16)                       // Canvas update frequency
#define CLR_CANV_NULL                  (0x00FFFFFF)               // Zero for the canvas with the alpha channel
#define CLR_DEF_FORE_COLOR             (C'0x2D,0x43,0x48')        // Default color for texts of objects on canvas
#define CLR_DEF_FORE_COLOR_OPACITY     (255)                      // Default color non-transparency for canvas object texts
#define CLR_DEF_FRAME_COLOR            (C'0x66,0x6C,0x6F')        // Default color for object frames on canvas
#define CLR_DEF_FRAME_COLOR_OPACITY    (255)                      // Default color non-transparency for canvas object frames
#define CLR_DEF_FRAME_COLOR_DARKNESS   (-2.0)                     // Default color opacity for canvas object frames (when using the background color)
#define CLR_DEF_FRAME_GBOX_COLOR       (C'0xDC,0xDC,0xDC')        // Default color for GroupBox object frames on canvas
#define CLR_DEF_OPACITY                (200)                      // Default color non-transparency for canvas objects
#define CLR_DEF_SHADOW_COLOR           (C'0x6B,0x6B,0x6B')        // Default color for canvas object shadows
#define CLR_DEF_SHADOW_OPACITY         (127)                      // Default color non-transparency for canvas objects
#define DEF_SHADOW_BLUR                (4)                        // Default blur for canvas object shadows
#define DEF_FONT                       ("Calibri")                // Default font
#define DEF_FONT_SIZE                  (8)                        // Default font size
#define DEF_CHECK_SIZE                 (12)                       // Verification flag default size
#define OUTER_AREA_SIZE                (16)                       // Size of one side of the outer area around the form workspace
#define DEF_FRAME_WIDTH_SIZE           (3)                        // Default form/panel/window frame width
//--- Graphical object parameters

チェックボックスフラグは、CheckBoxオブジェクトで12x12ピクセルのデフォルトサイズになります。

現在、ライブラリオブジェクト型リストのWinFormsセクションには、Base、Panel、Label型があります。同じ型が別の列挙に設定されているため、それらは必要ありません。ただし、ここでは、それらをWinFormsオブジェクトカテゴリの指標として使用できます。それでは、オブジェクトカテゴリのみが表示されるように、列挙内の名前を修正しましょう

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

WinFormsオブジェクトの場合、ライブラリオブジェクト型を型およびWinFormsオブジェクトカテゴリとして使用できます。グラフィック要素型リストの列挙では、そのカテゴリでの型を指定します

//+------------------------------------------------------------------+
//| 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
   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_COMMON_BASE,                 // Windows Forms base standard control
   GRAPH_ELEMENT_TYPE_WF_LABEL,                       // Windows Forms Label
   GRAPH_ELEMENT_TYPE_WF_CHECKBOX,                    // Windows Forms ChackBox
  };
//+------------------------------------------------------------------+


CheckBoxオブジェクト検証フラグは、3つの状態のいずれかを持つことができます。それらを指定する列挙を作成しましょう

//+------------------------------------------------------------------+
//| Control flag status                                              |
//+------------------------------------------------------------------+
enum ENUM_CANV_ELEMENT_CHEK_STATE
  {
   CANV_ELEMENT_CHEK_STATE_UNCHECKED,                 // Unchecked
   CANV_ELEMENT_CHEK_STATE_CHECKED,                   // Checked
   CANV_ELEMENT_CHEK_STATE_INDETERMINATE,             // Undefined
  };
//+------------------------------------------------------------------+
//| Integer properties of the graphical element on the canvas        |
//+------------------------------------------------------------------+


キャンバスベースのグラフィックの整数プロパティの列挙の最後に新しいプロパティを追加し、整数プロパティの数を44から48に増やします

//+------------------------------------------------------------------+
//| 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_PADDING_LEFT,                    // Left margin inside the control
   CANV_ELEMENT_PROP_PADDING_RIGHT,                   // Right margin inside the control
   CANV_ELEMENT_PROP_TEXT_ALIGN,                      // Text position within text label boundaries
   CANV_ELEMENT_PROP_CHECK_ALIGN,                     // Position of the verification flag within control borders
   CANV_ELEMENT_PROP_CHECKED,                         // Control verification flag status
   CANV_ELEMENT_PROP_CHECK_STATE,                     // Status of a control having a verification flag
   CANV_ELEMENT_PROP_AUTOCHECK,                       // Auto change flag status when it is selected
   
  };
#define CANV_ELEMENT_PROP_INTEGER_TOTAL (48)          // 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_PADDING_LEFT,                 // Sort by left margin inside the control
   SORT_BY_CANV_ELEMENT_PADDING_RIGHT,                // Sort by right margin inside the control
   SORT_BY_CANV_ELEMENT_TEXT_ALIGN,                   // Sort by text position within text label boundaries
   SORT_BY_CANV_ELEMENT_CHECK_ALIGN,                  // Sort by position of the verification flag within control borders
   SORT_BY_CANV_ELEMENT_CHECKED,                      // Sort by control verification flag status
   SORT_BY_CANV_ELEMENT_CHECK_STATE,                  // Sort by status of a control having a verification flag
   SORT_BY_CANV_ELEMENT_AUTOCHECK,                    // Sort by auto change flag status when it is selected
//--- 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
  };
//+------------------------------------------------------------------+

これで、リストを並べ替えて、新しいプロパティでオブジェクトを選択できるようになります。


BorderStyleプロパティは、異なるWinFormsオブジェクトに対して異なる目的を持ちます。Panelオブジェクトの場合、プロパティはオブジェクトフレームのスタイルを指定します。GroupBoxの場合、オブジェクトのグループの周りに描画されるフレームのタイプを設定します(オブジェクト自体にはフレームがありません)。したがって、さまざまなオブジェクトで同じメソッドを異なる目的に使用できます。
これを実現するには、すべてのWinFormsオブジェクトの基本クラスのファイル(\MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqh)で仮想化しましょう

//--- (1) Set and (2) return the font width type
   void              SetFontBoldType(ENUM_FW_TYPE type);
   ENUM_FW_TYPE      FontBoldType(void)                        const { return (ENUM_FW_TYPE)this.GetProperty(CANV_ELEMENT_PROP_BOLD_TYPE);               }
//--- (1) Set and (2) return the frame style
   virtual void      SetBorderStyle(const ENUM_FRAME_STYLE style)    { this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,style);                           }
   ENUM_FRAME_STYLE  BorderStyle(void)                         const { return (ENUM_FRAME_STYLE)this.GetProperty(CANV_ELEMENT_PROP_BORDER_STYLE);        }

継承されたクラスでメソッドを再定義すると、それぞれに個別のメソッド実装を作成できます。


コンテナカテゴリの基本オブジェクト

コンテナカテゴリで2番目のWinFormsオブジェクトを作成すると、多くのプロパティとメソッドが同じであり、オブジェクトからオブジェクトへと繰り返されることが明らかになりました。異なるオブジェクトでの重複や同じ型のメソッドを避けるために、それらすべてをこのカテゴリのオブジェクトが継承される単一の共通クラスに移動する必要があります。したがって、各子孫オブジェクトは、これらすべてのメソッドを親から受け取ります。同じカテゴリのオブジェクトごとに実装が異なるメソッドは、仮想化して、継承されたクラスで再定義する必要があります。

\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\で、CContainerクラスの新しいファイル(Container.mqh)を作成します。クラスは、ライブラリのすべてのWinFormsオブジェクトの基本クラスから継承する必要があり、そのファイルは作成されたクラスにインクルードされる必要があります

//+------------------------------------------------------------------+
//|                                                    Container.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\WForms\WinFormBase.mqh"
//+------------------------------------------------------------------+
//| Class of the base container object of WForms controls            |
//+------------------------------------------------------------------+
class CContainer : public CWinFormBase
  {
  }


これらのメソッドはカテゴリの他のクラスでも必要になるため、既存のPanelコンテナクラスから新しいクラスに多くのメソッドを移動する必要があります。これらのメソッドのほとんどは第6回の記事でPanelクラスを説明する際に検討したので、ここでは、クラス本体とそのメソッドの実装について簡単に検討します。

クラスオブジェクトには(Panelオブジェクトとは対照的に)アンダーレイオブジェクトがないため、何らかの方法でオブジェクトの作業領域を指定する必要があります。コンテナにバインドされた他のオブジェクトを配置できるオブジェクト領域は作業領域と見なされます。作業領域の限界を強調する新しいメソッドを紹介しましょう。

//+------------------------------------------------------------------+
//|                                                    Container.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\WForms\WinFormBase.mqh"
#include "..\..\WForms\Common Controls\CheckBox.mqh"
//+------------------------------------------------------------------+
//| Class of the base container object of WForms controls            |
//+------------------------------------------------------------------+
class CContainer : public CWinFormBase
  {
private:
//--- Create a new graphical object
   virtual CGCnvElement *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                          const int element_num,
                                          const string name,
                                          const int x,
                                          const int y,
                                          const int w,
                                          const int h,
                                          const color colour,
                                          const uchar opacity,
                                          const bool movable,
                                          const bool activity);

//--- Calculate Dock objects' binding coordinates
   void              CalculateCoords(CArrayObj *list);

protected:
//--- Adjust the element size to fit its content
   bool              AutoSizeProcess(const bool redraw);
   
public:
//--- Return the size and coordinates of the working area
   int               GetWidthWorkspace(void)       const
                       {
                        return this.Width()-::fmax(this.FrameWidthLeft(),this.PaddingLeft())-::fmax(this.FrameWidthRight(),this.PaddingRight());
                       }
   int               GetHeightWorkspace(void)      const
                       {
                        return this.Height()-::fmax(this.FrameWidthTop(),this.PaddingTop())-::fmax(this.FrameWidthBottom(),this.PaddingBottom());
                       }
   int               GetCoordXWorkspace(void)      const
                       {
                        return this.CoordX()+::fmax(this.FrameWidthLeft(),this.PaddingLeft());
                       }
   int               GetCoordYWorkspace(void)      const
                       {
                        return this.CoordY()+::fmax(this.FrameWidthTop(),this.PaddingTop());
                       }
   int               GetRightEdgeWorkspace(void)   const
                       {
                        return this.RightEdge()-::fmax(this.FrameWidthRight(),this.PaddingRight());
                       }
   int               GetBottomEdgeWorkspace(void)  const
                       {
                        return this.BottomEdge()-::fmax(this.FrameWidthBottom(),this.PaddingBottom());
                       }

//--- Return the list of bound WinForms objects with (1) any and (2) specified WinForms object type (from the base one and higher)
   CArrayObj        *GetListWinFormsObj(void);
   CArrayObj        *GetListWinFormsObjByType(const ENUM_GRAPH_ELEMENT_TYPE type);
//--- Return the pointer to the specified WinForms object with the specified type by index
   CWinFormBase     *GetWinFormsObj(const ENUM_GRAPH_ELEMENT_TYPE type,const int index);
   
//--- Set the (1) X, (2) Y coordinates, (3) element width and (4) height
   virtual bool      SetCoordX(const int coord_x)              { return CGCnvElement::SetCoordX(coord_x);   }
   virtual bool      SetCoordY(const int coord_y)              { return CGCnvElement::SetCoordY(coord_y);   }
   virtual bool      SetWidth(const int width)                 { return CGCnvElement::SetWidth(width);      }
   virtual bool      SetHeight(const int height)               { return CGCnvElement::SetHeight(height);    }
   
//--- Create a new attached element
   virtual bool      CreateNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                                      CGCnvElement *main,
                                      const int x,
                                      const int y,
                                      const int w,
                                      const int h,
                                      const color colour,
                                      const uchar opacity,
                                      const bool activity,
                                      const bool redraw);
//--- Redraw the object
   virtual void      Redraw(bool redraw)                             { CWinFormBase::Redraw(redraw);        }
   
//--- Reset the size of all bound objects to the initial ones
   bool              ResetSizeAllToInit(void);
//--- Place bound objects in the order of their Dock binding
   virtual bool      ArrangeObjects(const bool redraw);
   
//--- Set the (1) field width, (2) height, (3) the height of all fields around the control during auto scrolling
   void              SetAutoScrollMarginWidth(const int value)       { this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W,value);  }
   void              SetAutoScrollMarginHeight(const int value)      { this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H,value);  }
   void              SetAutoScrollMarginAll(const int value)
                       {
                        this.SetAutoScrollMarginWidth(value); this.SetAutoScrollMarginHeight(value);
                       }
   void              SetAutoScrollMargin(const int width,const int height)
                       {
                        this.SetAutoScrollMarginWidth(width); this.SetAutoScrollMarginHeight(height);
                       }
//--- Return the (1) field width and (2) height around the control during auto scrolling
   int               AutoScrollMarginWidth(void)               const { return (int)this.GetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W); }
   int               AutoScrollMarginHeight(void)              const { return (int)this.GetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H); }
  
//--- Set the flag of the element auto resizing depending on the content
   virtual void      SetAutoSize(const bool flag,const bool redraw)
                       {
                        bool prev=this.AutoSize();
                        if(prev==flag)
                           return;
                        CWinFormBase::SetAutoSize(flag,redraw);
                        if(prev!=this.AutoSize() && this.ElementsTotal()>0)
                           this.AutoSizeProcess(redraw);
                       }
//--- (1) Set and (2) return the mode of the element auto resizing depending on the content
   void              SetAutoSizeMode(const ENUM_CANV_ELEMENT_AUTO_SIZE_MODE mode,const bool redraw)
                       {
                        ENUM_CANV_ELEMENT_AUTO_SIZE_MODE prev=this.AutoSizeMode();
                        if(prev==mode)
                           return;
                        this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE,mode);
                        if(prev!=this.AutoSizeMode() && this.ElementsTotal()>0)
                           this.AutoSizeProcess(redraw);
                       }
   ENUM_CANV_ELEMENT_AUTO_SIZE_MODE AutoSizeMode(void)   const { return (ENUM_CANV_ELEMENT_AUTO_SIZE_MODE)this.GetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE); }
   
//--- (1) Set and (2) return the mode of binding element borders to the container
   virtual void      SetDockMode(const ENUM_CANV_ELEMENT_DOCK_MODE mode,const bool redraw)
                       {
                        if(this.DockMode()==mode)
                           return;
                        CWinFormBase::SetDockMode(mode,redraw);
                        CContainer *base=this.GetBase();
                        if(base!=NULL)
                           base.ArrangeObjects(redraw);
                       }

//--- Set the width of the form frame (1) to the left, (2) at the top, (3) to the right, (4) at the bottom and (5) on all sides of the control
   virtual void      SetFrameWidthLeft(const uint value)
                       {
                        this.m_frame_width_left=(int)value;
                        if(this.PaddingLeft()<this.FrameWidthLeft())
                           this.SetPaddingLeft(this.FrameWidthLeft());
                       }
   virtual void      SetFrameWidthTop(const uint value)
                       {
                        this.m_frame_width_top=(int)value;
                        if(this.PaddingTop()<this.FrameWidthTop())
                           this.SetPaddingTop(this.FrameWidthTop());
                       }
   virtual void      SetFrameWidthRight(const uint value)
                       {
                        this.m_frame_width_right=(int)value;
                        if(this.PaddingRight()<this.FrameWidthRight())
                           this.SetPaddingRight(this.FrameWidthRight());
                       }
   virtual void      SetFrameWidthBottom(const uint value)
                       {
                        this.m_frame_width_bottom=(int)value;
                        if(this.PaddingBottom()<this.FrameWidthBottom())
                           this.SetPaddingBottom(this.FrameWidthBottom());
                       }
   virtual void      SetFrameWidthAll(const uint value)
                       {
                        this.SetFrameWidthLeft(value); this.SetFrameWidthTop(value); this.SetFrameWidthRight(value); this.SetFrameWidthBottom(value);
                       }

//--- Constructors
                     CContainer(const long chart_id,
                                const int subwindow,
                                const string name,
                                const int x,
                                const int y,
                                const int w,
                                const int h);
                     CContainer(const string name) : CWinFormBase(::ChartID(),0,name,0,0,0,0)
                       {
                        CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_CONTAINER);
                        CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_CONTAINER);
                        this.m_type=OBJECT_DE_TYPE_GWF_CONTAINER; 
                        this.SetForeColor(CLR_DEF_FORE_COLOR);
                        this.SetFontBoldType(FW_TYPE_NORMAL);
                        this.SetMarginAll(3);
                        this.SetPaddingAll(0);
                        this.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false);
                        this.SetBorderStyle(FRAME_STYLE_NONE);
                        this.SetAutoScroll(false,false);
                        this.SetAutoScrollMarginAll(0);
                        this.SetAutoSize(false,false);
                        this.SetAutoSizeMode(CANV_ELEMENT_AUTO_SIZE_MODE_GROW,false);
                        this.Initialize();
                       }
//--- Destructor
                    ~CContainer();
  };
//+------------------------------------------------------------------+

他のメソッドについては、前回の記事でPanelオブジェクトの作成を考慮した時から知っています。

クラスコンストラクタで、すべての変数をデフォルト値で初期化します。

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


クラスデストラクタで、ライブラリWinFormsオブジェクトの基本オブジェクトのクラスの親クラスであるフォームオブジェクトクラスにある初期化解除メソッドを呼び出します。

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CContainer::~CContainer()
  {
   CForm::Deinitialize();
  }
//+------------------------------------------------------------------+


新しいグラフィカルオブジェクトを作成するメソッドは、同じクラスのオブジェクトを除きコンテナオブジェクトカテゴリからではなく、すべての既存(そして少し後で考慮される)WinFormsオブジェクト(およびそれ以外)を作成するための文字列を備えています。

//+------------------------------------------------------------------+
//| Create a new graphical object                                    |
//+------------------------------------------------------------------+
CGCnvElement *CContainer::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                           const int obj_num,
                                           const string obj_name,
                                           const int x,
                                           const int y,
                                           const int w,
                                           const int h,
                                           const color colour,
                                           const uchar opacity,
                                           const bool movable,
                                           const bool activity)
  {
   string name=this.CreateNameDependentObject(obj_name);
   CGCnvElement *element=NULL;
   switch(type)
     {
      case GRAPH_ELEMENT_TYPE_ELEMENT :
         element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),name,x,y,w,h,colour,opacity,movable,activity);
        break;
      case GRAPH_ELEMENT_TYPE_FORM :
         element=new CForm(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_CONTAINER :
         element=new CContainer(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_LABEL :
         element=new CLabel(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_CHECKBOX :
         element=new CCheckBox(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      default:
        break;
     }
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",name);
   return element;
  }
//+------------------------------------------------------------------+

コンテナカテゴリからオブジェクトを作成できないのはなぜでしょうか。その理由は、それらがまさにこのクラスの子孫であり、まだそれらについて何も知らないからです。ただし、ここで独自のクラス(CContainer)のオブジェクトを作成することは可能です。これは仮想メソッドであるため、派生クラスでこのクラスの子孫クラスオブジェクトの作成を設定できます。


新しいバインドされた要素を作成するメソッドもPanelオブジェクトクラスから取得され、新しく作成されたオブジェクトのパラメータを設定するための新しい文字列が追加されています

//+------------------------------------------------------------------+
//| Create a new attached element                                    |
//+------------------------------------------------------------------+
bool CContainer::CreateNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                                  CGCnvElement *main,
                                  const int x,
                                  const int y,
                                  const int w,
                                  const int h,
                                  const color colour,
                                  const uchar opacity,
                                  const bool activity,
                                  const bool redraw)
  {
//--- If the object type is less than the base WinForms object
   if(element_type<GRAPH_ELEMENT_TYPE_WF_BASE)
     {
      //--- report the error and return 'false'
      CMessage::ToLog(DFUN,MSG_PANEL_OBJECT_ERR_OBJ_MUST_BE_WFBASE);
      return false;
     }
//--- If failed to create a new graphical element, return 'false'
   CWinFormBase *obj=CForm::CreateAndAddNewElement(element_type,main,x,y,w,h,colour,opacity,activity);
   if(obj==NULL)
      return false;
//--- Set the text color of the created object as that of the base panel
   obj.SetForeColor(this.ForeColor());
//--- If the object type is a container
   if(obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_CONTAINER)
     {
      //--- set the frame color equal to the background color 
      obj.SetColorFrame(obj.ColorBackground());
     }
//--- If the object type is a panel
   if(obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_PANEL)
     {
      //--- set the frame color equal to the background color 
      obj.SetColorFrame(obj.ColorBackground());
     }
//--- If the object type is GroupBox
   if(obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_GROUPBOX)
     {
      //--- set the frame color equal to the background color 
      obj.SetColorFrame(obj.ColorBackground());
     }
//--- If the object type is a text label,
   if(obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_LABEL)
     {
      //--- set the object text color depending on the one passed to the method
      //--- or the panel text color or the one passed to the method and the frame color equal to the text color 
      obj.SetForeColor(colour==clrNONE ? this.ForeColor() : colour);
      obj.SetColorFrame(main!=NULL ? main.ColorBackground() : obj.ForeColor());
     }
//--- If the object type is CheckBox
   if(obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_CHECKBOX)
     {
      //--- set the object text color depending on the one passed to the method
      //--- or the object text color or the one passed to the method and the frame color equal to the text color 
      obj.SetForeColor(colour==clrNONE ? this.ForeColor() : colour);
      obj.SetColorFrame(main!=NULL ? main.ColorBackground() : obj.ForeColor());
     }
//--- If the panel has auto resize enabled and features bound objects, call the resize method
   if(this.AutoSize() && this.ElementsTotal()>0)
      this.AutoSizeProcess(redraw);
//--- Redraw the panel and all added objects, and return 'true'
   this.Redraw(redraw);
   return true;
  }
//+------------------------------------------------------------------+

このメソッドでは既存および将来の(ただし、Defines.mqhファイルで既に指定されている)オブジェクトをすべて設定できます。CWinFormBase基本オブジェクトタイプが作成され、ここでは親クラスであるため既知であるからです。作成されたオブジェクトのパラメータの設定を定義する、コードブロックで設定されたすべてのパラメータは、CWinFormBaseクラスリストから使用され、衝突もエラーも発生しません。

このメソッドは、新しく作成されたオブジェクトを処理するコードブロックによって引き続き補完されます。初期化の際にクラスで不明なパラメータの設定を必要とする場合、メソッドは仮想です。新しいオブジェクトの未知のプロパティの処理は、それらの新しいクラスの再定義されたメソッドで設定されます。

以下は、バインドされているすべてのオブジェクトのサイズを初期値に戻すメソッドです。

//+------------------------------------------------------------------+
//| Reset the size of all bound objects to the initial ones          |
//+------------------------------------------------------------------+
bool CContainer::ResetSizeAllToInit(void)
  {
   bool res=true;
   CArrayObj *list=this.GetListWinFormsObj();
   if(list==NULL)
      return false;
   for(int i=0;i<list.Total();i++)
     {
      CWinFormBase *obj=list.At(i);
      if(obj==NULL)
        {
         res &=false;
         continue;
        }
      res &=obj.Resize(i,obj.GetWidthInit(),obj.GetHeightInit());
     }
   return res;
  }
//+------------------------------------------------------------------+

ここでは、WinFormsオブジェクトのみのリストを取得します。次に、取得したリストによるループで、各オブジェクトに初期サイズを設定します

以下は、内容に合わせて要素の大きさを調整するメソッドです。

//+------------------------------------------------------------------+
//| Adjust the element size to fit its content                       |
//+------------------------------------------------------------------+
bool CContainer::AutoSizeProcess(const bool redraw)
  {
//--- Get the list of bound objects with WinForms type basic and higher
   CArrayObj *list=this.GetListWinFormsObj();
//--- Get objects with the maximum and minimum X and Y coordinates from the list by their indices
   CWinFormBase *maxx=list.At(CSelect::FindGraphCanvElementMax(list,CANV_ELEMENT_PROP_COORD_X));
   CWinFormBase *minx=list.At(CSelect::FindGraphCanvElementMin(list,CANV_ELEMENT_PROP_COORD_X));
   CWinFormBase *maxy=list.At(CSelect::FindGraphCanvElementMax(list,CANV_ELEMENT_PROP_COORD_Y));
   CWinFormBase *miny=list.At(CSelect::FindGraphCanvElementMin(list,CANV_ELEMENT_PROP_COORD_Y));
//--- If at least one of the four objects is not received, return 'false'
   if(maxx==NULL || minx==NULL || maxy==NULL || miny==NULL)
      return false;

//--- Get the minimum X and Y coordinate
   int min_x=minx.CoordX();
   int min_y=fmin(miny.CoordY(),maxy.BottomEdge());
//--- Calculate the total width and height of all bound objects
   int w=maxx.RightEdge()-min_x;
   int h=int(::fmax(miny.CoordY(),maxy.BottomEdge())-min_y);
//--- Calculate the number of pixels, by which we need to resize the container in width and height
   int excess_x=w-this.GetWidthWorkspace();
   int excess_y=h-this.GetHeightWorkspace();
//--- Calculate the offset, by which the bound objects are to be moved
   int shift_x=this.GetCoordXWorkspace()-min_x;
   int shift_y=this.GetCoordYWorkspace()-min_y;
//--- If failed to change the container size, return 'true'
   if(excess_x==0 && excess_y==0)
      return true;
//--- If it is necessary to move the attached objects inside the container along the X or Y coordinate
   bool res=true;
   if(shift_x>0 || shift_y>0)
     {
      //--- In the loop by all attached objects,
      for(int i=0;i<list.Total();i++)
        {
         //--- get the next object
         CWinFormBase *obj=list.At(i);
         if(obj==NULL)
            continue;
         //--- If the object needs to be shifted horizontally, write the shift result to 'res'
         if(shift_x>0)
            res &=obj.Move(obj.CoordX()+shift_x,obj.CoordY());
         //--- If the object needs to be shifted vertically, write the shift result to 'res'
         if(shift_y>0)
            res &=obj.Move(obj.CoordX(),obj.CoordY()+shift_y);
         //--- Set new relative object X and Y coordinates
         obj.SetCoordXRelative(obj.CoordX()-this.GetCoordXWorkspace());
         obj.SetCoordYRelative(obj.CoordY()-this.GetCoordYWorkspace());
        }
     }
//--- Return the result of resizing the container
   return
     (
      //--- If we failed to move at least one bound object, return 'false'
      !res ? false :
      //--- Otherwise, if only a size increase
      this.AutoSizeMode()==CANV_ELEMENT_AUTO_SIZE_MODE_GROW ? 
      this.Resize(this.Width()+(excess_x>0  ? excess_x : 0),this.Height()+(excess_y>0  ? excess_y : 0),redraw) :
      //--- if both increase and decrease
      this.Resize(this.Width()+(excess_x!=0 ? excess_x : 0),this.Height()+(excess_y!=0 ? excess_y : 0),redraw)
     );
  }
//+------------------------------------------------------------------+

このメソッドもPanelオブジェクトから移動されました。ただし、クラスにはアンダーレイがないため、ここではプロパティ値の代わりにオブジェクトの作業領域パラメータの値を使用します

現在、このメソッドは正しく機能しません。その改善については、コンテナ内のオブジェクトをインデックス順に並べる方法の 改善と合わせて次の記事で検討します。

//+------------------------------------------------------------------+
//| Place bound objects in the order of their Dock binding           |
//+------------------------------------------------------------------+
bool CContainer::ArrangeObjects(const bool redraw)
  {
//--- Get the list of bound objects with WinForms type basic and higher
   CArrayObj *list=this.GetListWinFormsObj();
   CWinFormBase *prev=NULL, *obj=NULL, *elm=NULL;
//--- In the loop by all bound objects,
   for(int i=0;i<list.Total();i++)
     {
      //--- Get the current and previous elements from the list
      obj=list.At(i);
      prev=list.At(i-1);
      //--- If the object is not received, move on
      if(obj==NULL)
         continue;
      int x=0, y=0; // Object binding coordinates
      //--- Depending on the current object binding mode...
      //--- Top
      if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_TOP)
        {
         //--- If failed to change the object size (for the entire working area width and by the initial object height), move on to the next one
         if(!obj.Resize(this.GetWidthWorkspace(),obj.GetHeightInit(),false))
            continue;
         //--- Get the object binding coordinates
         x=this.GetCoordXWorkspace();
         y=(prev!=NULL ? prev.BottomEdge()+1 : this.GetCoordYWorkspace());
         //--- If failed to move the object to the obtained coordinates, move on to the next one
         if(!obj.Move(x,y,false))
            continue;
        }
      //--- Bottom
      if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_BOTTOM)
        {
         //--- If failed to change the object size (for the entire working area width and by the initial object height), move on to the next one
         if(!obj.Resize(this.GetWidthWorkspace(),obj.GetHeightInit(),false))
            continue;
         //--- Get the object binding coordinates
         x=this.GetCoordXWorkspace();
         y=(prev!=NULL ? prev.CoordY()-obj.Height()-1 : this.GetBottomEdgeWorkspace()-obj.Height()-1);
         //--- If failed to move the object to the obtained coordinates, move on to the next one
         if(!obj.Move(x,y,false))
            continue;
        }
      //--- Left
      if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_LEFT)
        {
         //--- If failed to change the object size (for the initial object width and the entire working area height), move on to the next one
         if(!obj.Resize(obj.GetWidthInit(),this.GetHeightWorkspace(),false))
            continue;
         //--- Get the object binding coordinates
         x=(prev!=NULL ? prev.RightEdge()+1 : this.GetCoordXWorkspace());
         y=this.GetCoordYWorkspace();
         //--- If failed to move the object to the obtained coordinates, move on to the next one
         if(!obj.Move(x,y,false))
            continue;
        }
      //--- Right
      if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_RIGHT)
        {
         //--- If failed to change the object size (for the initial object width and the entire working area height), move on to the next one
         if(!obj.Resize(obj.GetWidthInit(),this.GetHeightWorkspace(),false))
            continue;
         //--- Get the object binding coordinates
         x=(prev!=NULL ? prev.CoordX()-obj.Width()-1 : this.GetRightEdgeWorkspace()-obj.Width());
         y=this.GetCoordYWorkspace();
         //--- If failed to move the object to the obtained coordinates, move on to the next one
         if(!obj.Move(x,y,false))
            continue;
        }
      //--- Binding with filling
      if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_FILL)
        {
         //--- If failed to change the object size (for the entire working area width and height), move on to the next one
         if(!obj.Resize(this.GetWidthWorkspace(),this.GetHeightWorkspace(),false))
            continue;
         //--- Get the object binding coordinates
         x=this.GetCoordXWorkspace();
         y=this.GetCoordYWorkspace();
         //--- If failed to move the object to the obtained coordinates, move on to the next one
         if(!obj.Move(x,y,false))
            continue;
        }
      //--- No binding
      if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_NONE)
        {
         //--- Reset the object size
         obj.Resize(obj.GetWidthInit(),obj.GetHeightInit(),false);
         //--- Get the initial object location coordinates
         x=this.GetCoordXWorkspace()+obj.CoordXRelativeInit();
         y=this.GetCoordYWorkspace()+obj.CoordYRelativeInit();
         //--- If failed to move the object to the obtained coordinates, move on to the next one
         if(!obj.Move(x,y,false))
            continue;
        }
      //--- Calculate and set the relative object coordinates
      obj.SetCoordXRelative(x-this.GetCoordXWorkspace());
      obj.SetCoordYRelative(y-this.GetCoordYWorkspace());
     }

//--- If auto resizing mode is enabled
   if(this.AutoSize())
      this.AutoSizeProcess(false);

//--- Redraw the object with the redraw flag and return 'true'
   this.Redraw(redraw); 
   return true;
  }
//+------------------------------------------------------------------+

上記の両方のメソッドは、作り直す必要があります。これらは、Panelオブジェクトクラスに存在していたという理由だけでここに存在します。後で作り直します。

以下のメソッドも、Panelオブジェクトクラスから移動されました。それらは変更なしで移動されました。

//+------------------------------------------------------------------+
//| Return the list of bound objects                                 |
//| of any WinForms base type and higher                             |
//+------------------------------------------------------------------+
CArrayObj *CContainer::GetListWinFormsObj(void)
  {
   return CSelect::ByGraphCanvElementProperty(this.GetListElements(),CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_BASE,EQUAL_OR_MORE);
  }
//+------------------------------------------------------------------+
//| Return the list of bound objects                                 |
//| with the specified WinForms object type                          |
//+------------------------------------------------------------------+
CArrayObj *CContainer::GetListWinFormsObjByType(const ENUM_GRAPH_ELEMENT_TYPE type)
  {
   return CSelect::ByGraphCanvElementProperty(this.GetListElements(),CANV_ELEMENT_PROP_TYPE,type,EQUAL);
  }
//+------------------------------------------------------------------+
//| Return the pointer to the specified WinForms object              |
//| with the specified type by index                                 |
//+------------------------------------------------------------------+
CWinFormBase *CContainer::GetWinFormsObj(const ENUM_GRAPH_ELEMENT_TYPE type,const int index)
  {
   CArrayObj *list=this.GetListWinFormsObjByType(type);
   return(list!=NULL ? list.At(index) : NULL);
  }
//+------------------------------------------------------------------+
//| Calculate Dock objects' binding coordinates                      |
//+------------------------------------------------------------------+
void CContainer::CalculateCoords(CArrayObj *list)
  {
   
  }
//+------------------------------------------------------------------+

これで、コンテナオブジェクトの基本クラスのトピックは完了です。

次に、GroupBoxオブジェクトの新しいクラスを作成しましょう。これは、他のWinFormsオブジェクトを格納するためのコンテナでもあります。


「GroupBox」WinFormsオブジェクト

\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\で、CGroupBoxクラスの新しいファイルGroupBox.mqhを作成します。クラスは、コンテナオブジェクトの新しく作成された基本クラスから継承され、そのファイルとPanelオブジェクトクラスのファイルは、クラスファイルにインクルードする必要があります

//+------------------------------------------------------------------+
//|                                                     GroupBox.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Container.mqh"
#include "Panel.mqh"
//+------------------------------------------------------------------+
//| GroupBox object class of the WForms controls                     |
//+------------------------------------------------------------------+
class CGroupBox : public CContainer
  {
  }

クラスのprivate、protect、publicセクションで、既に使い慣れたメソッドを追加します。
GroupBoxオブジェクトはオブジェクトのグループを囲むフレームを備えているため、そのようなフレームを描画するメソッドをprivateセクションで宣言します

//+------------------------------------------------------------------+
//| GroupBox object class of the WForms controls                     |
//+------------------------------------------------------------------+
class CGroupBox : public CContainer
  {
private:
//--- Draw a frame
   void              DrawFrame(void);
//--- Create a new graphical object
   virtual CGCnvElement *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                          const int element_num,
                                          const string name,
                                          const int x,
                                          const int y,
                                          const int w,
                                          const int h,
                                          const color colour,
                                          const uchar opacity,
                                          const bool movable,
                                          const bool activity);
                                          
protected:
//--- Initialize the variables
   virtual void      Initialize(void);

public:
//--- 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);
//--- Clear the element completely
   virtual void      Erase(const bool redraw=false);
//--- Set a frame style
   virtual void      SetBorderStyle(const ENUM_FRAME_STYLE style)
                       {
                        if((this.FrameWidthTop()<2 || this.FrameWidthBottom()<2 || this.FrameWidthLeft()<2 || this.FrameWidthRight()<2) && 
                            style>FRAME_STYLE_FLAT)
                           this.SetFrameWidthAll(2);
                        this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,style);
                       }
   
//--- Constructors
                     CGroupBox(const long chart_id,
                               const int subwindow,
                               const string name,
                               const int x,
                               const int y,
                               const int w,
                               const int h);
                     CGroupBox(const string name) : CContainer(::ChartID(),0,name,0,0,0,0)
                       {
                        CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_GROUPBOX);
                        CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_GROUPBOX);
                        this.m_type=OBJECT_DE_TYPE_GWF_CONTAINER;
                        this.Initialize();
                       }
//--- Destructor
                    ~CGroupBox(){ CForm::Deinitialize(); }
  };
//+------------------------------------------------------------------+

フレームスタイルを設定するメソッドで、渡されたスタイルを確認します。フレームがフラットでない場合、その幅は2ピクセル以上にする必要がありますこの場合、フレームのすべての辺に2ピクセルの幅が設定されます


パラメトリックコンストラクタで、オブジェクトの初期サイズと座標を設定し、初期化メソッドを呼び出します

//+------------------------------------------------------------------+
//| Constructor indicating the chart and subwindow ID                |
//+------------------------------------------------------------------+
CGroupBox::CGroupBox(const long chart_id,
                     const int subwindow,
                     const string name,
                     const int x,
                     const int y,
                     const int w,
                     const int h) : CContainer(chart_id,subwindow,name,x,y,w,h)
  {
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_GROUPBOX);
   CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_GROUPBOX);
   this.m_type=OBJECT_DE_TYPE_GWF_CONTAINER;
   this.SetCoordXInit(x);
   this.SetCoordYInit(y);
   this.SetWidthInit(w);
   this.SetHeightInit(h);
   this.Initialize();
  }
//+------------------------------------------------------------------+

ご覧のとおり、WinFormsオブジェクトタイプはGroupBoxとして設定され、ライブラリオブジェクトタイプはコンテナとして設定されています。


新しいグラフィカルオブジェクトを作成するメソッドでは、PanelオブジェクトGroupBoxクラスオブジェクトCheckBoxクラスオブジェクトを作成します。これらは、記事の後半で実装します。

//+------------------------------------------------------------------+
//| Create a new graphical object                                    |
//+------------------------------------------------------------------+
CGCnvElement *CGroupBox::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                          const int obj_num,
                                          const string obj_name,
                                          const int x,
                                          const int y,
                                          const int w,
                                          const int h,
                                          const color colour,
                                          const uchar opacity,
                                          const bool movable,
                                          const bool activity)
  {
   string name=this.CreateNameDependentObject(obj_name);
   CGCnvElement *element=NULL;
   switch(type)
     {
      case GRAPH_ELEMENT_TYPE_ELEMENT :
         element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),name,x,y,w,h,colour,opacity,movable,activity);
        break;
      case GRAPH_ELEMENT_TYPE_FORM :
         element=new CForm(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_PANEL :
         element=new CPanel(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_GROUPBOX :
         element=new CGroupBox(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_LABEL :
         element=new CLabel(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_CHECKBOX :
         element=new CCheckBox(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      default:
        break;
     }
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",name);
   return element;
  }
//+------------------------------------------------------------------+


以下は、変数の初期化メソッドです。

//+------------------------------------------------------------------+
//| Initialize the variables                                         |
//+------------------------------------------------------------------+
void CGroupBox::Initialize(void)
  {
//--- Clear all object lists and set sorted list flags for them
   this.m_list_elements.Clear();
   this.m_list_elements.Sort();
   this.m_list_tmp.Clear();
   this.m_list_tmp.Sort();
//--- GroupBox has no shadow object
   this.m_shadow_obj=NULL;
   this.m_shadow=false;
//--- The width of the object frame on each side is 1 pixel by default
   this.SetFrameWidth(1,1,1,1);
//--- The object does not have a gradient filling (neither vertical, nor horizontal)
   this.m_gradient_v=false;
   this.m_gradient_c=false;
//--- Reset all "working" flags and variables
   this.m_mouse_state_flags=0;
   this.m_offset_x=0;
   this.m_offset_y=0;
   CGCnvElement::SetInteraction(false);
//--- Create an animation object and add it to the list for storing such objects
   this.m_animations=new CAnimations(CGCnvElement::GetObject());
   this.m_list_tmp.Add(this.m_animations);
//--- Set a transparent background for the object background and the default color for the frame
   this.SetColorBackground(CLR_CANV_NULL);
   this.SetOpacity(0);
   this.SetColorFrame(CLR_DEF_FRAME_GBOX_COLOR);
//--- Set the default color and text opacity, as well as the absence of the object frame
   this.SetForeColor(CLR_DEF_FORE_COLOR);
   this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY);
   this.SetBorderStyle(FRAME_STYLE_SIMPLE);
//--- Set the default text parameters
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.SetText("GroupBox");
   this.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP);
   this.SetTextAlign(ANCHOR_LEFT_UPPER);
//--- Set the default object parameters
   this.SetAutoSize(false,false);
   this.SetMarginAll(3);
   this.SetPaddingAll(3);
   this.SetEnabled(true);
   this.SetVisible(true,false);
  }
//+------------------------------------------------------------------+

このメソッドでは、すべてのクラス変数はデフォルト値を使用して初期化されます。一部の変数の初期化値は、親クラスで設定された値とは異なります。

以下は、オブジェクトをクリアするメソッドです。

//+------------------------------------------------------------------+
//| Clear the element filling it with color and opacity              |
//+------------------------------------------------------------------+
void CGroupBox::Erase(const color colour,const uchar opacity,const bool redraw=false)
  {
//--- Fill the element having the specified color and the redrawing flag
   CGCnvElement::Erase(colour,opacity,redraw);
//--- Draw a frame encasing a group of objects
   this.DrawFrame();
//--- Draw a header above the frame
   CGCnvElement::Text(6,0,this.Text(),this.ForeColor(),this.ForeColorOpacity());
//--- Update the element having the specified redrawing flag
   this.Update(redraw);
  }
//+------------------------------------------------------------------+
//| Clear the element with a gradient fill                           |
//+------------------------------------------------------------------+
void CGroupBox::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false)
  {
//--- Fill the element having the specified color array and the redrawing flag
   CGCnvElement::Erase(colors,opacity,vgradient,cycle,redraw);
//--- Draw a frame encasing a group of objects
   this.DrawFrame();
//--- Draw a header above the frame
   CGCnvElement::Text(6,0,this.Text(),this.ForeColor(),this.ForeColorOpacity());
//--- Update the element having the specified redrawing flag
   this.Update(redraw);
  }
//+------------------------------------------------------------------+
//| Clear the element completely                                     |
//+------------------------------------------------------------------+
void CGroupBox::Erase(const bool redraw=false)
  {
//--- Fully clear the element with the redrawing flag
   CGCnvElement::Erase(redraw);
  }
//+------------------------------------------------------------------+

メソッドは仮想です。オブジェクト全体を背景色(デフォルトは透明)で塗りつぶすだけでなく、フレームとその上のオブジェクトグループヘッダーテキストも表示されます。

以下は、フレームを描画するメソッドです。

//+------------------------------------------------------------------+
//| Draw the frame                                                   |
//+------------------------------------------------------------------+
void CGroupBox::DrawFrame(void)
  {
//--- Get half of the text height
   int w=0;
   int h=0;
   this.TextSize(Text(),w,h);
   int height=this.Height()-h/2;
//--- Depending on the frame style, draw its necessary type
   switch(this.BorderStyle())
     {
      case FRAME_STYLE_FLAT :
        this.DrawFrameFlat(0,h/2,this.Width(),height,this.FrameWidthTop(),this.FrameWidthBottom(),this.FrameWidthLeft(),this.FrameWidthRight(),this.ColorFrame(),this.ForeColorOpacity());
        break;
      case FRAME_STYLE_BEVEL :
        this.DrawFrameBevel(0,h/2,this.Width(),height,this.FrameWidthTop(),this.FrameWidthBottom(),this.FrameWidthLeft(),this.FrameWidthRight(),this.ColorFrame(),this.ForeColorOpacity());
        break;
      case FRAME_STYLE_STAMP :
        this.DrawFrameStamp(0,h/2,this.Width(),height,this.FrameWidthTop(),this.FrameWidthBottom(),this.FrameWidthLeft(),this.FrameWidthRight(),this.ColorFrame(),this.ForeColorOpacity());
        break;
      //--- FRAME_STYLE_SIMPLE
      default:
        this.DrawFrameSimple(0,h/2,this.Width(),height,this.FrameWidthTop(),this.FrameWidthBottom(),this.FrameWidthLeft(),this.FrameWidthRight(),this.ColorFrame(),this.ForeColorOpacity());
        break;
     }
//--- If the text set for an object is not an empty string, erase the frame area where a text should be located using the transparent color
   if(this.Text()!="")
      this.DrawRectangleFill(5,h/2-1,w+7,h/2+this.FrameWidthTop()+1,CLR_CANV_NULL,0);
  }
//+------------------------------------------------------------------+

メソッドのロジックは、コードのコメントで説明されています。一言でいえば、コンテナ内にあるオブジェクトのグループを囲むフレームを描画する必要があります。フレームをオブジェクト全体のエッジに沿って描画し、そのプロパティでスタイルと色を指定します。フレームの上端は、オブジェクトの上端ではなく、ヘッダーの中央に沿って配置します。フレームの初期Y座標を計算するには、フォントの高さを2で割ります。これがフレームのY座標になります。ヘッダーテキストは、フレームに直接描画しないでください。つまり、テキストの位置にフレームラインがあってはなりません。
これを実現するには、線の上に透明な色の長方形を描画して、適切な場所で線を消去するだけです。四角形のサイズは、各辺から1ピクセルずつラベルサイズを超える必要があります。

「GroupBox」WinFormsオブジェクトの準備が整いました。

Panelオブジェクトクラスの\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Panel.mqhファイルを開き、そこから基本クラスに移動されたすべてのメソッドを削除します。また、コンテナオブジェクト基本クラスのファイルとGroupBoxクラスのファイルをクラスファイルにインクルードします。このクラスは、基本コンテナオブジェクトから継承されます

//+------------------------------------------------------------------+
//|                                                        Panel.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Container.mqh"
#include "GroupBox.mqh"
//+------------------------------------------------------------------+
//| Panel object class of WForms controls                            |
//+------------------------------------------------------------------+
class CPanel : public CContainer

クラスのprivateセクションから、Dockオブジェクトがバインドされている座標を持つオブジェクトへのポインタの変数と、そのようなオブジェクトを使用してアンダーレイを設定するメソッドを削除します。

class CPanel : public CWinFormBase
  {
private:
   CGCnvElement     *m_obj_top;                                      // Pointer to the object whose coordinates the current upper object is bound to
   CGCnvElement     *m_obj_bottom;                                   // Pointer to the object whose coordinates the current bottom object is bound to
   CGCnvElement     *m_obj_left;                                     // Pointer to the object whose coordinates the current left object is bound to
   CGCnvElement     *m_obj_right;                                    // Pointer to the object whose coordinates the current right object is bound to
   CGCnvElement     *m_underlay;                                     // Underlay for placing elements

//--- Create a new graphical object
   virtual CGCnvElement *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                          const int element_num,
                                          const string name,
                                          const int x,
                                          const int y,
                                          const int w,
                                          const int h,
                                          const color colour,
                                          const uchar opacity,
                                          const bool movable,
                                          const bool activity);
//--- Return the initial coordinates of a bound object
   virtual void      GetCoords(int &x,int &y);
//--- Create the underlay object
   bool              CreateUnderlayObj(void);
//--- Set the underlay as a coordinate system zero
   void              SetUnderlayAsBase(void);


不要な文字列は親クラスに設定されているため、クラスコンストラクタから削除します。

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

さらに、コンストラクタで、初期化リストの以前のCWinFormBaseの代わりに、新しいオブジェクト型とCContainerクラスの初期化を設定します。

//--- Constructors
                     CPanel(const long chart_id,
                            const int subwindow,
                            const string name,
                            const int x,
                            const int y,
                            const int w,
                            const int h);
                     CPanel(const string name) : CContainer(::ChartID(),0,name,0,0,0,0)
                       {
                        CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_PANEL);
                        CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_PANEL);
                        this.m_type=OBJECT_DE_TYPE_GWF_CONTAINER; 
                        this.CreateUnderlayObj();
                       }
//--- Destructor
                    ~CPanel(){ CForm::Deinitialize(); }
  };
//+------------------------------------------------------------------+
//| Constructor indicating the chart and subwindow ID                |
//+------------------------------------------------------------------+
CPanel::CPanel(const long chart_id,
               const int subwindow,
               const string name,
               const int x,
               const int y,
               const int w,
               const int h) : CContainer(chart_id,subwindow,name,x,y,w,h)
  {
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_PANEL);
   CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_PANEL);
   this.m_type=OBJECT_DE_TYPE_GWF_CONTAINER;
   this.CreateUnderlayObj();
   this.SetCoordXInit(x);
   this.SetCoordYInit(y);
   this.SetWidthInit(w);
   this.SetHeightInit(h);
  }
//+------------------------------------------------------------------+


新しいグラフィカルオブジェクトを作成するメソッドで、新しいオブジェクトの作成を設定します

//+------------------------------------------------------------------+
//| Create a new graphical object                                    |
//+------------------------------------------------------------------+
CGCnvElement *CPanel::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                       const int obj_num,
                                       const string obj_name,
                                       const int x,
                                       const int y,
                                       const int w,
                                       const int h,
                                       const color colour,
                                       const uchar opacity,
                                       const bool movable,
                                       const bool activity)
  {
   string name=this.CreateNameDependentObject(obj_name);
   CGCnvElement *element=NULL;
   switch(type)
     {
      case GRAPH_ELEMENT_TYPE_ELEMENT :
         element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),name,x,y,w,h,colour,opacity,movable,activity);
        break;
      case GRAPH_ELEMENT_TYPE_FORM :
         element=new CForm(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_GROUPBOX :
         element=new CGroupBox(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_PANEL :
         element=new CPanel(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_LABEL :
         element=new CLabel(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_CHECKBOX :
         element=new CCheckBox(this.ChartID(),this.SubWindow(),name,x,y,w,h);
        break;
      default:
        break;
     }
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",name);
   return element;
  }
//+------------------------------------------------------------------+

以下でCheckBoxオブジェクトの作成を検討します。

クラスの残りの変更は重要ではありません。ここでそれらを検討する意味はありません。記事に添付されているファイルでご覧ください。主なことは、基本クラスに移動されたメソッドの削除です。

次に、WinForms標準コントロールオブジェクトの基本オブジェクトを同じ方法で作成しましょう。


標準コントロールカテゴリの基本オブジェクト

このオブジェクトは前回の記事で検討したテキストラベルオブジェクトのメソッドを格納するためのものです。このオブジェクトのメソッドのほとんどは、このカテゴリの他のオブジェクトで複製されるため、ここ(および他のカテゴリ)にも基本オブジェクトが必要です。

\MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ライブラリ ファイルで、CCommonBaseクラスの新しいファイル(CommonBase.mqh)を作成します。
クラスはライブラリWinFormsオブジェクトの基本クラスから継承する必要があります
クラスファイルをファイルにインクルードします

//+------------------------------------------------------------------+
//|                                                   CommonBase.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\WForms\WinFormBase.mqh"
//+------------------------------------------------------------------+
//| Class of the base WForms standard control object                 |
//+------------------------------------------------------------------+
class CCommonBase : public CWinFormBase
  {
  }


クラスはかなり小さくなります。全体を見てみましょう。

//+------------------------------------------------------------------+
//| Class of the base WForms standard control object                 |
//+------------------------------------------------------------------+
class CCommonBase : public CWinFormBase
  {
private:

protected:
//--- Set the element width and height automatically
   virtual void      AutoSetWH(void)   { return;   }
//--- Initialize the variables
   virtual void      Initialize(void);
   
public:
//--- 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);
//--- Clear the element completely
   virtual void      Erase(const bool redraw=false);

//--- Constructor
                     CCommonBase(const long chart_id,
                                 const int subwindow,
                                 const string name,
                                 const int x,
                                 const int y,
                                 const int w,
                                 const int h);
  };
//+------------------------------------------------------------------+

ここではオブジェクトの自動サイズ設定用に空の仮想メソッドを宣言しています。各クラスは、オブジェクトサイズの設定に使用される独自のサイズ基準を持つことができるため、このメソッドは継承されたクラスで実装する必要があります。

クラスコンストラクタは、オブジェクトの種類すべてのデフォルトプロパティ値を指定します。
すべての値を設定したら、オブジェクトが再描画されます。

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CCommonBase::CCommonBase(const long chart_id,
                         const int subwindow,
                         const string name,
                         const int x,
                         const int y,
                         const int w,
                         const int h) : CWinFormBase(chart_id,subwindow,name,x,y,w,h)
  {
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_COMMON_BASE);
   CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_COMMON_BASE);
   this.m_type=OBJECT_DE_TYPE_GWF_COMMON;
   this.SetCoordX(x);
   this.SetCoordY(y);
   this.SetWidth(w);
   this.SetHeight(h);
   this.Initialize();
   if(this.AutoSize())
      this.AutoSetWH();
   this.SetWidthInit(this.Width());
   this.SetHeightInit(this.Height());
   this.SetCoordXInit(x);
   this.SetCoordYInit(y);
   this.Redraw(false);
  }
//+------------------------------------------------------------------+


以下は初期化メソッドです。

//+------------------------------------------------------------------+
//| Initialize the variables                                         |
//+------------------------------------------------------------------+
void CCommonBase::Initialize(void)
  {
//--- Clear all object lists and set sorted list flags for them
   this.m_list_elements.Clear();
   this.m_list_elements.Sort();
   this.m_list_tmp.Clear();
   this.m_list_tmp.Sort();
//--- Standard control has no shadow object
   this.m_shadow_obj=NULL;
   this.m_shadow=false;
//--- The width of the object frame on each side is 1 pixel by default
   this.m_frame_width_right=1;
   this.m_frame_width_left=1;
   this.m_frame_width_top=1;
   this.m_frame_width_bottom=1;
//--- The object does not have a gradient filling (neither vertical, nor horizontal)
   this.m_gradient_v=false;
   this.m_gradient_c=false;
//--- Reset all "working" flags and variables
   this.m_mouse_state_flags=0;
   this.m_offset_x=0;
   this.m_offset_y=0;
   CGCnvElement::SetInteraction(false);
//--- Create an animation object and add it to the list for storing such objects
   this.m_animations=new CAnimations(CGCnvElement::GetObject());
   this.m_list_tmp.Add(this.m_animations);
//--- Set the transparent color for the object background
   this.SetColorBackground(CLR_CANV_NULL);
   this.SetOpacity(0);
//--- Set the default color and text opacity, as well as the absence of the object frame
   this.SetForeColor(CLR_DEF_FORE_COLOR);
   this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY);
   this.SetBorderStyle(FRAME_STYLE_NONE);
//--- Set the default text parameters
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.SetText("");
   this.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP);
   this.SetTextAlign(ANCHOR_LEFT_UPPER);
//--- Set the default object parameters
   this.SetAutoSize(false,false);
   this.SetMarginAll(3);
   this.SetPaddingAll(0);
   this.SetEnabled(true);
   this.SetVisible(true,false);
  }
//+------------------------------------------------------------------+


以下は、オブジェクトの背景をクリアおよび塗りつぶすメソッドです。

//+------------------------------------------------------------------+
//| Clear the element filling it with color and opacity              |
//+------------------------------------------------------------------+
void CCommonBase::Erase(const color colour,const uchar opacity,const bool redraw=false)
  {
//--- Fill the element having the specified color and the redrawing flag
   CGCnvElement::Erase(colour,opacity,redraw);
//--- If the object has a frame, draw it
   if(this.BorderStyle()!=FRAME_STYLE_NONE && redraw)
      this.DrawFormFrame(this.FrameWidthTop(),this.FrameWidthBottom(),this.FrameWidthLeft(),this.FrameWidthRight(),this.ColorFrame(),255,this.BorderStyle());
//--- Update the element having the specified redrawing flag
   this.Update(redraw);
  }
//+------------------------------------------------------------------+
//| Clear the element with a gradient fill                           |
//+------------------------------------------------------------------+
void CCommonBase::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false)
  {
//--- Fill the element having the specified color array and the redrawing flag
   CGCnvElement::Erase(colors,opacity,vgradient,cycle,redraw);
//--- If the object has a frame, draw it
   if(this.BorderStyle()!=FRAME_STYLE_NONE && redraw)
      this.DrawFormFrame(this.FrameWidthTop(),this.FrameWidthBottom(),this.FrameWidthLeft(),this.FrameWidthRight(),this.ColorFrame(),255,this.BorderStyle());
//--- Update the element having the specified redrawing flag
   this.Update(redraw);
  }
//+------------------------------------------------------------------+
//| Clear the element completely                                     |
//+------------------------------------------------------------------+
void CCommonBase::Erase(const bool redraw=false)
  {
//--- Fully clear the element with the redrawing flag
   CGCnvElement::Erase(redraw);
  }
//+------------------------------------------------------------------+

これらすべてのメソッドは、他のライブラリオブジェクトで既に見てきました。すべてコード内でコメントされており、説明は必要ありません。各オブジェクトの初期化とクリーンアップは似ていますが、変数のデフォルト値と、背景の描画とその上にいくつかの要素を描画する原則と順序にはわずかな違いがあります。このため、各クラスはこれらのメソッドの独自の実装を持つことができます。

一部のメソッドを「テキストラベル」オブジェクトクラスから標準コントロールの基本オブジェクトのクラスに移動したため、\MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\Label.mqhのCLabelクラスを修正する必要があります。

WinFormBase.mqhの代わりに、基本オブジェクトファイルクラスをクラスにインクルードしてそこからクラスを継承します

//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "CommonBase.mqh"
//+------------------------------------------------------------------+
//| Label object class of WForms controls                            |
//+------------------------------------------------------------------+
class CLabel : public CCommonBase


クラスコンストラクタの初期化リストで、新しい親クラスの初期化を設定して新しいライブラリオブジェクトタイプを設定します。

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CLabel::CLabel(const long chart_id,
               const int subwindow,
               const string name,
               const int x,
               const int y,
               const int w,
               const int h) : CCommonBase(chart_id,subwindow,name,x,y,w,h)
  {
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_LABEL);
   CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_LABEL);
   this.m_type=OBJECT_DE_TYPE_GWF_COMMON;
   this.SetCoordX(x);
   this.SetCoordY(y);
   this.SetWidth(w);
   this.SetHeight(h);
   this.Initialize();
   this.SetMargin(3,0,3,0);
   this.SetWidthInit(this.Width());
   this.SetHeightInit(this.Height());
   this.SetCoordXInit(x);
   this.SetCoordYInit(y);
   this.Redraw(false);
  }
//+------------------------------------------------------------------+

クラスの残りの変更は重要ではなく、現在のクラスから親クラスに移動されたメソッドの削除に関係しています。
以下に添付されているファイルでご覧ください。


「CheckBox」WinFormsオブジェクト

CheckBoxオブジェクトは、ラベル付きのチェックボックスです。ラベルとフラグは、オブジェクトの境界に対してそれぞれ9つの位置に配置できます。

  • 左上
  • 中央左
  • 左下
  • 中央下
  • 右下
  • 中央右
  • 右上
  • 中央上
  • 中心

チェックボックスとテキストの位置にはさまざまな組み合わせがあるため、テキストの位置を調整して、可能であればチェックボックスと重ならないようにする必要があります。オブジェクトのフレームを表示することができます。

オブジェクトにはテキストがあるため、テキスト(およびフラグ)のサイズはオブジェクトのサイズを自動的に変更するために使用されますが、「テキストラベル」オブジェクトから継承し、3つの組み合わせでチェックボックスを表示する機能を追加することは理にかなっています。

  • 未確認
  • 確認済み
  • 未定義

「未定義」状態は、CheckBoxが同じオブジェクトのグループのステータスを表示し、一部が選択されて一部が選択されていない場合に発生します。

\MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\で、CLabelクラスの新しいファイル(Label.mqh)を作成します。CLabelクラスファイルをファイルにインクルードし、クラスを継承する必要があります

//+------------------------------------------------------------------+
//|                                                     CheckBox.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Label.mqh"
//+------------------------------------------------------------------+
//| CheckBox object class of the WForms controls                     |
//+------------------------------------------------------------------+
class CCheckBox : public CLabel
  {
  }


クラスのprivateセクションで、テキストラベルとチェックボックスの座標とサイズを格納するための変数と、オブジェクトのサイズを変更し、テキストとチェックボックスの座標を処理するためのメソッドを追加します。

class CCheckBox : public CLabel
  {
private:
   int               m_text_x;                                       // Text X coordinate
   int               m_text_y;                                       // Text Y coordinate
   int               m_check_x;                                      // Checkbox X coordinate
   int               m_check_y;                                      // Checkbox Y coordinate
   int               m_check_w;                                      // Checkbox width
   int               m_check_h;                                      // Checkbox height
//--- Set the element width and height automatically
   virtual void      AutoSetWH(void);
//--- Set X and Y coordinates(1) of the checkbox and (2) the text depending on the alignment type
   void              SetCheckFlagCoords(int &x,int &y);
   void              SetTextCoords(int &x,int &y);
//--- Set the corrected text coordinates depending on the text alignment and checkbox
   void              SetCorrectTextCoords(void);

protected:

protectedセクションとpublicセクションで、クラスを処理するメソッドを宣言します。

protected:
//--- Displays the checkbox for the specified state
   virtual void      ShowControlFlag(const ENUM_CANV_ELEMENT_CHEK_STATE state);
   
//--- (1) Set and (2) return the checkbox size on the element
   void              SetCheckWidth(const int width)                  { this.m_check_w=(width<5  ? 5 : width);  }
   void              SetCheckHeight(const int height)                { this.m_check_h=(height<5 ? 5 : height); }
   int               CheckWidth(void)                          const { return this.m_check_w;                  }
   int               CheckHeight(void)                         const { return this.m_check_h;                  }
   
public:
//--- Set the element (1) width and (2) height,
   virtual bool      SetWidth(const int width)                       { return CGCnvElement::SetWidth(width>this.m_check_w   ? width  : this.m_check_w);     }
   virtual bool      SetHeight(const int height)                     { return CGCnvElement::SetHeight(height>this.m_check_h ? height : this.m_check_h);     }
   
//--- (1) Set and (2) return the element checkbox location angle (alignment type)
   void              SetCheckAlign(const ENUM_ANCHOR_POINT anchor)   { this.SetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN,anchor);                              }
   ENUM_ANCHOR_POINT CheckAlign(void)                          const { return (ENUM_ANCHOR_POINT)this.GetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN);           }
   
//--- (1) Set and (2) return the checkbox status
   void              SetChecked(const bool flag)                     { this.SetProperty(CANV_ELEMENT_PROP_CHECKED,flag);                                    }
   bool              Checked(void)                             const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_CHECKED);                            }
   
//--- (1) Set and (2) return the control status
   void              SetCheckState(const ENUM_CANV_ELEMENT_CHEK_STATE state) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_STATE,state);                       }
   ENUM_CANV_ELEMENT_CHEK_STATE CheckState(void)               const { return (ENUM_CANV_ELEMENT_CHEK_STATE)this.GetProperty(CANV_ELEMENT_PROP_CHECK_STATE);}

//--- Redraw the object
   virtual void      Redraw(bool redraw);

//--- Constructor
                     CCheckBox(const long chart_id,
                               const int subwindow,
                               const string name,
                               const int x,
                               const int y,
                               const int w,
                               const int h);
  };
//+------------------------------------------------------------------+

これらのメソッドにはすべて、メソッドを説明するような名前が付けられています。それらの実装を考えてみましょう。

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

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CCheckBox::CCheckBox(const long chart_id,
                     const int subwindow,
                     const string name,
                     const int x,
                     const int y,
                     const int w,
                     const int h) : CLabel(chart_id,subwindow,name,x,y,w,h)
  {
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_CHECKBOX);
   CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_CHECKBOX);
   this.m_type=OBJECT_DE_TYPE_GWF_COMMON;
   this.SetCoordX(x);
   this.SetCoordY(y);
   this.SetCheckWidth(DEF_CHECK_SIZE);
   this.SetCheckHeight(DEF_CHECK_SIZE);
   this.SetWidth(w);
   this.SetHeight(h);
   this.Initialize();
   this.SetWidthInit(this.Width());
   this.SetHeightInit(this.Height());
   this.SetCoordXInit(x);
   this.SetCoordYInit(y);
   this.SetTextAlign(ANCHOR_LEFT);
   this.m_text_x=0;
   this.m_text_y=0;
   this.m_check_x=0;
   this.m_check_y=0;
   this.Redraw(false);
  }
//+------------------------------------------------------------------+


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

//+------------------------------------------------------------------+
//| Redraw the object                                                |
//+------------------------------------------------------------------+
void CCheckBox::Redraw(bool redraw)
  {
//--- Fill the object with the background color having full transparency
   this.Erase(this.ColorBackground(),0,true);
//--- Set corrected text coordinates relative to the checkbox
   this.SetCorrectTextCoords();
//--- Draw the text and checkbox within the set coordinates of the object and the binding point, and update the object 
   this.Text(this.m_text_x,this.m_text_y,this.Text(),this.ForeColor(),this.ForeColorOpacity(),this.TextAnchor());
   this.ShowControlFlag(this.CheckState());
   this.Update(redraw);
  }
//+------------------------------------------------------------------+

ここではすべてが簡単です。まず、オブジェクト全体を背景色(デフォルトでは透明)で塗りつぶして完全に消去します。次に、チェックボックスに相対的な有効なテキスト座標を計算し、テキストとチェックボックスを描画して、オブジェクトを更新します。


以下は、配置タイプに応じてXフラグとYフラグの座標を設定するメソッドです。

//+------------------------------------------------------------------+
//| Set X and Y checkbox coordinates                                 |
//| depending on the alignment type                                  |
//+------------------------------------------------------------------+
void CCheckBox::SetCheckFlagCoords(int &x,int &y)
  {
//--- Depending on the checkbox location
   switch(this.CheckAlign())
     {
      //--- The checkbox is located vertically from the left side of the object in the center
      case ANCHOR_LEFT : 
        x=0;
        y=(this.Height()-this.CheckHeight())/2;
        break;
      //--- The checkbox is located in the lower left corner of the object
      case ANCHOR_LEFT_LOWER : 
        x=0;
        y=this.Height()-this.CheckHeight()-1;
        break;
      //--- The checkbox is located in the center of the bottom edge of the object
      case ANCHOR_LOWER : 
        x=(this.Width()-this.CheckWidth())/2;
        y=this.Height()-this.CheckHeight()-1;
        break;
      //--- The checkbox is located in the lower right corner of the object
      case ANCHOR_RIGHT_LOWER : 
        x=this.Width()-this.CheckWidth()-1;
        y=this.Height()-this.CheckHeight()-1;
        break;
      //--- The checkbox is located vertically from the right side of the object in the center
      case ANCHOR_RIGHT : 
        x=this.Width()-this.CheckWidth()-1;
        y=(this.Height()-this.CheckHeight())/2;
        break;
      //--- The checkbox is located in the upper right corner of the object
      case ANCHOR_RIGHT_UPPER : 
        x=this.Width()-this.CheckWidth()-1;
        y=0;
        break;
      //--- The checkbox is located in the center of the upper edge of the object
      case ANCHOR_UPPER : 
        x=(this.Width()-this.CheckWidth())/2;
        y=0;
        break;
      //--- The checkbox is located in the object center
      case ANCHOR_CENTER : 
        x=(this.Width()-this.CheckWidth())/2;
        y=(this.Height()-this.CheckHeight())/2;
        break;
      //--- The checkbox is located in the upper left corner of the object
      //---ANCHOR_LEFT_UPPER
      default:
        x=0;
        y=0;
        break;
     }
  }
//+------------------------------------------------------------------+

このメソッドは、計算されたチェックボックスの座標が設定される変数を受け取ります。配置方法(オブジェクト境界内のチェックボックスの位置)に応じて、その座標を計算し、メソッドに渡される変数に設定します。


以下は、配置タイプに応じてXおよびYテキスト座標を設定するメソッドです。

//+------------------------------------------------------------------+
//| Set X and Y text coordinates                                     |
//| depending on the alignment type                                  |
//+------------------------------------------------------------------+
void CCheckBox::SetTextCoords(int &x,int &y)
  {
//--- Depending on the element text alignment type
   switch(this.TextAlign())
     {
      //--- The text is displayed in the upper left corner of the object
      case ANCHOR_LEFT_UPPER : 
        //--- Set the text binding point at the top left
        this.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP);
        //--- Set the text binding point coordinate
        x=this.FrameWidthLeft();
        y=this.FrameWidthTop();
        break;
      //--- The text is drawn vertically from the left side of the object in the center
      case ANCHOR_LEFT : 
        //--- Set the text binding point at the center left
        this.SetTextAnchor(FRAME_ANCHOR_LEFT_CENTER);
        //--- Set the text binding point coordinate
        x=this.FrameWidthLeft();
        y=this.Height()/2;
        break;
      //--- The text is displayed in the lower left corner of the object
      case ANCHOR_LEFT_LOWER : 
        //--- Set the text binding point at the bottom left
        this.SetTextAnchor(FRAME_ANCHOR_LEFT_BOTTOM);
        //--- Set the text binding point coordinate
        x=this.FrameWidthLeft();
        y=this.Height()-this.FrameWidthBottom();
        break;
      
      //--- The text is drawn at the center of the bottom edge of the object
      case ANCHOR_LOWER : 
        //--- Set the text anchor point at the bottom center
        this.SetTextAnchor(FRAME_ANCHOR_CENTER_BOTTOM);
        //--- Set the text binding point coordinate
        x=this.Width()/2;
        y=this.Height()-this.FrameWidthBottom();
        break;
      //--- The text is displayed in the lower right corner of the object
      case ANCHOR_RIGHT_LOWER : 
        //--- Set the text binding point at the bottom right
        this.SetTextAnchor(FRAME_ANCHOR_RIGHT_BOTTOM);
        //--- Set the text binding point coordinate
        x=this.Width()-this.FrameWidthRight();
        y=this.Height()-this.FrameWidthBottom();
        break;
      //--- The text is drawn vertically from the right side of the object in the center
      case ANCHOR_RIGHT : 
        //--- Set the text binding point at the center right
        this.SetTextAnchor(FRAME_ANCHOR_RIGHT_CENTER);
        //--- Set the text binding point coordinate
        x=this.Width()-this.FrameWidthRight();
        y=this.Height()/2;
        break;
      //--- The text is displayed in the upper right corner of the object
      case ANCHOR_RIGHT_UPPER : 
        //--- Set the text binding point at the top right
        this.SetTextAnchor(FRAME_ANCHOR_RIGHT_TOP);
        //--- Set the text binding point coordinate
        x=this.Width()-this.FrameWidthRight();
        y=this.FrameWidthTop();
        break;
      //--- The text is drawn at the center of the upper edge of the object
      case ANCHOR_UPPER : 
        //--- Set the text binding point at the center top
        this.SetTextAnchor(FRAME_ANCHOR_CENTER_TOP);
        //--- Set the text binding point coordinate
        x=this.Width()/2;
        y=this.FrameWidthTop();
        break;
      //--- The text is drawn at the object center
      //---ANCHOR_CENTER
      default:
        //--- Set the text binding point at the center
        this.SetTextAnchor(FRAME_ANCHOR_CENTER);
        //--- Set the text binding point coordinate
        x=this.Width()/2;
        y=this.Height()/2;
        break;
     }
  }
//+------------------------------------------------------------------+

ここでは、上記で検討したチェックボックス座標の計算方法とすべてが似ています。テキストアンカーポイントもここでさらに変更され、新しいテキストラベル座標の計算が簡素化されます。


以下は、テキストの配置とチェックボックスに応じて有効なテキスト座標を設定するメソッドです。

//+------------------------------------------------------------------+
//| Set valid text coordinates depending on                          |
//| text alignment and checkbox                                      |
//+------------------------------------------------------------------+
void CCheckBox::SetCorrectTextCoords(void)
  {
//--- Set checkbox and text coordinates depending on their alignment method
   this.SetCheckFlagCoords(this.m_check_x,this.m_check_y);
   this.SetTextCoords(this.m_text_x,this.m_text_y);
//--- Get the text size
   int text_w=0, text_h=0;
   this.TextSize(this.Text(),text_w,text_h);
//--- Depending on the checkbox location within the object boundaries
   switch(this.CheckAlign())
     {
      //--- The checkbox is located in the upper left corner of the object
      //--- The checkbox is located vertically from the left side of the object in the center
      //--- The checkbox is located in the lower left corner of the object
      case ANCHOR_LEFT_UPPER  : 
      case ANCHOR_LEFT        : 
      case ANCHOR_LEFT_LOWER  : 
        //--- If the text is left-aligned, set the text X coordinate with the checkbox width + 2 pixels
        if(this.TextAlign()==ANCHOR_LEFT_UPPER || this.TextAlign()==ANCHOR_LEFT || this.TextAlign()==ANCHOR_LEFT_LOWER)
           this.m_text_x=this.CheckWidth()+2;
        break;

      //--- The checkbox is located in the upper right corner of the object
      //--- The checkbox is located vertically from the right side of the object in the center
      //--- The checkbox is located in the lower right corner of the object
      case ANCHOR_RIGHT_UPPER : 
      case ANCHOR_RIGHT       : 
      case ANCHOR_RIGHT_LOWER : 
        //--- If the text is right-aligned, set the text X coordinate with the checkbox width + 2 pixels
        if(this.TextAlign()==ANCHOR_RIGHT_UPPER || this.TextAlign()==ANCHOR_RIGHT || this.TextAlign()==ANCHOR_RIGHT_LOWER)
           this.m_text_x=this.Width()-this.CheckWidth()-2;
        break;

      //--- The checkbox is located in the center of the bottom edge of the object
      case ANCHOR_LOWER : 
        //--- If the text is bottom-aligned, set the text X coordinate with the checkbox height
        if(this.TextAlign()==ANCHOR_LEFT_LOWER || this.TextAlign()==ANCHOR_LOWER || this.TextAlign()==ANCHOR_RIGHT_LOWER)
           this.m_text_y=this.m_check_y;
        break;
      
      //--- The checkbox is located in the center of the upper edge of the object
      case ANCHOR_UPPER : 
        //--- If the text is top-aligned, set the text X coordinate with the checkbox height
        if(this.TextAlign()==ANCHOR_LEFT_UPPER || this.TextAlign()==ANCHOR_UPPER || this.TextAlign()==ANCHOR_RIGHT_UPPER)
           this.m_text_y=this.m_check_h;
        break;
      //--- The checkbox is located in the object center
      //---ANCHOR_CENTER
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

ここで、チェックボックスとテキストラベルの相対位置に応じて、テキストがチェックボックスアイコンと重ならないように、新しいテキスト座標が設定されます。これは普遍的な解決策ではありませんが、ここではすべての主な相関関係が考慮されています。2つのオブジェクトコンポーネントのその他の衝突は、オブジェクト自体のサイズを変更するか、テキストとチェックボックスの位置の比率を正しく設定することで解決できます。

以下は、指定された状態のチェックボックスを表示するメソッドです。

//+------------------------------------------------------------------+
//| Display the checkbox for the specified state                     |
//+------------------------------------------------------------------+
void CCheckBox::ShowControlFlag(const ENUM_CANV_ELEMENT_CHEK_STATE state)
  {
//--- Draw the rectangle of checkbox boundaries
   this.DrawRectangle(this.m_check_x,this.m_check_y,this.m_check_x+this.CheckWidth(),this.m_check_y+this.CheckHeight(),this.ColorFrame());
//--- Create X and Y coordinate arrays for drawing a polyline
   int array_x[]={m_check_x+2,m_check_x+m_check_w/2-1,m_check_x+m_check_w-2};
   int array_y[]={m_check_y+m_check_h/2,m_check_y+m_check_h-3,m_check_y+3};
//--- Depending on the checkbox status passed to the method
   switch(state)
     {
      //--- Set checkbox
      case CANV_ELEMENT_CHEK_STATE_CHECKED :
        //--- Draw a polyline in the form of a checkmark inside the checkbox boundaries
        this.DrawPolylineAA(array_x,array_y,ColorFrame());
        break;
      //--- Unchecked checkbox
      case CANV_ELEMENT_CHEK_STATE_INDETERMINATE :
        //--- Draw a filled rectangle inside the checkbox boundaries
        this.DrawRectangleFill(m_check_x+3,m_check_y+3,m_check_x+m_check_w-3,m_check_y+m_check_h-3,ColorFrame());
        break;
      //--- Undefined state
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

メソッドに渡されたチェックボックスの状態に応じて、チェックボックスの境界内にチェックマークまたは塗りつぶされた四角形を描画します。チェックボックスの境界線のサイズに関係なく、描画されたチェックマークの比率が常に同じになるようにポリライン座標が計算されます。未定義状態の場合は四角形が描画されます。今のところ、これらのアイコンは1種類(チェックマークと1色の四角形)しかありません。将来的には、フラグの状態を表示するいくつかの種類を導入する予定です。

以下は、要素の幅と高さを自動的に設定するメソッドです。

//+------------------------------------------------------------------+
//| Set the element width and height automatically                   |
//+------------------------------------------------------------------+
void CCheckBox::AutoSetWH(void)
  {
//--- Define the variables for receiving the label width and height
   int w=0, h=0;
//--- Get the width and height depending on the object text
   CGCnvElement::TextSize(this.Text()!="" && this.Text()!=NULL ? this.Text() : " ",w,h);
//--- Add the Margin values of the object on the left and right to the resulting width, as well as the checkbox size
   w+=(this.MarginLeft()+this.MarginRight()+this.CheckWidth());
//--- If the width is equal to the size of the checkbox, set it to three pixels + checkbox size
   if(w==this.CheckWidth())
      w=this.CheckWidth()+3;
//--- Add the Margin values of the object on the top and bottom to the resulting height
   h+=(this.MarginTop()+this.MarginBottom());
//--- If failed to get the height, set it as "font size" * ratio
   if(h==0)
      h=(int)ceil(FontSize()*1.625);
//--- If the height is ultimately less than the size of the checkbox, set the height equal to the height of the checkbox
   if(h<this.CheckHeight())
      h=this.CheckHeight();
//--- Set the object width and height from the received values
   this.SetWidth(w);
   this.SetHeight(h);
  }
//+------------------------------------------------------------------+

親クラスのメソッドとは異なり、仮想メソッドではオブジェクトのサイズを変更するときにチェックボックスのサイズを考慮します。

クラスのファイルをCContainerクラスファイルにインクルード(クラスコンテナファイルを開いてクラスをインクルード) し、コンテナクラスからクラスオブジェクトを作成してバインドできるようにします。

//+------------------------------------------------------------------+
//|                                                    Container.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\WForms\WinFormBase.mqh"
#include "..\..\WForms\Common Controls\CheckBox.mqh"
//+------------------------------------------------------------------+
//| Class of the base container object of WForms controls            |
//+------------------------------------------------------------------+
class CContainer : public CWinFormBase


すべての新しいクラスがグラフィックのコレクションクラスに表示されたままになるようにするには、ファイル \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqhコレクションクラスにCGroupBoxクラスのファイルをインクルードします。

//+------------------------------------------------------------------+
//|                                      GraphElementsCollection.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Services\Select.mqh"
#include "..\Objects\Graph\WForms\Containers\GroupBox.mqh"
#include "..\Objects\Graph\WForms\Containers\Panel.mqh"

残りのクラスはGroupBox.mqhにインクルードされ、みえるようになります。

指定されたチャートとサブウィンドウのキャンバスに「GroupBox」WinFormsグラフィカルオブジェクトを作成するメソッドを記述します。

//--- Create the 'GroupBox' WinForms graphical object on canvas on the specified chart and subwindow
   int               CreateGroupBox(const long chart_id,
                                    const int subwindow,
                                    const string name,
                                    const int x,
                                    const int y,
                                    const int w,
                                    const int h,
                                    const string text,
                                    const color text_color=clrNONE,
                                    const color frame_color=WRONG_VALUE,
                                    const int  frame_width=WRONG_VALUE,
                                    ENUM_FRAME_STYLE frame_style=FRAME_STYLE_SIMPLE,
                                    const bool redraw=false)
                       {
                        int id=this.m_list_all_canv_elm_obj.Total();
                        CGroupBox *obj=new CGroupBox(chart_id,subwindow,name,x,y,w,h);
                        ENUM_ADD_OBJ_RET_CODE res=this.AddOrGetCanvElmToCollection(obj,id);
                        if(res==ADD_OBJ_RET_CODE_ERROR)
                           return WRONG_VALUE;
                        obj.SetID(id);
                        obj.SetActive(true);
                        obj.SetMovable(false);
                        obj.SetText(text);
                        obj.SetForeColor(text_color==clrNONE ? CLR_DEF_FORE_COLOR : text_color);
                        obj.SetColorBackground(CLR_CANV_NULL);
                        obj.SetColorFrame(frame_color==clrNONE ? CLR_DEF_FRAME_GBOX_COLOR : frame_color);
                        obj.SetBorderStyle(frame_style!=FRAME_STYLE_NONE ? frame_style : FRAME_STYLE_SIMPLE);
                        obj.SetOpacity(0,false);
                        obj.SetFrameWidthAll(frame_width==WRONG_VALUE ? 1 : frame_width);
                        //--- Draw the shadow drawing flag
                        obj.SetShadow(false);
                        if(redraw)
                           obj.Erase(CLR_CANV_NULL,0,redraw);
                        obj.SetActiveAreaShift(obj.FrameWidthLeft(),obj.FrameWidthBottom(),obj.FrameWidthRight(),obj.FrameWidthTop());
                        obj.Done();
                        return obj.ID();
                       }
 
//--- Create graphical object WinForms Panel object on canvas on a specified chart and subwindow

このメソッドは、オブジェクトの作成に必要なパラメータを受け取ります。オブジェクトが正常に作成されると、これらのパラメータがオブジェクトプロパティに設定されます。このメソッドは、作成時に取得したオブジェクトIDを返します。

カスタムプログラムから新しいオブジェクトを作成できるようにするには、ライブラリのメインオブジェクトクラスの\MQL5\Include\DoEasy\Engine.mqhで、新しいオブジェクトを作成および受信するためのメソッドを記述します。

以下は、「GroupBox」WFormオブジェクトを返すメソッドです。

//--- Return the WForm Panel object by object ID
   CPanel              *GetWFPanel(const int element_id)
                          {
                           CArrayObj *list=GetListCanvElementByType(GRAPH_ELEMENT_TYPE_WF_PANEL);
                           list=CSelect::ByGraphCanvElementProperty(list,CANV_ELEMENT_PROP_ID,element_id,EQUAL);
                           return(list!=NULL ? list.At(0) : NULL);
                          }
                          
//--- Return the GroupBox WForm object by object name on the current chart
   CGroupBox           *GetWFGroupBox(const string name)
                          {
                           string nm=(::StringFind(name,this.m_name_prefix)<0 ? this.m_name_prefix : "")+name;
                           CArrayObj *list=GetListCanvElementByType(GRAPH_ELEMENT_TYPE_WF_GROUPBOX);
                           list=CSelect::ByGraphCanvElementProperty(list,CANV_ELEMENT_PROP_CHART_ID,::ChartID(),EQUAL);
                           list=CSelect::ByGraphCanvElementProperty(list,CANV_ELEMENT_PROP_NAME_OBJ,nm,EQUAL);
                           return(list!=NULL ? list.At(0) : NULL);
                          }
//--- Return the GroupBox WForm object by chart ID and object name
   CGroupBox           *GetWFGroupBox(const long chart_id,const string name)
                          {
                           string nm=(::StringFind(name,this.m_name_prefix)<0 ? this.m_name_prefix : "")+name;
                           CArrayObj *list=GetListCanvElementByType(GRAPH_ELEMENT_TYPE_WF_GROUPBOX);
                           list=CSelect::ByGraphCanvElementProperty(list,CANV_ELEMENT_PROP_CHART_ID,chart_id,EQUAL);
                           list=CSelect::ByGraphCanvElementProperty(list,CANV_ELEMENT_PROP_NAME_OBJ,nm,EQUAL);
                           return(list!=NULL ? list.At(0) : NULL);
                          }
//--- Return the WForm GroupBox object by object ID
   CGroupBox           *GetWFGroupBox(const int element_id)
                          {
                           CArrayObj *list=GetListCanvElementByType(GRAPH_ELEMENT_TYPE_WF_GROUPBOX);
                           list=CSelect::ByGraphCanvElementProperty(list,CANV_ELEMENT_PROP_ID,element_id,EQUAL);
                           return(list!=NULL ? list.At(0) : NULL);
                          }

//--- Create the WinForm Element object

各メソッドで、GroupBox型のオブジェクトのリストを取得し、取得したリストをメソッドに渡されたパラメータで並べ替えます。目的のオブジェクトがリストにある場合は、それが唯一のオブジェクトであり、そのオブジェクトへのポインタがメソッドから返されます。リストにオブジェクトが見つからない場合、メソッドはNULLを返します。

「GroupBox」WinForm オブジェクトを作成するための 3 つのメソッドを追加します。

//--- Create the 'GroupBox' WinForm object
   CGroupBox           *CreateWFGroupBox(const long chart_id,
                                         const int subwindow,
                                         const string name,
                                         const int x,
                                         const int y,
                                         const int w,
                                         const int h,
                                         const string text,
                                         const color text_color=clrNONE,
                                         const color frame_color=clrNONE,
                                         const int frame_width=WRONG_VALUE,
                                         const ENUM_FRAME_STYLE frame_style=FRAME_STYLE_SIMPLE,
                                         const bool redraw=false)
                          {
                           int obj_id=this.m_graph_objects.CreateGroupBox(chart_id,subwindow,name,x,y,w,h,text,text_color,frame_color,frame_width,frame_style,redraw);
                           return this.GetWFGroupBox(obj_id);
                          }
//--- Create the Groupbox WinForm object in the specified subwindow on the current chart
   CGroupBox           *CreateWFGroupBox(const int subwindow,
                                         const string name,
                                         const int x,
                                         const int y,
                                         const int w,
                                         const int h,
                                         const string text,
                                         const color text_color=clrNONE,
                                         const color frame_color=clrNONE,
                                         const int frame_width=WRONG_VALUE,
                                         const ENUM_FRAME_STYLE frame_style=FRAME_STYLE_SIMPLE,
                                         const bool redraw=false)
                          {
                           return this.CreateWFGroupBox(::ChartID(),subwindow,name,x,y,w,h,text,text_color,frame_color,frame_width,frame_style,redraw);
                          }
//--- Create the GroupBox WinForm object in the main window of the current chart
   CGroupBox           *CreateWFGroupBox(const string name,
                                         const int x,
                                         const int y,
                                         const int w,
                                         const int h,
                                         const string text,
                                         const color text_color=clrNONE,
                                         const color frame_color=clrNONE,
                                         const int frame_width=WRONG_VALUE,
                                         const ENUM_FRAME_STYLE frame_style=FRAME_STYLE_SIMPLE,
                                         const bool redraw=false)
                          {
                           return this.CreateWFGroupBox(::ChartID(),0,name,x,y,w,h,text,text_color,frame_color,frame_width,frame_style,redraw);
                          }
   
//--- Fill in the array with IDs of the charts opened in the terminal

最初のメソッドは、メソッドに渡されたパラメータを使用して、指定されたサブウィンドウのIDで指定されたチャートにGroupBoxオブジェクトを作成します。上記のコレクションクラスからそのようなオブジェクトを作成するメソッドが呼び出され新しく作成されたオブジェクトのIDによって取得された、作成済みオブジェクトへのポインタ が返されます。他のすべてのメソッドは、現在のチャートIDとメインチャートウィンドウをパラメータ行で明示的に指定して、この(最初の)メソッドを呼び出します。

これで、新しいライブラリ オブジェクトの作成が完了しました。


検証

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

Panelオブジェクトを作成し、バインドされたオブジェクトを配置してみましょう。2 つのPanelオブジェクトにテキストラベルオブジェクトがバインドされています。これらのパネルの下にGroupBoxオブジェクトを作成して添付します。コンテナー オブジェクトからCheckBoxオブジェクトを作成してバインドする機能は提供していないので、メインパネルとは別にそのようなオブジェクトを作成してみましょう。オブジェクト パラメータを EA 設定にインストールして、それらをすばやく明確に変更し、結果を確認します。

グローバル領域で、英語版と ロシア語版のコンパイル用に2つの新しい列挙型と新しい入力を作成します。

//--- enumerations by compilation language
#ifdef COMPILE_EN
enum ENUM_AUTO_SIZE_MODE
  {
   AUTO_SIZE_MODE_GROW=CANV_ELEMENT_AUTO_SIZE_MODE_GROW,                // Grow
   AUTO_SIZE_MODE_GROW_SHRINK=CANV_ELEMENT_AUTO_SIZE_MODE_GROW_SHRINK   // Grow and Shrink
  };
enum ENUM_BORDER_STYLE
  {
   BORDER_STYLE_NONE=FRAME_STYLE_NONE,                                  // None
   BORDER_STYLE_SIMPLE=FRAME_STYLE_SIMPLE,                              // Simple
   BORDER_STYLE_FLAT=FRAME_STYLE_FLAT,                                  // Flat
   BORDER_STYLE_BEVEL=FRAME_STYLE_BEVEL,                                // Embossed (bevel)
   BORDER_STYLE_STAMP=FRAME_STYLE_STAMP,                                // Embossed (stamp)
  };
enum ENUM_CHEK_STATE
  {
   CHEK_STATE_UNCHECKED=CANV_ELEMENT_CHEK_STATE_UNCHECKED,              // Unchecked
   CHEK_STATE_CHECKED=CANV_ELEMENT_CHEK_STATE_CHECKED,                  // Checked
   CHEK_STATE_INDETERMINATE=CANV_ELEMENT_CHEK_STATE_INDETERMINATE,      // Indeterminate
  };
#else 
enum ENUM_AUTO_SIZE_MODE
  {
   AUTO_SIZE_MODE_GROW=CANV_ELEMENT_AUTO_SIZE_MODE_GROW,                // Increase only
   AUTO_SIZE_MODE_GROW_SHRINK=CANV_ELEMENT_AUTO_SIZE_MODE_GROW_SHRINK   // Increase and decrease
  };
enum ENUM_BORDER_STYLE
  {
   BORDER_STYLE_NONE=FRAME_STYLE_NONE,                                  // No frame
   BORDER_STYLE_SIMPLE=FRAME_STYLE_SIMPLE,                              // Simple frame
   BORDER_STYLE_FLAT=FRAME_STYLE_FLAT,                                  // Flat frame
   BORDER_STYLE_BEVEL=FRAME_STYLE_BEVEL,                                // Embossed (convex)
   BORDER_STYLE_STAMP=FRAME_STYLE_STAMP,                                // Embossed (concave)
  };
enum ENUM_CHEK_STATE
  {
   CHEK_STATE_UNCHECKED=CANV_ELEMENT_CHEK_STATE_UNCHECKED,              // Unchecked
   CHEK_STATE_CHECKED=CANV_ELEMENT_CHEK_STATE_CHECKED,                  // Checked
   CHEK_STATE_INDETERMINATE=CANV_ELEMENT_CHEK_STATE_INDETERMINATE,      // Undefined
  };
#endif 
//--- input parameters
sinput   bool                          InpMovable        =  true;                   // Movable forms flag
sinput   ENUM_INPUT_YES_NO             InpAutoSize       =  INPUT_YES;              // Autosize
sinput   ENUM_AUTO_SIZE_MODE           InpAutoSizeMode   =  AUTO_SIZE_MODE_GROW;    // Autosize mode
sinput   ENUM_BORDER_STYLE             InpFrameStyle     =  BORDER_STYLE_NONE;      // Label border style
sinput   ENUM_ANCHOR_POINT             InpTextAlign      =  ANCHOR_LEFT_UPPER;      // Label text align
sinput   ENUM_ANCHOR_POINT             InpCheckAlign     =  ANCHOR_LEFT_UPPER;      // Check flag align
sinput   ENUM_ANCHOR_POINT             InpCheckTextAlign =  ANCHOR_LEFT_UPPER;      // Check label text align
sinput   ENUM_CHEK_STATE               InpCheckState     =  CHEK_STATE_UNCHECKED;   // Check flag state
sinput   ENUM_INPUT_YES_NO             InpCheckAutoSize  =  INPUT_YES;              // CheckBox autosize
sinput   ENUM_BORDER_STYLE             InpCheckFrameStyle=  BORDER_STYLE_NONE;      // CheckBox border style
//--- global variables
CEngine        engine;
color          array_clr[];
//+------------------------------------------------------------------+


OnInit()ハンドラで、GroupBoxオブジェクトとCheckBoxオブジェクトを作成するためのコード ブロックを設定し、作成されたオブジェクトの数とそれらの配置座標を変更するための小さな修正を行い ます。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set EA global variables
   ArrayResize(array_clr,2);        // Array of gradient filling colors
   array_clr[0]=C'26,100,128';      // Original ≈Dark-azure color
   array_clr[1]=C'35,133,169';      // Lightened original color
//--- Create the array with the current symbol and set it to be used in the library
   string array[1]={Symbol()};
   engine.SetUsedSymbols(array);
   //--- Create the timeseries object for the current symbol and period, and show its description in the journal
   engine.SeriesCreate(Symbol(),Period());
   engine.GetTimeSeriesCollection().PrintShort(false); // Short descriptions

//--- Create WinForms Panel object
   CPanel *pnl=NULL;
   pnl=engine.CreateWFPanel("WFPanel",50,50,230,150,array_clr,200,true,true,false,-1,FRAME_STYLE_BEVEL,true,false);
   if(pnl!=NULL)
     {
      //--- Set Padding to 4
      pnl.SetPaddingAll(4);
      //--- Set the flags of relocation, auto resizing and auto changing mode from the inputs
      pnl.SetMovable(InpMovable);
      pnl.SetAutoSize(InpAutoSize,false);
      pnl.SetAutoSizeMode((ENUM_CANV_ELEMENT_AUTO_SIZE_MODE)InpAutoSizeMode,false);
      //--- In the loop, create 2 bound panel objects
      CPanel *obj=NULL;
      for(int i=0;i<2;i++)
        {
         //--- create the panel object with calculated coordinates, width of 90 and height of 40
         CPanel *prev=pnl.GetElement(i-1);
         int xb=0, yb=0;
         int x=(prev==NULL ? xb : xb+prev.Width()+20);
         int y=0;
         if(pnl.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_PANEL,pnl,x,y,90,40,C'0xCD,0xDA,0xD7',200,true,false))
           {
            obj=pnl.GetElement(i);
            if(obj==NULL)
               continue;
            obj.SetFrameWidthAll(3);
            obj.SetBorderStyle(FRAME_STYLE_BEVEL);
            obj.SetColorBackground(obj.ChangeColorLightness(obj.ColorBackground(),4*i));
            obj.SetForeColor(clrRed);
            //--- Calculate the width and height of the future text label object
            int w=obj.Width()-obj.FrameWidthLeft()-obj.FrameWidthRight()-4;
            int h=obj.Height()-obj.FrameWidthTop()-obj.FrameWidthBottom()-4;
            //--- Create a text label object
            obj.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_LABEL,obj,2,2,w,h,clrNONE,255,false,false);
            //--- Get the pointer to a newly created object
            CLabel *lbl=obj.GetElement(0);
            if(lbl!=NULL)
              {
               //--- If the object has an even or zero index in the list, set the default text color for it
               if(i % 2==0)
                  lbl.SetForeColor(CLR_DEF_FORE_COLOR);
               //--- If the object index in the list is odd, set the object opacity to 127
               else
                  lbl.SetForeColorOpacity(127);
               //--- Set the font Black width type and
               //--- specify the text alignment from the EA settings
               lbl.SetFontBoldType(FW_TYPE_BLACK);
               lbl.SetTextAlign(InpTextAlign);
               //--- For an object with an even or zero index, specify the Bid price for the text, otherwise - the Ask price of the symbol 
               lbl.SetText(GetPrice(i % 2==0 ? SYMBOL_BID : SYMBOL_ASK));
               //--- Set the frame width and type for a text label and update the modified object
               lbl.SetFrameWidthAll(1);
               lbl.SetBorderStyle((ENUM_FRAME_STYLE)InpFrameStyle);
               lbl.Update(true);
              }
           }
        }
      //--- Create the 'GroupBox' WinForms object
      CGroupBox *gbox=NULL;
      //--- GroupBox width is a width of the main panel underlay,
      //--- while the Y coordinate is an indent from attached panels by 6 pixels
      int w=pnl.GetUnderlay().Width();
      int y=obj.BottomEdgeRelative()+6;
      //--- If the attached GroupBox object is created
      if(pnl.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_GROUPBOX,pnl,0,y,w,100,C'0x91,0xAA,0xAE',0,true,false))
        {
         //--- get the pointer to the GroupBox object by its index in the list of bound objects
         gbox=pnl.GetElement(2);
         if(gbox!=NULL)
           {
            //--- set the "indented frame" type, the frame color matches the main panel background color,
            //--- while the text color is the background color of the last attached panel darkened by 1
            gbox.SetBorderStyle(FRAME_STYLE_STAMP);
            gbox.SetColorFrame(pnl.ColorBackground());
            gbox.SetForeColor(gbox.ChangeColorLightness(obj.ColorBackground(),-1));
           }
        }
      //--- Create an independent CheckBox object separately from the main panel directly on the chart
      CCheckBox *cbox=new CCheckBox(ChartID(),0,"CBox",pnl.RightEdge()+20,pnl.CoordY()+10,100,60);
      //--- If the object has been created
      if(cbox!=NULL)
        {
         //--- Add the newly created object to the list of library objects temporarily to avoid memory leaks
         ListStorage.Add(cbox);
         //--- Set object parameters from EA inputs
         cbox.SetAutoSize((bool)InpCheckAutoSize,false);
         cbox.SetCheckAlign(InpCheckAlign);
         cbox.SetTextAlign(InpCheckTextAlign);
         //--- Set the displayed text, frame style and checkbox status
         cbox.SetText("CheckBox");
         cbox.SetBorderStyle((ENUM_FRAME_STYLE)InpCheckFrameStyle);
         cbox.SetCheckState((ENUM_CANV_ELEMENT_CHEK_STATE)InpCheckState);
         //--- Redraw the object
         cbox.Redraw(true);
        }
      //--- Redraw all objects according to their hierarchy
      pnl.Redraw(true);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+


OnChartEvent()ハンドラで、オブジェクトタイプを変更して、オブジェクトタイプのキャストエラーを回避します。

   //--- If a key is pressed
   if(id==CHARTEVENT_KEYDOWN)
     {
      CPanel *panel=engine.GetWFPanel(0);
      if(panel!=NULL && (lparam==KEY_UP || lparam==KEY_DOWN || lparam==KEY_LEFT || lparam==KEY_RIGHT || lparam==KEY_FILL || lparam==KEY_ORIGIN || lparam==KEY_INDEX))
        {
         for(int i=0;i<panel.ElementsTotal();i++)
           {
            CWinFormBase *obj=panel.GetElement(i);
            if(obj!=NULL)
              {
               if(lparam==KEY_UP)
                  obj.SetDockMode(CANV_ELEMENT_DOCK_MODE_TOP,false);
               else if(lparam==KEY_DOWN)
                  obj.SetDockMode(CANV_ELEMENT_DOCK_MODE_BOTTOM,false);
               else if(lparam==KEY_LEFT)
                  obj.SetDockMode(CANV_ELEMENT_DOCK_MODE_LEFT,false);
               else if(lparam==KEY_RIGHT)
                  obj.SetDockMode(CANV_ELEMENT_DOCK_MODE_RIGHT,false);
               else if(lparam==KEY_FILL)
                  obj.SetDockMode(CANV_ELEMENT_DOCK_MODE_FILL,false);
               else if(lparam==KEY_ORIGIN)
                  obj.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false);
               else if(lparam==KEY_INDEX)
                 {
                  obj.SetDockMode((ENUM_CANV_ELEMENT_DOCK_MODE)i,true);
                  Sleep(i>0 ? 500 : 0);
                 }
              }
           }
         panel.Redraw(true);
        }

以前は、ライブラリのWinFormsオブジェクトの基本クラスではなく、CPanelオブジェクトの特定の型をここで取得していました。この型(パネル)のオブジェクトのみをテストに使用したため、エラーは発生しませんでした。

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


ご覧のとおり、CheckBoxオブジェクトコンポーネントの配置は正しく機能しており、GroupBoxオブジェクトがパネル上に作成され、それにバインドされています。

今のところ、そのようなオブジェクトはすべて静的であり、マウスと対話する機能はありません。これは、後で複数のWinFormsオブジェクトで一斉に実装します。

次の段階

次回の記事では、WinFormsオブジェクトの開発を続けます。

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

目次に戻る

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

DoEasyコントロール(第1部):最初のステップ
DoEasyコントロール(第2部):CPanelクラスでの作業
DoEasyコントロール(第3部):バインドされたコントロールの作成
DoEasyコントロール(第4部):パネルコントロール、Padding、Dockパラメータ
DoEasyコントロール(第5部):WinForms基本オブジェクト、Panelコントロール、AutoSizeパラメータ
DoEasyコントロール(第6部):パネルコントロール、内部コンテンツに合わせたコンテナサイズの自動変更
DoEasyコントロール(第7部):テキスト ラベル コントロール



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

添付されたファイル |
MQL5.zip (4364.52 KB)
ニューラルネットワークの実験(第1回):幾何学の再検討 ニューラルネットワークの実験(第1回):幾何学の再検討
この記事では、実験と非標準的なアプローチを使用して、収益性の高い取引システムを開発し、ニューラルネットワークがトレーダーに役立つかどうかを確認します。
Volumesによる取引システムの設計方法を学ぶ Volumesによる取引システムの設計方法を学ぶ
最も人気のあるテクニカル指標に基づいて取引システムを設計する方法を学ぶための連載の新しい記事です。今回は、Volumes指標について紹介します。出来高という概念は、金融市場の取引において非常に重要な要素の1つであり、注意を払う必要があります。この記事では、Volumes指標を使用した簡単な取引システムの設計方法について説明します。
機械学習や取引におけるメタモデル:取引注文のオリジナルタイミング 機械学習や取引におけるメタモデル:取引注文のオリジナルタイミング
機械学習におけるメタモデル:人間がほとんど介在しない取引システムの自動作成 - いつ、どのように取引をおこなうかはモデルが自ら決定します。
MFIによる取引システムの設計方法を学ぶ MFIによる取引システムの設計方法を学ぶ
最も人気のあるテクニカル指標に基づいて取引システムを設計する連載のこの新しい記事では、新しくマネーフローインデックス(Money Flow Index、MFI)テクニカル指標を考察します。その詳細を学び、MQL5によって簡単な取引システムを開発し、MetaTrader 5で実行します。