English Русский 中文 Español Deutsch 日本語
Interfaces Gráficas III: Grupos de Botões Simples e Multifuncionais (Capítulo 2)

Interfaces Gráficas III: Grupos de Botões Simples e Multifuncionais (Capítulo 2)

MetaTrader 5Exemplos | 23 agosto 2016, 11:14
1 487 0
Anatoli Kazharski
Anatoli Kazharski

Conteúdo

 


Introdução

O primeiro artigo Interfaces gráficas I: Preparação da Estrutura da Biblioteca (Capítulo 1) considera em detalhes a finalidade desta biblioteca. A lista completa dos links para os artigos se encontra no final de cada capítulo da série. Lá, você também pode encontrar e baixar a versão completa da biblioteca, no estágio de desenvolvimento atual. Os arquivos devem estar localizados nas mesmas pastas que o arquivo baixado.

O primeiro capítulo desta terceira parte se tratava dos botões simples e multifuncionais. O segundo artigo se dedicará aos grupos de botões interconectados entre si. Eles são usados para criar os elementos nas aplicações, que permitem ao usuário selecionar uma das opções a partir de um determinado conjunto (grupo).

 


Desenvolvimento da Classe para Criar os Grupos de Botões Simples

Um grupo de botões simples é em sua essência um array de objetos gráficos do tipo OBJ_BUTTON. A característica diferencial de tais controles é que apenas um botão do grupo pode ser pressionado de cada vez. Nesta fase, a classe deste controle pode ser criada de duas maneiras:

  1. através da criação de um grupo de controle já implementado do tipo CSimpleButton;
  2. através da criação de um grupo de objetos primitivos do tipo CButton.

A segunda opção é mais simples, uma vez que ela não exige a criação de um método adicional para cada controle do tipo CSimpleButton para chegar à base de ponteiros. Por isso nós vamos utilizar esta função. 

Crie o arquivo ButtonsGroup.mqh com a classe CButtonsGroup na pasta Controls que contém todos os controles e inclua-o no arquivo WndContainer.mqh. A classe deve ter os métodos virtuais e o ponteiro do formulário como foi demonstrado para todos os outros controles previamente desenvolvidos. Nós não vamos discuti-los aqui, indo direto para a descrição das propriedades e dos métodos para a sua construção. 

Algumas propriedades serão comuns para cada botão dentro de um grupo, mas haverá algumas que serão únicas também. Abaixo encontramos dois grupos de propriedades relacionadas com a aparência de botões.

Propriedades comuns dos botões:

  • alturas;
  • cor dos botões bloqueados;
  • cor do quadro nos modo disponível e bloqueado;
  • cor do texto em diferentes estados;
  • prioridade para o clique esquerdo do mouse.

Propriedades únicas dos botões:

  • estado do botão (pressionado/solto);
  • margens a partir do ponto da borda do formulário;
  • texto;
  • largura;
  • cores dos botões em diferentes estados;
  • gradientes para os botões.

As margens para cada botão permitirão organizar os botões em qualquer sequência.

Fig. 1.  Exemplos dos botões organizados em um grupo.

Fig. 1.  Exemplos dos botões organizados em um grupo.


Declare os arrays dinâmicos para os objetos do tipo CButton e as propriedades únicas dos botões, como é mostrado no código abaixo. 

//+------------------------------------------------------------------+
//| Classe para criar um grupo de botões simples                     |
//+------------------------------------------------------------------+
class CButtonsGroup : public CElement
  {
private:
   //--- Objetos para a criação de um botão
   CButton           m_buttons[];
   //--- Gradientes do botão
   struct ButtonsGradients
     {
      color             m_buttons_color_array[];
     };
   ButtonsGradients  m_buttons_total[];
   //--- Propriedades do botão:
   //    Arrays de propriedades únicas dos botões
   bool              m_buttons_state[];
   int               m_buttons_x_gap[];
   int               m_buttons_y_gap[];
   string            m_buttons_text[];
   int               m_buttons_width[];
   color             m_buttons_color[];
   color             m_buttons_color_hover[];
   color             m_buttons_color_pressed[];
   //--- Altura dos botões
   int               m_button_y_size;
   //--- Cor dos botões bloqueados
   color             m_back_color_off;
   //--- Cor do quadro no modo ativo e bloqueado
   color             m_border_color;
   color             m_border_color_off;
   //--- Cor do texto
   color             m_text_color;
   color             m_text_color_off;
   color             m_text_color_pressed;
   //--- Prioridade do botão esquerdo do mouse
   int               m_buttons_zorder;
   //---
public:
   //--- Número de botões
   int               ButtonsTotal(void)                       const { return(::ArraySize(m_buttons));  }
   //--- (1) Altura dos botões
   void              ButtonYSize(const int y_size)                  { m_button_y_size=y_size;          }
   //--- (1) Cores de fundo de um botão bloqueado e um quadro ((2) disponível/(3) bloqueado)
   void              BackColorOff(const color clr)                  { m_back_color_off=clr;            }
   void              BorderColor(const color clr)                   { m_border_color=clr;              }
   void              BorderColorOff(const color clr)                { m_border_color_off=clr;          }
   //--- Cor do texto
   void              TextColor(const color clr)                     { m_text_color=clr;                }
   void              TextColorOff(const color clr)                  { m_text_color_off=clr;            }
   void              TextColorPressed(const color clr)              { m_text_color_pressed=clr;        }
  };

O tamanho dos arrays dinâmicos serão definidos no momento da formação de um grupo de botões antes de sua criação (anexando ao gráfico). Toda vez que o método CButtonsGroup::AddButton() for chamado, os arrays serão incrementados de um elemento, sendo preenchidos com os parâmetros passados.

class CButtonsGroup : public CElement
  {
public:
   //--- Adiciona um botão com as propriedades especificadas antes de sua criação
   void              AddButton(const int x_gap,const int y_gap,const string text,const int width,
                               const color button_color,const color button_color_hover,const color button_color_pressed);
  };
//+------------------------------------------------------------------+
//| Adiciona um botão                                                |
//+------------------------------------------------------------------+
void CButtonsGroup::AddButton(const int x_gap,const int y_gap,const string text,const int width,
                              const color button_color,const color button_color_hover,const color pressed_button_color)
  {
//--- Aumenta o tamanho do array por um elemento
   int array_size=::ArraySize(m_buttons);
   ::ArrayResize(m_buttons,array_size+1);
   ::ArrayResize(m_buttons_total,array_size+1);
   ::ArrayResize(m_buttons_state,array_size+1);
   ::ArrayResize(m_buttons_x_gap,array_size+1);
   ::ArrayResize(m_buttons_y_gap,array_size+1);
   ::ArrayResize(m_buttons_text,array_size+1);
   ::ArrayResize(m_buttons_width,array_size+1);
   ::ArrayResize(m_buttons_color,array_size+1);
   ::ArrayResize(m_buttons_color_hover,array_size+1);
   ::ArrayResize(m_buttons_color_pressed,array_size+1);
//--- Armazena os valores dos parâmetros passados
   m_buttons_x_gap[array_size]         =x_gap;
   m_buttons_y_gap[array_size]         =y_gap;
   m_buttons_text[array_size]          =text;
   m_buttons_width[array_size]         =width;
   m_buttons_color[array_size]         =button_color;
   m_buttons_color_hover[array_size]   =button_color_hover;
   m_buttons_color_pressed[array_size] =pressed_button_color;
   m_buttons_state[array_size]         =false;
  }

Ao criar um grupo de botões, o processo de criação da interface gráfica será interrompido e uma mensagem relevante serão impressa no registro, se antes disso não houver botões que foram adicionados usando o método CButtonsGroup::AddButton(). Os botões serão criados em um loop como é mostrado na versão reduzida do método CButtonsGroup:ÇCreateButtons() no código abaixo. 

class CButtonsGroup : public CElement
  {
public:
   //--- Métodos para a criação de um botão
   bool              CreateButtonsGroup(const long chart_id,const int subwin,const int x,const int y);
   //---
private:
   bool              CreateButtons(void);
  };
//+------------------------------------------------------------------+
//| Cria os botões                                                   |
//+------------------------------------------------------------------+
bool CButtonsGroup::CreateButtons(void)
  {
//--- Coordenadas
   int l_x =m_x;
   int l_y =m_y;
//--- Obtém o número de botões
   int buttons_total=ButtonsTotal();
//--- Se não existir um botão em um grupo, reporta
   if(buttons_total<1)
     {
      ::Print(__FUNCTION__," > Este método era para ser chamado, "
              "se um grupo conter pelo menos um botão! Use the CButtonsGroup::AddButton() method");
      return(false);
     }
//--- Cria o número especificado de botões
   for(int i=0; i<buttons_total; i++)
     {
      //--- Elaborando o nome do objeto
      //--- Calcula as coordenadas
      //--- Configura um botão
      //--- Define as propriedades
      //--- Armazena as margens da borda do painel, coordenadas e o tamanho
      //--- Inicializa o array de gradiente
      //--- Armazena o ponteiro de objeto
     }
//---
   return(true);
  }

Vamos criar dois modos para este tipo de grupo de botão. Para configurar isso, adicione um campo especial e o método para a classe, como é mostrado no código abaixo. O valor padrão será false, significando que o modo que permite ter todos os botões soltos num grupo está ativado. O valor padrão true significa que um botão em um grupo será sempre pressionado.

class CButtonsGroup : public CElement
  {
public:
   //--- O modo do botão de radio
   bool              m_radio_buttons_mode;
   //---
public:
   //--- Estabelecendo o modo de botão de radio
   void              RadioButtonsMode(const bool flag)              { m_radio_buttons_mode=flag;       }
  };

Igual como em qualquer outro controle, esta classe deve conter um método para bloquear o controle. Para este tipo de grupo de botão, é importante garantir que, ao desbloquear um botão previamente pressionado ele restaura a aparência de seu estado

class CButtonsGroup : public CElement
  {
private:
   //--- Disponível/bloqueado
   bool              m_buttons_group_state;
   //---
public:
   //--- Estado geral do grupo de botões (disponível/bloqueado)
   bool              ButtonsGroupState(void)                  const { return(m_buttons_group_state);   }
   void              ButtonsGroupState(const bool state);
  };
//+------------------------------------------------------------------+
//| Altera o estado dos botões                                       |
//+------------------------------------------------------------------+
void CButtonsGroup::ButtonsGroupState(const bool state)
  {
   m_buttons_group_state=state;
//---
   int buttons_total=ButtonsTotal();
   for(int i=0; i<buttons_total; i++)
     {
      m_buttons[i].State(false);
      m_buttons[i].Color((state)? m_text_color : m_text_color_off);
      m_buttons[i].BackColor((state)? m_buttons_color[i]: m_back_color_off);
      m_buttons[i].BorderColor((state)? m_border_color : m_border_color_off);
     }
//--- Pressiona o botão se ele foi pressionado antes do bloqueio
   if(m_buttons_group_state)
     {
      if(m_selected_button_index!=WRONG_VALUE)
        {
         m_buttons_state[m_selected_button_index]=true;
         m_buttons[m_selected_button_index].Color(m_text_color_pressed);
         m_buttons[m_selected_button_index].BackColor(m_buttons_color_pressed[m_selected_button_index]);
        }
     }
  }

Nós precisamos de um método para alternar o estado do botão quando pressionado. Nós também vamos exigir os campos e métodos para armazenar e obter o texto e o índice do botão em destaque.

No início do método para alternar o estado do botão no código abaixo, há uma verificação da quantidade de botões em um grupo. Se for verificado que não há botões, uma mensagem relevante será impressa no registro. O programa não vai sair do método. O programa irá continuar e em algum momento ele encontrará um erro que irá exceder o tamamho do array m_buttons_state[]. Isto significa que o desenvolvedor do aplicativo deve adicionar pelo menos um botão ao grupo para evitar tal erro. Depois da verificação, se existir pelo menos um botão, o programa irá ajustar o índice passado no caso dele exceder o tamanho do array. Em seguida, o estado do botão é alterado pelo índice especificado. Depois disso, todos os botões, exceto o pressionado, tornam-se soltos (a cor relevante está definida) em um loop, considerando o modo do grupo. Em outras palavras, se o modo do botão de radio está ativado, pelo menos um botão deve estar pressionado sempre, então, durante cada iteração é realizado uma verificação de uma condição de igualdade do índice passado para o índice atual do loop. Se o modo está ativado quando todos os botões podem ser soltos, então, a parte da verificação do índice, é verificado o estado atual do botão. Se a condição for atendida, então a sinalização do botão pressionado é definida, independentemente do modo. No final do método, na classe onde o texto e o índice do botão destacado serão guardados, os seus campos terão valores correspondentes a este sinalizador. Se não houver um botão pressionado, os valores são definidos como vazios ("" e WRONG_VALUE). 

class CButtonsGroup : public CElement
  {
private:
   //--- (1) Texto e (2) o índice do botão em destaque
   string            m_selected_button_text;
   int               m_selected_button_index;
   //---
public:
   //--- Retorna (1) o texto e (2) o índice do botão em destaque
   string            SelectedButtonText(void)                 const { return(m_selected_button_text);  }
   int               SelectedButtonIndex(void)                const { return(m_selected_button_index); }
   //--- Alterna o estado do botão pelo índice especificado
   void              SelectionButton(const int index);
  };
//+------------------------------------------------------------------+
//| Alterna o estado do botão pelo índice especificado               |
//+------------------------------------------------------------------+
void CButtonsGroup::SelectionButton(const int index)
  {
//--- Para verificar por um botão pressionado em um grupo
   bool check_pressed_button=false;
//--- Obtém o número de botões
   int buttons_total=ButtonsTotal();
//--- Se não existir um botão em um grupo, reporta
   if(buttons_total<1)
     {
      ::Print(__FUNCTION__," > Este método era para ser chamado, "
              "se um grupo conter pelo menos um botão! Use the CButtonsGroup::AddButton() method");
     }
//--- Ajusta o valor do índice, se o intervalo do array for excedido
   int correct_index=(index>=buttons_total)? buttons_total-1 : (index<0)? 0 : index;
//--- Altera o estado do botão para o seu oposto
   m_buttons_state[correct_index]=(m_buttons_state[correct_index])? false : true;
//--- Iteração sobre um grupo de botões
   for(int i=0; i<buttons_total; i++)
     {
      //--- É realizado uma verificação de acordo com o modo
      bool condition=(m_radio_buttons_mode)? (i==correct_index) : (i==correct_index && m_buttons_state[i]);
      //--- Se a condição for atendida, faça o botão ser pressionado
      if(condition)
        {
         if(m_radio_buttons_mode)
            m_buttons_state[i]=true;
         //--- Há um botão pressionado
         check_pressed_button=true;
         //--- Define uma cor
         m_buttons[i].Color(m_text_color_pressed);
         m_buttons[i].BackColor(m_buttons_color_pressed[i]);
         CElement::InitColorArray(m_buttons_color_pressed[i],m_buttons_color_pressed[i],m_buttons_total[i].m_buttons_color_array);
        }
      //--- Se a condição não for atendida, faça o botão ser solto
      else
        {
         //--- Define as cores e o estado desativado
         m_buttons_state[i]=false;
         m_buttons[i].Color(m_text_color);
         m_buttons[i].BackColor(m_buttons_color[i]);
         CElement::InitColorArray(m_buttons_color[i],m_buttons_color_hover[i],m_buttons_total[i].m_buttons_color_array);
        }
      //--- Zera o estado normal do botão
      m_buttons[i].State(false);
     }
//--- Se houver um botão pressionado, armazena o seu texto e índice
   m_selected_button_text  =(check_pressed_button) ? m_buttons[correct_index].Description() : "";
   m_selected_button_index =(check_pressed_button) ? correct_index : WRONG_VALUE;
  }

Para lidar com o pressionamento de um grupo de botão, crie o método CButtonsGroup::OnClickButton(). Semelhante a muitos outros métodos homônimos que foram considerados anteriormente, são realizadas as seguintes verificações:

  • para o nome;
  • para o identificador. Para extrair o identificador a partir do nome do objeto utilize método CButtonsGroup::IdFromObjectName(). O código do método é semelhante aos métodos homônimos considerados anteriormente em outras classes de controles, assim, nós não vamos discutir isso aqui;
  • para o estado atual (disponível/bloqueado).

Se todas as verificações foram passadas ​​e o programa não tiver deixado o método, será realizado a alternância do estado do botão no grupo pelo método CButtonsGroup::SelectionButton() considerado anteriormente. No final deste método, é enviado uma mensagem que contém os dados sobre o botão pressionado para o fluxo de eventos. Esta mensagem pode ser recebida no manipulador da classe personalizada.

class CButtonsGroup : public CElement
  {
private:
   //--- Manipulando o pressionamento do botão
   bool              OnClickButton(const string clicked_object);
   //--- Obtém o identificador do nome do botão
   int               IdFromObjectName(const string object_name);
  };
//+------------------------------------------------------------------+
//| Manipulador de eventos do gráfico                                |
//+------------------------------------------------------------------+
void CButtonsGroup::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Manipula o evento do clique do botão esquerdo do mouse sobre o objeto
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      if(OnClickButton(sparam))
         return;
     }
  }
//+------------------------------------------------------------------+
//| Pressionando o botão em um grupo                                 |
//+------------------------------------------------------------------+
bool CButtonsGroup::OnClickButton(const string pressed_object)
  {
//--- Sai, se o pressionamento não foi no elemento de menu
   if(::StringFind(pressed_object,CElement::ProgramName()+"_buttons_",0)<0)
      return(false);
//--- Obtém o identificador do nome do objeto
   int id=IdFromObjectName(pressed_object);
//--- Sai, se os identificadores não corresponderem
   if(id!=CElement::Id())
      return(false);
//--- Para verificar o índice
   int check_index=WRONG_VALUE;
//--- Verifica, se o botão pressionado estava em um dos botões deste grupo
   int buttons_total=ButtonsTotal();
//--- Sai, se os botões estão bloqueados
   if(!m_buttons_group_state)
     {
      for(int i=0; i<buttons_total; i++)
         m_buttons[i].State(false);
      //---
      return(false);
     }
//--- Se o pressionamento ocorreu, armazena o índice
   for(int i=0; i<buttons_total; i++)
     {
      if(m_buttons[i].Name()==pressed_object)
        {
         check_index=i;
         break;
        }
     }
//--- Sai, se o botão deste grupo não foi pressionado
   if(check_index==WRONG_VALUE)
      return(false);
//--- Alterna o estado do botão
   SelectionButton(check_index);
//--- Envia um sinal sobre ele
   ::EventChartCustom(m_chart_id,ON_CLICK_BUTTON,CElement::Id(),m_selected_button_index,m_selected_button_text);
   return(true);
  }

Agora, nós precisamos configurar a reação do grupo de botões para quando o cursor do mouse estiver sobre eles e para o botão esquerdo do mouse. Para isso, nós vamos escrever o método CButtonsGroup::CheckPressedOverButton(), que será chamado no manipulador do controle durante o tratamento do evento CHARTEVENT_MOUSE_MOVE. Antes do método ser chamado, as seguintes verificações serão realizadas: (1) se o controle é visível, (2) se ele está disponível, (3) se o formulário está disponível e (4) se o botão esquerdo do mouse está pressionado.

class CButtonsGroup : public CElement
  {
private:
   //--- Verifica o pressionamento do botão esquerdo do mouse sobre um grupo de botões
   void              CheckPressedOverButton(void);
  };
//+------------------------------------------------------------------+
//| Manipulador de eventos do gráfico                                |
//+------------------------------------------------------------------+
void CButtonsGroup::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Manipulação do evento do movimento do cursor
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Sai, se o controle está oculto
      if(!CElement::IsVisible())
         return;
      //--- Sai, se os botões estão bloqueados
      if(!m_buttons_group_state)
         return;
      //--- Define o foco
      int x=(int)lparam;
      int y=(int)dparam;
      int buttons_total=ButtonsTotal();
      for(int i=0; i<buttons_total; i++)
        {
         m_buttons[i].MouseFocus(x>m_buttons[i].X() && x<m_buttons[i].X2() && 
                                 y>m_buttons[i].Y() && y<m_buttons[i].Y2());
        }
      //--- Sai, se o formulário for bloqueado
      if(m_wnd.IsLocked())
         return;
      //--- Sai, se o botão do mouse não for pressionado
      if(sparam!="1")
         return;
      //--- Verifica o pressionamento do botão esquerdo do mouse sobre um grupo de botões
      CheckPressedOverButton();
      return;
     }
  }
//+------------------------------------------------------------------+
// Verifica o pressionamento do botão esquerdo do mouse sobre um grupo de botões |
//+------------------------------------------------------------------+
void CButtonsGroup::CheckPressedOverButton(void)
  {
   int buttons_total=ButtonsTotal();
//--- Define a cor, dependendo da localização do pressionamento do botão esquerdo do mouse
   for(int i=0; i<buttons_total; i++)
     {
      //--- Se houver um foco, então, a cor do botão pressionado
      if(m_buttons[i].MouseFocus())
         m_buttons[i].BackColor(m_buttons_color_pressed[i]);
      //--- Se não houver um foco, então ...
      else
        {
         //--- ...se um grupo de botões não estiver pressionado, atribuí a cor de fundo
         if(!m_buttons_state[i])
            m_buttons[i].BackColor(m_buttons_color[i]);
        }
     }
  }

Tudo está pronto para testar um grupo de botões simples na aplicação de teste. Faça uma cópia do EA que nós fizemos os testes anteriormente. Remova todos os controles, exceto o menu principal com os seus menus de contexto. Nós vamos usar este programa para testar vários grupos de botões neste artigo.

Crie uma instância da classe CButtonsGroup do grupo de botões na classe personalizada. Declare o método CProgram::CreateButtonsGroup1() para a sua criação e a margem da borda do formulário. 

class CProgram : public CWndEvents
  {
private:
   //--- Grupo de botões simples
   CButtonsGroup     m_buttons_group1;
   //---
private:
   //--- Grupo de botões simples
#define BUTTONS_GROUP1_GAP_X (7)
#define BUTTONS_GROUP1_GAP_Y (50)
   bool              CreateButtonsGroup1(void);
  };

Crie um grupo de quatro botões. Organize-os horizontalmente. Para este exemplo, nós vamos fazer dois botões vermelhos e dois azuis. A implementação do método CProgram::CreateButtonsGroup1() é mostrada no código abaixo. Se você precisa de um botão para ser destacado logo após o grupo de botões ser criado, use o método público CButtonsGroup::SelectionButton()

//+------------------------------------------------------------------+
//| Cria um grupo de botões simples                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateButtonsGroup1(void)
  {
//--- Armazena o ponteiro da janela
   m_buttons_group1.WindowPointer(m_window);
//--- Coordenadas
   int x =m_window.X()+BUTTONS_GROUP1_GAP_X;
   int y =m_window.Y()+BUTTONS_GROUP1_GAP_Y;
//--- Propriedades
   int    buttons_x_gap[]         ={0,72,144,216};
   string buttons_text[]          ={"BUTTON 1","BUTTON 2","BUTTON 3","BUTTON 4"};
   int    buttons_width[]         ={70,70,70,70};
   color  buttons_color[]         ={C'195,0,0',C'195,0,0',clrRoyalBlue,clrRoyalBlue};
   color  buttons_color_hover[]   ={C'255,51,51',C'255,51,51',C'85,170,255',C'85,170,255'};
   color  buttons_color_pressed[] ={C'135,0,0',C'135,0,0',C'50,100,135',C'50,100,135'};
//--- Define as propriedades
   m_buttons_group1.TextColor(clrWhite);
   m_buttons_group1.TextColorPressed(clrGold);
//--- Adiciona quatro botões para um grupo
   for(int i=0; i<4; i++)
      m_buttons_group1.AddButton(buttons_x_gap[i],0,buttons_text[i],buttons_width[i],
                                 buttons_color[i],buttons_color_hover[i],buttons_color_pressed[i]);
//--- Criar um grupo de botões
   if(!m_buttons_group1.CreateButtonsGroup(m_chart_id,m_subwin,x,y))
      return(false);
//--- Realce o segundo botão no grupo
   m_buttons_group1.SelectionButton(1);
//--- Adiciona um objeto ao array comum de grupos de objetos
   CWndContainer::AddToElementsArray(0,m_buttons_group1);
   return(true);
  }

Após compilar os arquivos e carregar o programa no gráfico, você deve obter o resultado como é mostrado na imagem abaixo.

Fig. 2. Teste do grupo de botões de controle simples.

Fig. 2. Teste do grupo de botões de controle simples.


Nós terminamos o desenvolvimento do primeiro grupo de botões. A versão completa da classe CButtonsGroup pode ser baixada no final deste artigo. O próximo controle que vamos considerar é um grupo de botões de radio. 


 


Desenvolvimento da Classe para Criar os Grupos de Botões de Radio

Crie o arquivo RadioButtons.mqh com a classe CRadioButtons que deve conter os métodos virtuais padrões e os membros da classe para armazenar e obter o ponteiro do formulário. Você pode ver os exemplos nas classes de outros controles acima. Inclua o arquivo RadioButtons.mqh na biblioteca (WndContainer.mqh).

Cada elemento de rádio será composto por três objetos primitivos:

  1. fundo;
  2. ícone;
  3. rótulo de texto.

Fig. 3. Partes integrantes dos botões de radio.

Fig. 3. Partes integrantes dos botões de radio.


Ao contrário de um grupo de botões simples, um grupo de botões de radio terá apenas um modo. Isso ocorre pois neste controle todos os botões não podem ser soltos simultaneamente. Um botão neste grupo será sempre pressionado. A cor de fundo do grupo é geralmente a mesma que o plano de fundo do formulário em que o grupo está ligado. Essencialmente, ele é usado para identificar o foco e monitorar o pressionamento de um botão de radio (prioridade mais elevada). Nesta versão, nós podemos configurar a alteração da cor apenas para o rótulo de texto quando o cursor entra na área do fundo do botão e sai de lá. As listas de propriedades únicas e comuns de um botão de radio são diferentes das listas de propriedades de um botão simples, como é mostrado abaixo.

Propriedades comuns:

  • Cor de fundo e do quadro.
  • Cor do texto.
  • Altura.
  • Botão com ícones para o estado (1) ativo, (2) desativado e (3) bloqueado.
  • Prioridade do botão esquerdo do mouse.

Propriedades únicas:

  • Texto.
  • Largura.
  • Estado. Apenas um botão no grupo pode ser pressionado.
  • Margens. Semelhante aos botões simples, os botões de radio podem ser organizadas em qualquer ordem (mosaico, horizontal, vertical, etc.).
  • Gradientes para os rótulos de texto.


Você pode ver como ele é no código da classe CRadioButtons abaixo. O redimensionamento das propriedades do array e o seu preenchimento com os valores são realizados com o método público CRadioButtons::AddButton() antes de criar o controle na classe personalizada. Se não há botões adicionados, então, a criação da interface gráfica será terminada. Isso foi demonstrado no desenvolvimento da classe para a criação de um grupo de botões simples, portanto, nós não vamos mais gastar tempo com ele.

//+------------------------------------------------------------------+
//| Classe para a criação dos grupos de botões de radio              |
//+------------------------------------------------------------------+
class CRadioButtons : public CElement
  {
private:
   //--- Gradientes dos rótulos de texto
   struct LabelsGradients
     {
      color             m_labels_color_array[];
     };
   LabelsGradients   m_labels_total[];
   //--- Propriedades do botão:
   //     (1) Cor e (2) a prioridade do plano de fundo do botão esquerdo do mouse
   color             m_area_color;
   int               m_area_zorder;
   //--- Arrays para as propriedades únicas dos botões
   bool              m_buttons_state[];
   int               m_buttons_x_gap[];
   int               m_buttons_y_gap[];
   int               m_buttons_width[];
   string            m_buttons_text[];
   //--- Altura dos botões
   int               m_button_y_size;
   //--- Ícones para os botões no estado ativo, desativado e bloqueado
   string            m_icon_file_on;
   string            m_icon_file_off;
   string            m_icon_file_on_locked;
   string            m_icon_file_off_locked;
   //--- Cor do texto
   color             m_text_color;
   color             m_text_color_off;
   color             m_text_color_hover;
   //--- Prioridade do botão esquerdo do mouse
   int               m_buttons_zorder;
   //---
public:
   //--- Definindo os ícones para o botão no estado ativo, desativado e bloqueado
   void              IconFileOn(const string file_path)           { m_icon_file_on=file_path;         }
   void              IconFileOff(const string file_path)          { m_icon_file_off=file_path;        }
   void              IconFileOnLocked(const string file_path)     { m_icon_file_on_locked=file_path;  }
   void              IconFileOffLocked(const string file_path)    { m_icon_file_off_locked=file_path; }
   //--- (1) A cor do fundo, (2) a cor do texto
   void              AreaColor(const color clr)                   { m_area_color=clr;                 }
   void              TextColor(const color clr)                   { m_text_color=clr;                 }
   void              TextColorOff(const color clr)                { m_text_color_off=clr;             }
   void              TextColorHover(const color clr)              { m_text_color_hover=clr;           }

   //--- Adiciona um botão com as propriedades especificadas antes de sua criação
   void              AddButton(const int x_gap,const int y_gap,const string text,const int width);
  };

Em seguida, nós precisamos criar os arrays de instâncias de classes de objetos primitivos e os métodos para a sua criação. Semelhante ao grupo de botões simples, os botões de radio serão criados em um loop. No entanto, aqui o loop será localizado no método principal e o índice, que participará na formação do nome de cada objeto, será passado para os métodos de criação desses objetos.

class CRadioButtons : public CElement
  {
private:
   //--- Objetos para a criação de um botão
   CRectLabel        m_area[];
   CBmpLabel         m_icon[];
   CLabel            m_label[];
   //---
public:
   //--- Métodos para a criação de um botão
   bool              CreateRadioButtons(const long chart_id,const int window,const int x,const int y);
   //---
private:
   bool              CreateArea(const int index);
   bool              CreateRadio(const int index);
   bool              CreateLabel(const int index);
   //---
public:
   //--- Número de botões
   int               RadioButtonsTotal(void)                const { return(::ArraySize(m_icon));      }
  };
//+------------------------------------------------------------------+
//| Cria um grupo de objetos de botões                               |
//+------------------------------------------------------------------+
bool CRadioButtons::CreateRadioButtons(const long chart_id,const int window,const int x,const int y)
  {
//--- Retorna se não há nenhum ponteiro do formulário
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
     {
      ::Print(__FUNCTION__," > Antes de criar um grupo de botões de radio, a classe deve ser passada "
              "para o ponteiro do formulário: CButtonsGroup::WindowPointer(CWindow &object)");
      return(false);
     }
//--- Inicializa as variáveis​
   m_id       =m_wnd.LastId()+1;
   m_chart_id =chart_id;
   m_subwin   =window;
   m_x        =x;
   m_y        =y;
//--- Obtém o número de botões no grupo
   int radio_buttons_total=RadioButtonsTotal();
//--- Se não existir um botão em um grupo, reporta
   if(radio_buttons_total<1)
     {
      ::Print(__FUNCTION__," > Este método era para ser chamado, "
              "se um grupo conter pelo menos um botão! Utiliza o método CRadioButtons::AddButton()");
      return(false);
     }
//--- Configura um grupo de botões
   for(int i=0; i<radio_buttons_total; i++)
     {
      CreateArea(i);
      CreateRadio(i);
      CreateLabel(i);
      //--- Zera o foco
      m_area[i].MouseFocus(false);
     }
//--- Oculta o elemento se ela for uma janela de diálogo ou está minimizada
   if(m_wnd.WindowType()==W_DIALOG || m_wnd.IsMinimized())
      Hide();
//---
   return(true);
  }

Essa classe também deve conter os métodos para alterar o estado de um controle (disponível/bloqueado) e alternar o estado do botão pelo índice especificado. Aqui, estes métodos são um pouco mais simples do que na classe CButtonsGroup, pois um grupo de elementos de radio possui um único modo. Você pode estudar estes métodos nos arquivos anexados deste artigo. Além disso, esta classe requer os métodos para obter o texto e o índice do botão destacado como na classe dos botões simples.

class CButtonsGroup : public CElement
  {
private:
   //--- (1) Texto e (2) o índice do botão em destaque
   string            m_selected_button_text;
   int               m_selected_button_index;
   //--- Disponível/bloqueado
   bool              m_buttons_group_state;
   //---
public:
   //--- Estado geral do grupo de botões (disponível/bloqueado)
   bool              ButtonsGroupState(void)                  const { return(m_buttons_group_state);   }
   void              ButtonsGroupState(const bool state);
   //--- Retorna (1) o texto e (2) o índice do botão em destaque
   string            SelectedButtonText(void)                 const { return(m_selected_button_text);  }
   int               SelectedButtonIndex(void)                const { return(m_selected_button_index); }
   //--- Alterna o estado do botão pelo índice especificado
   void              SelectionButton(const int index);
  };

Nós vamos usar o novo identificador ON_CLICK_LABEL para enviar uma mensagem sobre o pressionamento dos controles que se parecem com um rótulo de texto no formulário. Adicione isso ao arquivo Defines.mqh:

#define ON_CLICK_LABEL            (10) // Pressionando o rótulo de texto

A implementação do método de tratamento do pressionamento do grupo de botões é mostrada abaixo. Depois de passar pelas seguintes verificações: (1) o tipo de controle que ele pertence, (2) o identificador e (3) sua disponibilidade, o índice do botão pressionado será identificado pelo exato nome num loop. Se um botão deste grupo for pressionado e este botão não está em destaque atualmente, será realizado a alternância e uma mensagem será enviada, podendo ser recebida na classe personalizada.

class CButtonsGroup : public CElement
  {
private:
   //--- Manipulando o pressionamento do botão
   bool              OnClickButton(const string pressed_object);
   //--- Obtendo o identificador do nome do botão de radio
   int               IdFromObjectName(const string object_name);
  };
//+------------------------------------------------------------------+
//| Manipulador de eventos do gráfico                                |
//+------------------------------------------------------------------+
void CRadioButtons::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Manipula o evento do clique do botão esquerdo do mouse sobre o objeto
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Alterna o estado do botão
      if(OnClickButton(sparam))
         return;
     }
  }
//+------------------------------------------------------------------+
//| Pressionando o botão de radio                                    |
//+------------------------------------------------------------------+
bool CRadioButtons::OnClickButton(const string pressed_object)
  {
//--- Sai, se o pressionamento não foi no elemento de menu
   if(::StringFind(pressed_object,CElement::ProgramName()+"_radio_area_",0)<0)
      return(false);
//--- Obtém o identificador e o índice a partir do nome do objeto
   int id=IdFromObjectName(pressed_object);
//--- Sai, se o pressionamento não foi para o elemento ao qual este menu de contexto está ligado
   if(id!=CElement::Id())
      return(false);
//--- Para verificar o índice
   int check_index=WRONG_VALUE;
//--- Sai, se os botões estão bloqueados
   if(!m_radio_buttons_state)
      return(false);
//--- Se o pressionamento ocorreu, armazena o índice
   int radio_buttons_total=RadioButtonsTotal();
   for(int i=0; i<radio_buttons_total; i++)
     {
      if(m_area[i].Name()==pressed_object)
        {
         check_index=i;
         break;
        }
     }
//--- Sai, se não houver o pressionamento de um botão neste grupo ou
//    se este já for um botão de radio em destaque
   if(check_index==WRONG_VALUE || check_index==m_selected_button_index)
      return(false);
//--- Alterna o estado do botão
   SelectionRadioButton(check_index);
//--- Envia um sinal sobre ele
   ::EventChartCustom(m_chart_id,ON_CLICK_LABEL,CElement::Id(),check_index,m_selected_button_text);
   return(true);
  }

Agora, tudo está pronto para o teste. Adicione quatro grupos de quatro botões de radio (CRadioButtons) e um grupo de botões simples (CButtonsGroup) ao EA, que foi utilizado para o teste de um grupo de botões simples. 

class CProgram : public CWndEvents
  {
private:
   //--- Grupo de botões de radio 1
   CRadioButtons     m_radio_buttons1;
   //--- Grupo de botões simples  2
   CButtonsGroup     m_buttons_group2;
   //--- Grupos de botões de radio 2,3,4
   CRadioButtons     m_radio_buttons2;
   CRadioButtons     m_radio_buttons3;
   CRadioButtons     m_radio_buttons4;
   //---
private:
   //--- Grupo de botões de radio 1
#define RADIO_BUTTONS1_GAP_X     (7)
#define RADIO_BUTTONS1_GAP_Y     (75)
   bool              CreateRadioButtons1();
   //--- Grupo de botões simples  2
#define BUTTONS_GROUP2_GAP_X     (7)
#define BUTTONS_GROUP2_GAP_Y     (100)
   bool              CreateButtonsGroup2(void);
   //--- Grupos de botões de radio 2,3,4
#define RADIO_BUTTONS2_GAP_X     (7)
#define RADIO_BUTTONS2_GAP_Y     (125)
   bool              CreateRadioButtons2();
#define RADIO_BUTTONS3_GAP_X     (105)
#define RADIO_BUTTONS3_GAP_Y     (125)
   bool              CreateRadioButtons3();
#define RADIO_BUTTONS4_GAP_X     (203)
#define RADIO_BUTTONS4_GAP_Y     (125)
   bool              CreateRadioButtons4();
  };
//+------------------------------------------------------------------+
//| Cria o painel de negociação                                      |
//+------------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Criação de um formulário para os controles
//--- Criação dos controles:
//    Menu principal
//--- Menus de contexto

//--- Grupo de botões simples 1
//--- Grupo de botões de radio 1
   if(!CreateRadioButtons1())
      return(false);
//--- Grupo de botões simples  2
   if(!CreateButtonsGroup2())
      return(false);
   //--- Grupos de botões de radio 2,3,4
   if(!CreateRadioButtons2())
      return(false);
   if(!CreateRadioButtons3())
      return(false);
   if(!CreateRadioButtons4())
      return(false);
//--- Redesenho do gráfico
   m_chart.Redraw();
   return(true);
  }

Nós vamos utilizar a implementação do método de um deles como exemplo. O resto irá diferir apenas nos valores de parâmetros. 

//+------------------------------------------------------------------+
//| Cria um grupo de botões de radio 1                               |
//+------------------------------------------------------------------+
bool CProgram::CreateRadioButtons1(void)
  {
//--- Passa o objeto do painel
   m_radio_buttons1.WindowPointer(m_window);
//--- Coordenadas
   int x =m_window.X()+RADIO_BUTTONS1_GAP_X;
   int y =m_window.Y()+RADIO_BUTTONS1_GAP_Y;
//--- Propriedades
   int    buttons_x_offset[] ={0,98,196};
   int    buttons_y_offset[] ={0,0,0};
   string buttons_text[]     ={"Radio Button 1","Radio Button 2","Radio Button 3"};
   int    buttons_width[]    ={92,92,92};
//---
   for(int i=0; i<3; i++)
      m_radio_buttons1.AddButton(buttons_x_offset[i],buttons_y_offset[i],buttons_text[i],buttons_width[i]);
//--- Criar um grupo de botões
   if(!m_radio_buttons1.CreateRadioButtons(m_chart_id,m_subwin,x,y))
      return(false);
//--- Realce o segundo botão no grupo
   m_radio_buttons1.SelectedRadioButton(1);
//--- Bloqueia os botões de radio
   m_radio_buttons1.RadioButtonsState(false);
//--- Adiciona um objeto ao array comum de grupos de objetos
   CWndContainer::AddToElementsArray(0,m_radio_buttons1);
   return(true);
  }

Vamos criar dois botões no grupo adicional de botões (segundo) do tipo CButtonsGroup. Para fins de ilustração, vamos organizar isso de modo que o segundo botão deste grupo irá bloquear os primeiros grupos de botões simples e de radio e o primeiro irá torná-los disponíveis.

//+------------------------------------------------------------------+
//| Manipulador de eventos                                           |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Pressionando o botão de evento
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     {
      ::Print("id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Se o identificador do segundo grupo ou os botões simples e 
      //     o texto do botão em destaque neste grupo corresponde ao parâmetro de string da mensagem
      if(lparam==m_buttons_group2.Id() && sparam==m_buttons_group2.SelectedButtonText())
        {
         //--- Se este é o índice do primeiro botão, desbloqueie os controles especificados
         if((int)dparam==0)
           {
            m_buttons_group1.ButtonsGroupState(true);
            m_radio_buttons1.RadioButtonsState(true);
           }
         //--- Se este é o índice do segundo botão, bloqueia os controles especificado
         else
           {
            m_buttons_group1.ButtonsGroupState(false);
            m_radio_buttons1.RadioButtonsState(false);
           }
        }
      return;
     }     
  }

Compile os arquivos e carregue o programa ao gráfico. Nesta fase de desenvolvimento, você deve obter o resultado como é mostrado na imagem abaixo.

Fig. 4. Teste do controle botão de radio.

Fig. 4. Teste do controle botão de radio.


Nós terminamos o desenvolvimento da classe para a criação do grupo de controle botões de radio. Você pode baixar a versão completa nos arquivos anexados deste artigo. 

 


Desenvolvimento da Classe para Criar os Grupos de Botões com Ícone

Nós já criamos anteriormente a classe CIconButton para criar o controle botão com ícone. Agora, nós vamos implementar um controle que nos permitirá criar um grupo de tais botões. Crie o arquivo IconButtonsGroup.mqh com a classe CIconButtonsGroup onde você poderá declarar e implementar os métodos virtuais padrões na pasta Controls que contém os arquivos criados anteriormente com as classes de controles. Inclua este arquivo WndContainer.mqh na biblioteca.

Não vamos descrever isto em detalhes já que a classe CIconButtonsGroup é essencialmente uma composição dos métodos que já foram considerados na classe CButtonsGroup e CRadioButtons. Semelhante a classe CRadioButtons de botões de radio, os objetos do grupo de botões serão criados com métodos privados em um loop do método principal para a criação do controle. O único parâmetro desses métodos é o índice que será utilizado para formar os nomes dos objetos gráficos. Nós podemos organizar com que os botões deste grupo alterem a sua cor de fundo e o texto quando o cursor do mouse estiver sobre eles. 

Os métodos relativos à manipulação de eventos já foram discutidos neste artigo. Eles são os mesmos neste tipo de grupo de botões, por isso, nós vamos mostrar apenas o conteúdo da classe CIconButtonsGroup no código abaixo. A implementação dos métodos que estão fora do corpo da classe podem ser encontrados nos arquivos anexados neste artigo.

//+------------------------------------------------------------------+
//| Classe para criar um grupo de botões com ícones                  |
//+------------------------------------------------------------------+
class CIconButtonsGroup : public CElement
  {
private:
   //--- Ponteiro para o formulário ao qual o controle será anexado
   CWindow          *m_wnd;
   //--- Objetos para a criação de um botão
   CButton           m_buttons[];
   CBmpLabel         m_icons[];
   CLabel            m_labels[];
   //--- Gradientes dos rótulos de texto
   struct IconButtonsGradients
     {
      color             m_back_color_array[];
      color             m_label_color_array[];
     };
   IconButtonsGradients   m_icon_buttons_total[];
   //--- Propriedades do botão:
   //    Arrays de propriedades únicas dos botões
   bool              m_buttons_state[];
   int               m_buttons_x_gap[];
   int               m_buttons_y_gap[];
   string            m_buttons_text[];
   int               m_buttons_width[];
   string            m_icon_file_on[];
   string            m_icon_file_off[];
   //--- Altura dos botões
   int               m_buttons_y_size;
   //--- A cor do fundo em diferentes modos
   color             m_back_color;
   color             m_back_color_off;
   color             m_back_color_hover;
   color             m_back_color_pressed;
   //--- Cor do quadro
   color             m_border_color;
   color             m_border_color_off;
   //--- Margens do ícone
   int               m_icon_x_gap;
   int               m_icon_y_gap;
   //--- Margens do texto e do rótulo de texto
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Cor do rótulo de texto em diferentes modos
   color             m_label_color;
   color             m_label_color_off;
   color             m_label_color_hover;
   color             m_label_color_pressed;
   //--- (1) Texto e (2) o índice do botão em destaque
   string            m_selected_button_text;
   int               m_selected_button_index;
   //--- Prioridade Geral dos objetos não clicáveis
   int               m_zorder;
   //--- Prioridade do botão esquerdo do mouse
   int               m_buttons_zorder;
   //--- Disponível/bloqueado
   bool              m_icon_buttons_state;
   //---
public:
                     CIconButtonsGroup(void);
                    ~CIconButtonsGroup(void);
   //--- Métodos para a criação de um botão
   bool              CreateIconButtonsGroup(const long chart_id,const int window,const int x,const int y);
   //---
private:
   bool              CreateButton(const int index);
   bool              CreateIcon(const int index);
   bool              CreateLabel(const int index);
   //---
public:
   //--- (1) Armazena o ponteiro do formulário, (2) a altura do botão, (3) o número de botões,
   //     (4) o estado geral do botão (disponível/bloqueado)
   void              WindowPointer(CWindow &object)               { m_wnd=::GetPointer(object);      }
   void              ButtonsYSize(const int y_size)               { m_buttons_y_size=y_size;         }
   int               IconButtonsTotal(void)                 const { return(::ArraySize(m_icons));    }
   bool              IconButtonsState(void)                 const { return(m_icon_buttons_state);    }
   void              IconButtonsState(const bool state);
   //--- Cores de fundo do botão
   void              BackColor(const color clr)                   { m_back_color=clr;                }
   void              BackColorOff(const color clr)                { m_back_color_off=clr;            }
   void              BackColorHover(const color clr)              { m_back_color_hover=clr;          }
   void              BackColorPressed(const color clr)            { m_back_color_pressed=clr;        }
   //--- Margens do ícone
   void              IconXGap(const int x_gap)                    { m_icon_x_gap=x_gap;              }
   void              IconYGap(const int y_gap)                    { m_icon_y_gap=y_gap;              }
   //--- Margens do rótulo de texto
   void              LabelXGap(const int x_gap)                   { m_label_x_gap=x_gap;             }
   void              LabelYGap(const int y_gap)                   { m_label_y_gap=y_gap;             }
   //--- Retorna (1) o texto e (2) o índice do botão em destaque
   string            SelectedButtonText(void)               const { return(m_selected_button_text);  }
   int               SelectedButtonIndex(void)              const { return(m_selected_button_index); }
   //--- Alterna o estado de um botão de opção pelo índice especificado
   void              SelectedRadioButton(const int index);

   //--- Adiciona um botão com as propriedades especificadas antes de sua criação
   void              AddButton(const int x_gap,const int y_gap,const string text,
                               const int width,const string icon_file_on,const string icon_file_off);
   //--- Altera a cor
   void              ChangeObjectsColor(void);
   //---
public:
   //--- Manipulador de eventos do gráfico
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Timer
   virtual void      OnEventTimer(void);
   //--- Mover o controle
   virtual void      Moving(const int x,const int y);
   //--- (1) Exibe, (2) oculta, (3) reseta, (4) remove
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- (1) Definir (2), resetar as prioridades para o clique esquerdo do mouse
   virtual void      SetZorders(void);
   virtual void      ResetZorders(void);
   //---
private:
   //--- Manipulando o pressionamento do botão
   bool              OnClickButton(const string pressed_object);
   //--- Verifica o pressionamento do botão esquerdo do mouse sobre um grupo de botões
   void              CheckPressedOverButton(void);
   //--- Obtendo o identificador do nome do botão de radio
   int               IdFromObjectName(const string object_name);
  };

Vamos testar este controle. Como um exemplo, crie um grupo de botões com ícones no formulário do mesmo EA onde nós testamos anteriormente os grupos de botões do tipo CButtonsGroup e CRadioButtons. Para isso, adicione as seguintes linhas de código para a classe personalizada como é mostrado no código abaixo.

class CProgram : public CWndEvents
  {
private:
   //--- Grupo de botões com ícones 1
   CIconButtonsGroup m_icon_buttons_group1;
   //---
private:
   //--- Grupo de botões com ícones 1
#define IBUTTONS_GROUP1_GAP_X    (7)
#define IBUTTONS_GROUP1_GAP_Y    (190)
   bool              CreateIconButtonsGroup1(void);
  };
//+------------------------------------------------------------------+
//| Cria o painel de negociação                                      |
//+------------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Criação de um formulário para os controles
//--- Criação dos controles:
//    Menu principal
//--- Menus de contexto

//--- Grupo de botões simples 1
//--- Grupo de botões de radio 1
//--- Grupo de botões simples  2
//--- Grupos de botões de radio 2,3,4
//--- Grupo de botões com ícones 1
   if(!CreateIconButtonsGroup1())
      return(false);
//--- Redesenho do gráfico
   m_chart.Redraw();
   return(true);
  }

Compile os arquivos e carregue o programa ao gráfico. Você deve obter o resultado como é mostrado na imagem abaixo.

Fig. 5. Teste do grupo de botões com ícones.

Fig. 5. Teste do grupo de botões com ícones.


O desenvolvimento da classe para criar o controle grupo de botões com ícone foi concluído. Você pode baixar a versão completa nos arquivos anexados deste artigo.

 


Conclusão

Este é o fim da terceira parte da série sobre o desenvolvimento da biblioteca para a criação das interfaces gráficas nos terminais de negociação MetaTrader. Atualmente, a estrutura da biblioteca possui o seguinte aspecto:

Fig. 6. Estrutura da biblioteca no atual estágio de desenvolvimento.

Fig. 6. Estrutura da biblioteca no atual estágio de desenvolvimento.


Na próxima (quarta) parte da série, nós vamos continuar com o desenvolvimento da biblioteca. Nós vamos considerar os seguintes tópicos: 

  • Modo multi-janela. 
  • Sistema de gestão de prioridades do clique esquerdo do mouse sobre os objetos gráficos. 
  • Elementos de interface informativos como a barra de estado e as dicas de ferramentas.

Os arquivos abaixo com os arquivos da biblioteca no atual estágio de desenvolvimento, imagens e os arquivos dos programas considerados neste artigo podem ser baixados para a realização de testes nos terminais MetaTrader. Se você tiver dúvidas sobre a utilização do material a partir desses arquivos, você poderá consultar a descrição detalhada do desenvolvimento da biblioteca em um dos artigos da lista abaixo ou fazer sua pergunta nos comentários deste artigo. 

Lista de artigos (capítulos) da terceira parte:

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/2298

Arquivos anexados |
Auto-otimização do EA: Algoritmos evolutivos e genéticos Auto-otimização do EA: Algoritmos evolutivos e genéticos
Este artigo aborda os principais princípios estabelecidos nos algoritmos evolutivos, suas variedades e características. Vamos fazer uma experiência com um Expert Advisor simples, usado como exemplo para mostrar os benefícios do sistema de negociação a partir da otimização. Também iremos considerar programas de software que implementam otimizações genéticas, evolutivas, entre outros, fornecendo exemplos de aplicação ao otimizar um conjunto preditor e os parâmetros do sistema de negociação.
Interfaces Gráficas III: Botões Simples e Multifuncionais (Capítulo 1) Interfaces Gráficas III: Botões Simples e Multifuncionais (Capítulo 1)
Vamos começar a estudos sobre o controle chamado botão. Nós vamos mostrar exemplos de várias classes para a criação de um botão simples, botões com funcionalidades estendidas (botão com ícones/imagens e botão de divisão - "split button") e aqueles que são interconectados (grupos de botões e botão de radio). Além disso, nós vamos apresentar alguns incrementos para as classes existentes afim de ampliar a capacidade dos controles.
Como adicionar rapidamente paneis de controle a indicadores e conselheiros (EA) Como adicionar rapidamente paneis de controle a indicadores e conselheiros (EA)
Você deseja adicionar ao seu indicador ou conselheiro um painel gráfico para um controle fácil e rápido, mas não sabe como fazê-lo? Neste artigo, vou mostrar passo a passo como "atar" o painel de diálogo com os parâmetros de entrada do seu programa MQL4/MQL5.
Por onde começar ao criar um robô de negociação para operar na Bolsa de Valores de Moscou MOEX Por onde começar ao criar um robô de negociação para operar na Bolsa de Valores de Moscou MOEX
Na bolsa de valores de Moscou, muitos traders gostariam de automatizar seus algoritmos de negociação, mas não sabem por onde começar. A linguagem MQL5 não só oferece uma enorme gama de funções de negociação, mas também classes prontas que facilitam os primeiros passos no mundo do trading algorítmico.