English Русский 中文 Deutsch 日本語 Português
preview
DoEasy. Elementos de control (Parte 28): Estilos de barra en el control «ProgressBar»

DoEasy. Elementos de control (Parte 28): Estilos de barra en el control «ProgressBar»

MetaTrader 5Ejemplos | 17 marzo 2023, 16:24
326 0
Artyom Trishkin
Artyom Trishkin

Contenido


Concepto

El control ProgressBar que creamos para la biblioteca actualmente tiene un estilo para mostrar la barra de progreso: una línea continua (Continuous). No obstante, dicho control tiene dos estilos de visualización más: los bloques segmentados (Blocks) y el desplazamiento continuo de un bloque en un objeto (Marquee). Si con el estilo Blocks todo está claro (en lugar de una línea continua, se dibujan bloques ubicados por separado), el estilo Marquee, en cambio, se podrá usar si no conocemos de antemano la cantidad de iteraciones que deberán mostrarse visualmente usando el control ProgressBar. En este caso, durante la ejecución del objeto, un solo bloque igual a la mitad de la anchura de la barra de progreso se desplazará constantemente. 

Además de crear estos dos nuevos estilos, añadiremos texto a la barra de progreso que se muestra dentro. El texto en sí se representará mediante un objeto normal de la clase CLabel de la biblioteca, y no estará vinculado al objeto de barra de progreso, sino al objeto de marca de agua, que será la base del control ProgressBar. El texto se representará dentro de un objeto de etiqueta de texto totalmente transparente con el tamaño de la anchura y la altura de la barra de progreso, y este objeto siempre estará en primer plano, siempre sobre todos los objetos en el control ProgressBar.

Por defecto, el texto no se mostrará en la barra de progreso, pero siempre se podrá añadir justo en el momento en que se ejecute un programa creado sobre la base de la biblioteca; solo deberemos especificar el texto a mostrar y sus atributos (fuente, tamaño, banderas de la fuente, color, opacidad, etc.)


Mejorando las clases de la biblioteca

Antes de comenzar a desarrollar nuevos estilos para el control ProgressBar, simplificaremos los constructores del elemento gráfico básico. En los constructores protegidos y paramétricos, tras crear un objeto, estableceremos los valores de sus propiedades. En ambos constructores, esta será una larga lista de más de cien parámetros diferentes para los elementos gráficos de biblioteca que se añadirán constantemente al crear nuevos objetos. Por consiguiente, deberemos escribir constantemente la configuración de las propiedades del objeto dos veces: en los constructores protegidos y en los constructores paramétricos de la clase CGCnvElement. Lo lógico sería sacar la configuración de todas estas propiedades a un método de inicialización aparte. Al mismo tiempo, si algunas propiedades deben configurarse de forma diferente en constructores distintos, simplemente las transmitiremos en los parámetros formales del nuevo método y las indicaremos en ellos.

En el archivo \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh, añadiremos a la estructura del objeto las nuevas propiedades:

   struct SData
     {
      //--- Object integer properties
      int            id;                                       // Element ID
      int            type;                                     // Graphical element type
      
      //---...
      //---...

      //---
      int            group;                                    // Group the graphical element belongs to
      int            tab_size_mode;                            // Tab size setting mode
      int            tab_page_number;                          // Tab index number
      int            tab_page_row;                             // Tab row index
      int            tab_page_column;                          // Tab column index
      int            progress_bar_minimum;                     // The lower bound of the range ProgressBar operates in
      int            progress_bar_maximum;                     // The upper bound of the range ProgressBar operates in
      int            progress_bar_step;                        // ProgressBar increment needed to redraw it
      int            progress_bar_style;                       // ProgressBar style
      int            progress_bar_value;                       // Current ProgressBar value from Min to Max
      int            progress_bar_marquee_speed;               // Progress bar animation speed in case of Marquee style
      //---
      ulong          tooltip_initial_delay;                    // Tooltip display delay
      ulong          tooltip_auto_pop_delay;                   // Tooltip display duration
      ulong          tooltip_reshow_delay;                     // One element new tooltip display delay
      bool           tooltip_show_always;                      // Display a tooltip in inactive window
      int            tooltip_icon;                             // Icon displayed in a tooltip
      bool           tooltip_is_balloon;                       // Tooltip in the form of a "cloud"
      bool           tooltip_use_fading;                       // Fade when showing/hiding a tooltip
      //--- Object real properties

      //--- Object string properties
      uchar          name_obj[64];                             // Graphical element object name
      uchar          name_res[64];                             // Graphical resource name
      uchar          text[256];                                // Graphical element text
      uchar          descript[256];                            // Graphical element description
      uchar          tooltip_title[256];                       // Element tooltip title
      uchar          tooltip_text[256];                        // Element tooltip text
     };
   SData             m_struct_obj;                             // Object structure

La estructura del objeto gráfico será necesaria para escribir correctamente las propiedades del objeto en un archivo y leerlas desde este durante la restauración. Las propiedades ahora escritas en esta estructura ya las hemos añadido al objeto, pero aún no las hemos añadido a la estructura. Incluso si los campos de la estructura no coinciden con las propiedades del objeto, en esta etapa de desarrollo no habrá nada de qué preocuparse, ya que hasta ahora no hemos guardado el objeto en un archivo ni leído sus propiedades desde el mismo. Obviamente, más tarde guardaremos las propiedades de los objetos gráficos en un archivo y las leeremos desde allí, y luego realmente necesitaremos que los campos de la estructura coincidan totalmente con las propiedades del objeto.

En la sección privada de la clase, declararemos un nuevo método para inicializar las propiedades del elemento gráfico:

//--- Save the colors to the background color array
   void              SaveColorsBG(color &colors[])                         { this.CopyArraysColors(this.m_array_colors_bg,colors,DFUN);      }
   void              SaveColorsBGMouseDown(color &colors[])                { this.CopyArraysColors(this.m_array_colors_bg_dwn,colors,DFUN);  }
   void              SaveColorsBGMouseOver(color &colors[])                { this.CopyArraysColors(this.m_array_colors_bg_ovr,colors,DFUN);  }
   void              SaveColorsBGInit(color &colors[])                     { this.CopyArraysColors(this.m_array_colors_bg_init,colors,DFUN); }

//--- Initialize property values
   void              Initialize(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                                const int element_id,const int element_num,
                                const int x,const int y,const int w,const int h,
                                const string descript,const bool movable,const bool activity);

public:

Las propiedades del objeto creado se transmitirán al método, que tendrá diferentes valores en diferentes constructores, o se especificarán directamente en los constructores, en sus parámetros formales, es decir, se transmitirán desde el exterior. Después transmitiremos todas esas propiedades al método a través de sus parámetros.


En cada uno de los constructores, eliminaremos la larga lista de ajustes de las propiedades del objeto, reemplazándola con una llamada al método de inicialización:

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const int      element_id,
                           const int      element_num,
                           const long     chart_id,
                           const int      wnd_num,
                           const string   descript,
                           const int      x,
                           const int      y,
                           const int      w,
                           const int      h,
                           const color    colour,
                           const uchar    opacity,
                           const bool     movable=true,
                           const bool     activity=true,
                           const bool     redraw=false) : m_shadow(false)
  {
   this.SetTypeElement(element_type);
   this.m_type=OBJECT_DE_TYPE_GELEMENT; 
   this.m_element_main=main_obj;
   this.m_element_base=base_obj;
   this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
   this.m_name=this.CreateNameGraphElement(element_type);
   this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id);
   this.m_subwindow=wnd_num;
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.m_text_anchor=0;
   this.m_text_x=0;
   this.m_text_y=0;
   this.SetBackgroundColor(colour,true);
   this.SetOpacity(opacity);
   this.m_shift_coord_x=0;
   this.m_shift_coord_y=0;
   if(::ArrayResize(this.m_array_colors_bg,1)==1)
      this.m_array_colors_bg[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1)
      this.m_array_colors_bg_dwn[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1)
      this.m_array_colors_bg_ovr[0]=this.BackgroundColor();
   if(this.Create(chart_id,wnd_num,x,y,w,h,redraw))
     {
      this.Initialize(element_type,element_id,element_num,x,y,w,h,descript,movable,activity);
      this.SetVisibleFlag(false,false);
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
     }
  }
//+------------------------------------------------------------------+
//| Protected constructor                                            |
//+------------------------------------------------------------------+
CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const long    chart_id,
                           const int     wnd_num,
                           const string  descript,
                           const int     x,
                           const int     y,
                           const int     w,
                           const int     h) : m_shadow(false)
  {
   this.m_type=OBJECT_DE_TYPE_GELEMENT; 
   this.m_element_main=main_obj;
   this.m_element_base=base_obj;
   this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
   this.m_name=this.CreateNameGraphElement(element_type);
   this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id);
   this.m_subwindow=wnd_num;
   this.m_type_element=element_type;
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.m_text_anchor=0;
   this.m_text_x=0;
   this.m_text_y=0;
   this.SetBackgroundColor(CLR_CANV_NULL,true);
   this.SetOpacity(0);
   this.m_shift_coord_x=0;
   this.m_shift_coord_y=0;
   if(::ArrayResize(this.m_array_colors_bg,1)==1)
      this.m_array_colors_bg[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1)
      this.m_array_colors_bg_dwn[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1)
      this.m_array_colors_bg_ovr[0]=this.BackgroundColor();
   if(this.Create(chart_id,wnd_num,x,y,w,h,false))
     {
      this.Initialize(element_type,0,0,x,y,w,h,descript,false,false);
      this.SetVisibleFlag(false,false);
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
     }
  }
//+------------------------------------------------------------------+

Como podemos ver, en ambos constructores, los valores propios inherentes a cada constructor específico se transmiten al método de inicialización.


Luego trasladaremos al nuevo método de inicialización la configuración de propiedades eliminada de los constructores de clase:

//+------------------------------------------------------------------+
//| Initialize the properties                                        |
//+------------------------------------------------------------------+
void CGCnvElement::Initialize(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                              const int element_id,const int element_num,
                              const int x,const int y,const int w,const int h,
                              const string descript,const bool movable,const bool activity)
  {
   this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,this.m_canvas.ResourceName()); // Graphical resource name
   this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,CGBaseObj::ChartID());         // Chart ID
   this.SetProperty(CANV_ELEMENT_PROP_WND_NUM,CGBaseObj::SubWindow());        // Chart subwindow index
   this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,CGBaseObj::Name());            // Element object name
   this.SetProperty(CANV_ELEMENT_PROP_TYPE,element_type);                     // Graphical element type
   this.SetProperty(CANV_ELEMENT_PROP_ID,element_id);                         // Element ID
   this.SetProperty(CANV_ELEMENT_PROP_NUM,element_num);                       // Element index in the list
   this.SetProperty(CANV_ELEMENT_PROP_COORD_X,x);                             // Element's X coordinate on the chart
   this.SetProperty(CANV_ELEMENT_PROP_COORD_Y,y);                             // Element's Y coordinate on the chart
   this.SetProperty(CANV_ELEMENT_PROP_WIDTH,w);                               // Element width
   this.SetProperty(CANV_ELEMENT_PROP_HEIGHT,h);                              // Element height
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,0);                      // Active area offset from the left edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,0);                       // Active area offset from the upper edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,0);                     // Active area offset from the right edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,0);                    // Active area offset from the bottom edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_MOVABLE,movable);                       // Element moveability flag
   this.SetProperty(CANV_ELEMENT_PROP_ACTIVE,activity);                       // Element activity flag
   this.SetProperty(CANV_ELEMENT_PROP_INTERACTION,false);                     // Flag of interaction with the outside environment
   this.SetProperty(CANV_ELEMENT_PROP_ENABLED,true);                          // Element availability flag
   this.SetProperty(CANV_ELEMENT_PROP_RIGHT,this.RightEdge());                // Element right border
   this.SetProperty(CANV_ELEMENT_PROP_BOTTOM,this.BottomEdge());              // Element bottom border
   this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_X,this.ActiveAreaLeft());     // X coordinate of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y,this.ActiveAreaTop());      // Y coordinate of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.ActiveAreaRight());      // Right border of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.ActiveAreaBottom());    // Bottom border of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X,0);                      // Visibility scope X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,0);                      // Visibility scope Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,w);                  // Visibility scope width
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,h);                 // Visibility scope height
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAYED,true);                        // Non-hidden control display flag
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE,CANV_ELEMENT_DISPLAY_STATE_NORMAL);// Control display state
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION,DEF_CONTROL_PROCESS_DURATION);  // Control display duration
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_X,0);                      // Control area X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_Y,0);                      // Control area Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_WIDTH,0);                  // Control area width
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_HEIGHT,0);                 // Control area height
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_RIGHT,0);                 // Right scroll area X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_RIGHT,0);                 // Right scroll area Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_RIGHT,0);             // Right scroll area width
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_RIGHT,0);            // Right scroll area height
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_BOTTOM,0);                // Bottom scroll area X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_BOTTOM,0);                // Bottom scroll area Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_BOTTOM,0);            // Bottom scroll area width
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_BOTTOM,0);           // Bottom scroll area height
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_LEFT_AREA_WIDTH,0);              // Left edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_BOTTOM_AREA_WIDTH,0);            // Bottom edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH,0);             // Right edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH,0);               // Top edge area width
   //---
   this.SetProperty(CANV_ELEMENT_PROP_BELONG,ENUM_GRAPH_OBJ_BELONG::GRAPH_OBJ_BELONG_PROGRAM);  // Graphical element affiliation
   this.SetProperty(CANV_ELEMENT_PROP_ZORDER,0);                              // Priority of a graphical object for receiving the event of clicking on a chart
   this.SetProperty(CANV_ELEMENT_PROP_BOLD_TYPE,FW_NORMAL);                   // Font width type
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,FRAME_STYLE_NONE);         // Control frame style
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP,0);                     // Control frame top size
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM,0);                  // Control frame bottom size
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT,0);                    // Control frame left size
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT,0);                   // Control frame right size
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR,this.BackgroundColor());   // Control frame color
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE,false);                        // Flag of the element auto resizing depending on the content
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE,CANV_ELEMENT_AUTO_SIZE_MODE_GROW); // Mode of the element auto resizing depending on the content
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL,false);                      // Auto scrollbar flag
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W,0);                 // Width of the field inside the element during auto scrolling
   this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H,0);                 // Height of the field inside the element during auto scrolling
   this.SetProperty(CANV_ELEMENT_PROP_DOCK_MODE,CANV_ELEMENT_DOCK_MODE_NONE); // Mode of binding control borders to the container
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_TOP,0);                          // Top margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM,0);                       // Bottom margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT,0);                         // Left margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT,0);                        // Right margin between the fields of this and another control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_TOP,0);                         // Top margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM,0);                      // Bottom margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_LEFT,0);                        // Left margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT,0);                       // Right margin inside the control
   this.SetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN,ANCHOR_LEFT_UPPER);          // Text position within text label boundaries
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN,ANCHOR_LEFT_UPPER);         // Position of the checkbox within control borders
   this.SetProperty(CANV_ELEMENT_PROP_CHECKED,false);                         // Control checkbox status
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_STATE,CANV_ELEMENT_CHEK_STATE_UNCHECKED);  // Status of a control having a checkbox
   this.SetProperty(CANV_ELEMENT_PROP_AUTOCHECK,true);                        // Auto change flag status when it is selected
   //---
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR,CLR_DEF_CHECK_BACK_COLOR);            // Color of control checkbox background
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY,CLR_DEF_CHECK_BACK_OPACITY);  // Opacity of the control checkbox background color
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_BACK_MOUSE_DOWN);// Color of control checkbox background when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_OVER,CLR_DEF_CHECK_BACK_MOUSE_OVER);// Color of control checkbox background when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR,CLR_DEF_CHECK_BORDER_COLOR);                // Color of control checkbox frame
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY,CLR_DEF_CHECK_BORDER_OPACITY);      // Opacity of the control checkbox frame color
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_BORDER_MOUSE_DOWN);// Color of control checkbox frame when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_OVER,CLR_DEF_CHECK_BORDER_MOUSE_OVER);// Color of control checkbox frame when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR,CLR_DEF_CHECK_FLAG_COLOR);                  // Control checkbox color
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY,CLR_DEF_CHECK_FLAG_OPACITY);        // Control checkbox color opacity
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_FLAG_MOUSE_DOWN);  // Control checkbox color when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER,CLR_DEF_CHECK_FLAG_MOUSE_OVER);  // Control checkbox color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,CLR_DEF_FORE_COLOR);                              // Default text color for all control objects
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,CLR_DEF_FORE_COLOR_OPACITY);              // Opacity of the default text color for all control objects
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_DOWN,CLR_DEF_FORE_COLOR_MOUSE_DOWN);        // Default control text color when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_OVER,CLR_DEF_FORE_COLOR_MOUSE_OVER);        // Default control text color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_STATE_ON,CLR_DEF_FORE_COLOR);                     // Text color of the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_STATE_ON_MOUSE_DOWN,CLR_DEF_FORE_COLOR_MOUSE_DOWN);// Default control text color when clicking on the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_STATE_ON_MOUSE_OVER,CLR_DEF_FORE_COLOR_MOUSE_OVER);// Default control text color when hovering the mouse over the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN,this.BackgroundColor());         // Control background color when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER,this.BackgroundColor());         // Control background color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_STATE_ON,CLR_DEF_CONTROL_STD_BACK_COLOR_ON);// Background color of the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_STATE_ON_MOUSE_DOWN,CLR_DEF_CONTROL_STD_BACK_DOWN_ON);// Control background color when clicking on the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_STATE_ON_MOUSE_OVER,CLR_DEF_CONTROL_STD_BACK_OVER_ON);// Control background color when clicking on the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN,CLR_DEF_BORDER_MOUSE_DOWN);          // Control frame color when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER,CLR_DEF_BORDER_MOUSE_OVER);          // Control frame color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_TOGGLE,false);                                        // Toggle flag of the control featuring a button
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_STATE,false);                                         // Status of the Toggle control featuring a button
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_GROUP,false);                                         // Button group flag
   this.SetProperty(CANV_ELEMENT_PROP_LIST_BOX_MULTI_COLUMN,false);                                // Horizontal display of columns in the ListBox control
   this.SetProperty(CANV_ELEMENT_PROP_LIST_BOX_COLUMN_WIDTH,0);                                    // Width of each ListBox control column
   this.SetProperty(CANV_ELEMENT_PROP_TAB_MULTILINE,false);                                        // Several lines of tabs in TabControl
   this.SetProperty(CANV_ELEMENT_PROP_TAB_ALIGNMENT,CANV_ELEMENT_ALIGNMENT_TOP);                   // Location of tabs inside the control
   this.SetProperty(CANV_ELEMENT_PROP_ALIGNMENT,CANV_ELEMENT_ALIGNMENT_TOP);                       // Location of an object inside the control
   this.SetProperty(CANV_ELEMENT_PROP_TEXT,"");                                                    // Graphical element text
   this.SetProperty(CANV_ELEMENT_PROP_DESCRIPTION,descript);                                       // Graphical element description
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_FIXED_PANEL,0);                              // Panel that retains its size when the container is resized
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_SPLITTER_FIXED,true);                        // Separator moveability flag
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_SPLITTER_DISTANCE,50);                       // Distance from edge to separator
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_SPLITTER_WIDTH,4);                           // Separator width
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_SPLITTER_ORIENTATION,0);                     // Separator location
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_PANEL1_COLLAPSED,false);                     // Flag for collapsed panel 1
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_PANEL1_MIN_SIZE,25);                         // Panel 1 minimum size
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_PANEL2_COLLAPSED,false);                     // Flag for collapsed panel 1
   this.SetProperty(CANV_ELEMENT_PROP_SPLIT_CONTAINER_PANEL2_MIN_SIZE,25);                         // Panel 2 minimum size
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_INITIAL_DELAY,500);                                  // Tooltip display delay
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_AUTO_POP_DELAY,5000);                                // Tooltip display duration
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY,100);                                   // One element new tooltip display delay
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_SHOW_ALWAYS,false);                                  // Display a tooltip in inactive window
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_ICON,CANV_ELEMENT_TOOLTIP_ICON_NONE);                // Icon displayed in a tooltip
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_IS_BALLOON,false);                                   // Tooltip in the form of a "cloud"
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_USE_FADING,true);                                    // Fade when showing/hiding a tooltip
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TITLE,"");                                           // Tooltip title for the element
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT,"");                                            // Tooltip text for the element
   this.SetProperty(CANV_ELEMENT_PROP_GROUP,0);                               // Group the graphical element belongs to
   this.SetProperty(CANV_ELEMENT_PROP_TAB_SIZE_MODE,CANV_ELEMENT_TAB_SIZE_MODE_NORMAL);// Tab size setting mode
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_NUMBER,0);                     // Tab index number
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_ROW,0);                        // Tab row index
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_COLUMN,0);                     // Tab column index
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM,100);              // The upper bound of the range ProgressBar operates in
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM,0);                // The lower bound of the range ProgressBar operates in
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,10);                  // ProgressBar increment needed to redraw it
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS); // ProgressBar style
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,50);                 // Current ProgressBar value from Min to Max
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,10);    // Progress bar animation speed in case of Marquee style
  }
//+------------------------------------------------------------------+

Aquí simplemente hemos trasladado las líneas eliminadas de los constructores de clases. Los valores de propiedad que eran diferentes en distintos constructores ahora se transmitirán y establecerán en las propiedades del objeto usando los parámetros formales de los métodos.


En el método que crea la estructura del objeto, en los nuevos campos de la estructura, escribiremos un registro de los valores de las propiedades correspondientes del elemento gráfico:

//+------------------------------------------------------------------+
//| Create the object structure                                      |
//+------------------------------------------------------------------+
bool CGCnvElement::ObjectToStruct(void)
  {
//--- Save integer properties
   this.m_struct_obj.id=(int)this.GetProperty(CANV_ELEMENT_PROP_ID);                               // Element ID
   this.m_struct_obj.type=(int)this.GetProperty(CANV_ELEMENT_PROP_TYPE);                           // Graphical element type
   this.m_struct_obj.belong=(int)this.GetProperty(CANV_ELEMENT_PROP_BELONG);                       // Graphical element affiliation
   this.m_struct_obj.number=(int)this.GetProperty(CANV_ELEMENT_PROP_NUM);                          // Element ID in the list

   //---...
   //---...

   this.m_struct_obj.border_right_area_width=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH);    // Right edge area width
   this.m_struct_obj.border_top_area_width=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH);        // Top edge area width
   //---
   this.m_struct_obj.tooltip_initial_delay=this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_INITIAL_DELAY);    // Tooltip display delay
   this.m_struct_obj.tooltip_auto_pop_delay=this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_AUTO_POP_DELAY);  // Tooltip display duration
   this.m_struct_obj.tooltip_reshow_delay=this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY);      // One element new tooltip display delay
   this.m_struct_obj.tooltip_show_always=this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_SHOW_ALWAYS);        // Display a tooltip in inactive window
   this.m_struct_obj.tooltip_icon=(int)this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_ICON);                 // Icon displayed in the tooltip
   this.m_struct_obj.tooltip_is_balloon=(bool)this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_IS_BALLOON);    // Balloon tooltip
   this.m_struct_obj.tooltip_use_fading=(bool)this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_USE_FADING);    // Fade when showing and hiding the tooltip
      //---
   this.m_struct_obj.group=(int)this.GetProperty(CANV_ELEMENT_PROP_GROUP);                               // Group the graphical element belongs to
   this.m_struct_obj.tab_size_mode=(int)this.GetProperty(CANV_ELEMENT_PROP_TAB_SIZE_MODE);               // Tab size setting mode
   this.m_struct_obj.tab_page_number=(int)this.GetProperty(CANV_ELEMENT_PROP_TAB_PAGE_NUMBER);           // Tab index number
   this.m_struct_obj.tab_page_row=(int)this.GetProperty(CANV_ELEMENT_PROP_TAB_PAGE_ROW);                 // Tab row index
   this.m_struct_obj.tab_page_column=(int)this.GetProperty(CANV_ELEMENT_PROP_TAB_PAGE_COLUMN);           // Tab column index
   this.m_struct_obj.progress_bar_maximum=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM); // The upper bound of the range ProgressBar operates in
   this.m_struct_obj.progress_bar_minimum=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM); // The lower bound of the range ProgressBar operates in
   this.m_struct_obj.progress_bar_step=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP);       // ProgressBar increment needed to redraw it
   this.m_struct_obj.progress_bar_style=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE);     // ProgressBar style
   this.m_struct_obj.progress_bar_value=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE);     // Current ProgressBar value from Min to Max
   this.m_struct_obj.progress_bar_marquee_speed=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED);// Progress bar animation speed in case of Marquee style
//--- Save real properties

//--- Save string properties
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_OBJ),this.m_struct_obj.name_obj);   // Graphical element object name
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_RES),this.m_struct_obj.name_res);   // Graphical resource name
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TEXT),this.m_struct_obj.text);           // Graphical element text
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_DESCRIPTION),this.m_struct_obj.descript);// Graphical element description
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_TITLE),this.m_struct_obj.tooltip_title);// Tooltip title for the element
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT),this.m_struct_obj.tooltip_text);  // Tooltip text for the element
   //--- Save the structure to the uchar array
   ::ResetLastError();
   if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array))
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY,true);
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+


En el método que crea un objeto a partir de una estructura, escribiremos un registro de los valores de las propiedades del objeto a partir de los campos correspondientes de la estructura que hemos añadido hoy:

//+------------------------------------------------------------------+
//| Create the object from the structure                             |
//+------------------------------------------------------------------+
void CGCnvElement::StructToObject(void)
  {
//--- Save integer properties
   this.SetProperty(CANV_ELEMENT_PROP_ID,this.m_struct_obj.id);                                    // Element ID
   this.SetProperty(CANV_ELEMENT_PROP_TYPE,this.m_struct_obj.type);                                // Graphical element type
   this.SetProperty(CANV_ELEMENT_PROP_BELONG,this.m_struct_obj.belong);                            // Graphical element affiliation
   this.SetProperty(CANV_ELEMENT_PROP_NUM,this.m_struct_obj.number);                               // Element index in the list

   //---...
   //---...

   this.SetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH,this.m_struct_obj.border_right_area_width);      // Right edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH,this.m_struct_obj.border_top_area_width);          // Top edge area width
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_INITIAL_DELAY,this.m_struct_obj.tooltip_initial_delay);             // Tooltip display delay
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_AUTO_POP_DELAY,this.m_struct_obj.tooltip_auto_pop_delay);// Tooltip display duration
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY,this.m_struct_obj.tooltip_reshow_delay);// One element new tooltip display delay
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_SHOW_ALWAYS,this.m_struct_obj.tooltip_show_always);// Display a tooltip in inactive window
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_ICON,this.m_struct_obj.tooltip_icon);              // Icon displayed in a tooltip
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_IS_BALLOON,this.m_struct_obj.tooltip_is_balloon);  // Balloon tooltip
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_USE_FADING,this.m_struct_obj.tooltip_use_fading);  // Fade when showing/hiding a tooltip
   this.SetProperty(CANV_ELEMENT_PROP_GROUP,this.m_struct_obj.group);                            // Group the graphical element belongs to
   this.SetProperty(CANV_ELEMENT_PROP_TAB_SIZE_MODE,this.m_struct_obj.tab_size_mode);            // Tab size setting mode
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_NUMBER,this.m_struct_obj.tab_page_number);        // Tab index number
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_ROW,this.m_struct_obj.tab_page_row);              // Tab row index
   this.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_COLUMN,this.m_struct_obj.tab_page_column);        // Tab column index
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MAXIMUM,this.m_struct_obj.progress_bar_maximum);// The upper bound of the range ProgressBar operates in
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM,this.m_struct_obj.progress_bar_minimum);// The lower bound of the range ProgressBar operates in
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,this.m_struct_obj.progress_bar_step);    // ProgressBar increment needed to redraw it
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,this.m_struct_obj.progress_bar_style);  // ProgressBar style
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,this.m_struct_obj.progress_bar_value);  // Current ProgressBar value from Min to Max
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,this.m_struct_obj.progress_bar_marquee_speed);  // Progress bar animation speed in case of Marquee style
//--- Save real properties

//--- Save string properties
   this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,::CharArrayToString(this.m_struct_obj.name_obj));   // Graphical element object name
   this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,::CharArrayToString(this.m_struct_obj.name_res));   // Graphical resource name
   this.SetProperty(CANV_ELEMENT_PROP_TEXT,::CharArrayToString(this.m_struct_obj.text));           // Graphical element text
   this.SetProperty(CANV_ELEMENT_PROP_DESCRIPTION,::CharArrayToString(this.m_struct_obj.descript));// Graphical element description
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TITLE,::CharArrayToString(this.m_struct_obj.tooltip_title));// Tooltip title for the element
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT,::CharArrayToString(this.m_struct_obj.tooltip_text));  // Tooltip text for the element
  }
//+------------------------------------------------------------------+

Ahora el objeto del elemento gráfico se guardará correctamente en un archivo y se restaurará desde el mismo.


El destello que recorre la barra de progreso puede tener la forma de un paralelepípedo. Este será rectángulo biselado con los vértices de la cara superior desplazados 6 píxeles desde los vértices de la cara inferior. Para un objeto pequeño, este desplazamiento será suficiente para que el objeto parezca bastante inclinado. Pero a medida que aumente su altura, el bisel, fijado rígidamente en seis píxeles, se volverá indistinguible. Para corregir esta situación, deberemos hacer que el bisel sea un valor relativo: cuanto más alto sea el objeto, más acusado será el bisel. Entonces, para establecer el tamaño del desplazamiento de los vértices, usaremos la altura del objeto; luego, visualmente, el bisel quedará a 45 grados.

En el archivo \MQL5\Include\DoEasy\Objects\Graph\WForms\GlareObj.mqh, en el método que dibuja la forma del destello de un objeto en forma de paralelogramo, corregiremos la inicialización de los parámetros de las coordenadas del vértice. En lugar del número 6, asignaremos el valor de la altura del objeto gráfico:

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

Ahora los vértices estarán desplazados en el valor de la altura del objeto y el bisel siempre estará a unos 45 grados, independientemente de la altura del objeto.


Para crear un estilo de la barra de progreso "Bloques segmentados", podemos usar diferentes opciones, desde crear y dibujar directamente cada bloque hasta simplemente dibujarlos. Haremos esto: ya tenemos una barra de progreso completamente llena, y solo necesitaremos borrar el fondo de este objeto en aquellos lugares donde no haya bloques. Luego obtendremos la apariencia de una barra de progreso que constará de bloques segmentados. La desventaja de este enfoque es que se deberá calcular la ubicación de cada bloque. La ventaja de este enfoque es su simplicidad de implementación.

En el archivo \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\BarProgressBar.mqh, añadiremos las variables a la sección privada para almacenar los parámetros de los segmentos y declararemos un método para la segmentación del fondo del objeto:

//+------------------------------------------------------------------+
//| BarProgressBar object class of the ProgressBar control           |
//+------------------------------------------------------------------+
class CBarProgressBar : public CWinFormBase
  {
private:
   int               m_segment_s;                                 // Segment countdown start
   int               m_segment_x;                                 // Last segment X coordinate
   int               m_segment_w;                                 // Segment width
   int               m_segment_d;                                 // Distance between segments
//--- Segment the background
   void              Segmentation(void);
//--- (1) Set and (2) return a pause before displaying the effect
   void              SetShowDelay(const long delay)               { this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY,delay);             }
   ulong             ShowDelay(void)                              { return this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_RESHOW_DELAY);            }
//--- Initialize the properties
   void              Initialize(void);
protected:
//--- Protected constructor with object type, chart ID and subwindow
                     CBarProgressBar(const ENUM_GRAPH_ELEMENT_TYPE type,
                                     CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h);
public:

Las variables declaradas contendrán los parámetros iniciales a partir de los cuales se podrá calcular la ubicación de los segmentos. La anchura del segmento siempre será 3/4 de la altura, mientras que la distancia entre los segmentos se calculará a partir de la anchura del segmento resultante. Estos datos se registrarán al inicializarse el objeto, y luego se podrán usar para calcular la ubicación de cualquier segmento según su número. Como no estamos dibujando los segmentos en sí, sino los espacios entre ellos, el punto de partida será la anchura del primer segmento contado desde cero o desde uno. Si la altura de la barra de progreso es superior a tres píxeles, deberemos dibujar un espacio vacío de un píxel alrededor del borde del objeto en todos los lados. Esto separará los segmentos del borde exterior de la barra, convirtiéndolos en unidades visualmente independientes. En este caso, el rellenado del primer segmento deberá comenzar desde la unidad, es decir, habrá un espacio vacío de un píxel desde el borde del objeto hasta el primer segmento. Si la altura de la barra de progreso es de tres píxeles o menos, no necesitaremos dibujar un espacio vacío; este ocupará toda el área utilizable del objeto en el que se dibujan los segmentos. En este caso, la separación al comienzo del primer segmento deberá ser cero.

En la sección pública de la clase, escribiremos el método que retornará el estilo de la barra de progreso y los métodos que devolverán los valores de las variables de los parámetros de los segmentos, y también declararemos los métodos para calcular la anchura del segmento y la distancia entre ellos. También necesitaremos redefinir los métodos virtuales para eliminar el fondo del objeto:

public:
//--- Set the (1) animation speed in case of Marquee style, (2) display style, (3) increment value and (4) the current value of the ProgressBar control
   void              SetMarqueeAnimationSpeed(const int value)    { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,value);  }
   void              SetStyle(const ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE style) { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE,style); }
   void              SetStep(const int value)                     { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STEP,value);                }
   void              SetValue(const int value)                    { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,value);               }
   
//--- Return the display style
   ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE Style(void) const
                       { return (ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_STYLE); }

//--- Return (1) the X coordinate of the last segment, (2) segment width, (3) distance between segments and (4) segment countdown start
   int               SegmentX(void)                         const { return this.m_segment_x; }
   int               SegmentWidth(void)                     const { return this.m_segment_w; }
   int               SegmentDistance(void)                  const { return this.m_segment_d; }
   int               SegmentStart(void)                     const { return this.m_segment_s; }
   
//--- Calculate (1) the segment width and (2) the distance between segments
   int               CalculateSegmentWidth(void);
   int               CalculateSegmentDistance(const int width);

//--- Supported object properties (1) integer, (2) real and (3) string ones
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)  { return true; }

//--- 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);
   
//--- Constructor
                     CBarProgressBar(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h);
//--- Timer
   virtual void      OnTimer(void);
  };
//+------------------------------------------------------------------+

En los métodos de limpieza, colorearemos el fondo del elemento con su color de fondo. Como consecuencia, después de colorear, deberemos eliminar el fondo en aquellos lugares que supongan los espacios entre los segmentos. En estos métodos, llamaremos al método declarado en la sección privada para segmentar el fondo dibujado del objeto, y como son virtuales, siempre llamaremos a estos métodos al llamar al método de limpieza si el objeto es una barra de progreso o su sucesor.

En el método de inicialización de propiedades del objeto, introduciremos los valores predeterminados para las variables que almacenan los parámetros de segmentación. La coordenada X del último segmento y el inicio de la cuenta será igual a cero; a continuación, calcularemos directamente la anchura del segmento y la distancia entre ellos:

//+------------------------------------------------------------------+
//| Initialize the properties                                        |
//+------------------------------------------------------------------+
void CBarProgressBar::Initialize(void)
  {
   this.SetPaddingAll(0);
   this.SetMarginAll(0);
   this.SetBorderSizeAll(0);
   this.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
   this.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
   this.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
   this.SetShowDelay(2000);
   this.m_segment_x=0;
   this.m_segment_s=0;
   this.m_segment_w=this.CalculateSegmentWidth();
   this.m_segment_d=this.CalculateSegmentDistance(this.m_segment_w);
  }
//+------------------------------------------------------------------+


Vamos a echar un vistazo a los métodos declarados.

Método que limpia un elemento con rellenado de color y opacidad:

//+------------------------------------------------------------------+
//| Clear the element filling it with color and opacity              |
//+------------------------------------------------------------------+
void CBarProgressBar::Erase(const color colour,const uchar opacity,const bool redraw=false)
  {
//--- Fill the element having the specified color and the redrawing flag
   CGCnvElement::EraseNoCrop(colour,opacity,false);
//--- Segment the background
   this.Segmentation();
//--- If the object has a frame, draw it
   if(this.BorderStyle()!=FRAME_STYLE_NONE)
      this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),this.BorderStyle());
//--- Crop the excess and update the element with the specified redraw flag
   this.Crop();
   this.Update(redraw);
  }
//+------------------------------------------------------------------+

Aquí, en primer lugar, todo el fondo del elemento se pintará por completo, y luego llamaremos al método de segmentación, que borrará el fondo en aquellos lugares del objeto donde no debería haber segmentos. Además, si el objeto tiene un marco, este se dibujará; las partes del objeto que sobresalgan del contenedor principal se cortarán y el fondo del objeto se actualizará con el indicador de redibujado del gráfico transmitido al método.

Método que limpia el elemento con rellenado de gradiente:

//+------------------------------------------------------------------+
//| Clear the element with a gradient fill                           |
//+------------------------------------------------------------------+
void CBarProgressBar::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::EraseNoCrop(colors,opacity,vgradient,cycle,false);
//--- Segment the background
   this.Segmentation();
//--- If the object has a frame, draw it
   if(this.BorderStyle()!=FRAME_STYLE_NONE)
      this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),this.BorderStyle());
//--- Crop the excess and update the element with the specified redraw flag
   this.Crop();
   this.Update(redraw);
  }
//+------------------------------------------------------------------+

La lógica del método es idéntica a la lógica del método anterior, salvo que en lugar de transmitirse un solo color al método, se transmitirá un array de colores para el rellenado de gradiente y su indicador de dirección: vertical/horizontal y cíclico.


Método que calcula la anchura del segmento:

//+------------------------------------------------------------------+
//| Calculate the segment width                                      |
//+------------------------------------------------------------------+
int CBarProgressBar::CalculateSegmentWidth(void)
  {
   int w=(int)::ceil((this.Height()-2)/1.75);
   return(w>3 ? w : 3);
  }
//+------------------------------------------------------------------+

La anchura de cualquier segmento deberá ser 2/3 de su altura. Este método calculará la anchura del segmento según la altura del objeto de la barra de progreso. Tomaremos la altura del objeto menos dos píxeles. Más a menudo, la altura de la barra de progreso será de más de tres píxeles, lo cual significará que se dibujará un espacio libre de un píxel a cada lado de la barra de progreso a lo largo de su perímetro, lo que reducirá la altura visible del segmento en dos píxeles (uno por encima y otro por debajo). La altura resultante se dividirá por 1,75, lo cual dará una relación de lados de 3/4. Si la anchura resultante es inferior a tres píxeles, la anchura será igual a tres píxeles, ya que los segmentos que tienen una altura demasiado pequeña se verán mal con una anchura de 1-2 píxeles.


Método que calcula la distancia entre segmentos:

//+------------------------------------------------------------------+
//| Calculate the distance between segments                          |
//+------------------------------------------------------------------+
int CBarProgressBar::CalculateSegmentDistance(const int width)
  {
   int d=(int)::ceil(width/6);
   return(d<1 ? 1 : d);
  }
//+------------------------------------------------------------------+

Aquí todo es simple: Primero transmitiremos al método la anchura a partir de la cual se deberá calcular la separación. La distancia entre los segmentos deberá ser seis veces inferior a la anchura del bloque, pero no inferior a un píxel.


Método de segmentación del fondo:

//+------------------------------------------------------------------+
//| Segment the background                                           |
//+------------------------------------------------------------------+
void CBarProgressBar::Segmentation(void)
  {
//--- If the drawing style is not "Segmented blocks", leave
   if(this.Style()!=CANV_ELEMENT_PROGRESS_BAR_STYLE_BLOCKS)
      return;
//--- Reset the X coordinate of the segment
   this.m_segment_x=0;
//--- Get the block width as 3/4 of its height
   int w=this.SegmentWidth();
//--- Get the distance between the segments (six times less than the block width)
   int d=this.SegmentDistance();
//--- Get the countdown start
   this.m_segment_s=w+(this.Height()>3 ? 1 : 0);
//--- In the loop from the beginning of the countdown to the width of the progress bar with a step in the block width + indent between segments
   for(int i=this.SegmentStart();i<this.Width();i+=w+d)
     {
      //--- draw an empty fully transparent rectangle (erasing the element background)
      this.DrawRectangleFill(i,0,i+d-1,this.Height()-1,CLR_CANV_NULL,0);
      //--- Store the X coordinate of the segment
      this.m_segment_x=i;
     }
//--- If the height of the progress line is more than three pixels, draw a completely transparent frame around the perimeter
   if(this.Height()>3)
      this.DrawRectangle(0,0,this.Width()-1,this.Height()-1,CLR_CANV_NULL,0);
  }
//+------------------------------------------------------------------+

La lógica del método se detalla en los comentarios al código. Si el estilo de la barra de progreso es "Bloques segmentados", entonces recorreremos en un ciclo todo el fondo del objeto y borraremos el fondo donde no tenga que haber segmentos. Si la altura del objeto es más de tres píxeles, también borraremos el fondo a lo largo del perímetro con un borde de un píxel de anchura, lo cual hará que los segmentos se separen de los bordes de la barra de progreso.


En el objeto ProgressBar, añadiremos la capacidad de incluir una descripción que se muestre en la barra de progreso. La descripción no se mostrará por defecto, pero para incluirla bastará con definir su texto. La descripción será construida por un objeto CLabel constantemente adjunto al objeto. Obviamente, podremos crear tantos objetos como deseemos y colocarlos en los lugares correctos. Pero el objeto de descripción de la barra de progreso se creará por defecto al crear ProgressBar, y será más fácil acceder a él mediante métodos especiales.

En el archivo de clase CProgressBar \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ProgressBar.mqh, eliminaremos la variable de la sección privada para almacenar el número de pasos omitidos, ya que no era necesaria:

//+------------------------------------------------------------------+
//| ArrowLeftRightBox object class of WForms controls                |
//+------------------------------------------------------------------+
class CProgressBar : public CContainer
  {
private:
   int               m_progress_bar_max;  // Maximum progress bar width
   int               m_value_by_max;      // Value relative to Maximum
   int               m_steps_skipped;     // Number of skipped steps of increasing the width of the progress bar

//--- Create a new graphical object


En el mismo lugar, en la sección privada, declararemos las variables para almacenar las propiedades de la etiqueta de texto con una descripción de la barra de progreso:

//+------------------------------------------------------------------+
//| ArrowLeftRightBox object class of WForms controls                |
//+------------------------------------------------------------------+
class CProgressBar : public CContainer
  {
private:
   int               m_progress_bar_max;           // Maximum progress bar width
   int               m_value_by_max;               // Value relative to Maximum
   int               m_progress_bar_text_x;        // X coordinate of the text label with the description of the progress bar
   int               m_progress_bar_text_y;        // Y coordinate of the text label with the description of the progress bar
   color             m_progress_bar_text_color;    // Color of the text describing the progress bar
   uchar             m_progress_bar_text_opacity;  // Opacity of the text describing the progress bar
   string            m_progress_bar_text;          // Text describing the progress bar
   ENUM_FRAME_ANCHOR m_progress_bar_text_anchor;   // Method for binding the text with a progress bar description
//--- Create a new graphical object

Asimismo, necesitaremos variables para establecer y retornar las propiedades del objeto de etiqueta de texto que actúa como una descripción de la barra de progreso.


Los datos que se muestran en la línea de descripción pueden ser los reales, mostrando cada paso de la ejecución, o bien como un porcentaje de los pasos ya completados.

En la sección pública de la clase, añadiremos los métodos que retornan el valor Value en una representación de texto y el valor Value como un porcentaje representado por valores numéricos y de texto:

//--- (1) Set and (2) return the current value of the progress bar in the range from Min to Max as a number and (3) as a text
   void              SetValue(const int value);
   int               Value(void)                         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE);   }
   string            ValueDescription(void)              const { return (string)this.Value();                                          }
//--- Return the current progress bar value in the range from Min to Max as a percentage in the form of (1) a number and (2) a text
   double            ValuePercent(void) const;
   string            ValuePercentDescription(void)       const { return ::DoubleToString(this.ValuePercent(),2)+"%";                   }
   
//--- (1) Set and (2) return the upper bound of the ProgressBar operating range


Para acceder de forma simplificada al objeto de destello, en la sección pública de la clase, declararemos los métodos para establecer sus propiedades, añadiremos los métodos para obtener los punteros a los objetos adjuntos creadosy declararemos los métodos para trabajar con el objeto de descripción de la barra de progreso:

//--- (1) Set and (2) return the lower bound of the ProgressBar operating range
   void              SetMinimum(const int value)               { this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM,value);       }
   int               Minimum(void)                       const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MINIMUM); }
   
//--- Set (1) style, (2) opacity and (3) color for the glare object
   void              SetGlareStyle(const ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE style);
   void              SetGlareOpacity(const uchar opacity);
   void              SetGlareColor(const color clr);

//--- Return the pointer to the (1) progress bar object, (2) glare object and (3) the text label object with the progress bar description
   CBarProgressBar  *GetProgressBar(void)                { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,0);     }
   CGlareObj        *GetGlareObj(void)                   { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,0);            }
   CLabel           *GetProgressDescriptionObj(void)     { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_LABEL,0);                }

//--- Set the (1) text, (2) color
//--- (3) opacity, (4) X, (5) Y coordinates, (6) font, (7) size and (8) font flags to the progress bar text label
   void              SetBarDescriptionText(const string text,const bool redraw=false);
   void              SetBarDescriptionColor(const color clr,const bool redraw=false,const bool set_init_color=false);
   void              SetBarDescriptionOpacity(const uchar opacity,const bool redraw=false);
   void              SetBarDescriptionX(const int x,const bool redraw=false);
   void              SetBarDescriptionY(const int y,const bool redraw=false);
   void              SetBarDescriptionFontName(const string font,const bool redraw=false);
   void              SetBarDescriptionFontSize(const int size,const bool relative=false,const bool redraw=false);
   void              SetBarDescriptionFontFlags(const uint flags,const bool redraw=false);
   
//--- (1) hide and (2) display the progress bar text label
   void              HideBarDescription(void);
   void              ShowBarDescription(void);
     
//--- Resets the progress bar values to the set minimum


En el constructor de clases, inicializaremos las variables declaradas con los valores predeterminados:

//+------------------------------------------------------------------+
//| Initialize the element properties                                |
//+------------------------------------------------------------------+
void CProgressBar::Initialize(void)
  {
   this.SetBorderSizeAll(1);
   this.SetBorderStyle(FRAME_STYLE_SIMPLE);
   this.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BACK_COLOR,true);
   this.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BORDER_COLOR,true);
   this.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
   this.SetMarqueeAnimationSpeed(10);
   this.SetMaximum(100);
   this.SetMinimum(0);
   this.SetValue(50);
   this.SetStep(10);
   this.SetStyle(CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS);
   this.m_progress_bar_max=this.Width()-this.BorderSizeLeft()-this.BorderSizeRight();
   this.m_value_by_max=this.Value()*100/this.Maximum();
   this.m_progress_bar_text="";
   this.m_progress_bar_text_x=1;
   this.m_progress_bar_text_y=0;
   this.m_progress_bar_text_color=CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR;
   this.m_progress_bar_text_opacity=255;
   this.m_progress_bar_text_anchor=FRAME_ANCHOR_LEFT_TOP;
  }
//+------------------------------------------------------------------+


En el método que crea el objeto de barra de progreso, también crearemos un objeto resaltado. Entonces, añadiremos allí la creación de la descripción del objeto de barra de progreso:

//+------------------------------------------------------------------+
//| Create the progress bar object                                   |
//+------------------------------------------------------------------+
void CProgressBar::CreateProgressBar(void)
  {
//--- Set the length of the progress bar equal to the object Value()
//--- The height of the progress bar is set equal to the height of the object minus the top and bottom border sizes
   int w=this.CalculateProgressBarWidth();
   int h=this.Height()-this.BorderSizeTop()-this.BorderSizeBottom();
   if(h<1)
      h=1;
//--- Create the progress bar object
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,0,0,w,h,clrNONE,255,false,false);
//--- Create a description of the progress bar, get the text label object and set the default parameters
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_LABEL,1,0,this.Width()-2,this.Height()-2,clrNONE,0,false,false);
   CLabel *obj=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_LABEL,0);
   if(obj!=NULL)
     {
      obj.SetText(this.m_progress_bar_text);
      obj.SetFontName(DEF_FONT);
      obj.SetFontSize(DEF_FONT_SIZE);
      obj.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP);
      obj.SetTextAlign(ANCHOR_LEFT_UPPER);
      this.HideBarDescription();
     }
//--- Create the glare object
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,0,0,w,h,CLR_CANV_NULL,0,true,false);
//--- Add the current CProgressBar object to the list of active elements of the collection
   this.AddObjToListActiveElements();
  }
//+------------------------------------------------------------------+

Inmediatamente después de crear la etiqueta de texto, obtendremos el puntero a este objeto y configuraremos algunas propiedades para él: el texto, el nombre de fuente, el tamaño de fuente, el método de anclaje y la alineación del texto, y luego ocultaremos el objeto creado. Los parámetros restantes del objeto se podrán obtener más tarde obteniendo el puntero a este objeto usando el método GetProgressDescriptionObj() y luego configurando las propiedades necesarias para el objeto ya recibido.
Si intentamos crear un objeto de barra de progreso con una altura inferior a un píxel, nada funcionará: el objeto no se podrá crear con un tamaño cero. Por lo tanto, introduciremos una verificación para el tamaño cero y lo corregiremos de ser así.


En el método que crea un nuevo objeto gráfico, añadiremos un bloque de código para crear el objeto de etiqueta de texto:

//+------------------------------------------------------------------+
//| Create a new graphical object                                    |
//+------------------------------------------------------------------+
CGCnvElement *CProgressBar::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                             const int obj_num,
                                             const string descript,
                                             const int x,
                                             const int y,
                                             const int w,
                                             const int h,
                                             const color colour,
                                             const uchar opacity,
                                             const bool movable,
                                             const bool activity)
  {
   CGCnvElement *element=NULL;
   switch(type)
     {
      case GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR  :
         element=new CBarProgressBar(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ         :
         element=new CGlareObj(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_LABEL             :
         element=new CLabel(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      default:
        break;
     }
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type));
   return element;
  }
//+------------------------------------------------------------------+

Ahora el objeto ProgressBar podrá crear objetos vinculados con los tipos «Barra de progreso», «Resaltado» y «Etiqueta de texto».


El objeto «Barra de progreso» será un control activo que se procesará en el temporizador. En este momento, el temporizador estará procesando un resaltado que se ejecutará a lo largo de la barra de progreso, pero también necesitaremos procesar en el temporizador la barra de progreso mostrada en el estilo "Marquee". En este modo, la barra de progreso tendrá una anchura fija igual a la mitad de la anchura del objeto completo, y se desplazará constantemente dentro del objeto ProgressBar, mostrando así el progreso de un proceso cuyo número de iteraciones no se conocerá de antemano.

Ahora añadiremos el siguiente procesamiento de la barra de progreso al manejador del temporizador del objeto:

//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void CProgressBar::OnTimer(void)
  {
   CBarProgressBar *bar=this.GetProgressBar();
   if(bar!=NULL)
     {
      if(bar.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE)
        {
         int x=bar.CoordX()+8;
         if(x>this.RightEdge())
            x=this.CoordX()-bar.Width();
         bar.Move(x,bar.CoordY());
         bar.Redraw(true);
        }
      else
         bar.OnTimer();
     }
  }
//+------------------------------------------------------------------+

Aquí, si el estilo de visualización de la barra de progreso es «Desplazamiento continuo», obtendremos la coordenada X en la que se debe desplazar el objeto. Por el momento, añadiremos un desplazamiento de 8 píxeles a la coordenada X actual y cambiaremos la barra de progreso a la nueva coordenada en horizontal. Primero verificaremos que el objeto de la barra de progreso esté completamente fuera de su contenedor a la derecha; en este caso, configuraremos su coordenada X para que el objeto tenga el valor de su anchura a la izquierda más allá del borde izquierdo de su contenedor. El método Redraw(), además de redibujar el objeto, realizará una función más: cortará las partes del objeto que sobresalgan de los bordes del contenedor. Por lo tanto, hemos creado un ciclo completo de desplazamiento de la barra de progreso dentro de su contenedor y, al mismo tiempo, se cortan las partes que sobresalen más allá de los bordes.
Si el objeto tiene un estilo de representación diferente, llamaremos al temporizador del objeto de la barra de progreso para mostrar el objeto resaltado.


Como ahora tenemos el estilo de dibujado de la barra de progreso "Bloques segmentados", necesitaremos mejorar el método que establece el valor de la barra de progreso. Actualmente, este método, tras establecer el valor, cambia inmediatamente el tamaño del objeto según el nuevo valor. No obstante, como los bloques segmentados no deben dibujarse píxel a píxel, sino bloque a bloque, deberemos comprender cuántos bloques pueden caber en la anchura establecida de la barra de progreso. Si la anchura es suficiente para dibujar un nuevo segmento, el objeto cambiará su anchura ya establecida en su propiedad. Si la anchura no es suficiente (el segmento dibujado actual estará incompleto, cortado), deberemos restar la anchura de un segmento a la anchura establecida del objeto y establecer exactamente dicha anchura para la barra de progreso, luego se dibujará solo el penúltimo segmento con todos los anteriores. Por lo tanto, la anchura del objeto cambiará solo cuando todos los segmentos se puedan dibujar completamente sin recortarlos, lo cual nos ofrecerá un cambio bloque a bloque en la anchura visible de la barra de progreso. En este caso, el valor Value siempre será el que se ha transmitido al objeto. Es decir, solo cambiaremos visualmente la anchura del objeto de forma discreta, y el valor Value en este será siempre el que está establecido para él.

Vamos a introducir las mejoras descritas anteriormente en el método que establece el valor actual de la barra de progreso:

//+------------------------------------------------------------------+
//| Set the current value of the progress bar                        |
//+------------------------------------------------------------------+
void CProgressBar::SetValue(const int value)
  {
//--- Correct the value passed to the method and set it to the object property
   int v=(value<this.Minimum() ? this.Minimum() : value>this.Maximum() ? this.Maximum() : value);
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,v);
//--- Get the progress bar object
   CBarProgressBar *bar=this.GetProgressBar();
   if(bar!=NULL)
     {
      //--- Set 'value' for the progress bar
      bar.SetValue(v);
      //--- Calculate the width of the progress bar object
      int w=this.CalculateProgressBarWidth();
      //--- If the calculated width is greater than the maximum possible value, set the maximum width
      if(w>this.m_progress_bar_max)
         w=this.m_progress_bar_max;
      //--- If the width is less than 1, then
      if(w<1)
        {
         //--- hide the progress bar and redraw the chart to display changes immediately
         bar.Hide();
         ::ChartRedraw(bar.ChartID());
        }
      //--- If the width value is not less than 1
      else
        {
         //--- If the progress bar is hidden, display it and
         if(!bar.IsVisible())
            bar.Show();
         //--- If the style of the progress bar is "Continuous line", change the width of the object to the calculated value
         if(this.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS)
            bar.Resize(w,bar.Height(),true);
         //--- Otherwise, if the progress bar style is "Segmented blocks"
         else if(this.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_BLOCKS)
           {
            //--- Segment width including indent
            int wd=bar.SegmentWidth()+bar.SegmentDistance();
            //--- The number of segments that fit the width of the progress bar
            int num=w/(wd>0 ? wd : 1);
            //--- The X coordinate of the last segment calculated from the beginning of the segment count
            int wx=bar.SegmentStart()+num*wd;
            //--- If the calculated width of the progress bar is less than the coordinate of the last segment, and this is not the last segment,
            //--- set the width of the progress bar equal to the penultimate segment coordinate
            if(w<wx-bar.SegmentDistance() && w<this.m_progress_bar_max)
               w=wx-wd+bar.SegmentDistance();
            //--- If the calculated width of the progress bar is less than the coordinate of the last segment, or it is not the last segment,
            if(w<wx-bar.SegmentDistance() || w==this.m_progress_bar_max)
               //--- change the size of the progress bar in accordance with the received and adjusted width
               bar.Resize(w,bar.Height(),true);
           }
        }
      //--- If the progress bar description text is set,
      if(this.m_progress_bar_text!="")
        {
         //--- get the object description of the progress bar and bring it to the foreground
         CLabel *obj=this.GetProgressDescriptionObj();
         if(obj!=NULL)
            obj.BringToTop();
        }
     }
  }
//+------------------------------------------------------------------+

La lógica del método se explica con detalle en los comentarios al código. El texto de la descripción también deberá procesarse: cada vez que cambie el valor de la barra de progreso, es posible que también debamos cambiar la descripción. Por lo tanto, este objeto siempre se pondrá en primer plano si el texto está configurado para él.


El método que calcula la anchura de la barra de progreso deberá modificarse para que retorne la mitad del tamaño del control ProgressBar si el estilo de la barra de progreso se establece en "Desplazamiento continuo":

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

  {
   this.m_value_by_max=this.Value()*100/this.Maximum();
   return(this.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE ? this.m_progress_bar_max/2 : this.m_progress_bar_max*this.m_value_by_max/100);
  }
//+------------------------------------------------------------------+

Ahora el método retornará el tamaño correcto de la barra de desplazamiento para cualquiera de sus estilos de visualización.


En el método que establece la nueva anchura, deberemos asignar la anchura establecida en el objeto al objeto de etiqueta de texto utilizado para mostrar la descripción de la barra de progreso:

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

Si el tamaño del objeto de etiqueta de texto no se ajusta al tamaño de la barra de progreso, es posible que el texto escrito con el tamaño aparente de la barra de progreso no quepa en un objeto cuyo anchura sea inferior a lo que parece visualmente. Esto hará que el texto simplemente se corte. Por ello, es necesario que la etiqueta de texto y la barra de progreso tengan las mismas dimensiones.

Vamos a ver los métodos auxiliares utilizados para facilitar el acceso a las propiedades de los objetos vinculados al control ProgressBar.

Método que establece el estilo para el objeto de destello:

//+------------------------------------------------------------------+
//| Set the glare object style                                       |
//+------------------------------------------------------------------+
void CProgressBar::SetGlareStyle(const ENUM_CANV_ELEMENT_VISUAL_EFF_STYLE style)
  {
   CGlareObj *obj=this.GetGlareObj();
   if(obj==NULL)
      return;
   obj.SetVisualEffectStyle(style);
  }
//+------------------------------------------------------------------+

Aquí, obtendremos el puntero al objeto de destello y estableceremos el estilo para el objeto resultante.


Método que establece la opacidad para el objeto de destello:

//+------------------------------------------------------------------+
//| Set the opacity of the highlight object                          |
//+------------------------------------------------------------------+
void CProgressBar::SetGlareOpacity(const uchar opacity)
  {
   CGlareObj *obj=this.GetGlareObj();
   if(obj==NULL)
      return;
   obj.SetOpacity(opacity);
  }
//+------------------------------------------------------------------+

Primero obtendremos el puntero al objeto de destello y luego estableceremos el valor de opacidad para el objeto resultante.


Método que establece un color para el objeto de destello:

//+------------------------------------------------------------------+
//| Set the color for the glare object                               |
//+------------------------------------------------------------------+
void CProgressBar::SetGlareColor(const color clr)
  {
   CGlareObj *obj=this.GetGlareObj();
   if(obj==NULL)
      return;
   obj.SetColor(clr);
  }
//+------------------------------------------------------------------+

Ahora obtendremos el puntero al objeto de destello y estableceremos el valor de color transmitido al método para el objeto resultante.


Método que establece un texto para la etiqueta de texto de la barra de progreso:

//+------------------------------------------------------------------+
//| Set a text to the text label of the progress bar                 |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionText(const string text,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text=text;
   obj.SetText(text);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+

Aquí, obtendremos el puntero al objeto de etiqueta de texto. Luego estableceremos la variable m_progress_bar_text en el texto transmitido al método y estableceremos este texto en el objeto. Como el texto se mostrará directamente en el objeto, para evitar la superposición de un texto sobre otro, deberemos borrar el fondo y todo lo que se ha dibujado en él. A continuación, mostraremos el texto y actualizaremos el elemento.


Método que establece el color del texto de la barra de progreso en la etiqueta de texto:

//+------------------------------------------------------------------+
//| Set the text color of the progress bar to the text label         |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionColor(const color clr,const bool redraw=false,const bool set_init_color=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text_color=clr;
   obj.SetForeColor(clr,false);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+

Después obtendremos el puntero al objeto de etiqueta de texto, estableceremos la variable m_progress_bar_text_color en el color transmitido al método y luego estableceremos este color en el objeto como el color del texto. Como el texto se mostrará directamente, para evitar la superposición de un texto sobre otro, borraremos el fondo de la etiqueta de texto y, a continuación, mostraremos el texto y actualizaremos el elemento.


Método que establece la opacidad en la etiqueta de texto de la barra de progreso:

//+------------------------------------------------------------------+
//| Set opacity to the progress bar text label                       |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionOpacity(const uchar opacity,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text_opacity=opacity;
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+

La lógica del método es idéntica a la anterior, pero estableciendo el valor de opacidad en la variable y el objeto correspondientes.


Método que establece la coordenada x de la etiqueta de texto de la barra de progreso:

//+------------------------------------------------------------------+
//| Set the X coordinate to the text label of the progress bar       |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionX(const int x,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text_x=x;
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+


Método que establece la coordenada Y en la etiqueta de texto de la barra de progreso:

//+------------------------------------------------------------------+
//| Set the Y coordinate to the text label of the progress bar       |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionY(const int y,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   this.m_progress_bar_text_y=y;
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+


Método que establece la fuente en la etiqueta de texto de la barra de progreso:

//+------------------------------------------------------------------+
//| Set the font in the text label of the progress bar               |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionFontName(const string font,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetFontName(font);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+


Método que establece el tamaño de fuente en la etiqueta de texto de la barra de progreso:

//+------------------------------------------------------------------+
//| Set the font size to the progress bar text label                 |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionFontSize(const int size,const bool relative=false,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetFontSize(size,relative);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+


Método que establece las banderas de fuente en la etiqueta de texto de la barra de progreso:

//+------------------------------------------------------------------+
//| Set the font flags in the text label of the progress bar         |
//+------------------------------------------------------------------+
void CProgressBar::SetBarDescriptionFontFlags(const uint flags,const bool redraw=false)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetFontFlags(flags);
   obj.Erase(false);
   obj.Text(this.m_progress_bar_text_x,this.m_progress_bar_text_y,this.m_progress_bar_text,this.m_progress_bar_text_color,this.m_progress_bar_text_opacity,this.m_progress_bar_text_anchor);
   obj.Update(redraw);
  }
//+------------------------------------------------------------------+

Todos los métodos mostrados arriba tienen la misma lógica y nos permiten establecer rápidamente los parámetros de fuente y texto deseados en la descripción de la barra de progreso (en la etiqueta de texto). Los cambios se muestran directamente en la pantalla.


Si necesitamos ocultar la descripción de la barra de progreso, además de ocultarla, el objeto deberá establecer su bandera de no visualización, ya que se pondrá constantemente en primer plano, lo cual hará que se visualice. Si, después de ocultar un objeto, configuramos la bandera de no visualización para él, dicho objeto no se redibujará hasta que obtenga la bandera de visualización nuevamente.

Método para ocultar la etiqueta de texto de la barra de progreso:

//+------------------------------------------------------------------+
//| Hide the progress bar text label                                 |
//+------------------------------------------------------------------+
void CProgressBar::HideBarDescription(void)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetDisplayed(false);
   obj.Hide();
  }
//+------------------------------------------------------------------+

Aquí, obtendremos la etiqueta de texto del objeto con una descripción de la barra de progreso, configuraremos la bandera de no visualización y ocultaremos el objeto.


Método que muestra la etiqueta de texto de la barra de progreso:

//+------------------------------------------------------------------+
//| Display a text label for the progress bar                        |
//+------------------------------------------------------------------+
void CProgressBar::ShowBarDescription(void)
  {
   CLabel *obj=this.GetProgressDescriptionObj();
   if(obj==NULL)
      return;
   obj.SetDisplayed(true);
   obj.Show();
  }
//+------------------------------------------------------------------+

Aquí, obtendremos el puntero al objeto de etiqueta de texto con la descripción de la barra de progreso, configuraremos la bandera de visualización y mostraremos el objeto.


Método que retorna el valor actual de la barra de progreso en el rango de Min a Max como un porcentaje:

//+------------------------------------------------------------------+
//| Return the current value of the progress bar                     |
//| in the range from Min to Max as a percentage                     |
//+------------------------------------------------------------------+
double CProgressBar::ValuePercent(void) const
  {
   double range=this.Maximum()-this.Minimum();
   return(this.Value()*100.0/(range>0 ? range : 1));
  }
//+------------------------------------------------------------------+

Si necesitamos obtener el valor Value de la barra de progreso como un porcentaje del rango de Min a Max, este método calculará y retornará un valor que indicará qué porcentaje del rango especificado ha sido procesado ya. El 100% será la diferencia entre los valores máximo y mínimo establecidos en el objeto ProgressBar.

Veamos lo que tenemos ahora.


Simulación

Para la prueba, tomaremos el asesor experto del artículo anterior y lo guardaremos en la nueva carpeta \MQL5\Experts\TestDoEasy\Part128\ con el nuevo nombre TestDoEasy128.mq5.

Vamos a crear una enumeración de los estilos de la barra de progreso para la versión en inglés de la compilación y la versión de la compilación en el idioma del usuario:

//--- enumerations by compilation language
#ifdef COMPILE_EN
enum ENUM_AUTO_SIZE_MODE
  {
   AUTO_SIZE_MODE_GROW=CANV_ELEMENT_AUTO_SIZE_MODE_GROW,                               // Grow
   AUTO_SIZE_MODE_GROW_SHRINK=CANV_ELEMENT_AUTO_SIZE_MODE_GROW_SHRINK                  // Grow and Shrink
  };
enum ENUM_BORDER_STYLE
  {
   BORDER_STYLE_NONE=FRAME_STYLE_NONE,                                                 // None
   BORDER_STYLE_SIMPLE=FRAME_STYLE_SIMPLE,                                             // Simple
   BORDER_STYLE_FLAT=FRAME_STYLE_FLAT,                                                 // Flat
   BORDER_STYLE_BEVEL=FRAME_STYLE_BEVEL,                                               // Embossed (bevel)
   BORDER_STYLE_STAMP=FRAME_STYLE_STAMP,                                               // Embossed (stamp)
  };
enum ENUM_CHEK_STATE
  {
   CHEK_STATE_UNCHECKED=CANV_ELEMENT_CHEK_STATE_UNCHECKED,                             // Unchecked
   CHEK_STATE_CHECKED=CANV_ELEMENT_CHEK_STATE_CHECKED,                                 // Checked
   CHEK_STATE_INDETERMINATE=CANV_ELEMENT_CHEK_STATE_INDETERMINATE,                     // Indeterminate
  };
enum ENUM_ELEMENT_ALIGNMENT
  {
   ELEMENT_ALIGNMENT_TOP=CANV_ELEMENT_ALIGNMENT_TOP,                                   // Top
   ELEMENT_ALIGNMENT_BOTTOM=CANV_ELEMENT_ALIGNMENT_BOTTOM,                             // Bottom
   ELEMENT_ALIGNMENT_LEFT=CANV_ELEMENT_ALIGNMENT_LEFT,                                 // Left
   ELEMENT_ALIGNMENT_RIGHT=CANV_ELEMENT_ALIGNMENT_RIGHT,                               // Right
  };
enum ENUM_ELEMENT_TAB_SIZE_MODE
  {
   ELEMENT_TAB_SIZE_MODE_NORMAL=CANV_ELEMENT_TAB_SIZE_MODE_NORMAL,                     // Fit to tab title text width
   ELEMENT_TAB_SIZE_MODE_FIXED=CANV_ELEMENT_TAB_SIZE_MODE_FIXED,                       // Fixed size
   ELEMENT_TAB_SIZE_MODE_FILL=CANV_ELEMENT_TAB_SIZE_MODE_FILL,                         // Fit TabControl Size
  };
enum ENUM_ELEMENT_PROGRESS_BAR_STYLE
  {
   ELEMENT_PROGRESS_BAR_STYLE_BLOCKS=CANV_ELEMENT_PROGRESS_BAR_STYLE_BLOCKS,           // Blocks
   ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS=CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS,   // Continuous
   ELEMENT_PROGRESS_BAR_STYLE_MARQUEE=CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE,         // Marquee
  };  
#else 
enum ENUM_AUTO_SIZE_MODE
  {
   AUTO_SIZE_MODE_GROW=CANV_ELEMENT_AUTO_SIZE_MODE_GROW,                               // Increase only
   AUTO_SIZE_MODE_GROW_SHRINK=CANV_ELEMENT_AUTO_SIZE_MODE_GROW_SHRINK                  // Increase and decrease
  };
enum ENUM_BORDER_STYLE
  {
   BORDER_STYLE_NONE=FRAME_STYLE_NONE,                                                 // No frame
   BORDER_STYLE_SIMPLE=FRAME_STYLE_SIMPLE,                                             // Simple frame
   BORDER_STYLE_FLAT=FRAME_STYLE_FLAT,                                                 // Flat frame
   BORDER_STYLE_BEVEL=FRAME_STYLE_BEVEL,                                               // Embossed (convex)
   BORDER_STYLE_STAMP=FRAME_STYLE_STAMP,                                               // Embossed (concave)
  };
enum ENUM_CHEK_STATE
  {
   CHEK_STATE_UNCHECKED=CANV_ELEMENT_CHEK_STATE_UNCHECKED,                             // Unchecked
   CHEK_STATE_CHECKED=CANV_ELEMENT_CHEK_STATE_CHECKED,                                 // Checked
   CHEK_STATE_INDETERMINATE=CANV_ELEMENT_CHEK_STATE_INDETERMINATE,                     // Undefined
  };
enum ENUM_ELEMENT_ALIGNMENT
  {
   ELEMENT_ALIGNMENT_TOP=CANV_ELEMENT_ALIGNMENT_TOP,                                   // Top
   ELEMENT_ALIGNMENT_BOTTOM=CANV_ELEMENT_ALIGNMENT_BOTTOM,                             // Bottom
   ELEMENT_ALIGNMENT_LEFT=CANV_ELEMENT_ALIGNMENT_LEFT,                                 // Left
   ELEMENT_ALIGNMENT_RIGHT=CANV_ELEMENT_ALIGNMENT_RIGHT,                               // Right
  };
enum ENUM_ELEMENT_TAB_SIZE_MODE
  {
   ELEMENT_TAB_SIZE_MODE_NORMAL=CANV_ELEMENT_TAB_SIZE_MODE_NORMAL,                     // By tab title width
   ELEMENT_TAB_SIZE_MODE_FIXED=CANV_ELEMENT_TAB_SIZE_MODE_FIXED,                       // Fixed size
   ELEMENT_TAB_SIZE_MODE_FILL=CANV_ELEMENT_TAB_SIZE_MODE_FILL,                         // By TabControl size
  };
enum ENUM_ELEMENT_PROGRESS_BAR_STYLE
  {
   ELEMENT_PROGRESS_BAR_STYLE_BLOCKS=CANV_ELEMENT_PROGRESS_BAR_STYLE_BLOCKS,           // Segmented blocks
   ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS=CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS,   // Continuous bar
   ELEMENT_PROGRESS_BAR_STYLE_MARQUEE=CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE,         // Continuous scrolling
  };  
#endif 
//--- input parameters


Luego añadiremos dos nuevos parámetros a los parámetros de entrada: el estilo de la barra de progreso y la bandera para mostrar los valores de la barra de progreso como un porcentaje:

//--- input parameters
sinput   bool                          InpMovable           =  true;                   // Panel Movable flag
sinput   ENUM_INPUT_YES_NO             InpAutoSize          =  INPUT_YES;              // Panel Autosize
sinput   ENUM_AUTO_SIZE_MODE           InpAutoSizeMode      =  AUTO_SIZE_MODE_GROW;    // Panel Autosize mode
sinput   ENUM_BORDER_STYLE             InpFrameStyle        =  BORDER_STYLE_SIMPLE;    // Label border style
sinput   ENUM_ANCHOR_POINT             InpTextAlign         =  ANCHOR_CENTER;          // Label text align
sinput   ENUM_INPUT_YES_NO             InpTextAutoSize      =  INPUT_NO;               // Label autosize
sinput   ENUM_ANCHOR_POINT             InpCheckAlign        =  ANCHOR_LEFT;            // Check flag align
sinput   ENUM_ANCHOR_POINT             InpCheckTextAlign    =  ANCHOR_LEFT;            // Check label text align
sinput   ENUM_CHEK_STATE               InpCheckState        =  CHEK_STATE_UNCHECKED;   // Check flag state
sinput   ENUM_INPUT_YES_NO             InpCheckAutoSize     =  INPUT_YES;              // CheckBox autosize
sinput   ENUM_BORDER_STYLE             InpCheckFrameStyle   =  BORDER_STYLE_NONE;      // CheckBox border style
sinput   ENUM_ANCHOR_POINT             InpButtonTextAlign   =  ANCHOR_CENTER;          // Button text align
sinput   ENUM_INPUT_YES_NO             InpButtonAutoSize    =  INPUT_YES;              // Button autosize
sinput   ENUM_AUTO_SIZE_MODE           InpButtonAutoSizeMode=  AUTO_SIZE_MODE_GROW;    // Button Autosize mode
sinput   ENUM_BORDER_STYLE             InpButtonFrameStyle  =  BORDER_STYLE_NONE;      // Button border style
sinput   bool                          InpButtonToggle      =  true ;                  // Button toggle flag
sinput   bool                          InpButtListMSelect   =  false;                  // ButtonListBox Button MultiSelect flag
sinput   bool                          InpListBoxMColumn    =  true;                   // ListBox MultiColumn flag
sinput   bool                          InpTabCtrlMultiline  =  false;                   // Tab Control Multiline flag
sinput   ENUM_ELEMENT_ALIGNMENT        InpHeaderAlignment   =  ELEMENT_ALIGNMENT_TOP;  // TabHeader Alignment
sinput   ENUM_ELEMENT_TAB_SIZE_MODE    InpTabPageSizeMode   =  ELEMENT_TAB_SIZE_MODE_FILL; // TabHeader Size Mode
sinput   int                           InpTabControlX       =  10;                     // TabControl X coord
sinput   int                           InpTabControlY       =  20;                     // TabControl Y coord
sinput   ENUM_CANV_ELEMENT_TOOLTIP_ICON InpTooltipIcon      =  CANV_ELEMENT_TOOLTIP_ICON_NONE;  // Tooltip Icon
sinput   string                        InpTooltipTitle      =  "";                     // Tooltip Title
sinput   ENUM_ELEMENT_PROGRESS_BAR_STYLE InpProgressBarStyle=  ELEMENT_PROGRESS_BAR_STYLE_BLOCKS;  // Progress Bar Style
sinput   bool                          InpProgressBarPercent=  false;                  // Show progress bar values as a percentage
//--- global variables


En el controlador OnInit() del asesor experto, al crear el control ProgressBar, configurará el estilo de la barra de progreso de la variable en los ajustes y establecerá los parámetros para describir la barra de progreso:

                     //--- If this is the first tab and the second panel
                     if(n==0 && j==1)
                       {
                        //--- Create the ProgressBar control on it
                        if(split_container.CreateNewElement(j,GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,4,4,100,12,clrNONE,255,false,false))
                          {
                           CProgressBar *progress_bar=split_container.GetPanelElementByType(j,GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,0);
                           if(progress_bar!=NULL)
                             {
                              //--- Set the style of the progress bar specified in the EA settings
                              progress_bar.SetStyle((ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE)InpProgressBarStyle);
                              //--- Set the parameters for describing the progress bar
                              progress_bar.SetBarDescriptionText("Progress Bar ");
                              progress_bar.SetBarDescriptionColor(panel.BackgroundColor());
                              progress_bar.SetBarDescriptionOpacity(255);
                              progress_bar.SetBarDescriptionY(-2);
                             }
                          }
                       }


En el ciclo de visualización y redibujado de todos los paneles, mostraremos una descripción con el estilo de la barra de progreso "Línea continua", y en cada iteración del ciclo de incremento del valor Value de la barra de progreso, mostraremos los valores Value ​en la descripción dependiendo de la configuración: en porcentaje o en pasos completados. Al final del ciclo, escribiremos en la descripción de la barra de progreso un mensaje sobre la finalización del ciclo de incremento con la fuente cambiada al estilo Bold.
Para configurar los parámetros del objeto de destello, utilizaremos los métodos de acceso rápido a este objeto:

//--- Display and redraw all created panels
   for(int i=0;i<FORMS_TOTAL;i++)
     {
      //--- Get the panel object
      pnl=engine.GetWFPanel("WinForms Panel"+(string)i);
      if(pnl!=NULL)
        {
         //--- display and redraw the panel
         pnl.Show();
         pnl.Redraw(true);
         //--- Get the TabControl object from the panel
         CTabControl *tc=pnl.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,0);
         //--- Get the SplitContainer object from the first tab of the TabControl object
         CSplitContainer *sc=tc.GetTabElementByType(0,GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,0);
         //--- Get the second panel from the SplitContainer object
         CSplitContainerPanel *scp=sc.GetPanel(1);
         //--- Get the ProgressBar object from the received panel
         CProgressBar *pb=scp.GetElementByType(GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,0);
         //--- Wait for 1/10 of a second
         Sleep(100);
         //--- Get the width of the ProgressBar object
         int w=pb.Width();
         //--- In the loop, increase the width of the ProgressBar by 180 pixels with a delay of 1/50
         for(int n=0;n<180;n++)
           {
            Sleep(20);
            pb.Resize(w+n,pb.Height(),true);
           }
         //--- Set the values for PerformStep of the ProgressBar object
         pb.SetValuesForProcessing(0,350,1,0);
         //--- Reset ProgressBar to minimum
         pb.ResetProgressBar();
         //--- If the style of the progress bar is "Continuous line", display the progress bar description
         if(pb.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS)
            pb.ShowBarDescription();
         //--- Wait for 1/5 second
         Sleep(200);
         //--- If the style of the progress bar is not "Continuous scrolling"
         if(pb.Style()!=CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE)
           {
            //--- In the loop from the minimum to the maximum value of ProgressBar
            for(int n=0;n<=pb.Maximum();n++)
              {
               //--- call the method for increasing the progress bar by a given step with a wait of 1/5 second
               pb.PerformStep();
               //--- Set the number of completed steps in the description of the progress bar
               pb.SetBarDescriptionText("Progress Bar, pass: "+(InpProgressBarPercent ? pb.ValuePercentDescription() : pb.ValueDescription()));
               Sleep(20);
              }
           }
         //--- Wait for 1/2 second, set the description font type to Bold and write a completion message on the progress bar
         Sleep(500);
         pb.SetBarDescriptionFontFlags(FW_BOLD);
         pb.SetBarDescriptionText("Progress Bar: Done");
         //--- Set the glare object type - rectangle, opacity 40, color - white
         pb.SetGlareStyle(CANV_ELEMENT_VISUAL_EFF_STYLE_RECTANGLE);
         pb.SetGlareOpacity(40);
         pb.SetGlareColor(clrWhite);
        }
     }
        
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+


Vamos a compilar el asesor y a ejecutarlo en el gráfico:


Como podemos ver, todos los modos declarados funcionan bien.


¿Qué es lo próximo?

En el próximo artículo, comenzaremos a desarrollar el control TrackBar.

Volver al contenido

*Artículos de esta serie:

 
DoEasy. Elementos de control (Parte 26): Mejoramos el objeto WinForms "ToolTip" y comenzamos a desarrollar "ProgressBar"
DoEasy. Elementos de control (Parte 27): Seguimos trabajando en el objeto WinForms "ProgressBar"

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/11823

Archivos adjuntos |
MQL5.zip (4527.27 KB)
Algoritmos de optimización de la población: Algoritmo de optimización de cuco (Cuckoo Optimization Algorithm — COA) Algoritmos de optimización de la población: Algoritmo de optimización de cuco (Cuckoo Optimization Algorithm — COA)
El siguiente algoritmo que analizaremos será la optimización de la búsqueda de cuco usando los vuelos de Levy. Este es uno de los últimos algoritmos de optimización, así como el nuevo líder en la clasificación.
Algoritmos de optimización de la población: Optimización del Lobo Gris (Grey Wolf Optimizer - GWO) Algoritmos de optimización de la población: Optimización del Lobo Gris (Grey Wolf Optimizer - GWO)
Hoy analizaremos uno de los algoritmos de optimización más modernos: la Optimización del Lobo Gris. El original comportamiento de las funciones de prueba hace que este sea uno de los algoritmos más interesantes entre los analizados anteriormente. Uno de los líderes para la aplicación en el entrenamiento de redes neuronales y funciones suaves con muchas variables.
Recetas MQL5 - Servicios Recetas MQL5 - Servicios
Este artículo describe las capacidades versátiles de los servicios, como los programas MQL5 que no requieren un gráfico vinculante. Asimismo, se detallan las diferencias de los servicios respecto a otros programas MQL5, enfatizando los matices del trabajo del desarrollador con los servicios. Como ejemplos, el lector podrá estudiar varias tareas que abarcan una amplia gama de funcionalidades que pueden implementarse como un servicio.
Redes neuronales: así de sencillo (Parte 34): Función cuantílica totalmente parametrizada Redes neuronales: así de sencillo (Parte 34): Función cuantílica totalmente parametrizada
Seguimos analizando algoritmos de aprendizaje Q distribuidos. En artículos anteriores hemos analizado los algoritmos de aprendizaje Q distribuido y cuantílico. En el primero, enseñamos las probabilidades de los rangos de valores dados. En el segundo, enseñamos los rangos con una probabilidad determinada. Tanto en el primer algoritmo como en el segundo, usamos el conocimiento a priori de una distribución y enseñamos la otra. En el presente artículo, veremos un algoritmo que permite al modelo aprender ambas distribuciones.