DoEasy. Controles (Parte 28): Estilos de barra no controle ProgressBar
Conteúdo
Ideia
Atualmente, o controle ProgressBar criado para a biblioteca possui um único estilo de exibição, uma barra de progresso, que é uma linha contínua (Continuous). No entanto, esse controle tem mais dois estilos de exibição: blocos segmentados (Blocks) e rolagem contínua do bloco em um objeto (Marquee). O estilo Blocks é bastante claro (a linha contínua é substituída por blocos localizados separadamente). O estilo Marquee pode ser usado quando o número de iterações a serem visualmente exibidas usando o controle ProgressBar não é conhecido antecipadamente. Nesse caso, um único bloco com metade da largura da barra de progresso rolará constantemente.
Além de criar esses dois novos estilos, vamos adicionar texto à barra de progresso que será exibido dentro dela. O próprio texto será representado por um objeto regular da classe CLabel da biblioteca, e não será vinculado ao objeto da barra de progresso, mas ao objeto de fundo, que é a base do controle ProgressBar. O texto será renderizado dentro de um objeto de rótulo de texto totalmente transparente dimensionado para a largura e altura da barra de progresso, e esse objeto estará sempre em primeiro plano, isto é, acima de todos os objetos no controle ProgressBar.
Por padrão, o texto não será exibido na barra de progresso, mas sempre poderá ser adicionado durante a execução de um programa criado com base na biblioteca. Basta especificar o texto de saída e seus atributos (fonte, tamanho, sinalizadores da fonte, cor, opacidade, etc.).
Modificando as classes da biblioteca
Antes de começarmos a desenvolver novos estilos para o controle ProgressBar, vamos simplificar os construtores do elemento gráfico básico. Após criar um objeto, configuramos os valores de suas propriedades nos construtores protegido e paramétrico. Nos dois construtores, há uma lista longa de mais de cem diferentes parâmetros de elementos gráficos de biblioteca, que são constantemente adicionados quando novos objetos são criados. Dessa forma, temos que definir as propriedades do objeto duas vezes - nos construtores protegido e paramétrico da classe CGCnvElement. Seria lógico mover a configuração de todas essas propriedades para um método de inicialização separado. Ao mesmo tempo, se algumas propriedades devem ser definidas de forma diferente em diferentes construtores, elas podem ser passadas nos parâmetros formais do novo método.
No arquivo \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh, adicione novas propriedades à estrutura do objeto:
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
A estrutura de um objeto gráfico é necessária para a escrita correta das propriedades do objeto em um arquivo e para a leitura dessas propriedades do arquivo durante a restauração. As propriedades já adicionadas ao objeto agora devem ser adicionadas à estrutura. Mesmo que os campos da estrutura não correspondam às propriedades do objeto, não há nada com que se preocupar neste estágio de desenvolvimento, já que ainda não implementamos a gravação do objeto em um arquivo e a leitura de suas propriedades. Posteriormente, salvaremos as propriedades dos objetos gráficos em um arquivo e precisaremos de uma correspondência completa dos campos da estrutura com as propriedades do objeto.
Na seção privada da classe, declaramos um novo método para inicializar as propriedades do 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:
O método receberá as propriedades do objeto criado, que têm valores diferentes em diferentes construtores ou são especificadas diretamente nos parâmetros formais dos construtores, e passará todas essas propriedades para o método por meio de seus parâmetros.
Remova a longa lista de definição das propriedades do objeto em cada um dos construtores e substitua-a por uma chamada ao método de inicialização:
//+------------------------------------------------------------------+ //| 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, os valores próprios de cada construtor específico são passados para o método de inicialização em ambos os construtores.
No novo método de inicialização, mova a definição das propriedades do objeto que foi removida dos construtores da classe:
//+------------------------------------------------------------------+ //| 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 } //+------------------------------------------------------------------+
Aqui, simplesmente movemos as linhas que foram removidas dos construtores da classe. Os valores das propriedades que eram diferentes em diferentes construtores agora são passados e definidos para as propriedades do objeto por meio dos parâmetros formais do método.
No método que cria a estrutura do objeto, adicione a definição dos valores apropriados das propriedades do elemento gráfico nos novos campos da estrutura:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
No método que cria um objeto a partir de uma estrutura, implemente a definição das propriedades do objeto a partir dos campos correspondentes da estrutura que foram adicionados neste artigo:
//+------------------------------------------------------------------+ //| 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 } //+------------------------------------------------------------------+
Agora, o objeto do elemento gráfico será salvo corretamente em um arquivo e restaurado a partir de um arquivo.
Um efeito de brilho ao longo da barra de progresso pode ter a forma de um paralelepípedo. Trata-se de um quadrilátero distorcido, cujos vértices da face superior são deslocados em 6 pixels em relação aos vértices da face inferior. Para um objeto pequeno, esse deslocamento é suficiente para fazer com que ele pareça bastante inclinado. No entanto, à medida que sua altura aumenta, o ângulo de inclinação, fixo em seis pixels, torna-se indistinguível. Para corrigir essa situação, é necessário tornar o ângulo de inclinação um valor relativo, ou seja, quanto maior o objeto, maior será o ângulo de inclinação. Portanto, para definir o tamanho do deslocamento dos vértices, usaremos a altura do objeto. Dessa forma, o ângulo de inclinação será sempre de aproximadamente 45 graus.
No arquivo \MQL5\Include\DoEasy\Objects\Graph\WForms\GlareObj.mqh, no método que desenha a forma do objeto brilho na forma de um paralelogramo, corrigimos a inicialização dos parâmetros das coordenadas dos vértices. Em vez do número 6, atribuímos o valor da altura do 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(); } //+------------------------------------------------------------------+
Agora, os vértices serão deslocados de acordo com o valor da altura do objeto e o ângulo de inclinação será sempre de aproximadamente 45 graus, independentemente da altura do objeto.
Para criar um estilo de barra de progresso "Blocos Segmentados", é possível usar diferentes opções, desde a criação direta de cada bloco até o simples desenho deles. Para isso, faremos o seguinte: já temos uma barra de progresso totalmente preenchida e só precisamos apagar o fundo desse objeto nos locais onde não há blocos. Dessa forma, obtemos a aparência de uma barra de progresso composta por blocos segmentados. A desvantagem dessa abordagem é que a localização de cada bloco deve ser calculada. No entanto, a vantagem dessa abordagem é a simplicidade de sua implementação.
No arquivo \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\BarProgressBar.mqh, adicione variáveis à seção privada para armazenar os parâmetros do segmento e declare um método para a segmentação do fundo do 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:
As variáveis declaradas conterão os parâmetros iniciais a partir dos quais a localização dos segmentos poderá ser calculada. A largura do segmento sempre será de 3/4 da altura e a distância entre os segmentos será calculada a partir da largura do segmento resultante. Esses dados serão registrados quando o objeto for inicializado e, em seguida, poderão ser usados para calcular a localização de qualquer segmento por seu número. Como não estamos desenhando os segmentos em si, mas os espaços entre eles, o ponto de partida será a largura do primeiro segmento, contado a partir de zero ou de um. Se a altura da barra de progresso for superior a três pixels, um espaço vazio de um pixel deverá ser desenhado redor da borda do objeto em todos os lados. Isso separará os segmentos da borda externa da barra, tornando-os unidades visualmente independentes. Nesse caso, o preenchimento do primeiro segmento deverá começar em um, que é um espaço vazio de um pixel da borda do objeto até o primeiro segmento. Se a altura da barra de progresso for de três pixels ou menos, não será necessário desenhar um espaço vazio, já que ele ocupará toda a área utilizável do objeto no qual os segmentos são desenhados. Nesse caso, o recuo no início do primeiro segmento deverá ser zero.
Na seção pública da classe, escreveremos um método que retorna o estilo da barra de progresso e métodos que retornam os valores dos parâmetros variáveis dos segmentos. Também declararemos métodos para calcular a largura do segmento e a distância entre eles. Além disso, precisaremos sobrescrever os métodos virtuais para limpar o fundo do 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); }; //+------------------------------------------------------------------+
Nos métodos de limpeza, o fundo do elemento é preenchido com sua cor de fundo. Em seguida, chamaremos o método declarado na seção privada para segmentar o fundo desenhado do objeto, removendo o fundo nos locais que são os espaços entre os segmentos. Como esses métodos são virtuais, serão sempre esses métodos que serão chamados quando o método de limpeza for chamado, caso o objeto seja uma barra de progresso ou seu sucessor.
No método de inicialização das propriedades do objeto, inseriremos os valores padrão para as variáveis que armazenam os parâmetros de segmentação. A coordenada X do último segmento e a origem serão iguais a zero, enquanto a largura do segmento e a distância entre eles serão calculadas imediatamente:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Vejamos os métodos declarados com mais detalhes.
Método que limpa o elemento, preenchendo-o com cor e opacidade:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Primeiro, o fundo do elemento é totalmente pintado e, em seguida, é executado o método de segmentação para apagar o fundo nos locais onde não deveria haver segmentos. Se o objeto possuir uma moldura, ela será desenhada e as partes que se projetam além do contêiner pai serão recortadas. Por fim, o plano de fundo do objeto será atualizado com o sinalizador de redesenho do gráfico, que é passado para o método.
Método que limpa o elemento com preenchimento 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); } //+------------------------------------------------------------------+
A lógica desse método é semelhante à do método anterior, com a diferença de que ele recebe uma matriz de cores para preencher o gradiente e um sinalizador de direção (vertical/horizontal e cíclico), em vez de uma única cor.
Método que calcula a largura do segmento:
//+------------------------------------------------------------------+ //| Calculate the segment width | //+------------------------------------------------------------------+ int CBarProgressBar::CalculateSegmentWidth(void) { int w=(int)::ceil((this.Height()-2)/1.75); return(w>3 ? w : 3); } //+------------------------------------------------------------------+
A largura de cada segmento deve ser 2/3 de sua altura. Esse método calcula a largura do segmento com base na altura do objeto da barra de progresso, que é reduzida em dois pixels (um acima e outro abaixo) para acomodar o espaço livre de um pixel desenhado em cada lado da barra ao longo de seu perímetro. A altura resultante é dividida por 1,75, o que resulta em uma proporção de 3/4. Se a largura calculada for inferior a três pixels, a largura será ajustada para três pixels, já que segmentos muito estreitos com 1-2 pixels ficam ruins visualmente.
Método que calcula a distância entre segmentos:
//+------------------------------------------------------------------+ //| Calculate the distance between segments | //+------------------------------------------------------------------+ int CBarProgressBar::CalculateSegmentDistance(const int width) { int d=(int)::ceil(width/6); return(d<1 ? 1 : d); } //+------------------------------------------------------------------+
Tudo é simples aqui, pois o método recebe a largura com a qual o recuo é calculado. A distância entre os segmentos deve ser seis vezes menor que a largura do bloco, mas não menor que um pixel.
Método que segmenta o plano de fundo:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
No código, a lógica desse método está descrita em seus comentários. Se o estilo da barra de progresso for "Blocos segmentados", percorremos em loop todo o plano de fundo do objeto e apagamos o fundo onde não deveria haver segmentos. Se a altura do objeto for superior a três pixels, apagamos também o fundo ao longo do perímetro com uma borda de um pixel de largura, o que separa os segmentos das bordas da barra de progresso.
Para adicionar uma descrição à barra de progresso, basta definir o texto desejado. Por padrão, a descrição não é exibida, mas é possível criar quantos objetos CLabel forem necessários e posicioná-los corretamente. O objeto descrição da barra de progresso é criado automaticamente com o ProgressBar e pode ser facilmente acessado usando métodos específicos.
No arquivo da classe CProgressBar \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ProgressBar.mqh, removemos a variável da seção privada para armazenar o número de passos ignorados, pois não era necessário:
//+------------------------------------------------------------------+ //| 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
No mesmo local, na seção privada, declararemos variáveis para armazenar as propriedades do rótulo de texto com uma descrição da barra de progresso:
//+------------------------------------------------------------------+ //| 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
Vamos precisar de variáveis para definir e retornar as propriedades do objeto rótulo de texto, que atua como uma descrição da barra de progresso.
Os dados exibidos na linha de descrição podem ser reais e exibir cada etapa da execução ou uma porcentagem das etapas já concluídas.
Na seção pública da classe, vamos adicionar métodos que retornam o valor Value como texto e o valor Value como porcentagem, representada por valores numéricos e textuais:
//--- (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 acesso simplificado ao objeto brilho, na seção pública da classe, declararemos métodos para definir suas propriedades, adicionaremos métodos para obter ponteiros para os objetos anexados que estão sendo criados e declararemos métodos para trabalhar com o objeto descrição da barra de progresso:
//--- (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
No construtor da classe, inicializamos as variáveis declaradas com valores padrão:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Como no método que cria o objeto barra de progresso, também é criado um objeto brilho, vamos adicionar a criação do objeto descrição da barra de progresso lá:
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
Logo após criar um rótulo de texto, obtemos um ponteiro para o objeto e definimos algumas propriedades, como texto, nome da fonte, tamanho da fonte, método de ancoragem e alinhamento do texto. Em seguida, ocultamos o objeto criado. Os demais parâmetros do objeto podem ser definidos posteriormente, obtendo um ponteiro para ele usando o método GetProgressDescriptionObj() e definindo as propriedades necessárias.
Se tentarmos criar um objeto barra de progresso com altura inferior a um pixel, nada será exibido, pois o objeto não pode ter tamanho zero. Portanto, vamos adicionar uma verificação de tamanho e corrigir o valor, se necessário.
No método que cria um novo objeto gráfico, adicionamos um bloco de código para criar um objeto rótulo 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; } //+------------------------------------------------------------------+
Agora o objeto ProgressBar pode criar objetos anexados com os tipos "Barra de progresso", "Efeito de brilho" e "Rótulo de texto".
O objeto ProgressBar é o controle ativo que é processado pelo temporizador. No momento, o temporizador está processando um efeito de brilho que percorre a barra de progresso. Porém, também precisamos processar a barra de progresso no estilo "Marquee". Nesse modo, a barra de progresso tem uma largura fixa, igual à metade da largura do objeto completo, e rola constantemente dentro do ProgressBar, mostrando o andamento do processo cujo número de iterações não é conhecido antecipadamente.
Vamos adicionar o seguinte processamento da barra de progresso ao manipulador do temporizador do 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(); } } //+------------------------------------------------------------------+
Se o estilo de exibição da barra de progresso for "Rolagem contínua", obtemos a coordenada X com a qual o objeto precisa ser deslocado. Neste momento, adicionamos um deslocamento de 8 pixels à coordenada X atual e deslocamos a barra de progresso para a nova coordenada horizontalmente. Verificamos primeiro se o objeto da barra de progresso está completamente fora de seu contêiner à direita. Nesse caso, definimos sua coordenada X para que o objeto fique alinhado com a borda esquerda de seu contêiner, além de sua largura à esquerda. O método Redraw() também corta as partes do objeto que se projetam além das bordas do contêiner, criando um ciclo completo de movimentação da barra de progresso dentro de seu contêiner.
Se o objeto tiver um estilo de renderização diferente, chamamos o temporizador do objeto da barra de progresso para exibir o objeto brilho.
Agora que temos um estilo de desenho de barra de progresso "Blocos segmentados", precisamos refinar o método que define o valor da barra de progresso. Atualmente, após definir o valor, o método redimensiona imediatamente o objeto de acordo com o novo valor. Porém, como os blocos segmentados não devem ser desenhados pixel a pixel, mas bloco a bloco, precisamos calcular quantos blocos cabem na largura definida da barra de progresso. Se a largura for suficiente para desenhar um novo segmento, o objeto altera sua largura conforme configurado em sua propriedade. Se a largura não for suficiente (o segmento atual ficará incompleto, cortado), subtraímos a largura de um segmento da largura definida do objeto e definimos exatamente essa largura para a barra de progresso. Então, apenas o penúltimo segmento, junto com todos os anteriores, será desenhado. Assim, a largura do objeto mudará apenas quando todos os segmentos puderem ser desenhados completamente, sem recortá-los. Esse processo cria uma alteração bloco a bloco na largura visível da barra de progresso. O valor Value sempre será aquele que foi passado para o objeto. Ou seja, apenas alteramos visualmente a largura do objeto discretamente, enquanto o valor de Value permanece o mesmo.
Vamos fazer as melhorias descritas acima no método que define o valor atual da barra de progresso:
//+------------------------------------------------------------------+ //| 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(); } } } //+------------------------------------------------------------------+
A lógica do método é descrita nos comentários do código. O texto da descrição também precisa ser processado: cada vez que alteramos o valor da barra de progresso, pode ser necessário alterar também a descrição. Portanto, esse objeto sempre é trazido para o primeiro plano se tiver texto.
O método que calcula a largura da barra de progresso precisa ser modificado para que retorne metade do tamanho do controle ProgressBar se o estilo da barra de progresso estiver definido como "Rolagem contínua":
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Agora o método retornará o tamanho correto da barra de rolagem para qualquer um de seus estilos de exibição.
No método que define a nova largura, devemos atribuir a largura definida no objeto ao objeto rótulo de texto usado para exibir a descrição da barra de progresso:
//+------------------------------------------------------------------+ //| Set the 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; } //+------------------------------------------------------------------+
Se o tamanho do objeto de rótulo de texto não for ajustado ao tamanho da barra de progresso, o texto escrito com base no tamanho aparente da barra de progresso pode não caber em um objeto cuja largura seja menor do que aparenta visualmente. Isso fará com que o texto seja cortado. Portanto, é necessário que o rótulo de texto e a barra de progresso tenham as mesmas dimensões para evitar esse problema.
Vejamos os métodos auxiliares usados para facilitar o acesso às propriedades dos objetos vinculados ao controle ProgressBar.
Método que define o estilo do objeto brilho:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Aqui: obtemos um ponteiro para o objeto brilho e definimos o estilo para o objeto resultante.
Método que define a opacidade para o objeto brilho:
//+------------------------------------------------------------------+ //| Set the opacity of the highlight object | //+------------------------------------------------------------------+ void CProgressBar::SetGlareOpacity(const uchar opacity) { CGlareObj *obj=this.GetGlareObj(); if(obj==NULL) return; obj.SetOpacity(opacity); } //+------------------------------------------------------------------+
Obtemos um ponteiro para o objeto brilho e definimos o valor de opacidade para o objeto resultante.
Método que define a cor do objeto brilho:
//+------------------------------------------------------------------+ //| Set the color for the glare object | //+------------------------------------------------------------------+ void CProgressBar::SetGlareColor(const color clr) { CGlareObj *obj=this.GetGlareObj(); if(obj==NULL) return; obj.SetColor(clr); } //+------------------------------------------------------------------+
Obtemos um ponteiro para o objeto brilho e definimos o valor da cor, passado para o método, que o objeto resultante recebe.
Método que define o rótulo de texto da barra de progresso:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Aqui: obtemos um ponteiro para o objeto de rótulo de texto. Definimos a variável m_progress_bar_text para o texto passado para o método e, em seguida, definimos esse texto para o objeto. Como o texto será exibido imediatamente no objeto, para evitar a sobreposição de texto, o fundo e tudo o que foi desenhado nele deve ser apagado. Em seguida, exibimos o texto e atualizamos o elemento.
Método que define no rótulo de texto a cor do texto da barra de progresso:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Obtemos um ponteiro para o objeto de rótulo de texto. Definimos a variável m_progress_bar_text_color com a cor passada para o método e, em seguida, definimos essa cor para o objeto como a cor do texto. Como o texto será exibido imediatamente, para evitar a sobreposição de texto, o fundo do rótulo do texto é apagado e, em seguida, o texto é exibido e o elemento é atualizado.
Método que define no rótulo de texto da barra de progresso a opacidade:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
A lógica do método é idêntica à anterior, mas definimos o valor de opacidade na variável e o objeto correspondentes.
Método que define a coordenada x do rótulo de texto da barra de progresso:
//+------------------------------------------------------------------+ //| 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 define a coordenada Y do rótulo de texto da barra de progresso:
//+------------------------------------------------------------------+ //| 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 define a fonte no rótulo de texto da barra de progresso:
//+------------------------------------------------------------------+ //| 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 define o tamanho da fonte do rótulo de texto da barra de progresso:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
O método que define os sinalizadores de fonte no rótulo de texto da barra de progresso:
//+------------------------------------------------------------------+ //| 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 os métodos mostrados acima têm a mesma lógica e permitem definir rapidamente os parâmetros de texto e fonte desejados na descrição da barra de progresso (no rótulo do texto). As alterações são imediatamente exibidas na tela.
Se precisarmos esconder a descrição da barra de progresso, então, além de ocultá-la, o objeto precisa ser ajustado para não exibi-la, pois sempre é trazido para o primeiro plano. Se, no entanto, depois de ocultar um objeto, o sinalizador que indica que ele não deve ser exibido tem de ser marcado antes, e o objeto não será redesenhado até receber novamente o sinalizador de exibição.
Método para ocultar o rótulo de texto da barra de progresso:
//+------------------------------------------------------------------+ //| Hide the progress bar text label | //+------------------------------------------------------------------+ void CProgressBar::HideBarDescription(void) { CLabel *obj=this.GetProgressDescriptionObj(); if(obj==NULL) return; obj.SetDisplayed(false); obj.Hide(); } //+------------------------------------------------------------------+
Aqui: obtemos o objeto rotulo de texto com uma descrição da barra de progresso, marcamos o sinalizador de não exibição e escondemos o objeto.
Método que exibe o rótulo de texto da barra de progresso:
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
Aqui: obtemos o ponteiro para o objeto rótulo de texto com uma descrição da barra de progresso, definimos o sinalizador de exibição e mostramos o objeto.
Método que retorna o valor atual da barra de progresso no intervalo de Min a Max em porcentagem:
//+------------------------------------------------------------------+ //| 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)); } //+------------------------------------------------------------------+
Se precisarmos obter o Value da barra de progresso como uma porcentagem do intervalo de Min a Max, esse método calculará e retornará o valor de quantos por cento do intervalo especificado já foram processados. 100% é a diferença entre os valores máximo e mínimo definidos no objeto ProgressBar.
Vamos verificar o que temos.
Teste
Para testar, vamos pegar o Expert Advisor do artigo anterior e salvá-lo na nova pasta \MQL5\Experts\TestDoEasy\Part128\ com o novo nome TestDoEasy128.mq5.
Vamos criar uma enumeração dos estilos da barra de progresso para a versão em inglês da compilação e a versão da compilação no idioma do usuário:
//--- 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
Vamos adicionar dois novos parâmetros aos parâmetros de entrada - o estilo da barra de progresso e o sinalizador para exibir os valores da barra de progresso como uma porcentagem:
//--- 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
No manipulador OnInit() do Expert Advisor, ao criar o controle ProgressBar, definimos o estilo da barra de progresso da variável nas configurações e definimos os parâmetros para descrever a barra de progresso:
//--- 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); } } }
No ciclo de exibição e redesenho de todos os painéis, exibiremos a descrição com a barra de progresso estilo "Linha contínua" e a cada iteração do ciclo de incrementaremos o Value da barra de progresso, exibiremos os Value na descrição, dependendo das configurações - em porcentagens ou em passos concluídos. Ao final do ciclo, escreveremos na descrição da barra de progresso uma mensagem sobre a conclusão do ciclo de incremento com a fonte alterada para o estilo Bold.
Para definir os parâmetros do objeto brilho, usaremos os métodos de acesso 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 of a 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); } //+------------------------------------------------------------------+
Compilamos o Expert Advisor e o iniciamos no gráfico:
Como você pode ver, todos os modos declarados funcionam bem.
O que virá a seguir?
No próximo artigo, começaremos a desenvolver o controle TrackBar.
*Artigos desta série:
DoEasy. Controles (Parte 26): Finalizamos o objeto WinForms "ToolTip" e começamos a desenvolver a barra de progresso "ProgressBar"
DoEasy. Controles (Parte 27): Continuamos a trabalhar no objeto WinForms "ProgressBar"
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/11823
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso