English Русский Español Deutsch 日本語 Português
preview
DoEasy. C控件(第 7 部分):文本标签控件

DoEasy. C控件(第 7 部分):文本标签控件

MetaTrader 5示例 | 29 八月 2022, 07:56
565 0
Artyom Trishkin
Artyom Trishkin

内容


概述

任何程序都会涉及在屏幕上显示信息。 MS Visual Studio 采用的是文本标签控件,此外还有其它元素。 MetaTrader 5 也提供了 "Text label(文本标签)" 图形对象。 此外,在终端中创建程序 GUI 的所有图形元素都提供了在画布上显示文本的能力。 但有时这也许不太方便。 因此,在本文中,我将创建一个独立的“文本标签”控件。

这样的对象能够将其容器放置在任何位置,而其自身的功能将重现 MS Visual Studio 文本标签的功能。 我们能够为欲显示的文本设置字体参数。 文本将定位在“文本标签”对象的边界以内。 顺而推之,对象的大小既能够按照指定宽度和高度设置,也可以根据标签所用字体的大小自动调整其大小。 此外,我们将能够使用对象边框(沿围绕整个“文本标签”对象边界的矩形边框)。 对象边框既可以是平面,亦或是三维的。 这将给我们足够的机会在程序 GUI 元素内部进行适当设计来显示文本。

为了将所有的新对象参数显示在某处,或者为了我们能够通过所需参数选择对象,我们应将“文本标签”对象使用的所有属性添加到函数库图形元素的整数型、实数型、和字符串型属性的枚举之中。 我试图在所有函数库对象中坚持这个理念,因为它允许我们使用其所提供的功能,并以足够的灵活性快速搜索、选择和排序函数库对象。


改进库类

首先,往函数库中添加新的文本消息。

在 \MQL5\Include\DoEasy\Data.mqh 中,加入函数库新消息索引:

   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

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


与新增索引相对应的消息

   {"Элемент управления \"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"},
   
  };
//+---------------------------------------------------------------------+



除了“文本标签”控件中的文本颜色外,我们还将用到其不透明度,例如,这将允许我们在程序 GUI 元素上创建文本平滑出现/消失的效果。 此外,我们还需要设置文本标签对象所要显示的文本,以及构建 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_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



添加文本标签类型至函数库对象类型列表当中:

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



将文本标签元素添加到图形元素类型列表当中:

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



将所有新常量(以前添加到 WimForms 对象但未放置在枚举中的常量,以及新的常量)添加到画布上的图形元素的整数型属性列表当中:

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


将整数型属性的总数从 38 增加到 44


在基于画布的图形元素字符串型属性列表中,添加一个新属性 —“图形元素文本”,并将字符串型属性总数从 2 增加到 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
//+------------------------------------------------------------------+



将所有新属性添加到画布上图形元素的可能排序准则的枚举当中:

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


现在,我们可以根据新属性选择和排序所有图形元素。


CWinFormBase 类作为函数库所有 WinForms 对象的基类。 依序,该类是自具有鼠标交互功能的窗体对象衍生而来。 我们需要继承类中的一些私密变量。 由于私密变量和方法仅在声明它们的类中可见,因此我们需要将它们从私密部分移动到受保护部分,以便它们在继承类中也能可见。

在 \MQL5\Include\DoEasy\Objects\Graph\Form.mqh 窗体对象文件中,移动私密部分的变量

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


至受保护部分,并把一些方法虚化,如此我们就可以在继承类中重定义它们:

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:



由于我们现在针对 WinForms 对象采用的是构建函数库对象的一般概念,并将向图形元素属性添加 WinForms 的对象参数,因此我们需要删除存储对象属性的 CWinFormBase 基类变量,并重写设置和获取这些属性的所有方法。

在 \MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqh 中,从受保护部分中删除所有已无必要的变量

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



在类的公开部分,重写在属性里接收和设置对象属性枚举的方法,并添加新方法,处理“文本标签”对象文本以及设置和获取 WinForms 对象的一般属性

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


在所有重写的方法中,我们现在的数值写入和读取并不是直接针对变量,而是使用 SetProperty() 和 GetProperty() 方法在对象属性的枚举中获取它们。这一点在第一篇文章中的构建函数库对象的概念时就已初步进行了讲述。

在类构造函数中,将所创建对象的文本设置为“空字符串”,在 Defines.mqh 里为文本颜色和其不透明度设置默认值:

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



在设置粗体字体标志和字体宽度类型的方法中,在对象属性中设置初值,替代设置变量值:

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



“文本标签”控件类:

在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ 中,创建一个 CLabel 类的新文件 Label.mqhCWinFormBase 类应该是基类其文件将包含在新创建的类文件中

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


在类的私密部分、受保护部分 和公开部分当中,添加类方法的声明:

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


如您所见,我已经在受保护和公开部分中声明了 CWinFormBase 基类的虚拟方法。 这些方法的逻辑应该与基本方法的逻辑略有不同。 故此,它们将在该类中被重新定义。

例如,在设置元素文本的方法中,首先调用基类方法。 传递给方法的新值将会赋值给对象属性。 然后,如果设置了对象自动调整大小标志,则调用设置新大小的私密方法,而大小对应于对象画布上显示的文本大小,如下所示:

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



该类拥有参数构造函数,而默认构造函数和析构函数是自动创建的。

构造对象的图表 ID 及其子窗口,以及对象名称、坐标和大小,都传递给参数化构造函数:

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


首先,将图形元素类型设置到所有父类,并为对象设置 WinForms 标签库对象类型。
接下来,设置对象和坐标,并调用虚拟方法来设置函数库图形元素的主要参数。 该方法在类中重新定义,因为它与基准对象的相同方法略有不同。 我们将在下面考虑它。
如果对象自动调整大小标志设置为适配文本,则调用相应的方法调整对象的大小(该标志目前始终处于禁用状态,但稍后可以更改)。
调整大小之后(设置标志),设置初始对象大小,及其初始坐标.
最后重新绘制整个对象

虚拟方法初始化变量:

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


虚拟方法重新定义了基本对象方法 — 其它默认值也在此处设置。 此外,还有对标签对象唯一的属性值的初始化。


虚拟 Erase 方法重新定义基准对象方法,以完全不透明度绘制对象边框:

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



重新绘制对象的虚拟方法:

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


该方法重新定义基类方法。 这里首先删除对象背景(用完全透明的背景色填充)。 接下来依据元素内部的文本来定义文本绑定点。 计算文本绑定点坐标(标签坐标原点)已计算,文本应在所计算坐标范围内显示文本,并更新对象。

文本绑定点在 TextOut() 函数帮助 中进行了直观标记和解释:



自动设置元素宽度和高度的方法:

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


方法逻辑已在代码注释中讲述。 首先,根据为对象设置的文本和字体参数我们得到文本大小。 如果标签为“空”,我们将使用空格(“”)进行测量。 接下来,把左侧和右侧的对象边距值加进结果宽度,以及顶部和底部的边距值加进高度值。 如果无法获得文本高度,则通过将为对象设置的字体大小,乘以我根据经验选择的比率,来计算其近似大小。 我在 MS Visual Studio 中依据字体大小比较了对象大小值,并从不同大小的几个测量值中取了平均值,得到了 1.625 的比值。 我不知道是否还有其它更准确的方法。 我也许找到了更好的方法来依据字体大小计算对象大小。 完成所有计算后,将为对象设置获得的宽度和高度值。

“文本标签”对象的创建至此完毕。

由于 WinForms Panel 对象是一个用于将其它相同类型对象绑定到它的容器,因此所有创建的相同类型的对象都应该对它可见。 为了实现这一点,每个已创建的 WinForms 对象的文件将包含在面板对象文件之中。

打开面板对象文件 \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Panel.mqh,并将新创建的文本标签对象的文件包含到其中:

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



从类的私密部分删除不必要的变量,因为它们现在都会在基准 WinForms 对象属性中设置:

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



在类的公开部分,声明两个新方法接收拥有指定类型的绑定 WinForms 对象列表,和依据此类型的对象列表中的索引获取指向指定 WinForms 的指针

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)



从类中删除 SetAutoScroll() 和 AutoScroll(),因为它们是 CWinFormBase 父类的成员,并且是为处理对象属性而非类变量而调整的:

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



遵照类似的方式重写处理对象属性的类方法,并添加按宽度和高度同时设置 AutoScrollMargin 的方法

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



在创建新图形对象的方法中,添加创建文本标签对象的代码模块

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


这里一切都很清晰,不需要任何评论。


我们重写创建新绑定元素的方法:

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


方法逻辑已在代码注释中讲述。 除了方法本身的小逻辑改进之外,我们还添加了处理文本标签对象创建的代码模块。 我希望这里一切都很清楚,不需要多加解释。 如果您有任何疑问,请随时在下面的评论中提问。


返回拥有 WinForms 对象指定类型的附加对象列表的方法:

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


在此,我们简单地返回在 CSelect 类中接收到的含有指定 WinForms 对象类型的列表。 如果获取列表失败,或没有指定类型的对象,则该方法返回 NULL


该方法返回指向依据索引并符合指定类型的绑定 WinForms 对象的指针:

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


这里我们得到含有指定类型的对象列表,和通过指定索引从列表返回的指向对象的指针。
如果获取列表失败,或指定索引不存在,则该方法返回 NULL

一切都准备好,可以进行测试了。


测试

为了执行测试,我们取用来自上一篇文章中的 EA,并将其保存到 \MQL5\Experts\TestDoEasy\Part107\,命名为 TstDE107.mq5

由于所有图形对象的名称都包含程序名,而图表 ID + 程序启动后经历的处理器跳价次数 + 伪随机数,用于在 CCanvas 类的 Create() 方法中创建图形对象资源

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


...图形对象的名称可能超过 63 个字符,导致资源创建错误。 为此,我们现在必须减少程序名长度。 稍后,我将不得不解决构造图形对象名称的问题,因为每个绑定对象都继承了它所绑定对象的名称,并添加了一个表示层次结构的新元素作为结尾。 对象层次中相互关联的嵌套对象越多,对象名称越长。 这是一个错误的概念,由于超过了图形对象名称的长度,最终会导致在创建图形对象时出错。 但现在,我们只能先缩短程序名本身的长度。

在主面板上创建了六个面板对象。 在每个面板上创建单个文本标签对象。 对象大小将等于面板大小减去两侧的两点。 在 EA 设置中,显示文本标签对象的边框类型,以及文本标签对象内的文本对齐值,这将令我们能够清楚地看到文本在对象内的显示位置和方式。

在全局区域中,创建枚举,描述用于编译的对象边框类型,包括程序英文版,和函数库用户语言版本,并添加新程序输入

//+------------------------------------------------------------------+
//|                                                     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[];
//+------------------------------------------------------------------+



OnInit() 处理程序中,添加用于创建文本标签对象的代码模块

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


整个逻辑在代码中有详细注释。 在创建文本标签对象之前,为标签绑定到的面板设置文本背景色。 此颜色应由文本标签对象继承。 这就是我在这里检查的内容。 之后,我们将根据需要在文本对象本身中修改其颜色。

OnTick() 处理程序中,我将为每个文本标签输入要价和出价值。 对于列表中处于偶数索引的对象,输入出价,而对于奇数索引对象,输入要价

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


在 EA 列表的最后,添加返回出价或要价字符串值的函数:

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

根据传递给函数的值,选择要把哪个价格值(“要价”或“出价”)写入的内容,并将指定类型的字符串价格值添加到文本中。

编译 EA,并在图表上启动它:


正如我们所见,文本显示在其对象内的正确位置,其大小可以通过为其指定边框的存在来查看。 对象中包含价格的文本将根据图表上相应价格的刷新而更新。

当创建面板及其对象时,我们可以看到明显的不舒适视觉效果。 当构建、移动和重新构建图表上的对象时,我将在优化视觉显示时消除它们。


下一步是什么?

在下一篇文章中,我将继续开发 WinForms 对象。

以下是 MQL5 的当前函数库版本、测试 EA,和图表事件控制指标的所有文件,供您测试和下载。 在评论中留下您的问题、意见和建议。

返回内容目录

*该系列的前几篇文章:

DoEasy. 控件 (第 1 部分): 第一步
DoEasy. 控件 (第 2 部分): 操控 CPanel 类
DoEasy. 控件 (第 3 部分): 创建绑定控件
DoEasy. 控件 (第 4 部分): 面板控件,Padding(填充)和 Dock(驻靠)参数
DoEasy. 控件 (第 5 部分): 基准 WinForms 对象,面板控件,AutoSize 参数
DoEasy. 控件 (第 6 部分): 面板控件,自动调整容器大小来适应内部内容



本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/11045

附加的文件 |
MQL5.zip (4357.39 KB)
从头开始开发智能交易系统(第 18 部分):新订单系统 (I) 从头开始开发智能交易系统(第 18 部分):新订单系统 (I)
这是新订单系统的第一部分。 自从我们在文章中开始打造这个 EA 以来,它已经历了各种变化和改进,同时保持了相同的图表订单系统模型。
数据科学和机器学习(第 04 部分):预测当前股市崩盘 数据科学和机器学习(第 04 部分):预测当前股市崩盘
在本文中,我将尝试运用我们的逻辑模型,基于美国经济的基本面,来预测股市崩盘,我们将重点关注 NETFLIX 和苹果。利用 2019 年和 2020 年之前的股市崩盘,我们看看我们的模型在当前的厄运和低迷中会表现如何。
价格走势模型及其主要规定(第 1 部分):最简单的模型版本及其应用 价格走势模型及其主要规定(第 1 部分):最简单的模型版本及其应用
本文提供了数学上严格的价格运动和市场功能理论的基础。 到目前为止,我们还没有任何经过严格数学论证的价格走势理论。 取而代之的是,我们不得不基于经验假设进行处理,即价格在某种形态之后以某种方式移动。 当然,这些假设既没有得到统计数据的支持,也没有得到理论的支持。
视频:如何为简单自动交易设置 MetaTrader 5 和 MQL5 视频:如何为简单自动交易设置 MetaTrader 5 和 MQL5
在这个小视频课程中,您将学习如何下载、安装和设置 MetaTrader 5,并实现自动交易。 您还将学习如何调整图表设置,和自动交易选项。 您将完成第一次回溯测试,在本课程结束时,您就会知道如何导入一个可以全天候自动交易的智能交易系统,而无需呆坐在屏幕前。