Русский 中文 Español Deutsch 日本語 Português
Graphical Interfaces VII: The Tabs Control (Chapter 2)

Graphical Interfaces VII: The Tabs Control (Chapter 2)

MetaTrader 5Examples | 4 August 2016, 15:28
9 988 6
Anatoli Kazharski
Anatoli Kazharski

Contents


Introduction

The first article Graphical Interfaces I: Preparation of the Library Structure (Chapter 1) explains in detail what this library is for. You will find a list of articles with links at the end of each chapter. There, you can also download a complete version of the library at the current stage of development. The files must be placed in the same directories as they are located in the archive.

The first chapter of seventh part introduced three classes of controls for creating tables: text label table (CLabelsTable), edit box table (CTable) and rendered table (CCanvasTable). In this article (chapter two) we are going to consider the Tabs control. Two classes will be presented for this control - simple and with extended functionality.

 


Tabs control

Tabs are used to control the display of predefined sets of graphical interface controls. Often, multi-functional applications require a large number of controls to be fit into a confined space allocated for the graphical interface. Tabs can be used to group the controls by categories and to display only the currently needed group. This makes the interface much more accessible and more intuitive for the end user. On the surface, the tabs look like a group of buttons with labels (name of the controls group). At the same time, only one of them can be selected (active).

Let us enumerate all components of this control.

  1. Background or the area to fit a group of controls
  2. Tabs

 Fig. 1. Components of the «Tabs» control.

Fig. 1. Components of the Tabs control.

Let us create four modes to position the tabs relative to the area, where other controls will be placed: top, bottom, left and right. 

 


Developing a class for creating the Tabs control

Create the Tabs.mqh file and include it in the WndContainer.mqh file of the library:

//+------------------------------------------------------------------+
//|                                                 WndContainer.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Tabs.mqh"

The CTabs must be created in the Tabs.mqh file. In this class, just like in classes of other controls, it is necessary to create standard methods, as well as methods for storing the pointer to the form, to which this control will be attached.

//+------------------------------------------------------------------+
//| Class for creating tabs                                          |
//+------------------------------------------------------------------+
class CTabs : public CElement
  {
private:
   //--- Pointer to the form to which the element is attached
   CWindow          *m_wnd;
   //---
public:
                     CTabs(void);
                    ~CTabs(void);
   //--- (1) Stores the form pointer, (2) returns pointers to scrollbars
   void              WindowPointer(CWindow &object)               { m_wnd=::GetPointer(object);      }
   //---
public:
   //--- Chart event handler
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Timer
   virtual void      OnEventTimer(void);
   //--- Moving the element
   virtual void      Moving(const int x,const int y);
   //--- (1) Show, (2) hide, (3) reset, (4) delete
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- (1) Set, (2) reset priorities of the left mouse button press
   virtual void      SetZorders(void);
   virtual void      ResetZorders(void);
   //--- Reset the color
   virtual void      ResetColors(void) {}
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTabs::CTabs(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTabs::~CTabs(void)
  {
  }

Tab properties can be divided into unique and common ones. Let us enumerate both lists.

Unique properties

  • Array of pointers to the controls attached to the tab
  • Text
  • Width

Create the TElements structure for the unique properties and declare a dynamic array with this type: 

class CTabs : public CElement
  {
private:
   //--- Structure of properties and arrays of the controls attached to each tab
   struct TElements
     {
      CElement         *elements[];
      string            m_text;
      int               m_width;
     };
   TElements         m_tab[];
  };

Common properties

  • Tabs positioning mode
  • Color of the area background
  • Size of the tabs along the Y axis (height)
  • Colors of tabs in different states
  • Color of tab texts in different states
  • Color of tab borders
  • Priorities of the left mouse button press

To set the positioning mode the ENUM_TABS_POSITION enumeration must be added to the Enums.mqh file: 

//+------------------------------------------------------------------+
//| Enumeration of the tabs positioning                              |
//+------------------------------------------------------------------+
enum ENUM_TABS_POSITION
  {
   TABS_TOP    =0,
   TABS_BOTTOM =1,
   TABS_LEFT   =2,
   TABS_RIGHT  =3
  };

Declaration of fields and methods for setting the properties are provided in the code listing below: 

class CTabs : public CElement
  {
private:
   //--- Positioning of tabs
   ENUM_TABS_POSITION m_position_mode;
   //--- Color of the common area background
   int               m_area_color;
   //--- Size of the tabs along the Y axis
   int               m_tab_y_size;
   //--- Colors of tabs in different states
   color             m_tab_color;
   color             m_tab_color_hover;
   color             m_tab_color_selected;
   color             m_tab_color_array[];
   //--- Color of tab texts in different states
   color             m_tab_text_color;
   color             m_tab_text_color_selected;
   //--- Color of tab borders
   color             m_tab_border_color;
   //--- Priorities of the left mouse button press
   int               m_zorder;
   int               m_tab_zorder;
   //---
public:
   //--- (1) Set/set the tab positions (top/bottom/left/right), (2) set the tab size along the Y axis
   void              PositionMode(const ENUM_TABS_POSITION mode)     { m_position_mode=mode;          }
   ENUM_TABS_POSITION PositionMode(void)                       const { return(m_position_mode);       }
   void              TabYSize(const int y_size)                      { m_tab_y_size=y_size;           }
   //--- Color (1) of the common background, (2) colors of tabs in different states, (3) color of tab borders
   void              AreaColor(const color clr)                      { m_area_color=clr;              }
   void              TabBackColor(const color clr)                   { m_tab_color=clr;               }
   void              TabBackColorHover(const color clr)              { m_tab_color_hover=clr;         }
   void              TabBackColorSelected(const color clr)           { m_tab_color_selected=clr;      }
   void              TabBorderColor(const color clr)                 { m_tab_border_color=clr;        }
   //--- Color of tab texts in different states
   void              TabTextColor(const color clr)                   { m_tab_text_color=clr;          }
   void              TabTextColorSelected(const color clr)           { m_tab_text_color_selected=clr; }
  };

Before creating a control, it is necessary to add the required number of tabs with an indication of the displayed text and width. Let us write the CTabs::AddTab() method for that. The default values of the method arguments are «» (empty string) and 50 (width)

class CTabs : public CElement
  {
public:
   //--- Adds a tab
   void              AddTab(const string tab_text="",const int tab_width=50);
  };
//+------------------------------------------------------------------+
//| Adds a tab                                                       |
//+------------------------------------------------------------------+
void CTabs::AddTab(const string tab_text,const int tab_width)
  {
//--- Set the size of tab arrays
   int array_size=::ArraySize(m_tabs);
   ::ArrayResize(m_tabs,array_size+1);
   ::ArrayResize(m_tab,array_size+1);
//--- Store the passed properties
   m_tab[array_size].m_text  =tab_text;
   m_tab[array_size].m_width =tab_width;
//--- Store the number of tabs
   m_tabs_total=array_size+1;
  }

If a certain tab should be preselected when loading the MQL application on the chart, then, before creating the control, it is necessary to specify its index using the CTabs::SelectedTab() method. It will also require a private CTabs::CheckTabIndex() method to check and adjust the index of the selected tab, in case it exceeds range. 

class CTabs : public CElement
  {
private:
   //--- Index of the selected tab
   int               m_selected_tab;
   //---
public:
   //--- (1) Store and (2) return index of the selected tab
   void              SelectedTab(const int index)                    { m_selected_tab=index;          }
   int               SelectedTab(void)                         const { return(m_selected_tab);        }
   //---
private:
   //--- Check index of the selected tab
   void              CheckTabIndex(void);
  };
//+------------------------------------------------------------------+
//| Check index of the selected tab                                  |
//+------------------------------------------------------------------+
void CTabs::CheckTabIndex(void)
  {
//--- Checking for exceeding the array range
   int array_size=::ArraySize(m_tab);
   if(m_selected_tab<0)
      m_selected_tab=0;
   if(m_selected_tab>=array_size)
      m_selected_tab=array_size-1;
  }

To create the control, we will need three private methods and one public method: 

class CTabs : public CElement
  {
private:
   //--- Objects for creating the element
   CRectLabel        m_main_area;
   CRectLabel        m_tabs_area;
   CEdit             m_tabs[];
   //---
public:
   //--- Methods for creating the tabs
   bool              CreateTabs(const long chart_id,const int subwin,const int x,const int y);
   //---
private:
   bool              CreateMainArea(void);
   bool              CreateTabsArea(void);
   bool              CreateButtons(void);
  };

If no tab is added before attaching the control, then calling the CTabs::CreateTabs() public method will stop creation of the graphical interface and output this message to the log: 

//--- If there is no tab in the group, report
   if(m_tabs_total<1)
     {
      ::Print(__FUNCTION__," > This method is to be called, "
              "if a group contains at least one tab! Use the CTabs::AddTab() method");
      return(false);
     }

Determination and calculation of coordinates for the component objects of the control will also be different depending on the selected tab positioning mode. These calculations require the CTabs::SumWidthTabs() method, which returns the total width of all tabs. In left (TABS_LEFT) and right (TABS_RIGHT) tab positioning modes, it will return the width of the first tab. For the top (TABS_TOP) and bottom (TABS_BOTTOM) modes, the width of all tabs is summed. 

class CTabs : public CElement
  {
private:
   //--- Positioning of tabs
   ENUM_TABS_POSITION m_position_mode;
   //---
private:
   //--- Width of all tabs
   int               SumWidthTabs(void);
  };
//+------------------------------------------------------------------+
//| Total width of all tabs                                          |
//+------------------------------------------------------------------+
int CTabs::SumWidthTabs(void)
  {
   int width=0;
//--- If tabs are positioned right or left, return the width of the first tab
   if(m_position_mode==TABS_LEFT || m_position_mode==TABS_RIGHT)
      return(m_tab[0].m_width);
//--- Sum the width of all tabs
   for(int i=0; i<m_tabs_total; i++)
      width=width+m_tab[i].m_width;
//--- With consideration of one pixel overlay
   width=width-(m_tabs_total-1);
   return(width);
  }

The CTabs::CreateMainArea() method is designed for creating the area where groups of controls will be located. Calculation of coordinates and object sizes looks like this (shortened version of the method): 

//+------------------------------------------------------------------+
//| Create the common area background                                |
//+------------------------------------------------------------------+
bool CTabs::CreateMainArea(void)
  {
//--- Forming the object name
   string name=CElement::ProgramName()+"_tabs_main_area_"+(string)CElement::Id();
//--- Coordinates
   int x=0;
   int y=0;
//--- Size
   int x_size=0;
   int y_size=0;
//--- Calculating coordinates and sizes relative to positioning of tabs
   switch(m_position_mode)
     {
      case TABS_TOP :
         x      =CElement::X();
         y      =CElement::Y()+m_tab_y_size-1;
         x_size =CElement::XSize();
         y_size =CElement::YSize()-m_tab_y_size;
         break;
      case TABS_BOTTOM :
         x      =CElement::X();
         y      =CElement::Y();
         x_size =CElement::XSize();
         y_size =CElement::YSize()-m_tab_y_size;
         break;
      case TABS_RIGHT :
         x      =CElement::X();
         y      =CElement::Y();
         x_size =CElement::XSize()-SumWidthTabs()+1;
         y_size =CElement::YSize();
         break;
      case TABS_LEFT :
         x      =CElement::X()+SumWidthTabs()-1;
         y      =CElement::Y();
         x_size =CElement::XSize()-SumWidthTabs()+1;
         y_size =CElement::YSize();
         break;
     }
//--- Creating the object
   if(!m_main_area.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size))
      return(false);
//--- Setting the properties
//--- Margins from the edge
//--- Store the size
//--- Store coordinates
//--- Store the object pointer
//...
   return(true);
  }

The following is the calculation of coordinates and background sizes for the tabs depending on the positioning mode specified in the CTabs::CreateTabsArea() method: 

//+------------------------------------------------------------------+
//| Create the tab background                                        |
//+------------------------------------------------------------------+
bool CTabs::CreateTabsArea(void)
  {
//--- Forming the object name
   string name=CElement::ProgramName()+"_tabs_area_"+(string)CElement::Id();
//--- Coordinates
   int x=CElement::X();
   int y=CElement::Y();
//--- Size
   int x_size=SumWidthTabs();
   int y_size=0;
//--- Calculating sizes relative to positioning of tabs
   if(m_position_mode==TABS_TOP || m_position_mode==TABS_BOTTOM)
     {
      y_size=m_tab_y_size;
     }
   else
     {
      y_size=m_tab_y_size*m_tabs_total-(m_tabs_total-1);
     }
//--- Adjust the coordinates for positioning the tabs at the bottom and on the right
   if(m_position_mode==TABS_BOTTOM)
     {
      y=CElement::Y2()-m_tab_y_size-1;
     }
   else if(m_position_mode==TABS_RIGHT)
     {
      x=CElement::X2()-x_size;
     }
//--- Creating the object
   if(!m_tabs_area.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size))
      return(false);
//--- Setting the properties
//--- Margins from the edge
//--- Store the size
//--- Store coordinates
//--- Store the object pointer
//...
   return(true);
  }

The CTabs::CreateButtons() method only requires the calculation of coordinates to create tabs. The width is set in the custom class of the application before the control is created. Otherwise, the default value (width) is used. Below is a shortened version of the method: 

//+------------------------------------------------------------------+
//| Create tabs                                                      |
//+------------------------------------------------------------------+
bool CTabs::CreateButtons(void)
  {
//--- Coordinates
   int x =CElement::X();
   int y =CElement::Y();
//--- Calculating coordinates relative to positioning of tabs
   if(m_position_mode==TABS_BOTTOM)
      y=CElement::Y2()-m_tab_y_size-1;
   else if(m_position_mode==TABS_RIGHT)
      x=CElement::X2()-SumWidthTabs();
//--- Check index of the selected tab
   CheckTabIndex();
//--- Create tabs
   for(int i=0; i<m_tabs_total; i++)
     {
      //--- Forming the object name
      string name=CElement::ProgramName()+"_tabs_edit_"+(string)i+"__"+(string)CElement::Id();
      //--- Calculating coordinates relative to positioning of tabs for each individual tab
      if(m_position_mode==TABS_TOP || m_position_mode==TABS_BOTTOM)
         x=(i>0) ? x+m_tab[i-1].m_width-1 : CElement::X();
      else
         y=(i>0) ? y+m_tab_y_size-1 : CElement::Y();
      //--- Creating the object
      if(!m_tabs[i].Create(m_chart_id,name,m_subwin,x,y,m_tab[i].m_width,m_tab_y_size))
         return(false);
      //--- Setting the properties
      //--- Margins from the edge of the panel
      //--- Coordinates
      //--- Size
      //--- Initializing gradient array
      //--- Store the object pointer
     }
//---
   return(true);
  }

To attach any control to a specific tab, let us write the CTabs::AddToElementsArray() method. It has two arguments: (1) tab index, to which the control should be attached and (2) reference to the control, a pointer to which should be stored in the array of tab controls

class CTabs : public CElement
  {
public:
   //--- Add control to the tab array
   void              AddToElementsArray(const int tab_index,CElement &object);
  };
//+------------------------------------------------------------------+
//| Add control to the array of the specified tab                    |
//+------------------------------------------------------------------+
void CTabs::AddToElementsArray(const int tab_index,CElement &object)
  {
//--- Checking for exceeding the array range
   int array_size=::ArraySize(m_tab);
   if(array_size<1 || tab_index<0 || tab_index>=array_size)
      return;
//--- Add pointer of the passed control to array of the specified tab
   int size=::ArraySize(m_tab[tab_index].elements);
   ::ArrayResize(m_tab[tab_index].elements,size+1);
   m_tab[tab_index].elements[size]=::GetPointer(object);
  }

When switching tabs, it is necessary to hide the controls of the previous tab and display the controls of the newly selected tab. For this purpose, let us create the CTabs::ShowTabElements() method. A check for the control visibility is at the beginning of the method. If the control is hidden, then the program leaves the method. Next, it checks the index of the active tab and adjusts it, if necessary. Then it checks all tabs in a loop and performs the main task of the method.  

class CTabs : public CElement
  {
public:
   //--- Show controls of the selected tab only
   void              ShowTabElements(void);
  };
//+------------------------------------------------------------------+
//| Show controls of the selected tab only                           |
//+------------------------------------------------------------------+
void CTabs::ShowTabElements(void)
  {
//--- Leave, if the tabs are hidden
   if(!CElement::IsVisible())
      return;
//--- Check index of the selected tab
   CheckTabIndex();
//---
   for(int i=0; i<m_tabs_total; i++)
     {
      //--- Get the number of controls attached to the tab
      int tab_elements_total=::ArraySize(m_tab[i].elements);
      //--- If this tab is selected
      if(i==m_selected_tab)
        {
         //--- Display the tab controls
         for(int j=0; j<tab_elements_total; j++)
            m_tab[i].elements[j].Show();
        }
      //--- Hide the controls of inactive tabs
      else
        {
         for(int j=0; j<tab_elements_total; j++)
            m_tab[i].elements[j].Hide();
        }
     }
  }

The CTabs::OnClickTab() method will be used to handle the pressing of a tab. First, the program has to pass two checks: (1) based on the name of the pressed object and (2) based on the identifier of the control, retrieved from the object's name using the CTabs::IdFromObjectName() method. If the checks are passed, then the program (1) finds the pressed tab in a loop, (2) stores its index and (3) sets the corresponding colors. At the very end of the CTabs::ShowTabElements() method, the controls of only the active tab are made visible. 

class CTabs : public CElement
  {
private:
   //--- Handling the pressing on tab
   bool              OnClickTab(const string pressed_object);
   //--- Get the identifier from the object name
   int               IdFromObjectName(const string object_name);
  };
//+------------------------------------------------------------------+
//| Pressing a tab in a group                                        |
//+------------------------------------------------------------------+
bool CTabs::OnClickTab(const string clicked_object)
  {
//--- Leave, if the pressing was not on the table cell
   if(::StringFind(clicked_object,CElement::ProgramName()+"_tabs_edit_",0)<0)
      return(false);
//--- Get the identifier from the object name
   int id=IdFromObjectName(clicked_object);
//--- Leave, if the identifier does not match
   if(id!=CElement::Id())
      return(false);
//---
   for(int i=0; i<m_tabs_total; i++)
     {
      //--- If this tab is clicked
      if(m_tabs[i].Name()==clicked_object)
        {
         //--- Store index of the selected tab
         SelectedTab(i);
         //--- Set colors
         m_tabs[i].Color(m_tab_text_color_selected);
         m_tabs[i].BackColor(m_tab_color_selected);
        }
      else
        {
         //--- Set the colors for the inactive tabs
         m_tabs[i].Color(m_tab_text_color);
         m_tabs[i].BackColor(m_tab_color);
        }
     }
//--- Show controls of the selected tab only
   ShowTabElements();
   return(true);
  }

In this case, the code for the CTabs::OnEvent() main event handler is as shown in the listing below: 

//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void CTabs::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Handling of the cursor movement event
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Leave, if the element is hidden
      if(!CElement::IsVisible())
         return;
      //--- Coordinates
      int x=(int)lparam;
      int y=(int)dparam;
      for(int i=0; i<m_tabs_total; i++)
         m_tabs[i].MouseFocus(x>m_tabs[i].X() && x<m_tabs[i].X2() && y>m_tabs[i].Y() && y<m_tabs[i].Y2());
      //---
      return;
     }
//--- Handling the left mouse button click on the object
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Pressing a tab
      if(OnClickTab(sparam))
         return;
     }
  }

All the methods of the CTabs class have been considered. Now, let us test how all this works. 

 


Testing the Tabs Control

For testing, let us use the EA from the previous part of the series and remove everything except the main menu and status bar from its graphical interface. Let us make all tab positioning modes (top/bottom/right/left) easy to test, as well as their size (height) easy to adjust. For this purpose, add external parameters to the EA in the Program.mqh file with the custom class:

//--- External parameters of the Expert Advisor
input ENUM_TABS_POSITION TabsPosition =TABS_TOP; // Tabs Position
input                int TabsHeight   =20;       // Tabs Height

Next, in the custom class (CProgram) of the application, declare an instance of the CTabs class and method for creating a Tabs control indented from the edge points of the form: 

class CProgram : public CWndEvents
  {
private:
   //--- Tabs
   CTabs             m_tabs;
   //---
private:
   //--- Tabs
#define TABS1_GAP_X           (4)
#define TABS1_GAP_Y           (45)
   bool              CreateTabs(void);
  };

There will be four tabs in total. The displayed text and width of tabs can be adjusted by initializing arrays, the values of their elements are then passed in a loop using the CTabs::AddTab() method. Height and positioning of the tabs will be set by the external parameters. The second tab (index 1) will be selected by default (when the program is loaded on chart for the first time). The full code of the CProgram::CreateTabs() method can be seen in the listing below: 

//+------------------------------------------------------------------+
//| Create area with tabs                                            |
//+------------------------------------------------------------------+
bool CProgram::CreateTabs(void)
  {
#define TABS1_TOTAL 4
//--- Pass the panel object
   m_tabs.WindowPointer(m_window1);
//--- Coordinates
   int x=m_window1.X()+TABS1_GAP_X;
   int y=m_window1.Y()+TABS1_GAP_Y;
//--- Arrays with text and width for tabs
   string tabs_text[]={"Tab 1","Tab 2","Tab 3","Tab 4"};
   int tabs_width[]={90,90,90,90};
//--- Set properties before creation
   m_tabs.XSize(596);
   m_tabs.YSize(243);
   m_tabs.TabYSize(TabsHeight);
   m_tabs.PositionMode(TabsPosition);
   m_tabs.SelectedTab((m_tabs.SelectedTab()==WRONG_VALUE) ? 1 : m_tabs.SelectedTab());
   m_tabs.AreaColor(clrWhite);
   m_tabs.TabBackColor(C'225,225,225');
   m_tabs.TabBackColorHover(C'240,240,240');
   m_tabs.TabBackColorSelected(clrWhite);
   m_tabs.TabBorderColor(clrSilver);
   m_tabs.TabTextColor(clrGray);
   m_tabs.TabTextColorSelected(clrBlack);
//--- Add tabs with the specified properties
   for(int i=0; i<TABS1_TOTAL; i++)
      m_tabs.AddTab(tabs_text[i],tabs_width[i]);
//--- Create control
   if(!m_tabs.CreateTabs(m_chart_id,m_subwin,x,y))
      return(false);
//--- Add the object to the common array of object groups
   CWndContainer::AddToElementsArray(0,m_tabs);
   return(true);
  }

The method must be called in the main method for creating the graphical interface of the application (see the shortened version of the method in listing below): 

//+------------------------------------------------------------------+
//| Create an expert panel                                           |
//+------------------------------------------------------------------+
bool CProgram::CreateExpertPanel(void)
  {
//--- Creating form 1 for controls
//--- Creating controls:
//    Main menu
//--- Context menus
//--- Tabs
   if(!CreateTabs())
      return(false);
//--- Redrawing the chart
   m_chart.Redraw();
   return(true);
  }

Compile the program and load it on to the chart. The tab positioning modes will be changed successively in the external parameters (see screenshots below):

 Fig. 2. Tabs positioning mode — «Top».

Fig. 2. Tabs positioning mode — «Top».

 Fig. 3. Tabs positioning mode — «Bottom».

Fig. 3. Tabs positioning mode — «Bottom».

 Fig. 4. Tabs positioning mode — «Left».

Fig. 4. Tabs positioning mode — «Left».

 Fig. 5. Tabs positioning mode — «Right».

Fig. 5. Tabs positioning mode — «Right».


Now let us test how it works with groups of controls attached to each tab. To do that, create a separate copy of the same EA and delete the external parameters from it. Here, the tabs will be positioned at the top (TABS_TOP) of the workspace. 

  1. A text label table will be attached to the first tab. 
  2. An edit box table will be attached to the second. 
  3. A rendered table to the third.
  4. The fourth — a group of controls, containing:

    • four checkboxes;
    • four checkboxes with edit boxes;
    • four comboboxes with checkboxes;
    • one separation line. 

In the custom class (CProgram) of the test application, declare (1) instances of these controls, (2) methods for creating them and (3) margins from the edges of the form (see code listing below): 

class CProgram : public CWndEvents
  {
private:
   //--- Text label table
   CLabelsTable      m_labels_table;
   //--- Edit box table
   CTable            m_table;
   //--- Rendered table
   CCanvasTable      m_canvas_table;
   //--- Checkboxes
   CCheckBox         m_checkbox1;
   CCheckBox         m_checkbox2;
   CCheckBox         m_checkbox3;
   CCheckBox         m_checkbox4;
   //--- Checkboxes with edit boxes
   CCheckBoxEdit     m_checkboxedit1;
   CCheckBoxEdit     m_checkboxedit2;
   CCheckBoxEdit     m_checkboxedit3;
   CCheckBoxEdit     m_checkboxedit4;
   //--- Comboboxes with checkboxes
   CCheckComboBox    m_checkcombobox1;
   CCheckComboBox    m_checkcombobox2;
   CCheckComboBox    m_checkcombobox3;
   CCheckComboBox    m_checkcombobox4;
   //--- Separation line
   CSeparateLine     m_sep_line;
   //---
private:
   //--- Text label table
#define TABLE1_GAP_X          (5)
#define TABLE1_GAP_Y          (65)
   bool              CreateLabelsTable(void);
   //--- Edit box table
#define TABLE2_GAP_X          (5)
#define TABLE2_GAP_Y          (65)
   bool              CreateTable(void);
   //--- Rendered table
#define TABLE3_GAP_X          (5)
#define TABLE3_GAP_Y          (65)
   bool              CreateCanvasTable(void);
   //--- Separation line
#define SEP_LINE_GAP_X        (300)
#define SEP_LINE_GAP_Y        (70)
   bool              CreateSepLine(void);
   //--- Checkboxes
#define CHECKBOX1_GAP_X       (18)
#define CHECKBOX1_GAP_Y       (75)
   bool              CreateCheckBox1(const string text);
#define CHECKBOX2_GAP_X       (18)
#define CHECKBOX2_GAP_Y       (175)
   bool              CreateCheckBox2(const string text);
#define CHECKBOX3_GAP_X       (315)
#define CHECKBOX3_GAP_Y       (75)
   bool              CreateCheckBox3(const string text);
#define CHECKBOX4_GAP_X       (315)
#define CHECKBOX4_GAP_Y       (175)
   bool              CreateCheckBox4(const string text);
   //--- Checkboxes with edit boxes
#define CHECKBOXEDIT1_GAP_X   (40)
#define CHECKBOXEDIT1_GAP_Y   (105)
   bool              CreateCheckBoxEdit1(const string text);
#define CHECKBOXEDIT2_GAP_X   (40)
#define CHECKBOXEDIT2_GAP_Y   (135)
   bool              CreateCheckBoxEdit2(const string text);
#define CHECKBOXEDIT3_GAP_X   (337)
#define CHECKBOXEDIT3_GAP_Y   (105)
   bool              CreateCheckBoxEdit3(const string text);
#define CHECKBOXEDIT4_GAP_X   (337)
#define CHECKBOXEDIT4_GAP_Y   (135)
   bool              CreateCheckBoxEdit4(const string text);
   //--- Comboboxes with checkboxes
#define CHECKCOMBOBOX1_GAP_X  (40)
#define CHECKCOMBOBOX1_GAP_Y  (205)
   bool              CreateCheckComboBox1(const string text);
#define CHECKCOMBOBOX2_GAP_X  (40)
#define CHECKCOMBOBOX2_GAP_Y  (235)
   bool              CreateCheckComboBox2(const string text);
#define CHECKCOMBOBOX3_GAP_X  (337)
#define CHECKCOMBOBOX3_GAP_Y  (205)
   bool              CreateCheckComboBox3(const string text);
#define CHECKCOMBOBOX4_GAP_X  (337)
#define CHECKCOMBOBOX4_GAP_Y  (235)
   bool              CreateCheckComboBox4(const string text);
  };

In the previous articles, it had been repeatedly shown how to create controls and attach them to the form. Therefore, the code of only one of these methods will be provided here to show how to attach a control to a tab. The simplest of those controls - separation line - would suffice as an example. In the code listing below, the line that call to the CTabs::AddToElementsArray() method is highlighted in yellow. The first argument is index of the tab, to which a control should be attached. Here the index is 3, that is, the fourth tab. The second argument is the object of the control that must be attached to the specified tab.

//+------------------------------------------------------------------+
//| Creates a separation line                                        |
//+------------------------------------------------------------------+
bool CProgram::CreateSepLine(void)
  {
//--- Store the window pointer
   m_sep_line.WindowPointer(m_window1);
//--- Attach to the fourth tab of the first group of tabs
   m_tabs.AddToElementsArray(3,m_sep_line);
//--- Coordinates  
   int x=m_window1.X()+SEP_LINE_GAP_X;
   int y=m_window1.Y()+SEP_LINE_GAP_Y;
//--- Size
   int x_size=2;
   int y_size=210;
//--- Set properties before creation
   m_sep_line.DarkColor(C'213,223,229');
   m_sep_line.LightColor(clrWhite);
   m_sep_line.TypeSepLine(V_SEP_LINE);
//--- Creating an element
   if(!m_sep_line.CreateSeparateLine(m_chart_id,m_subwin,0,x,y,x_size,y_size))
      return(false);
//--- Add the element pointer to the base
   CWndContainer::AddToElementsArray(0,m_sep_line);
   return(true);
  }

Once the graphical interface of the application has been created, the CTabs::ShowTabElements() method must be called in order to display the controls of the active tabs only (see the shortened version of the method in listing below). If it is not done, then all controls of all tabs will be displayed. 

//+------------------------------------------------------------------+
//| Create an expert panel                                           |
//+------------------------------------------------------------------+
bool CProgram::CreateExpertPanel(void)
  {
//--- Creating form 1 for controls
//--- Creating controls:
//--- Main menu
//--- Context menus
//--- Status bar
//--- Tabs
//...
//--- Text label table
   if(!CreateLabelsTable())
      return(false);
//--- Edit box table
   if(!CreateTable())
      return(false);
//--- Create rendered table
   if(!CreateCanvasTable())
      return(false);
//--- Separation line
   if(!CreateSepLine())
      return(false);
//--- Checkboxes
   if(!CreateCheckBox1("Checkbox 1"))
      return(false);
   if(!CreateCheckBox2("Checkbox 2"))
      return(false);
   if(!CreateCheckBox3("Checkbox 3"))
      return(false);
   if(!CreateCheckBox4("Checkbox 4"))
      return(false);
//--- Checkboxes with edit boxes
   if(!CreateCheckBoxEdit1("Checkbox Edit 1:"))
      return(false);
   if(!CreateCheckBoxEdit2("Checkbox Edit 2:"))
      return(false);
   if(!CreateCheckBoxEdit3("Checkbox Edit 3:"))
      return(false);
   if(!CreateCheckBoxEdit4("Checkbox Edit 4:"))
      return(false);
//--- Comboboxes with checkboxes
   if(!CreateCheckComboBox1("CheckCombobox 1:"))
      return(false);
   if(!CreateCheckComboBox2("CheckCombobox 2:"))
      return(false);
   if(!CreateCheckComboBox3("CheckCombobox 3:"))
      return(false);
   if(!CreateCheckComboBox4("CheckCombobox 4:"))
      return(false);
//--- Display controls of the active tab only
   m_tabs.ShowTabElements();
//--- Redrawing the chart
   m_chart.Redraw();
   return(true);
  }

The result should be as in the screenshots below

 Fig. 6. Controls of the fist tab.

Fig. 6. Controls of the fist tab.

Fig. 7. Controls of the second tab. 

Fig. 7. Controls of the second tab.

 Fig. 8. Controls of the third tab.

Fig. 8. Controls of the third tab.

 Fig. 9. Controls of the fourth tab.

Fig. 9. Controls of the fourth tab.


Everything works as intended. The seventh part of the series dedicated to the library for creating graphical interfaces can be now concluded. As a supplement, you can download another class code (CIconTabs) for creating Tabs with extended functionality, which is provided in the article attachments. Unlike the CTabs class, a control of CIconTabs type can have adjustable icons for each tab. This can help to make the graphical interface more user-friendly, if necessary. 

The icons and displayed text can be accurately placed relative to the edge of each tab using special methods (see code listing below): 

//+------------------------------------------------------------------+
//| Class for creating icon tabs                                     |
//+------------------------------------------------------------------+
class CIconTabs : public CElement
  {
private:
   //--- Label margins
   int               m_icon_x_gap;
   int               m_icon_y_gap;
   //--- Text label margins
   int               m_label_x_gap;
   int               m_label_y_gap;
   //---
public:
   //--- Label margins
   void              IconXGap(const int x_gap)                       { m_icon_x_gap=x_gap;            }
   void              IconYGap(const int y_gap)                       { m_icon_y_gap=y_gap;            }
   //--- Text label margins
   void              LabelXGap(const int x_gap)                      { m_label_x_gap=x_gap;           }
   void              LabelYGap(const int y_gap)                      { m_label_y_gap=y_gap;           }
  };

An example of the Icon tabs control appearance is displayed in the screenshot below:

 Fig. 10. «Icon tabs» control.

Fig. 10. Icon tabs control.

The code of this expert can also be downloaded from the article attachments. 

 

 


Conclusion

Currently, the schematic of the library for creating graphical interfaces looks as shown below:

 Fig. 11. Structure of the library at the current stage of development.

Fig. 11. Structure of the library at the current stage of development.

The tables and tabs controls have been covered in the seventh part of the series about creating graphical interfaces in the MetaTrader trading terminals. Three classes (CLabelsTable, CTable and CCanvasTable) have been provided for creating tables and two classes (CTabs and CIconTabs) for creating tabs. 

The next (eighth) part of the series will consider the following controls.

  • Static and drop-down calendar.
  • Tree view.
  • File navigator.

You can find and download the material of the seventh part of the series in the attached files so you can test how it works. If you have questions on how to use the material, presented in these files, you can refer to the detailed description of the library development in one of the articles from the list below or ask your question in the comments below.

List of articles (chapters) of seventh part:

Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/2503

Attached files |
Last comments | Go to discussion (6)
Kamil Wu
Kamil Wu | 3 Apr 2019 at 04:04
HI , if I roll up the Dialog, and change the period.the Dialog is not ok.in MT4.
Jefferson Judge Metha
Jefferson Judge Metha | 11 Oct 2019 at 03:30

I am trying to add an input field to a tab but it wont work. 

input double whenToTrail=10.3;

class CProgram: public CWndEvents
{
protected:
   CSpinEdit         m_StartTS;
//Code
protected:
   bool              CreatetrailStop(const int x_gap, const int y_gap, const string text);
};


then the function

bool CProgram::CreatetrailStop(const int x_gap, const int y_gap, string text)
  {
//--- Save the pointer to the main element
   m_StartTS.WindowPointer(m_window);
//--- Coordinates
   int x = m_window.X() + x_gap;
   int y = m_window.Y() + y_gap;
//--- Reserve for the tab
   m_tabs.AddToElementsArray(1, m_StartTS);
//--- Properties
   m_StartTS.XSize(95);
   m_StartTS.YSize(15);
   m_StartTS.EditXSize(40);
   m_StartTS.MinValue(0.01);
   m_StartTS.StepValue(0.01);
   m_StartTS.SetDigits(1);
   m_StartTS.SetValue(NormalizeDouble(whenToTrail,1));
   
   m_StartTS.ResetMode(true);
//--- Create a control
   if(!m_StartTS.CreateSpinEdit(m_chart_id, m_subwin, text, x, y))
      return(false);
//--- Add the object to the common array of object groups
   CWndContainer::AddToElementsArray(0, m_StartTS);
   return(true);
  }

this object isn't attached to the Panel but is on thee chart. 

and after deleting the chart the object remains
barcla
barcla | 11 Jun 2021 at 17:58
Hi, this article interests me a lot, I tried to install it but when I compile it it gives me these errors:

resource file '\ Images \ EasyAndFastGUI \ Controls \ LeftTransp_black.bmp' not found Calendar.mqh 443 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ LeftTransp_blue.bmp' not found Calendar.mqh 444 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ calendar_today.bmp' not found Calendar.mqh 738 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ calendar_drop_on.bmp' not found DropCalendar.mqh 435 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ calendar_drop_off.bmp' not found DropCalendar.mqh 436 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ calendar_drop_locked.bmp' not found DropCalendar.mqh 437 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ RightTransp_rotate_black.bmp' not found TreeItem.mqh 247 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ RightTransp_rotate_white.bmp' not found TreeItem.mqh 248 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ pointer_x_resize.bmp' not found Pointer.mqh 8 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ pointer_x_resize_blue.bmp' not found Pointer.mqh 9 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ pointer_y_resize.bmp' not found Pointer.mqh 10 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ pointer_y_resize_blue.bmp' not found Pointer.mqh 11 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ pointer_xy1_resize.bmp' not found Pointer.mqh 12 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ pointer_xy1_resize_blue.bmp' not found Pointer.mqh 13 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ pointer_xy2_resize.bmp' not found Pointer.mqh 14 11
resource file '\ Images \ EasyAndFastGUI \ Controls \ pointer_xy2_resize_blue.bmp' not found Pointer.mqh 15 11
resource file '\ Images \ EasyAndFastGUI \ Icons \ bmp16 \ folder.bmp' not found FileNavigator.mqh 284 11
resource file '\ Images \ EasyAndFastGUI \ Icons \ bmp16 \ text_file.bmp' not found FileNavigator.mqh 285 11

I looked in the MQL5 zip file but the files are not there, is there any way to get them?
Thank you
Mohammad-Reza Yakhyan
Mohammad-Reza Yakhyan | 19 Jan 2023 at 17:32

How can I add CLabel to tabs, when I create CLabel item and want add to tabs compiler gives me these error:


CLabel m_overview_titlte_label;

bool CMainPanel::CreateOverviewTitleLabel(const string text)
  {

//--- Pass the panel object
   m_overview_title_label.WindowPointer(m_window);
//--- Attach to the fourth tab of the first group of tabs
   m_main_panel_tabs.AddToElementsArray(0,m_overview_title_label);  
   m_main_panel_tabs.AddToElementsArray( 
//--- Coordinates
   int x=m_window.X()+OVERVIE_TITLE_LABEL_GAP_X;
   int y=m_window.Y()+OVERVIE_TITLE_LABEL_GAP_Y;
//--- Set properties before creation
   m_overview_title_label.XSize(140);
   m_overview_title_label.YSize(18);
   //m_overview_title_label.
//--- Create control
   if(!m_overview_title_label.Create(m_chart_id,text,m_subwin,x,y))
      return(false);
//--- Add the object to the common array of object groups
   //CWndContainer::AddToElementsArray(0,m_overview_title_label);
   return(true);
  }


Compiler Error:

'WindowPointer' - function not defined MainPanel.mqh 233 27

'm_overview_title_label' - parameter conversion not allowed MainPanel.mqh 235 43

'm_overview_title_label' - variable of the same type expected MainPanel.mqh 235 43

Mohammad-Reza Yakhyan
Mohammad-Reza Yakhyan | 19 Jan 2023 at 21:42
Martin Fischer #:
Hi. A really nice article, but at the moment I've some questions:

1.)
I do not find an information, how I can add simple CLabel or CEdit controls to the form. (From objects.mqh)
They do not have a function like WindowPointer().
I can create these objects, but I can't attach them to the window.

The
does not work in this case...

2.)
Is the CComboBox a static object. Is it possible to modify the list of elements in the

ComboBox-Listview after the creation of the ComboBox?

Thank you!

I had same problem, I solve that by create a include file and write my label class and use that. You must create this file in Include\EasyAndFastGUI\Controls\MyLabel.mqh

That code is:

//+------------------------------------------------------------------+
//|                                                      MyLabel.mqh |
//|                                      Copyright 2023, Sassiz.Root |
//|                                         https://t.me/R00T_S4SS12 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Sassiz.Root"
#property link      "https://t.me/R00T_S4SS12"
#property strict

#include "Element.mqh"
#include "Window.mqh"
//+------------------------------------------------------------------+
//| Class for creating a checkbox                                    |
//+------------------------------------------------------------------+
class MyLabel : public CElement
  {
private:
   //--- Pointer to the form to which the element is attached
   CWindow          *m_wnd;
   //--- Objects for creating a checkbox

   CLabel            m_label;

   //--- Text of the checkbox
   string            m_label_text;
   //--- Text label margins
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Colors of the text label in different states
   color             m_label_color;
   color             m_label_color_off;
   color             m_label_color_hover;
   color             m_label_color_locked;
   color             m_label_color_array[];
   //--- Priorities of the left mouse button press
   int               m_zorder;
   int               m_area_zorder;

   //---
public:
                     MyLabel(void);
                    ~MyLabel(void);
   //--- Methods for creating a checkbox
   bool              CreateLabel(const long chart_id,const int subwin,const string text,const int x,const int y);
   //---
private:
   bool              CreateLabel2(void);
   //---
public:
   //--- (1) Stores the form pointer, (2) return/set the state of the checkbox
   void              WindowPointer(CWindow &object)                 { m_wnd=::GetPointer(object);            }

   //--- (1) Background color, (2) margins for the text label

   void              LabelXGap(const int x_gap)                     { m_label_x_gap=x_gap;                   }
   void              LabelYGap(const int y_gap)                     { m_label_y_gap=y_gap;                   }
   //--- Color of the text in different states
   void              LabelColor(const color clr)                    { m_label_color=clr;                     }

   //--- (1) Description of the checkbox, (2) return/set the state of the checkbox button
   string            LabelText(void)                          const { return(m_label.Description());         }

   //--- Changing the color
   void              ChangeObjectsColor(void);
   //---
public:
   //--- Chart event handler
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Timer
   virtual void      OnEventTimer(void);
   //--- Moving the element
   virtual void      Moving(const int x,const int y);
   //--- (1) Show, (2) hide, (3) reset, (4) delete
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- (1) Set, (2) reset priorities of the left mouse button press
   virtual void      SetZorders(void);
   virtual void      ResetZorders(void);
   //--- Reset the color
   virtual void      ResetColors(void);
   virtual void      SetText(string text);
   virtual void      SetFontSize(int fontSize);
   //---
private:
   //--- Handling of the press on the element
   bool              OnClickLabel(const string clicked_object);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
MyLabel::MyLabel(void) :      
                             m_label_x_gap(20),
                             m_label_y_gap(2),
                             m_label_color(clrBlack)
                             
  {
//--- Store the name of the element class in the base class
   CElement::ClassName(CLASS_NAME);
//--- Set priorities of the left mouse button click
   m_zorder      =0;
   m_area_zorder =1;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
MyLabel::~MyLabel(void)
  {
  }
//+------------------------------------------------------------------+
//| Event handling                                                |
//+------------------------------------------------------------------+
void MyLabel::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Handling of the cursor movement event
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Leave, if the element is hidden
      if(!CElement::IsVisible())
         return;
      //--- Leave, if numbers of subwindows do not match
      if(CElement::m_subwin!=CElement::m_mouse.SubWindowNumber())
         return;
      //--- Checking the focus over element
      CElement::MouseFocus(m_mouse.X()>X() && m_mouse.X()<X2() && m_mouse.Y()>Y() && m_mouse.Y()<Y2());
      return;
     }
//--- Handling the left mouse button click on the object
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Pressing on the checkbox
      if(OnClickLabel(sparam))
         return;
     }
  }
//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void MyLabel::OnEventTimer(void)
  {
//--- If the form is not blocked
   if(!m_wnd.IsLocked())
      //--- Changing the color of the element objects
      ChangeObjectsColor();
  }
//+------------------------------------------------------------------+
//| Creates a group of the checkbox objects                          |
//+------------------------------------------------------------------+
bool MyLabel::CreateLabel(const long chart_id,const int subwin,const string text,const int x,const int y)
  {
//--- Leave, if there is no form pointer
   if(!CElement::CheckWindowPointer(::CheckPointer(m_wnd)))
      return(false);
//--- Initializing variables
   m_id         =m_wnd.LastId()+1;
   m_chart_id   =chart_id;
   m_subwin     =subwin;
   m_x          =x;
   m_y          =y;
   m_label_text =text;
//--- Margins from the edge
   CElement::XGap(CElement::X()-m_wnd.X());
   CElement::YGap(CElement::Y()-m_wnd.Y());
//--- Creating an element

   if(!CreateLabel2())
      return(false);
//--- Hide the element if the window is a dialog one or is minimized
   if(m_wnd.WindowType()==W_DIALOG || m_wnd.IsMinimized())
      Hide();
//---
   return(true);
  }


//+------------------------------------------------------------------+
//| Creates checkbox label                                           |
//+------------------------------------------------------------------+
bool MyLabel::CreateLabel2(void)
  {
//--- Forming the object name
   string name=CElement::ProgramName()+"_lable_"+(string)CElement::Id();
//--- Coordinates
   int x =CElement::X()+m_label_x_gap;
   int y =CElement::Y()+m_label_y_gap;
//--- Text color according to the state
   color label_color=clrBlack;//(m_check_button_state) ? m_label_color : m_label_color_off;
//--- Set the object
   if(!m_label.Create(m_chart_id,name,m_subwin,x,y))
      return(false);
//--- set properties
   m_label.Description(m_label_text);
   m_label.Font(FONT);
   m_label.FontSize(FONT_SIZE);
   m_label.Color(label_color);
   m_label.Corner(m_corner);
   m_label.Anchor(m_anchor);
   m_label.Selectable(false);
   m_label.Z_Order(m_zorder);
   m_label.Tooltip("\n");
//--- Margins from the edge
   m_label.XGap(x-m_wnd.X());
   m_label.YGap(y-m_wnd.Y());
//--- Initializing gradient array
   CElement::InitColorArray(label_color,m_label_color_hover,m_label_color_array);
//--- Store the object pointer
   CElement::AddToArray(m_label);
   return(true);
  }
//+------------------------------------------------------------------+
//| Moving elements                                                  |
//+------------------------------------------------------------------+
void MyLabel::Moving(const int x,const int y)
  {
//--- Leave, if the element is hidden
   if(!CElement::IsVisible())
      return;
//--- Storing indents in the element fields
   CElement::X(x+XGap());
   CElement::Y(y+YGap());
//--- Storing coordinates in the fields of the objects
   m_label.X(x+m_label.XGap());
   m_label.Y(y+m_label.YGap());
//--- Updating coordinates of graphical objects
   m_label.X_Distance(m_label.X());
   m_label.Y_Distance(m_label.Y());
  }
//+------------------------------------------------------------------+
//| Changing the object color when the cursor is hovering over it    |
//+------------------------------------------------------------------+
void MyLabel::ChangeObjectsColor(void)
  {
//--- Leave, if the element is blocked

//---
   color label_color=clrBlack;//(m_check_button_state) ? m_label_color : m_label_color_off;
   CElement::ChangeObjectColor(m_label.Name(),CElement::MouseFocus(),OBJPROP_COLOR,label_color,m_label_color_hover,m_label_color_array);
  }
//+------------------------------------------------------------------+
//| Shows combobox                                                   |
//+------------------------------------------------------------------+
void MyLabel::Show(void)
  {
//--- Leave, if the element is already visible
   if(CElement::IsVisible())
      return;
//--- Make all objects visible
   for(int i=0; i<CElement::ObjectsElementTotal(); i++)
      CElement::Object(i).Timeframes(OBJ_ALL_PERIODS);
//--- State of visibility
   CElement::IsVisible(true);
  }
//+------------------------------------------------------------------+
//| Hides combobox                                                   |
//+------------------------------------------------------------------+
void MyLabel::Hide(void)
  {
//--- Leave, if the element is already visible
   if(!CElement::IsVisible())
      return;
//--- Hide all objects
   for(int i=0; i<CElement::ObjectsElementTotal(); i++)
      CElement::Object(i).Timeframes(OBJ_NO_PERIODS);
//--- State of visibility
   CElement::IsVisible(false);
  }
//+------------------------------------------------------------------+
//| Redrawing                                                        |
//+------------------------------------------------------------------+
void MyLabel::Reset(void)
  {
//--- Leave, if this is a drop-down element
   if(CElement::IsDropdown())
      return;
//--- Hide and show
   Hide();
   Show();
  }
//+------------------------------------------------------------------+
//| Deletion                                                         |
//+------------------------------------------------------------------+
void MyLabel::Delete(void)
  {
//--- Removing objects
   m_label.Delete();
//--- Emptying the array of the objects
   CElement::FreeObjectsArray();
//--- Initializing of variables by default values
   CElement::MouseFocus(false);
   CElement::IsVisible(true);
  }
//+------------------------------------------------------------------+
//| Seth the priorities                                              |
//+------------------------------------------------------------------+
void MyLabel::SetZorders(void)
  {
   m_label.Z_Order(m_zorder);
  }
//+------------------------------------------------------------------+
//| Reset the priorities                                             |
//+------------------------------------------------------------------+
void MyLabel::ResetZorders(void)
  {
   m_label.Z_Order(0);
  }
//+------------------------------------------------------------------+
//| Reset the color of the element objects                           |
//+------------------------------------------------------------------+
void MyLabel::ResetColors(void)
  {

//--- Reset the color
   m_label.Color(clrBlack);
//--- Zero the focus
   CElement::MouseFocus(false);
  }

//+------------------------------------------------------------------+
//| Clicking on the element header                                   |
//+------------------------------------------------------------------+
bool MyLabel::OnClickLabel(const string clicked_object)
  {

//--- The mouse cursor is currently over the element
   m_label.Color(m_label_color_hover);
//--- Send a message about it
   ::EventChartCustom(m_chart_id,ON_CLICK_LABEL,CElement::Id(),0,m_label.Description());
   return(true);
  }
//+------------------------------------------------------------------+


void MyLabel::SetText(string text){
   m_label.Description(text);
}

void MyLabel::SetFontSize(int fontSize){
   m_label.FontSize(fontSize);
}

Then create object from MyLabel Class like this and use it:

   //---Label
   MyLabel           m_overview_title_label;

Then:

//+------------------------------------------------------------------+
//| Creates OverviewTitleLabel                                       |
//+------------------------------------------------------------------+
bool CMainPanel::CreateOverviewTitleLabel(const string text)
  {

//--- Pass the panel object
   m_overview_title_label.WindowPointer(m_window);
//--- Attach to the fourth tab of the first group of tabs
   m_main_panel_tabs.AddToElementsArray(0,m_overview_title_label);  
//--- Coordinates
   int x=m_window.X()+OVERVIE_TITLE_LABEL_GAP_X;
   int y=m_window.Y()+OVERVIE_TITLE_LABEL_GAP_Y;
//--- Set properties before creation
   m_overview_title_label.XSize(140);
   m_overview_title_label.YSize(18);
   m_overview_title_label.SetText(text);
   m_overview_title_label.SetFontSize(18);
   //m_overview_title_label.
//--- Create control
   if(!m_overview_title_label.CreateLabel(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- Add the object to the common array of object groups
   CWndContainer::AddToElementsArray(0,m_overview_title_label);
   return(true);
  }
Graphical Interfaces VIII: The Calendar Control (Chapter 1) Graphical Interfaces VIII: The Calendar Control (Chapter 1)
In the part VIII of the series of articles dedicated to creating graphical interfaces in MetaTrader, we will consider complex composite controls like calendars, tree view, and file navigator. Due to the large amount of information, there are separate articles written for every subject. The first chapter of this part describes the calendar control and its expanded version — a drop down calendar.
Testing trading strategies on real ticks Testing trading strategies on real ticks
The article provides the results of testing a simple trading strategy in three modes: "1 minute OHLC", "Every tick" and "Every tick based on real ticks" using actual historical data.
Graphical Interfaces VIII: The Tree View Control (Chapter 2) Graphical Interfaces VIII: The Tree View Control (Chapter 2)
The previous chapter of part VIII on graphical interfaces has focused on the elements of static and drop-down calendar. The second chapter will be dedicated to an equally complex element — a tree view, that is included in every complete library used for creating graphical interfaces. A tree view implemented in this article contains multiple flexible settings and modes, thus allowing to adjust this element of control to your needs.
Graphical Interfaces VII: the Tables Controls (Chapter 1) Graphical Interfaces VII: the Tables Controls (Chapter 1)
The seventh part of the series on MetaTrader graphical interfaces deals with three table types: text label, edit box and rendered one. Another important and frequently used controls are tabs allowing you to show/hide groups of other controls and develop space effective interfaces in your MQL applications.