English Русский 中文 Español 日本語 Português
preview
DoEasy. Steuerung (Teil 7): Steuerung der Text Label

DoEasy. Steuerung (Teil 7): Steuerung der Text Label

MetaTrader 5Beispiele | 25 Juli 2022, 10:40
143 0
Artyom Trishkin
Artyom Trishkin

Inhalt


Konzept

Jedes Programm beinhaltet die Darstellung von Informationen auf dem Bildschirm. MS Visual Studio verwendet ein Text Label-Steuerelement zusätzlich zu anderen Elementen. MetaTrader 5 verfügt auch über das grafische Objekt „Text Label“. Außerdem bieten alle grafischen Elemente zur Erstellung von Programm-GUIs im Terminal auch die Möglichkeit, einen Text auf der Leinwand anzuzeigen. Dies kann jedoch manchmal unbequem sein. Daher werde ich in diesem Artikel ein unabhängiges Steuerelement „Text Label“ erstellen.

Ein solches Objekt kann seinen Container an beliebiger Stelle positionieren, während seine eigene Funktionalität die Funktionalität des MS Visual Studio-Text Label kopiert. Wir werden in der Lage sein, Schriftparameter für einen angezeigten Text festzulegen. Der Text muss innerhalb der Grenzen des Objekts „Text Label“ positioniert werden. Die Größe des Objekts wiederum kann entweder mit der angegebenen Breite und Höhe festgelegt werden oder automatisch an die verwendeten Schrift angepasst werden. Außerdem können wir den Objektrahmen (ein Rechteck, das das gesamte Objekt „Text Label“ entlang seiner Ränder einrahmt) verwenden. Der Objektrahmen kann entweder eben oder dreidimensional sein. Damit haben wir genügend Möglichkeiten, den Text im passenden Design innerhalb der Programm-GUI-Elemente darzustellen.

Damit alle neuen Objektparameter irgendwo angezeigt werden oder damit wir Objekte nach dem gewünschten Parameter auswählen können, fügen wir alle Eigenschaften, die das Objekt „Text Label“ verwendet, zu den Aufzählungen der Integer-, Real- und String-Eigenschaften der grafischen Elemente der Bibliothek hinzu. Ich versuche, dieses Konzept in allen Bibliotheksobjekten zu befolgen, da es uns erlaubt, die Möglichkeiten, die es für die schnelle Suche, Auswahl und Sortierung von Bibliotheksobjekten bietet, mit ausreichender Flexibilität zu nutzen.


Verbesserung des Bibliotheksklassen

Fügen wir zunächst neue Textnachrichten zur Bibliothek hinzu.

In \MQL5\Include\DoEasy\Data.mqh wurden neuen Nachrichtenindizes hinzugefügt:

   MSG_GRAPH_ELEMENT_TYPE_WF_PANEL,                   // Panel control
   MSG_GRAPH_ELEMENT_TYPE_WF_LABEL,                   // Label control
   MSG_GRAPH_OBJ_BELONG_PROGRAM,                      // Graphical object belongs to a program

...

//--- CPanel
   MSG_PANEL_OBJECT_ERR_FAILED_CREATE_UNDERLAY_OBJ,   // Failed to create the underlay object
   MSG_PANEL_OBJECT_ERR_OBJ_MUST_BE_WFBASE,           // Error. The created object should be of WinForms Base type or be derived from it

  };
//+------------------------------------------------------------------+

und die Textnachrichten, die den neu hinzugefügten Indizes entsprechen:

   {"Элемент управления \"Panel\"","Control element \"Panel\""},
   {"Элемент управления \"Label\"","Control element \"Label\""},
   {"Графический объект принадлежит программе","The graphic object belongs to the program"},

...

//--- CPanel
   {"Не удалось создать объект-подложку","Failed to create underlay object"},
   {"Ошибка. Создаваемый объект должен иметь тип WinForms Base или быть его наследником","Error. The object being created must be of type WinForms Base or be derived from it"},
   
  };
//+---------------------------------------------------------------------+


Zusätzlich zur Textfarbe im Steuerelement „Text Label“ werden wir auch seine Deckkraft verwenden, die es uns zum Beispiel ermöglicht, den Effekt des fließenden Auftauchens/Verschwindens von Text auf den GUI-Elementen des Programms zu erzeugen. Außerdem müssen wir den vom Text Labels-Objekt angezeigten Text sowie einige andere Parameter festlegen, die für die Erstellung von WinForms-Objekten erforderlich sind, die wir nicht zu den Eigenschaften des grafischen Elements hinzugefügt haben, obwohl sie bereits zuvor erstellt wurden.

Fügen wir in den Block der Canvas-Parameter in \MQL5\Include\DoEasy\Defines.mqh eine neue Makrosubstitution hinzu, die die Standard-Textopazität für Steuerelemente angibt:

//--- 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_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 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


Fügen wir der Liste der Bibliotheksobjekttypen einen Textetikettentyp hinzu:

//+------------------------------------------------------------------+
//| 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_PANEL,                                      // WinForms Panel object type
   OBJECT_DE_TYPE_GWF_LABEL,                                      // WinForms Label object type
//--- Animation


Fügen wir ein Element Text Label zur Liste der grafischen Elementtypen hinzu:

//+------------------------------------------------------------------+
//| 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_PANEL,                       // Windows Forms Panel
   GRAPH_ELEMENT_TYPE_WF_LABEL,                       // Windows Forms Label
  };
//+------------------------------------------------------------------+


Hinzufügen aller neuen Konstanten (sowohl derjenigen, die zuvor zu WimForms-Objekten hinzugefügt, aber nicht in die Aufzählung aufgenommen wurden, als auch der neuen) zur Liste der Integer-Eigenschaften eines grafischen Elements auf der Leinwand:

//+------------------------------------------------------------------+
//| Integer properties of the graphical element on the canvas        |
//+------------------------------------------------------------------+
enum ENUM_CANV_ELEMENT_PROP_INTEGER
  {
   //--- ...
   
   CANV_ELEMENT_PROP_FORE_COLOR,                      // Default text color for all control objects
   CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,              // Default text color opacity for all control objects
   CANV_ELEMENT_PROP_BOLD_TYPE,                       // Font width type
   CANV_ELEMENT_PROP_BORDER_STYLE,                    // Control frame style
   CANV_ELEMENT_PROP_AUTOSIZE,                        // Flag of the element auto resizing depending on the content
   CANV_ELEMENT_PROP_AUTOSIZE_MODE,                   // Mode of the element auto resizing depending on the content
   CANV_ELEMENT_PROP_AUTOSCROLL,                      // Auto scrollbar flag
   CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W,             // Width of the field inside the element during auto scrolling
   CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H,             // Height of the field inside the element during auto scrolling
   CANV_ELEMENT_PROP_DOCK_MODE,                       // Mode of binding control borders to the container
   CANV_ELEMENT_PROP_MARGIN_TOP,                      // Top margin between the fields of this and another control
   
   //--- ...

   CANV_ELEMENT_PROP_PADDING_RIGHT,                   // Right margin inside the control
   CANV_ELEMENT_PROP_TEXT_ALIGN,                      // Text position within text label boundaries
  };
#define CANV_ELEMENT_PROP_INTEGER_TOTAL (44)          // Total number of integer properties
#define CANV_ELEMENT_PROP_INTEGER_SKIP  (0)           // Number of integer properties not used in sorting
//+------------------------------------------------------------------+

Erhöhen wir die Gesamtzahl der ganzzahligen Eigenschaften von 38 auf 44.


Fügen wir in der Liste der Zeichenketteneigenschaften des Canvas-basierten grafischen Elements eine neue Eigenschaft hinzu - „Grafischer Elementtext“ - und erhöhen die Gesamtzahl der Zeichenketteneigenschaften von 2 auf 3:

//+------------------------------------------------------------------+
//| String properties of the graphical element on the canvas         |
//+------------------------------------------------------------------+
enum ENUM_CANV_ELEMENT_PROP_STRING
  {
   CANV_ELEMENT_PROP_NAME_OBJ = (CANV_ELEMENT_PROP_INTEGER_TOTAL+CANV_ELEMENT_PROP_DOUBLE_TOTAL), // Graphical element object name
   CANV_ELEMENT_PROP_NAME_RES,                        // Graphical resource name
   CANV_ELEMENT_PROP_TEXT,                            // Graphical element text
  };
#define CANV_ELEMENT_PROP_STRING_TOTAL  (3)           // Total number of string properties
//+------------------------------------------------------------------+


Wir sortieren nach neuer Eigenschaft zur Enumeration möglicher Kriterien zum Sortieren von grafischen Elementen auf der Leinwand hinzufügen:

//+------------------------------------------------------------------+
//| 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_FORE_COLOR,                   // Sort by default text color for all control objects
   SORT_BY_CANV_ELEMENT_FORE_COLOR_OPACITY,           // Sort by default text color opacity for all control objects
   SORT_BY_CANV_ELEMENT_BOLD_TYPE,                    // Sort by font width type
   SORT_BY_CANV_ELEMENT_BORDER_STYLE,                 // Sort by control frame style
   SORT_BY_CANV_ELEMENT_AUTOSIZE,                     // Sort by the flag of the control auto resizing depending on the content
   SORT_BY_CANV_ELEMENT_AUTOSIZE_MODE,                // Sort by the mode of the control auto resizing depending on the content
   SORT_BY_CANV_ELEMENT_AUTOSCROLL,                   // Sort by auto scrollbar flag
   SORT_BY_CANV_ELEMENT_AUTOSCROLL_MARGIN_W,          // Sort by width of the field inside the element during auto scrolling
   SORT_BY_CANV_ELEMENT_AUTOSCROLL_MARGIN_H,          // Sort by height of the field inside the element during auto scrolling
   SORT_BY_CANV_ELEMENT_DOCK_MODE,                    // Sort by mode of binding control borders to the container
   
   //--- ...

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

Jetzt können wir alle grafischen Elemente nach neuen Eigenschaften auswählen und sortieren.


Die Klasse CWinFormBase dient als Basisklasse für alle WinForms-Objekte der Bibliothek. Die Klasse wiederum ist von dem Formularobjekt abgeleitet, das die Mausinteraktion aufweist. Wir werden einige seiner privaten Variablen in den geerbten Klassen benötigen. Da private Variablen und Methoden nur in der Klasse sichtbar sind, in der sie deklariert wurden, müssen wir sie aus dem privaten Bereich in den geschützten Bereich verschieben, damit sie in geerbten Klassen verfügbar sind.

Verschieben wir in der Formularobjektdatei \MQL5\Include\DoEasy\Objects\Graph\Form.mqh die Variablen aus dem privaten Abschnitt

//+------------------------------------------------------------------+
//| Form object class                                                |
//+------------------------------------------------------------------+
class CForm : public CGCnvElement
  {
private:
   CArrayObj         m_list_elements;                          // List of attached elements
   CAnimations      *m_animations;                             // Pointer to the animation object
   CShadowObj       *m_shadow_obj;                             // Pointer to the shadow object
   CMouseState       m_mouse;                                  // "Mouse status" class object
   ENUM_MOUSE_FORM_STATE m_mouse_form_state;                   // Mouse status relative to the form
   ushort            m_mouse_state_flags;                      // Mouse status flags
   color             m_color_frame;                            // Form frame color
   int               m_offset_x;                               // Offset of the X coordinate relative to the cursor
   int               m_offset_y;                               // Offset of the Y coordinate relative to the cursor
   int               m_init_x;                                 // Newly created form X coordinate
   int               m_init_y;                                 // Newly created form Y coordinate
   int               m_init_w;                                 // Newly created form width
   int               m_init_h;                                 // Newly created form height

//--- Reset the array size of (1) text, (2) rectangular and (3) geometric animation frames

in den geschützten Bereich und machen einige Methoden virtuell, damit wir sie in den geerbten Klassen neu definieren können:

protected:
   CArrayObj         m_list_elements;                          // List of attached elements
   CAnimations      *m_animations;                             // Pointer to the animation object
   CShadowObj       *m_shadow_obj;                             // Pointer to the shadow object
   CMouseState       m_mouse;                                  // "Mouse status" class object
   ENUM_MOUSE_FORM_STATE m_mouse_form_state;                   // Mouse status relative to the form
   ushort            m_mouse_state_flags;                      // Mouse status flags
   color             m_color_frame;                            // Form frame color
   int               m_offset_x;                               // Offset of the X coordinate relative to the cursor
   int               m_offset_y;                               // Offset of the Y coordinate relative to the cursor
   CArrayObj         m_list_tmp;                               // List for storing the pointers
   int               m_frame_width_left;                       // Form frame width to the left
   int               m_frame_width_right;                      // Form frame width to the right
   int               m_frame_width_top;                        // Form frame width at the top
   int               m_frame_width_bottom;                     // Form frame width at the bottom
   int               m_init_x;                                 // Newly created form X coordinate
   int               m_init_y;                                 // Newly created form Y coordinate
   int               m_init_w;                                 // Newly created form width
   int               m_init_h;                                 // Newly created form height
//--- Initialize the variables
   virtual void      Initialize(void);
   void              Deinitialize(void);
//--- Create a shadow object
   void              CreateShadowObj(const color colour,const uchar opacity);
//--- Return the name of the dependent object
   string            CreateNameDependentObject(const string base_name)  const
                       { return ::StringSubstr(this.NameObj(),::StringLen(::MQLInfoString(MQL_PROGRAM_NAME))+1)+"_"+base_name;   }
//--- Update coordinates of bound objects
   virtual bool      MoveDependentObj(const int x,const int y,const bool redraw=false);
//--- Create a new bound element and add it to the list of bound objects
   virtual CGCnvElement *CreateAndAddNewElement(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);
   
public:


Da wir nun das allgemeine Konzept der Konstruktion von Bibliotheksobjekten für WinForms-Objekte verwenden und WinForms-Objektparameter zu den Eigenschaften grafischer Elemente hinzufügen werden, müssen wir die Variablen der Basisklasse CWinFormBase zum Speichern von Objekteigenschaften entfernen und alle Methoden zum Setzen und Abrufen dieser Eigenschaften neu schreiben.

Entfernen wir in \MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqh die bereits unnötigen Variablen aus dem geschützten Abschnitt.

//+------------------------------------------------------------------+
//| Form object class                                                |
//+------------------------------------------------------------------+
class CWinFormBase : public CForm
  {
protected:
   color             m_fore_color;                                   // Default text color for all control objects
   ENUM_FW_TYPE      m_bold_type;                                    // Font width type
   ENUM_FRAME_STYLE  m_border_style;                                 // Control frame style
   bool              m_autosize;                                     // Flag of the element auto resizing depending on the content
   ENUM_CANV_ELEMENT_DOCK_MODE m_dock_mode;                          // Mode of binding control borders to the container
   int               m_margin[4];                                    // Array of gaps of all sides between the fields of the current and adjacent controls
   int               m_padding[4];                                   // Array of gaps of all sides inside controls

private:


Schreiben wir im öffentlichen Teil der Klasse die Methoden zum Empfangen und Setzen der Eigenschaften der Objekteigenschaftsaufzählungen um und fügen neue Methoden sowohl für die Behandlung des Textobjektes „Text Label“ als auch für das Setzen und Erhalten allgemeiner Eigenschaften von WinForms-Objekten hinzu:

public:
//--- ...
   
//--- ...

//--- Constructors
                     CWinFormBase(const long chart_id,
                                  const int subwindow,
                                  const string name,
                                  const int x,
                                  const int y,
                                  const int w,
                                  const int h);
                     CWinFormBase(const string name) : CForm(::ChartID(),0,name,0,0,0,0)
                       {
                        this.m_type=OBJECT_DE_TYPE_GWF_BASE; 
                       }
                       
//--- (1) Set and (2) return the default text color of all panel objects
   void              SetForeColor(const color clr)                   { this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,clr);                               }
   color             ForeColor(void)                           const { return (color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR);                     }
//--- (1) Set and (2) return the default text color opacity of all panel objects
   void              SetForeColorOpacity(const uchar value)          { this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,value);                     }
   uchar             ForeColorOpacity(void)                    const { return (uchar)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY);             }
//--- (1) Set and (2) return the element text
   virtual void      SetText(const string text)                      { this.SetProperty(CANV_ELEMENT_PROP_TEXT,text);                                    }
   string            Text(void)                                const { return this.GetProperty(CANV_ELEMENT_PROP_TEXT);                                  }
//--- (1) Set and (2) return the element text location angle (alignment type)
   void              SetTextAlign(const ENUM_ANCHOR_POINT anchor)    { this.SetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN,anchor);                            }
   ENUM_ANCHOR_POINT TextAlign(void)                           const { return (ENUM_ANCHOR_POINT)this.GetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN);         }
//--- (1) Set and (2) return the Bold font flag
   void              SetBold(const bool flag);
   bool              Bold(void);
//--- (1) Set and (2) return the Italic font flag
   void              SetItalic(const bool flag);
   bool              Italic(void);
//--- (1) Set and (2) return the Strikeout font flag
   void              SetStrikeout(const bool flag);
   bool              Strikeout(void);
//--- (1) Set and (2) return the Underline font flag
   void              SetUnderline(const bool flag);
   bool              Underline(void);
//--- (1) Set and (2) return the font style
   void              SetFontDrawStyle(ENUM_FONT_STYLE style);
   ENUM_FONT_STYLE   FontDrawStyle(void);
//--- (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
   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);        }

//--- (1) Set and (2) return the flag of the element auto resizing depending on the content
   virtual void      SetAutoSize(const bool flag,const bool redraw)  { this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE,flag);                                }
   bool              AutoSize(void)                                  { return (bool)this.GetProperty(CANV_ELEMENT_PROP_AUTOSIZE);                        }
//--- (1) Set and (2) return the auto scrollbar flag
   virtual void      SetAutoScroll(const bool flag,const bool redraw){ this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL,flag);                              }
   bool              AutoScroll(void)                                { return (bool)this.GetProperty(CANV_ELEMENT_PROP_AUTOSCROLL);                      }
   
//--- (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)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_DOCK_MODE,mode);
                       }
   ENUM_CANV_ELEMENT_DOCK_MODE DockMode(void)                  const { return (ENUM_CANV_ELEMENT_DOCK_MODE)this.GetProperty(CANV_ELEMENT_PROP_DOCK_MODE);}
   
//--- Set the gap (1) to the left, (2) at the top, (3) to the right, (4) at the bottom and (5) on all sides between the fields of this and another control
   void              SetMarginLeft(const int value)                  { this.SetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT,value);                            }
   void              SetMarginTop(const int value)                   { this.SetProperty(CANV_ELEMENT_PROP_MARGIN_TOP,value);                             }
   void              SetMarginRight(const int value)                 { this.SetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT,value);                           }
   void              SetMarginBottom(const int value)                { this.SetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM,value);                          }
   void              SetMarginAll(const int value)
                       {
                        this.SetMarginLeft(value); this.SetMarginTop(value); this.SetMarginRight(value); this.SetMarginBottom(value);
                       }
   void              SetMargin(const int left,const int top,const int right,const int bottom)
                       {
                        this.SetMarginLeft(left); this.SetMarginTop(top); this.SetMarginRight(right); this.SetMarginBottom(bottom);
                       }
//--- Return the gap (1) to the left, (2) at the top, (3) to the right and (4) at the bottom between the fields of this and another control
   int               MarginLeft(void)                          const { return (int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT);                      }
   int               MarginTop(void)                           const { return (int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_TOP);                       }
   int               MarginRight(void)                         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT);                     }
   int               MarginBottom(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM);                    }

//--- Set the gap (1) to the left, (2) at the top, (3) to the right, (4) at the bottom and (5) on all sides inside the control
   virtual void      SetPaddingLeft(const uint value)
                       {
                        int padding=((int)value<this.m_frame_width_left ? this.m_frame_width_left : (int)value);
                        this.SetProperty(CANV_ELEMENT_PROP_PADDING_LEFT,padding);
                       }
   virtual void      SetPaddingTop(const uint value)
                       {
                        int padding=((int)value<this.m_frame_width_top ? this.m_frame_width_top : (int)value);
                        this.SetProperty(CANV_ELEMENT_PROP_PADDING_TOP,padding);
                       }
   virtual void      SetPaddingRight(const uint value)
                       {
                        int padding=((int)value<this.m_frame_width_right ? this.m_frame_width_right : (int)value);
                        this.SetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT,padding);
                       }
   virtual void      SetPaddingBottom(const uint value)
                       {
                        int padding=((int)value<this.m_frame_width_bottom ? this.m_frame_width_bottom : (int)value);
                        this.SetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM,padding);
                       }
   virtual void      SetPaddingAll(const uint value)
                       {
                        this.SetPaddingLeft(value); this.SetPaddingTop(value); this.SetPaddingRight(value); this.SetPaddingBottom(value);
                       }
   virtual void      SetPadding(const int left,const int top,const int right,const int bottom)
                       {
                        this.SetPaddingLeft(left); this.SetPaddingTop(top); this.SetPaddingRight(right); this.SetPaddingBottom(bottom);
                       }
   
//--- Set the width of the element frame (1) to the left, (2) at the top, (3) to the right and (4) at the bottom
   virtual void      SetFrameWidthLeft(const uint value)             { this.m_frame_width_left=(int)value;                                               }
   virtual void      SetFrameWidthTop(const uint value)              { this.m_frame_width_top=(int)value;                                                }
   virtual void      SetFrameWidthRight(const uint value)            { this.m_frame_width_right=(int)value;                                              }
   virtual void      SetFrameWidthBottom(const uint value)           { this.m_frame_width_bottom=(int)value;                                             }
   virtual void      SetFrameWidthAll(const uint value)
                       {
                        this.SetFrameWidthLeft(value); this.SetFrameWidthTop(value); this.SetFrameWidthRight(value); this.SetFrameWidthBottom(value);
                       }
   virtual void      SetFrameWidth(const uint left,const uint top,const uint right,const uint bottom)
                       {
                        this.SetFrameWidthLeft(left); this.SetFrameWidthTop(top); this.SetFrameWidthRight(right); this.SetFrameWidthBottom(bottom);
                       }
   
//--- Return the width of the element frame (1) to the left, (2) at the top, (3) to the right and (4) at the bottom
   int               FrameWidthLeft(void)                      const { return this.m_frame_width_left;                                                   }
   int               FrameWidthTop(void)                       const { return this.m_frame_width_top;                                                    }
   int               FrameWidthRight(void)                     const { return this.m_frame_width_right;                                                  }
   int               FrameWidthBottom(void)                    const { return this.m_frame_width_bottom;                                                 }
   
//--- Return the gap (1) to the left, (2) at the top, (3) to the right and (4) at the bottom between the fields inside the control
   int               PaddingLeft(void)                         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_LEFT);                     }
   int               PaddingTop(void)                          const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_TOP);                      }
   int               PaddingRight(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT);                    }
   int               PaddingBottom(void)                       const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM);                   }
   
  };
//+------------------------------------------------------------------+

In allen überarbeiteten Methoden schreiben wir nun Werte und erhalten sie nicht in Variablen, sondern in Enumerationen von Objekteigenschaften mit Hilfe der Methoden SetProperty() und GetProperty(), wie es ursprünglich im Konzept des Aufbaus von Bibliotheksobjekten im ersten Artikel beschrieben wurde.

Legen wir im Klassenkonstruktor den Text für das erstellte Objekt als „leere Zeichenkette“ fest und setzen die in Defines.mqh festgelegten Standardwerte für die Textfarbe und ihre Deckkraft:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CWinFormBase::CWinFormBase(const long chart_id,
                           const int subwindow,
                           const string name,
                           const int x,
                           const int y,
                           const int w,
                           const int h) : CForm(chart_id,subwindow,name,x,y,w,h)
  {
//--- Set the graphical element and library object types as a base WinForms object
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_BASE);
   CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_BASE);
   this.m_type=OBJECT_DE_TYPE_GWF_BASE; 
//--- Initialize all variables
   this.SetText("");
   this.SetForeColor(CLR_DEF_FORE_COLOR);
   this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY);
   this.SetFontBoldType(FW_TYPE_NORMAL);
   this.SetMarginAll(0);
   this.SetPaddingAll(0);
   this.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false);
   this.SetBorderStyle(FRAME_STYLE_NONE);
   this.SetAutoSize(false,false);
   CForm::SetCoordXInit(x);
   CForm::SetCoordYInit(y);
   CForm::SetWidthInit(w);
   CForm::SetHeightInit(h);
   this.m_shadow=false;
   this.m_frame_width_right=0;
   this.m_frame_width_left=0;
   this.m_frame_width_top=0;
   this.m_frame_width_bottom=0;
   this.m_gradient_v=true;
   this.m_gradient_c=false;
  }
//+------------------------------------------------------------------+


In den Methoden, die das Kennzeichen für die Schriftart Bold und die Schriftbreite setzen, weisen wir die Werte den Objekteigenschaften zu, anstatt den Variablen:

//+------------------------------------------------------------------+
//| Set the Bold font flag                                           |
//+------------------------------------------------------------------+
void CWinFormBase::SetBold(const bool flag)
  {
   uint flags=this.GetFontFlags();
   if(flag)
     {
      this.SetFontBoldType(FW_TYPE_BOLD);
      CGCnvElement::SetFontFlags(flags | FW_BOLD);
     }
   else
      this.SetFontBoldType(FW_TYPE_NORMAL);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Set the font width type                                          |
//+------------------------------------------------------------------+
void CWinFormBase::SetFontBoldType(ENUM_FW_TYPE type)
  {
   this.SetProperty(CANV_ELEMENT_PROP_BOLD_TYPE,type);
   uint flags=this.GetFontFlags();
   switch(type)
     {
      case FW_TYPE_DONTCARE   : CGCnvElement::SetFontFlags(flags | FW_DONTCARE);    break;
      case FW_TYPE_THIN       : CGCnvElement::SetFontFlags(flags | FW_THIN);        break;
      case FW_TYPE_EXTRALIGHT : CGCnvElement::SetFontFlags(flags | FW_EXTRALIGHT);  break;
      case FW_TYPE_ULTRALIGHT : CGCnvElement::SetFontFlags(flags | FW_ULTRALIGHT);  break;
      case FW_TYPE_LIGHT      : CGCnvElement::SetFontFlags(flags | FW_LIGHT);       break;
      case FW_TYPE_REGULAR    : CGCnvElement::SetFontFlags(flags | FW_REGULAR);     break;
      case FW_TYPE_MEDIUM     : CGCnvElement::SetFontFlags(flags | FW_MEDIUM);      break;
      case FW_TYPE_SEMIBOLD   : CGCnvElement::SetFontFlags(flags | FW_SEMIBOLD);    break;
      case FW_TYPE_DEMIBOLD   : CGCnvElement::SetFontFlags(flags | FW_DEMIBOLD);    break;
      case FW_TYPE_BOLD       : CGCnvElement::SetFontFlags(flags | FW_BOLD);        break;
      case FW_TYPE_EXTRABOLD  : CGCnvElement::SetFontFlags(flags | FW_EXTRABOLD);   break;
      case FW_TYPE_ULTRABOLD  : CGCnvElement::SetFontFlags(flags | FW_ULTRABOLD);   break;
      case FW_TYPE_HEAVY      : CGCnvElement::SetFontFlags(flags | FW_HEAVY);       break;
      case FW_TYPE_BLACK      : CGCnvElement::SetFontFlags(flags | FW_BLACK);       break;
      default                 : CGCnvElement::SetFontFlags(flags | FW_NORMAL);      break;
     }
  }
//+------------------------------------------------------------------+


Steuerklasse „Text Label“

Wir erstellen in \MQL5\Include\DoEasy\Objects\Graph\WForms\CommonControls\ eine neue Datei Label.mqh mit der Klasse CLabel. Die Klasse CWinFormBase sollte eine Basisklasse sein. deren Datei in die Datei der neu erstellten Klasse eingebunden werden soll:

//+------------------------------------------------------------------+
//|                                                        Label.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"
//+------------------------------------------------------------------+
//| Label object class of WForms controls                            |
//+------------------------------------------------------------------+
class CLabel : public CWinFormBase
  {
  }

Fügen wir in den Abschnitten private, protected und public der Klasse die Deklarationen der Methoden der Klasse hinzu:

//+------------------------------------------------------------------+
//| Label object class of WForms controls                            |
//+------------------------------------------------------------------+
class CLabel : public CWinFormBase
  {
private:
//--- Set the element width and height automatically
   void              AutoSetWH(void);
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);
//--- Redraw the object
   virtual void      Redraw(bool redraw);
//--- Set the element text
   virtual void      SetText(const string text)
                       {
                        CWinFormBase::SetText(text);
                        if(this.AutoSize())
                           this.AutoSetWH();
                       }

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

Wie man sehen kann, habe ich die virtuellen Methoden der Basisklasse CWinFormBase in den Abschnitten protected und public deklariert. Diese Methoden sollten eine etwas andere Logik haben als die der Basismethode. Deshalb sollen sie in dieser Klasse neu definiert werden.

So wird z. B. in der Methode zum Setzen des Elementtextes zunächst die Methode der Basisklasse aufgerufen. Ein neuer Wert, der an die Methode übergeben wird, wird auf die Objekteigenschaft gesetzt. Wenn das Flag für die automatische Größenänderung des Objekts gesetzt ist, wird die private Methode zum Setzen einer neuen Größe aufgerufen. Die Größe soll der Größe des Textes entsprechen, der auf der unten betrachteten Objektleinwand angezeigt wird:

//--- Set the element text
   virtual void      SetText(const string text)
                       {
                        CWinFormBase::SetText(text);
                        if(this.AutoSize())
                           this.AutoSetWH();
                       }


Die Klasse hat einen parametrischen Konstruktor, während der Standardkonstruktor und -destruktor automatisch erstellt werden.

Die Chart-ID und das Unterfenster, in dem das Objekt konstruiert wird, sowie der Objektname, seine Koordinaten und seine Größe werden an den parametrischen Konstruktor übergeben:

//+------------------------------------------------------------------+
//| 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) : CWinFormBase(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_LABEL;
   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);
  }
//+------------------------------------------------------------------+

Zunächst wird der Typ des grafischen Elements in allen übergeordneten Klassen und der Objekttyp der WinForms Label-Bibliothek für das Objekt festgelegt.
Als Nächstes legen wir Objekt und Koordinaten fest und rufen die virtuelle Methode zum Einstellen der Hauptparameter des grafischen Bibliothekselements auf. Die Methode wird in der Klasse neu definiert, da sie sich geringfügig von der gleichen Methode des Basisobjekts unterscheidet. Wir werden sie weiter unten besprechen.
Wenn das Flag für die automatische Größenanpassung des Objekts so gesetzt ist, dass sie sich dem Text anpasst, rufen wir die entsprechende Methode zur Größenanpassung des Objekts auf (das Flag ist hier vorerst immer deaktiviert, aber das kann später geändert werden).
Nach der Größenänderung (bei gesetztem Flag) werden die Anfangsgröße des Objekts und seine Anfangskoordinaten festgelegt.
Zeichnen wir am Ende das gesamte Objekt neu.

Die virtuelle Methode zur Initialisierung der Variablen:

//+------------------------------------------------------------------+
//| Initialize the variables                                         |
//+------------------------------------------------------------------+
void CLabel::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();
//--- Text label 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.SetMargin(3,0,3,0);
   this.SetPaddingAll(0);
   this.SetEnabled(true);
   this.SetVisible(true,false);
  }
//+------------------------------------------------------------------+

Die virtuelle Methode definiert die Methode des Basisobjekts neu — andere Standardwerte werden hier festgelegt. Außerdem gibt es eine Initialisierung von Eigenschaftswerten, die nur für das Label-Objekt gelten.


Die virtuellen Löschmethoden, die die Basisobjektmethoden neu definieren, zeichnen den Objektrahmen mit voller Deckkraft:

//+------------------------------------------------------------------+
//| Clear the element filling it with color and opacity              |
//+------------------------------------------------------------------+
void CLabel::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 CLabel::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 CLabel::Erase(const bool redraw=false)
  {
//--- Fully clear the element with the redrawing flag
   CGCnvElement::Erase(redraw);
  }
//+------------------------------------------------------------------+


Die virtuelle Methode, die das Objekt neu zeichnet:

//+------------------------------------------------------------------+
//| Redraw the object                                                |
//+------------------------------------------------------------------+
void CLabel::Redraw(bool redraw)
  {
//--- Fill the object with the background color having full transparency
   this.Erase(this.ColorBackground(),0,true);
   int x=0;
   int y=0;
//--- 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 coordinate
        x=this.FrameWidthLeft();
        y=this.FrameWidthTop();
        //--- Set the text binding point at the top left
        this.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP);
        break;
      //--- The text is drawn vertically from the left side of the object in the center
      case ANCHOR_LEFT : 
        //--- Set the text binding point coordinate
        x=this.FrameWidthLeft();
        y=this.Height()/2;
        //--- Set the text binding point at the center left
        this.SetTextAnchor(FRAME_ANCHOR_LEFT_CENTER);
        break;
      //--- The text is displayed in the lower left corner of the object
      case ANCHOR_LEFT_LOWER : 
        //--- Set the text binding point coordinate
        x=this.FrameWidthLeft();
        y=this.Height()-this.FrameWidthBottom();
        //--- Set the text binding point at the bottom left
        this.SetTextAnchor(FRAME_ANCHOR_LEFT_BOTTOM);
        break;
      //--- The text is drawn at the center of the bottom edge of the object
      case ANCHOR_LOWER : 
        //--- Set the text binding point coordinate
        x=this.Width()/2;
        y=this.Height()-this.FrameWidthBottom();
        //--- Set the text anchor point at the bottom center
        this.SetTextAnchor(FRAME_ANCHOR_CENTER_BOTTOM);
        break;
      //--- The text is displayed in the lower right corner of the object
      case ANCHOR_RIGHT_LOWER : 
        //--- Set the text binding point coordinate
        x=this.Width()-this.FrameWidthRight();
        y=this.Height()-this.FrameWidthBottom();
        //--- Set the text binding point at the bottom right
        this.SetTextAnchor(FRAME_ANCHOR_RIGHT_BOTTOM);
        break;
      //--- The text is drawn vertically from the right side of the object in the center
      case ANCHOR_RIGHT : 
        //--- Set the text binding point coordinate
        x=this.Width()-this.FrameWidthRight();
        y=this.Height()/2;
        //--- Set the text binding point at the center right
        this.SetTextAnchor(FRAME_ANCHOR_RIGHT_CENTER);
        break;
      //--- The text is displayed in the upper right corner of the object
      case ANCHOR_RIGHT_UPPER : 
        //--- Set the text binding point coordinate
        x=this.Width()-this.FrameWidthRight();
        y=this.FrameWidthTop();
        //--- Set the text binding point at the top right
        this.SetTextAnchor(FRAME_ANCHOR_RIGHT_TOP);
        break;
      //--- The text is drawn at the center of the upper edge of the object
      case ANCHOR_UPPER : 
        //--- Set the text binding point coordinate
        x=this.Width()/2;
        y=this.FrameWidthTop();
        //--- Set the text binding point at the center top
        this.SetTextAnchor(FRAME_ANCHOR_CENTER_TOP);
        break;
      //--- The text is drawn at the object center
      //---ANCHOR_CENTER
      default:
        //--- Set the text binding point coordinate
        x=this.Width()/2;
        y=this.Height()/2;
        //--- Set the text binding point at the center
        this.SetTextAnchor(FRAME_ANCHOR_CENTER);
        break;
     }
//--- Draw the text within the set coordinates of the object and the binding point of the text, and update the object 
   this.Text(x,y,this.Text(),this.ForeColor(),this.ForeColorOpacity(),this.TextAnchor());
   this.Update(redraw);
  }
//+------------------------------------------------------------------+

Die Methode redefiniert die Methode der Basisklasse. Hier wird zunächst der Objekthintergrund entfernt (mit einer vollständig transparenten Hintergrundfarbe gefüllt). Der Textbindungspunkt wird als Nächstes in Abhängigkeit vom Text innerhalb des Elements definiert. Die Koordinaten des Textbindungspunkts (Ursprung der Beschriftungskoordinaten) werden berechnet, der Text wird innerhalb der berechneten Koordinaten angezeigt und das Objekt wird aktualisiert.

Textbindungspunkte werden visuell markiert und in der Hilfe zur Funktion TextOut() erläutert:



Die Methode legt automatisch die Breite und Höhe des Elements fest:

//+------------------------------------------------------------------+
//| Set the element width and height automatically                   |
//+------------------------------------------------------------------+
void CLabel::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
   w+=(this.MarginLeft()+this.MarginRight());
//--- If failed to get the width, set it to three pixels
   if(w==0)
      w=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);
//--- Set the object width and height from the received values
   this.SetWidth(w);
   this.SetHeight(h);
  }
//+------------------------------------------------------------------+

Die Methodenlogik wird in den Codekommentaren beschrieben. Zunächst wird die Textgröße in Abhängigkeit von den für das Objekt eingestellten Text- und Schriftparametern ermittelt. Wenn die Bezeichnung „leer“ ist, wird ein Leerzeichen („ “) für die Messung verwendet. Als Nächstes addieren wir die Werte für die Objektränder links und rechts zur resultierenden Breite sowie die Werte für die Ränder oben und unten zum Höhenwert. Wenn die Texthöhe nicht ermittelt werden konnte, berechnen wir die ungefähre Größe, indem wir die für das Objekt eingestellte Schriftgröße mit einem Verhältnis multiplizieren, das ich empirisch ausgewählt habe. Ich habe die Werte für die Objektgröße in Abhängigkeit von der Schriftgröße in MS Visual Studio verglichen und den Durchschnittswert aus mehreren Messungen unterschiedlicher Größe genommen, um das Verhältnis von 1,625 zu erhalten. Mir ist keine andere, genauere Methode bekannt. Vielleicht finde ich später eine bessere Möglichkeit, die Objektgröße in Abhängigkeit von der Schriftgröße zu berechnen. Nachdem alle Berechnungen durchgeführt wurden, werden die ermittelten Werte für Breite und Höhe für das Objekt festgelegt.

Damit ist die Erstellung des Objekts „Text Label“ abgeschlossen.

Da das WinForms Panel-Objekt ein Container für die Bindung anderer gleichartiger Objekte ist, sollten alle erstellten Objekte desselben Typs für es sichtbar sein. Um dies zu erreichen, muss die Datei jedes erstellten WinForms-Objekts in die Panel-Objektdatei aufgenommen werden.

Öffnen wir die Objektdatei des Paneels \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Panel.mqh und binden die Datei eines neu erstellten Objects der Text Label darin ein:

//+------------------------------------------------------------------+
//|                                                        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 "..\..\WForms\WinFormBase.mqh"
#include "..\..\WForms\Common Controls\Label.mqh"
//+------------------------------------------------------------------+


Wir entfernen die unnötige Variablen aus dem privaten Abschnitt der Klasse, da sie jetzt in den grundlegenden WinForms-Objekteigenschaften festgelegt sind:

//+------------------------------------------------------------------+
//| Panel object class of WForms controls                            |
//+------------------------------------------------------------------+
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
   bool              m_autoscroll;                                   // Auto scrollbar flag
   int               m_autoscroll_margin[2];                         // Array of fields around the control during an auto scroll
   ENUM_CANV_ELEMENT_AUTO_SIZE_MODE m_autosize_mode;                 // Mode of the element auto resizing depending on the content
//--- Create a new graphical object


Im öffentlichen Abschnitt der Klasse deklarieren wir zwei neue Methoden, um die Liste der gebundenen WinForms-Objekte eines bestimmten Typs zu erhalten und um den Zeiger auf das angegebene WinForms-Objekt per Index in der Objektliste dieses Typs zu erhalten:

public:
//--- Return the underlay
   CGCnvElement     *GetUnderlay(void)                               { return this.m_underlay;              }
//--- Return the list of bound objects with (1) any and (2) specified basic WinForms type 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);
   
//--- Update the coordinates (shift the canvas)


Wir entfernen die Methoden SetAutoScroll() und AutoScroll() aus der Klasse, da sie Mitglieder der übergeordneten Klasse CWinFormBase sind und für die Handhabung von Objekteigenschaften und nicht von Klassenvariablen angepasst sind:

//--- Place bound objects in the order of their Dock binding
   bool              ArrangeObjects(const bool redraw);
   
//--- (1) Set and (2) return the auto scrollbar flag
   void              SetAutoScroll(const bool flag)                  { this.m_autoscroll=flag;              }
   bool              AutoScroll(void)                                { return this.m_autoscroll;            }
//--- Set the (1) field width, (2) height, (3) the height of all fields around the control during auto scrolling


Schreiben wir die Methoden der Klasse zur Behandlung von Objekteigenschaften in ähnlicher Weise um und fügen die Methode zur gleichzeitigen Einstellung von AutoScrollMargin nach Breite und Höhe hinzu:

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


In der Methode zur Erstellung eines neuen grafischen Objekts fügen wir den Codeblock zur Erstellung eines Text Label-Objekts hinzu:

//+------------------------------------------------------------------+
//| 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_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;
      default:
        break;
     }
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",name);
   return element;
  }
//+------------------------------------------------------------------+

Hier ist alles klar, und es sind keine Kommentare erforderlich.


Schreiben wir auch die Methode zur Erstellung eines neu gebundenen Elements neu:

//+------------------------------------------------------------------+
//| Create a new attached element                                    |
//+------------------------------------------------------------------+
bool CPanel::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 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 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 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;
  }
//+------------------------------------------------------------------+

Die Methodenlogik wird in den Codekommentaren beschrieben. Abgesehen von kleinen logischen Verbesserungen der Methode selbst, haben wir den Codeblock hinzugefügt, der die Erstellung des Objekts für Text Label behandelt. Ich hoffe, dass hier alles klar ist und keiner Erklärung bedarf. Wenn Sie Fragen haben, können Sie diese gerne im Kommentarteil stellen.


Die Methode gibt die Liste der angehängten Objekte mit dem in WinForms angegebenen Objekttyp zurück:

//+------------------------------------------------------------------+
//| Return the list of bound objects                                 |
//| with the specified WinForms object type                          |
//+------------------------------------------------------------------+
CArrayObj *CPanel::GetListWinFormsObjByType(const ENUM_GRAPH_ELEMENT_TYPE type)
  {
   return CSelect::ByGraphCanvElementProperty(this.GetListElements(),CANV_ELEMENT_PROP_TYPE,type,EQUAL);
  }
//+------------------------------------------------------------------+

Hier geben wir einfach die in der CSelect-Klasse erhaltene Liste mit dem angegebenen WinForms-Objekttyp zurück. Wenn es nicht gelingt, die Liste zu erhalten oder keine Objekte des angegebenen Typs vorhanden sind, gibt die Methode NULL zurück.


Die Methode liefert den Zeiger auf das gebundene WinForms-Objekt mit dem angegebenen Typ per Index:

//+------------------------------------------------------------------+
//| Return the pointer to the specified WinForms object              |
//| with the specified type by index                                 |
//+------------------------------------------------------------------+
CWinFormBase *CPanel::GetWinFormsObj(const ENUM_GRAPH_ELEMENT_TYPE type,const int index)
  {
   CArrayObj *list=this.GetListWinFormsObjByType(type);
   return(list!=NULL ? list.At(index) : NULL);
  }
//+------------------------------------------------------------------+

Hier erhalten wir die Liste der Objekte mit dem angegebenen Typ und geben den Zeiger auf das Objekt aus der Liste mit dem angegebenen Index zurück.
Wenn die Liste nicht erhalten werden kann oder ein nicht vorhandener Index angegeben wird, gibt die Methode NULL zurück.

Alles ist bereit für einen Test.


Test

Um den Test durchzuführen, verwenden wir den EA aus dem vorherigen Artikel und speichern ihn in \MQL5\Experts\TestDoEasy\Part107\ als TstDE107.mq5.

Da die Namen aller grafischen Objekte den Programmnamen enthalten, während die Chart-ID + die Anzahl der seit dem Programmstart verstrichenen Prozessor-Ticks + eine Pseudo-Zufallszahl verwendet werden, um eine grafische Objektressource in der Methode Create() der Klasse CCanvas zu erstellen:

//+------------------------------------------------------------------+
//| Create dynamic resource                                          |
//+------------------------------------------------------------------+
bool CCanvas::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
  {
   Destroy();
//--- prepare data array
   if(width>0 && height>0 && ArrayResize(m_pixels,width*height)>0)
     {
      //--- generate resource name
      m_rcname="::"+name+(string)ChartID()+(string)(GetTickCount()+MathRand());
      //--- initialize data with zeros
      ArrayInitialize(m_pixels,0);
      //--- create dynamic resource
      if(ResourceCreate(m_rcname,m_pixels,width,height,0,0,0,clrfmt))
        {
         //--- successfully created
         //--- complete initialization
         m_width =width;
         m_height=height;
         m_format=clrfmt;
         //--- succeed
         return(true);
        }
     }
//--- error - destroy object
   Destroy();
   return(false);
  }
//+------------------------------------------------------------------+

... der Name eines grafischen Objekts könnte 63 Zeichen überschreiten, was zu einem Fehler bei der Ressourcenerstellung führt. Daher müssen wir die Länge des Programmnamens vorerst reduzieren. Später werde ich das Problem der Konstruktion von grafischen Objektnamen lösen müssen, da jedes gebundene Objekt den Namen des Objekts erbt, an das es gebunden ist, mit dem Zusatz einer Endung, die ein neues Element in der Hierarchie anzeigt. Je mehr verschachtelte Objekte in der Hierarchie der Objekte miteinander verbunden sind, desto länger ist der Objektname. Dies ist ein falsches Konzept, das letztendlich zu einem Fehler bei der Erstellung eines grafischen Objekts führt, weil die Länge seines Namens überschritten wird. Aber kürzen wir erst einmal nur die Länge des Programmnamens selbst.

Auf der Hauptpaneel werden sechs Paneel-Objekte erstellt. Erstellen wir ein einzelnes Text Label-Objekt auf jedem der Paneels. Die Objektgröße entspricht der Paneelgröße minus zwei Punkte auf jeder Seite. In den EA-Einstellungen wird der Rahmentyp des Text Label-Objekts sowie den Wert für die Textausrichtung innerhalb des Text Label-Objekts gezeigt, damit wir deutlich sehen können, wo und wie der Text innerhalb des Objekts angezeigt wird.

Im globalen Bereich erstellen wir die Enumeration, die den Objektrahmentyp für die Kompilierung sowohl in der englischen Programmversion als auch in der Version in der Sprache des Bibliotheksnutzers beschreibt, und fügen neue Programmeingaben hinzu:

//+------------------------------------------------------------------+
//|                                                     TstDE107.mq5 |
//|                                  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"
//--- includes
#include <DoEasy\Engine.mqh>
//--- defines
#define  FORMS_TOTAL (3)   // Number of created forms
#define  START_X     (4)   // Initial X coordinate of the shape
#define  START_Y     (4)   // Initial Y coordinate of the shape
#define  KEY_LEFT    (65)  // (A) Left
#define  KEY_RIGHT   (68)  // (D) Right
#define  KEY_UP      (87)  // (W) Up
#define  KEY_DOWN    (88)  // (X) Down
#define  KEY_FILL    (83)  // (S) Filling
#define  KEY_ORIGIN  (90)  // (Z) Default
#define  KEY_INDEX   (81)  // (Q) By index

//--- 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)
  };
#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)
  };
#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
//--- global variables
CEngine        engine;
color          array_clr[];
//+------------------------------------------------------------------+


In OnInit() fügen wir den Codeblock für das Erstellen von Objekten der Text Label hinzu:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set EA global variables
   ArrayResize(array_clr,2);        // Array of gradient filling colors
   array_clr[0]=C'26,100,128';      // Original ≈Dark-azure color
   array_clr[1]=C'35,133,169';      // Lightened original color
//--- Create the array with the current symbol and set it to be used in the library
   string array[1]={Symbol()};
   engine.SetUsedSymbols(array);
   //--- Create the timeseries object for the current symbol and period, and show its description in the journal
   engine.SeriesCreate(Symbol(),Period());
   engine.GetTimeSeriesCollection().PrintShort(false); // Short descriptions
//--- Create WinForms Panel object
   CPanel *pnl=NULL;
   pnl=engine.CreateWFPanel("WFPanel",50,50,230,150,array_clr,200,true,true,false,-1,FRAME_STYLE_BEVEL,true,false);
   if(pnl!=NULL)
     {
      //--- Set Padding to 4
      pnl.SetPaddingAll(4);
      //--- Set the flags of relocation, auto resizing and auto changing mode from the inputs
      pnl.SetMovable(InpMovable);
      pnl.SetAutoSize(InpAutoSize,false);
      pnl.SetAutoSizeMode((ENUM_CANV_ELEMENT_AUTO_SIZE_MODE)InpAutoSizeMode,false);
      //--- In the loop, create 6 bound panel objects
      for(int i=0;i<6;i++)
        {
         //--- create the panel object with coordinates along the X axis in the center and 10 along the Y axis, the width of 80 and the height of 50
         CPanel *prev=pnl.GetElement(i-1);
         int xb=0, yb=0;
         int x=(i<3 ? (prev==NULL ? xb : prev.CoordXRelative()) : xb+prev.Width()+20);
         int y=(i<3 ? (prev==NULL ? yb : prev.BottomEdgeRelative()+16) : (i==3 ? yb : prev.BottomEdgeRelative()+16));
         if(pnl.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_PANEL,pnl,x,y,90,40,C'0xCD,0xDA,0xD7',200,true,false))
           {
            CPanel *obj=pnl.GetElement(i);
            if(obj==NULL)
               continue;
            obj.SetFrameWidthAll(3);
            obj.SetBorderStyle(FRAME_STYLE_BEVEL);
            obj.SetColorBackground(obj.ChangeColorLightness(obj.ColorBackground(),4*i));
            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,pnl,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);
              }
           }
        }
      //--- Redraw all objects according to their hierarchy
      pnl.Redraw(true);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Die gesamte Logik ist im Code detailliert kommentiert. Legen wir vor dem Erstellen von Text Label-Objekten die Texthintergrundfarbe für den Bereich fest, an den die Beschriftung gebunden ist. Diese Farbe sollte vom Text Label-Objekt abgeleitet werden. Das ist es, was hier überprüft wird. Danach werden wir die Farbe im Textobjekt selbst nach Bedarf ändern.

In OnTick() gebe ich die Werte für den Ask- und Bid-Preis in jedes Text Label ein. Für Objekte mit einem geraden Index in der Liste geben wir den Bid-Preis ein, für ungerade den Ask-Preis:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- Get the pointer to the panel object by name
   CPanel *pnl=engine.GetWFPanel("WFPanel");
   if(pnl!=NULL)
     {
      //--- Get the list of all bound panel objects
      CArrayObj *list=pnl.GetListWinFormsObjByType(GRAPH_ELEMENT_TYPE_WF_PANEL);
      //--- In the loop by bound panel objects,
      for(int i=0;i<list.Total();i++)
        {
         //--- get the pointer to the next panel object
         CPanel *obj=pnl.GetWinFormsObj(GRAPH_ELEMENT_TYPE_WF_PANEL,i);
         if(obj!=NULL)
           {
            //--- take the pointer to the first (and only) text label object from the received object
            CLabel *lbl=obj.GetWinFormsObj(GRAPH_ELEMENT_TYPE_WF_LABEL,0);
            if(lbl!=NULL)
              {
               //--- set the new text for the object and redraw it
               lbl.SetText(GetPrice(i % 2==0 ? SYMBOL_BID : SYMBOL_ASK));
               lbl.Redraw(false);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+

Ganz am Ende des EA-Listings fügen wir die Funktion hinzu, die den String-Wert des Bid- oder Ask-Preises zurückgibt:

//+------------------------------------------------------------------+
//| Return Bid/Ask string value                                      |
//+------------------------------------------------------------------+
string GetPrice(const ENUM_SYMBOL_INFO_DOUBLE price)
  {
   return((price==SYMBOL_ASK ? "Ask: " : "Bid: ")+DoubleToString(SymbolInfoDouble(Symbol(),price),Digits()));
  }
//+------------------------------------------------------------------+

Je nach dem an die Funktion übergebenen Wert wählen wir, was vor den Preiswert geschrieben werden soll („Ask“ oder „Bid“), und fügen den Preis als Text mit dem angegebenen Typ zum Text hinzu.

Kompilieren Sie den EA und starten Sie ihn auf dem Chart:


Wie wir sehen können, wird der Text an den richtigen Stellen innerhalb seines Objekts angezeigt, dessen Größe durch die Angabe eines Rahmens für ihn angezeigt wird. Der Text mit den Preisen innerhalb des Objekts wird entsprechend der Aktualisierung des entsprechenden Preises im Diagramm aktualisiert.

Bei der Erstellung des Paneels und seiner Objekte können wir offensichtliche visuelle unangenehme Effekte sehen. Sie werden verschwinden, wenn ich die visuelle Darstellung bei der Interaktion mit Objekten auf dem Diagramm optimiere, wenn sie konstruiert, verschoben und neu konstruiert werden.


Was kommt als Nächstes?

Im nächsten Artikel werde ich die Entwicklung von WinForms-Objekten fortsetzen.

Alle Dateien der aktuellen Bibliotheksversion, des Test-EA und des Chartereignis-Kontrollindikators für MQL5 sind unten angehängt, damit Sie sie testen und herunterladen können. Hinterlassen Sie Ihre Fragen, Kommentare und Vorschläge im Kommentarteil.

Zurück zum Inhalt

*Vorherige Artikel in dieser Reihe:

DoEasy. Steuerung (Teil 1): Erste Schritte
DoEasy. Steuerung (Teil 2): Arbeiten an der Klasse CPanel
DoEasy. Steuerung (Teil 3): Erstellen gebundener Steuerelemente
DoEasy. Steuerung (Teil 4): Paneel-Steuerung, Parameter für Padding und Dock
DoEasy. Steuerung (Teil 5): Basisobjekt von WinForms, Paneel-Steuerelement, Parameter AutoSize
DoEasy. Steuerung (Teil 6): Paneel-Steuerung, automatische Größenanpassung des Containers an den inneren Inhalt



Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/11045

Beigefügte Dateien |
MQL5.zip (4357.39 KB)
Lernen Sie, wie man ein Handelssystem mit der Standardabweichung entwirft Lernen Sie, wie man ein Handelssystem mit der Standardabweichung entwirft
Hier ist ein neuer Artikel in unserer Serie darüber, wie man ein Handelssystem mit den beliebtesten technischen Indikatoren in MetaTrader 5 Handelsplattform zu entwerfen. Lernen Sie, wie man ein Handelssystem mit Hilfe des Indikators der Standardabweichung entwickelt.
Neuronale Netze leicht gemacht (Teil 15): Datenclustering mit MQL5 Neuronale Netze leicht gemacht (Teil 15): Datenclustering mit MQL5
Wir fahren fort mit der Betrachtung der Clustermethode. In diesem Artikel werden wir eine neue CKmeans-Klasse erstellen, um eine der gängigsten k-means-Clustermethoden zu implementieren. Während der Tests gelang es dem Modell, etwa 500 Muster zu erkennen.
Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 16): Zugang zu Daten im Internet (II) Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 16): Zugang zu Daten im Internet (II)
Wie man Daten aus dem Web in einen Expert Advisor überträgt, ist nicht so offensichtlich. Das ist gar nicht so einfach, wenn man nicht alle Möglichkeiten des MetaTrader 5 kennt.
Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 15): Zugang zu Daten im Internet (I) Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 15): Zugang zu Daten im Internet (I)
Wie kann man über den MetaTrader 5 auf Online-Daten zugreifen? Es gibt viele Webseiten und Orte im Internet, die eine riesige Menge an Informationen bieten. Sie müssen nur wissen, wo Sie suchen und wie Sie diese Informationen am besten nutzen können.