English Русский 中文 Español Deutsch 日本語
Interfaces Gráficas VI: Os Controles Caixa de Seleção, Campo de Edição e seus Tipos Combinados (Capítulo 1)

Interfaces Gráficas VI: Os Controles Caixa de Seleção, Campo de Edição e seus Tipos Combinados (Capítulo 1)

MetaTrader 5Exemplos | 27 setembro 2016, 15:56
1 278 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. Você irã encontrar uma lista de artigos com os links no final de cada capítulo. 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.

A sexta parte da série consistirá de dois capítulos. No primeiro capítulo, nós vamos criar quatro controles:

  • Caixa de seleção (checkbox)
  • Campo de Edição
  • Campo de edição com a caixa de seleção
  • Lista combinada com a caixa de seleção

Nós vamos discutir apenas a caixa de seleção e o campo de edição já que a combinação dos dois não irá conter nada que nós não vimos antes. 

O segundo artigo será dedicado aos seguintes controles:

  • Deslizante
  • Deslizante duplo

 


O Controle Caixa de Seleção

O controle caixa de seleção é designado para o gerenciamento dos parâmetros que podem ter apenas dois estados. Um botão com dois ícones é usado para identificar o estado atual do parâmetro para o qual o controle está vinculado. O ícone com o símbolo de verificação significa que o parâmetro está habilitado (on). O ícone sem o símbolo de verificação significa que o parâmetro está desativado (off). Perto do botão é possível encontrar uma breve descrição do parâmetro. 

Este elemento será composto por três objetos gráficos. Eles são:

  1. Fundo
  2. Ícone (botão)
  3. Rótulo de texto

Fig. 1. Partes integrantes do controle caixa de seleção.

Fig. 1. Partes integrantes do controle caixa de seleção.

Vamos dar uma olhada mais a fundo na classe deste controle.

 


Desenvolvimento de uma Classe para a Criação do Controle Caixa de Seleção

Na terceira parte desta série, nós falamos sobre um controle semelhante - um botão com ícone e sua classe CIconButton (Veja o artigo Interfaces Gráficas III: Botões simples e Multifuncionais (Capítulo 1)). O controle caixa de seleção é semelhante à um botão com ícone no modo de dois estados. A única diferença aqui é que o botão em diferentes estados (on/off) possui uma cor de fundo e de texto diferente (se for definida), e no caso de uma caixa de seleção, apenas a cor do ícone e de texto que se alteram (se for definida). A cor de fundo da caixa de seleção será a mesma que a de fundo da janela ao qual ele está anexado. O fundo aqui será usado como a área para identificar o cursor do mouse em relação aos limites desta área e para identificar também o pressionamento do botão esquerdo do mouse sobre o controle. O controle caixa de seleção é mais simples do que um botão com ícone, já que ele tem menos propriedades que o usuário possa definir.

Crie o arquivo CheckBox.mqh e inclua-o no arquivo WndContainer.mqh da biblioteca:

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

Cria a classe CCheckBox com os métodos padrão para todos os elementos da biblioteca no arquivo CheckBox.mqh:

//+------------------------------------------------------------------+
//|                                                     CheckBox.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
//+------------------------------------------------------------------+
//| Classe para criar a caixa de seleção                             |
//+------------------------------------------------------------------+
class CCheckBox : public CElement
  {
private:
   //--- Ponteiro para o formulário ao qual o elemento está anexado
   CWindow          *m_wnd;
   //---
public:
                     CCheckBox(void);
                    ~CCheckBox(void);
   //--- Armazena o ponteiro do formulário
   void              WindowPointer(CWindow &object)                 { m_wnd=::GetPointer(object);            }
   //---
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);
   //--- Move o elemento
   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);
   //--- Resetar a cor
   virtual void      ResetColors(void);
  };

Antes do controle ser criado, o usuário será capaz de utilizar os métodos para a instalação das propriedades listadas abaixo:

  • Fundo do controle
  • Ícones para a caixa de seleção nos estados ativo e bloqueado
  • Margens para o rótulo de texto
  • Cores do rótulo de texto em diferentes estados

Haverá quatro ícones para o botão caixa de seleção - dois ícones para o estado ativo e dois para o estado bloqueado. Os ícones para todos os estados estão disponíveis no final deste artigo, mas você poderá utilizar os seus ícones personalizados. 

class CCheckBox : public CElement
  {
private:
   //--- Cor de fundo da caixa de seleção
   color             m_area_color;
   //--- Ícones da caixa de seleção nos estados ativo e bloqueado
   string            m_check_bmp_file_on;
   string            m_check_bmp_file_off;
   string            m_check_bmp_file_on_locked;
   string            m_check_bmp_file_off_locked;
   //--- Texto da caixa de seleção
   string            m_label_text;
   //--- Margens do rótulo de texto
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Cores do rótulo de texto em diferentes estados
   color             m_label_color;
   color             m_label_color_off;
   color             m_label_color_hover;
   color             m_label_color_locked;
   color             m_label_color_array[];
   //--- Prioridades do clique do botão esquerdo do mouse
   int               m_zorder;
   int               m_area_zorder;
   //---
public:
   //--- Definir os rótulos para o botão nos estados ativo e bloqueado
   void              CheckFileOn(const string file_path)            { m_check_bmp_file_on=file_path;         }
   void              CheckFileOff(const string file_path)           { m_check_bmp_file_off=file_path;        }
   void              CheckFileOnLocked(const string file_path)      { m_check_bmp_file_on_locked=file_path;  }
   void              CheckFileOffLocked(const string file_path)     { m_check_bmp_file_off_locked=file_path; }
   //--- (1) cor de fundo, (2) margens do rótulo de texto
   void              AreaColor(const color clr)                     { m_area_color=clr;                      }
   void              LabelXGap(const int x_gap)                     { m_label_x_gap=x_gap;                   }
   void              LabelYGap(const int y_gap)                     { m_label_y_gap=y_gap;                   }
   //--- Cor do texto em diferentes estados
   void              LabelColor(const color clr)                    { m_label_color=clr;                     }
   void              LabelColorOff(const color clr)                 { m_label_color_off=clr;                 }
   void              LabelColorHover(const color clr)               { m_label_color_hover=clr;               }
   void              LabelColorLocked(const color clr)              { m_label_color_locked=clr;              }
   //--- Descrição da caixa de seleção
   string            LabelText(void)                          const { return(m_label.Description());         }
  };

Para criar o controle de caixa de seleção, nós vamos precisar de três métodos privados e um público:

class CCheckBox : public CElement
  {
private:
   //--- Objetos para a criação da caixa de seleção
   CRectLabel        m_area;
   CBmpLabel         m_check;
   CLabel            m_label;
   //---
public:
   //--- Métodos para criar uma caixa de seleção
   bool              CreateCheckBox(const long chart_id,const int subwin,const string text,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateCheck(void);
   bool              CreateLabel(void);
  };

Vamos criar os métodos CCheckBox::CheckButtonState() e CCheckBox::CheckBoxState() para gerenciar o estado da caixa de seleção:

class CCheckBox : public CElement
  {
private:
   //--- Estado do botão da caixa de seleção
   bool              m_check_button_state;
   //--- Estado da caixa de seleção(disponível/bloqueado)
   bool              m_checkbox_state;
   //---
public:
   //--- Retorna/define o estado da caixa de seleção
   bool              CheckBoxState(void)                      const { return(m_checkbox_state);              }
   void              CheckBoxState(const bool state);
   //--- Retorna/define o estado do botão da caixa de seleção
   bool              CheckButtonState(void)                   const { return(m_check.State());               }
   void              CheckButtonState(const bool state);
  };

Para bloquear/desbloquear o controle, use o método CCheckBox::CheckBoxState():

//+------------------------------------------------------------------+
//| Define o estado do controle                                      |
//+------------------------------------------------------------------+
void CCheckBox::CheckBoxState(const bool state)
  {
//--- Estado do Controle
   m_checkbox_state=state;
//--- Ícone
   m_check.BmpFileOn((state)? "::"+m_check_bmp_file_on : "::"+m_check_bmp_file_on_locked);
   m_check.BmpFileOff((state)? "::"+m_check_bmp_file_off : "::"+m_check_bmp_file_off_locked);
//--- Cor do rótulo de texto
   m_label.Color((state)? m_label_color : m_label_color_locked);
  }

Para definir o estado do botão caixa de seleção, utilize o método CCheckBox::CheckButtonState(): 

//+------------------------------------------------------------------+
//| Define o estado do botão da caixa de seleção                     |
//+------------------------------------------------------------------+
void CCheckBox::CheckButtonState(const bool state)
  {
//--- Sai, se o controle está bloqueado
   if(!m_checkbox_state)
      return;
//--- Define o estado do botão
   m_check.State(state);
   m_check_button_state=state;
//--- Alterar as cores de acordo com o estado atual
   m_label.Color((state)? m_label_color : m_label_color_off);
   CElement::InitColorArray((state)? m_label_color : m_label_color_off,m_label_color_hover,m_label_color_array);
  }

Nós só temos que criar um método para lidar com o clique sobre o controle de caixa de seleção. Este método será chamado no manipulador principal do controle pelo evento CCheckBox::OnEvent() com o identificador CHARTEVENT_OBJECT_CLICK. Vamos chamá-lo de CCheckBox::OnClickLabel(). No início deste método, há uma verificação se o clique foi sobre a área de controle (no fundo). Para evitar confusão sobre qual objeto do controle que o clique deve exatamente levar em conta, o fundo possui uma prioridade para o clique do botão esquerdo do mouse no valor igual a 1 enquanto que os outros objetos tem o valor igual a 0. Portanto, mesmo que o clique foi quando o cursor estava sobre um botão da caixa de seleção ou de um rótulo de texto, ele será tratado como um clique no fundo do controle, que é o objeto com a maior prioridade nesta área. Então, nós vamos usar o método CCheckBox::CheckButtonState() para definir o estado oposto no botão caixa de seleção. No final do método, é enviado um evento personalizado com (1) o identificador do evento ON_CLICK_LABEL, (2) o identificador do elemento e (3) a descrição do elemento.

class CCheckBox : public CElement
  {
private:
   //--- Manipulação do clique sobre o elemento
   bool              OnClickLabel(const string clicked_object);
  };
//+------------------------------------------------------------------+
//| Manipulador de evento                                            |
//+------------------------------------------------------------------+
void CCheckBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Manipula o clique do botão esquerdo do mouse sobre o objeto
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Clique na caixa de seleção
      if(OnClickLabel(sparam))
         return;
     }
  }
//+------------------------------------------------------------------+
//| Clique no rótulo do elemento                                     |
//+------------------------------------------------------------------+
bool CCheckBox::OnClickLabel(const string clicked_object)
  {
//--- Sai se o nome for diferente
   if(m_area.Name()!=clicked_object)
      return(false);
//--- Sai, se o controle está bloqueado
   if(!m_checkbox_state)
      return(false);
//--- Muda para o estado oposto
   CheckButtonState(!m_check.State());
//--- O cursor do mouse está atualmente sobre o elemento
   m_label.Color(m_label_color_hover);
//--- Envia uma mensagem sobre ele
   ::EventChartCustom(m_chart_id,ON_CLICK_LABEL,CElement::Id(),0,m_label.Description());
   return(true);
  }

 

 


Teste do Controle Caixa de Seleção

Todos os métodos da classe CCheckBox estão prontos para que nós possamos testar o funcionamento deste controle. O arquivo com a classe deste controle já deve estar incluída na biblioteca. O EA para testes pode ser copiado do artigo anterior. Remova todos os controles dele, exceto o menu principal e a barra de estado. Crie duas caixas de seleção para o teste. Certifique-se de que a segunda caixa de seleção está bloqueada por padrão no momento de carregar o programa ao gráfico. A primeira caixa de seleção estará disponível para interação com o usuário, porém, no estado desativado. Habilitando a primeira caixa de seleção, será um sinal para desbloquear a segunda caixa de seleção. O mesmo irá funcionar para a situação oposta - desativando a primeira caixa de seleção será um sinal para bloquear a segunda caixa de seleção.

Na classe personalizada CProgram crie duas instâncias da classe CCheckBox e declare dois métodos para a criação das caixas de seleção e especifique as margens da borda do formulário em que eles serão anexados: 

//+------------------------------------------------------------------+
//| Classe para a criação de um aplicativo                           |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
   //--- Caixas de seleção
   CCheckBox         m_checkbox1;
   CCheckBox         m_checkbox2;
   //---
private:
   //--- Caixas de seleção
#define CHECKBOX1_GAP_X       (7)
#define CHECKBOX1_GAP_Y       (50)
   bool              CreateCheckBox1(const string text);
#define CHECKBOX2_GAP_X       (30)
#define CHECKBOX2_GAP_Y       (75)
   bool              CreateCheckBox2(const string text);
  };

A única diferença na implementação do método será que a disponibilidade da segunda caixa de seleção irá depender do estado da primeira:

//+------------------------------------------------------------------+
//| Cria a caixa de seleção 2                                        |
//+------------------------------------------------------------------+
bool CProgram::CreateCheckBox2(string text)
  {
//--- Passa o objeto do painel
   m_checkbox2.WindowPointer(m_window1);
//--- Coordenadas
   int x=m_window1.X()+CHECKBOX2_GAP_X;
   int y=m_window1.Y()+CHECKBOX2_GAP_Y;
//--- Define as propriedades antes da criação
   m_checkbox2.XSize(90);
   m_checkbox2.YSize(18);
   m_checkbox2.AreaColor(clrWhiteSmoke);
   m_checkbox2.LabelColor(clrBlack);
   m_checkbox2.LabelColorOff(clrBlack);
   m_checkbox2.LabelColorLocked(clrSilver);
//--- Cria o controle
   if(!m_checkbox2.CreateCheckBox(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- A disponibilidade irá depender do estado atual da primeira caixa de seleção
   m_checkbox2.CheckBoxState(m_checkbox1.CheckButtonState()); 
//--- Adiciona o objeto para o array comum dos grupos de objetos
   CWndContainer::AddToElementsArray(0,m_checkbox2);
   return(true);
  }

Coloque as chamadas do método para a criação da caixas de seleção no método principal da criação da interface gráfica. Uma versão resumida deste código é apresentado a seguir:

//+------------------------------------------------------------------+
//| Cria o painel de negociação                                      |
//+------------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Criação do formulário 1 para os controles
//--- Criação dos controles:
//    Menu principal
//--- Menus de contexto
//--- Criando a barra de status

//--- Caixas de seleção
   if(!CreateCheckBox1("Checkbox 1"))
      return(false);
   if(!CreateCheckBox2("Checkbox 2"))
      return(false);
//--- Redesenha o gráfico
   m_chart.Redraw();
   return(true);
  }

Nós vamos receber e processar uma mensagem com o identificador ON_CLICK_LABEL no manipulador de eventos da classe CProgram. A disponibilidade da segunda caixa de seleção será definido pelo estado da primeira como é mostrado no código abaixo: 

//+------------------------------------------------------------------+
//| Manipulador de eventos                                           |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- O evento clique na caixa de seleção
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Se o clique foi na primeira caixa de seleção
      if(lparam==m_checkbox1.Id())
        {
         //--- Define o estado da segunda caixa de seleção
         m_checkbox2.CheckBoxState(m_checkbox1.CheckButtonState());
        }
     }
  }

Agora, compile os arquivos e carregue o EA ao gráfico. O resultado deve ser como na imagem abaixo:

Fig. 2. Testando o controle caixa de seleção.

Fig. 2. Testando o controle caixa de seleção.


A imagem mostra que a segunda caixa de seleção está bloqueada. A indicação aqui é a cor do texto e o ícone do botão correspondente a este estado (as cores desvanecidas). Tudo está funcionando bem e nós vamos avançar para o desenvolvimento de uma classe para a criação do controle campo de edição. 

 


O Controle Campo de Edição

O controle campo de edição é usado para definir um valor numérico no campo de texto. O valor pode ser inserido manualmente ou com a ajuda dos botões de rolagem. Os valores máximos e mínimos (limites), bem como o passo da rolagem podem ser definidos pelo usuário. Se o botão com a seta para cima/baixo é pressionado uma vez, então o valor será aumentado/diminuído no passo especificado nas configurações. Se a seta de cima para baixo é pressionada e mantida para baixo, o valor no campo de edição será alterado rapidamente. A rolagem irá parar, tendo atingido o máximo ou mínimo permitido.

Este controle será composto por cinco objetos gráficos. Eles são:

  1. Fundo
  2. Rótulo de texto
  3. Campo de Edição
  4. Dois botões para a rolagem dos valores no controle campo de edição

Fig. 3. Partes integrantes do controle campo de edição.

Fig. 3. Partes integrantes do controle campo de edição.


Na próxima parte do artigo, nós vamos escrever uma classe para a criação deste controle de interface.

 


Desenvolvimento de uma Classe para a Criação do Controle Campo de Edição

Semelhante ao controle caixa de seleção, o controle campo de edição é simples, não sendo composto. Em outras palavras, ele é constituído por objetos simples e não contêm quaisquer outros controles. É por isso que não há necessidade de adições no arquivo WndContainer.mqh. Nós precisamos incluir apenas o arquivo com a classe do controle campo de edição.

Agora, crie o arquivo SpinEdit.mqh e inclua-o no arquivo WndContainer.mqh:

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

No arquivo SpinEdit.mqh, crie a classe CSpinEdit com os métodos padrão para todos os elementos da biblioteca como na descrição da classe CCheckBox no início deste artigo. É por isso que nós vamos diretamente para a descrição das propriedades do controle campo de edição. 

Abaixo está a lista de todas as propriedades do controle campo de edição que estará disponível para o usuário definir.

  • Cor de fundo
  • Texto da descrição do campo de edição
  • Margens do rótulo de texto
  • Cores do texto em diferentes estados
  • Tamanho do campo de edição
  • Margem do campo de edição do lado direito do elemento
  • Cores do campo de edição em estados diferentes
  • Cores do texto do campo de edição em diferentes estados
  • Cores do quadro do campo de edição em diferentes estados
  • Rótulos das chaves nos estados ativo e bloqueado
  • Margens do botão (do lado direito)
  • Modo de resetar o valor para a mínima
  • Valor mínimo e máximo
  • Passo para alterar o valor do campo de edição usando os botões
  • Modo de alinhamento de texto
  • Número de casas decimais

O código a seguir apresenta os campos e métodos da classe para definir as propriedades do controle listadas acima: 

//+------------------------------------------------------------------+
//| Classe para a criação do campo de edição                         |
//+------------------------------------------------------------------+
class CSpinEdit : public CElement
  {
private:
   //--- Cor de fundo do controle
   color             m_area_color;
   //--- Texto da descrição do campo de edição
   string            m_label_text;
   //--- Margens do rótulo de texto
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Cor do texto em diferentes estados
   color             m_label_color;
   color             m_label_color_hover;
   color             m_label_color_locked;
   color             m_label_color_array[];
   //--- Tamanho do campo de edição
   int               m_edit_x_size;
   int               m_edit_y_size;
   //--- Margem do campo de edição do lado direito do elemento
   int               m_edit_x_gap;
   //--- Cores do texto do campo de edição em diferentes estados
   color             m_edit_color;
   color             m_edit_color_locked;
   color             m_edit_text_color;
   color             m_edit_text_color_locked;
   color             m_edit_text_color_highlight;
   //--- Cores do quadro do campo de edição em diferentes estados
   color             m_edit_border_color;
   color             m_edit_border_color_hover;
   color             m_edit_border_color_locked;
   color             m_edit_border_color_array[];
   //--- Rótulos das chaves nos estados ativo e bloqueado
   string            m_inc_bmp_file_on;
   string            m_inc_bmp_file_off;
   string            m_inc_bmp_file_locked;
   string            m_dec_bmp_file_on;
   string            m_dec_bmp_file_off;
   string            m_dec_bmp_file_locked;
   //--- Margens do botão (do lado direito)
   int               m_inc_x_gap;
   int               m_inc_y_gap;
   int               m_dec_x_gap;
   int               m_dec_y_gap;
   //--- Modo de resetar o valor para a mínima
   bool              m_reset_mode;
   //--- Valor mínimo e máximo
   double            m_min_value;
   double            m_max_value;
   //--- Passo para alterar o valor do campo de edição
   double            m_step_value;
   //--- Modo de alinhamento de texto
   ENUM_ALIGN_MODE   m_align_mode;
   //--- Número de casas decimais
   int               m_digits;
   //---
public:
   //--- (1) Cor de fundo, (2) o texto da descrição do campo de edição, (3) margens do rótulo de texto
   void              AreaColor(const color clr)                     { m_area_color=clr;                   }
   string            LabelText(void)                          const { return(m_label.Description());      }
   void              LabelXGap(const int x_gap)                     { m_label_x_gap=x_gap;                }
   void              LabelYGap(const int y_gap)                     { m_label_y_gap=y_gap;                }
   //--- Cores do rótulo de texto em diferentes estados
   void              LabelColor(const color clr)                    { m_label_color=clr;                  }
   void              LabelColorHover(const color clr)               { m_label_color_hover=clr;            }
   void              LabelColorLocked(const color clr)              { m_label_color_locked=clr;           }
   //--- (1) Tamanho do campo de edição, (2) Margem do campo de edição do lado direito
   void              EditXSize(const int x_size)                    { m_edit_x_size=x_size;               }
   void              EditYSize(const int y_size)                    { m_edit_y_size=y_size;               }
   void              EditXGap(const int x_gap)                      { m_edit_x_gap=x_gap;                 }
   //--- Cores do campo de edição em estados diferentes
   void              EditColor(const color clr)                     { m_edit_color=clr;                   }
   void              EditColorLocked(const color clr)               { m_edit_color_locked=clr;            }
   //--- Cores do texto do campo de edição em diferentes estados
   void              EditTextColor(const color clr)                 { m_edit_text_color=clr;              }
   void              EditTextColorLocked(const color clr)           { m_edit_text_color_locked=clr;       }
   void              EditTextColorHighlight(const color clr)        { m_edit_text_color_highlight=clr;    }
   //--- Cores do quadro do campo de edição em diferentes estados
   void              EditBorderColor(const color clr)               { m_edit_border_color=clr;            }
   void              EditBorderColorHover(const color clr)          { m_edit_border_color_hover=clr;      }
   void              EditBorderColorLocked(const color clr)         { m_edit_border_color_locked=clr;     }
   //--- Definir os rótulos para o botão nos estados ativo e bloqueado
   void              IncFileOn(const string file_path)              { m_inc_bmp_file_on=file_path;        }
   void              IncFileOff(const string file_path)             { m_inc_bmp_file_off=file_path;       }
   void              IncFileLocked(const string file_path)          { m_inc_bmp_file_locked=file_path;    }
   void              DecFileOn(const string file_path)              { m_dec_bmp_file_on=file_path;        }
   void              DecFileOff(const string file_path)             { m_dec_bmp_file_off=file_path;       }
   void              DecFileLocked(const string file_path)          { m_dec_bmp_file_locked=file_path;    }
   //--- Margem dos botões do campo de edição
   void              IncXGap(const int x_gap)                       { m_inc_x_gap=x_gap;                  }
   void              IncYGap(const int y_gap)                       { m_inc_y_gap=y_gap;                  }
   void              DecXGap(const int x_gap)                       { m_dec_x_gap=x_gap;                  }
   void              DecYGap(const int y_gap)                       { m_dec_y_gap=y_gap;                  }
   //--- Modo de reset quando acontece o clique sobre o rótulo de texto
   bool              ResetMode(void)                                { return(m_reset_mode);               }
   void              ResetMode(const bool mode)                     { m_reset_mode=mode;                  }
   //--- Valor mínimo
   double            MinValue(void)                           const { return(m_min_value);                }
   void              MinValue(const double value)                   { m_min_value=value;                  }
   //--- Valor máximo
   double            MaxValue(void)                           const { return(m_max_value);                }
   void              MaxValue(const double value)                   { m_max_value=value;                  }
   //--- O passo do valor
   double            StepValue(void)                          const { return(m_step_value);               }
   void              StepValue(const double value)                  { m_step_value=(value<=0)? 1 : value; }
   //--- (1) Número de casas decimais, (2) o modo de alinhamento do texto
   void              SetDigits(const int digits)                    { m_digits=::fabs(digits);            }
   void              AlignMode(ENUM_ALIGN_MODE mode)                { m_align_mode=mode;                  }
  };

Para criar o controle campo de edição, nós vamos precisar de cinco métodos privados para criar objetos gráficos primitivos e um método público, que serão chamados na classe personalizada quando a interface gráfica for criada. Os ícones para os botões de rolagem podem ser baixados no final deste artigo. Eles são usados ​​por padrão, mas você poderá utilizar os seus ícones personalizados.

class CSpinEdit : public CElement
  {
private:
   //--- Objetos para a criação do campo de edição
   CRectLabel        m_area;
   CLabel            m_label;
   CEdit             m_edit;
   CBmpLabel         m_spin_inc;
   CBmpLabel         m_spin_dec;
   //---
public:
   //--- Métodos para criar o campo de edição
   bool              CreateSpinEdit(const long chart_id,const int subwin,const string label_text,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateLabel(void);
   bool              CreateEdit(void);
   bool              CreateSpinInc(void);
   bool              CreateSpinDec(void);
  };

Agora, nós estamos vamos discutir os modos e métodos de gestão dos estados e propriedades do controle após a sua criação. Vamos começar com o método CSpinEdit::SetValue() para ajustar e o armazenar o valor do controle campo de edição e também o método auxiliar CSpinEdit::HighlightLimit() para o destaque (realce) do texto no campo de edição quando os limites mínimos e máximos são ultrapassados.

No início do método CSpinEdit::SetValue(), há um ajuste considerando o passo para mudar o valor. Então, siga as verificações para ultrapassar os limites definidos (máximas/mínimas). Se os limites forem ultrapassados, então, um valor correspondente à verificação é definida e o método CSpinEdit::HighlightLimit() é chamado para destacar o texto. Se depois de todas as verificações e ajustes o valor se alterar em relação ao que foi armazenado, o novo valor substitui o antigo.

O método CSpinEdit::HighlightLimit() é bastante simples. Ali, a cor do realce é definido em primeiro lugar. É vermelho por padrão, podendo ser redefinido pelo usuário. Depois disso, há uma pausa de 100 milissegundos. Isto é suficiente para notar uma mudança temporária da cor. A cor do texto inicial é definida no final.

Abaixo está o código dos métodos descritos: 

class CSpinEdit : public CElement
  {
private:
   //--- Valor atual do campo de edição
   double            m_edit_value;
   //---
public:
   //--- Retorna e define o valor do campo de edição
   double            GetValue(void)                           const { return(m_edit_value);               }
   bool              SetValue(const double value);
   //--- Piscar quando o limite for atingido
   void              HighlightLimit(void);
  };
//+------------------------------------------------------------------+
//| Verifica o valor atual                                           |
//+------------------------------------------------------------------+
bool CSpinEdit::SetValue(double value)
  {
//--- Para o ajuste
   double corrected_value =0.0;
//--- Ajustar considerando o passo
   corrected_value=::MathRound(value/m_step_value)*m_step_value;
//--- Verifica a mínima/máxima
   if(corrected_value<m_min_value)
     {
      //--- Define o valor mínimo
      corrected_value=m_min_value;
      //--- Define o estado para On (ligado)
      m_spin_dec.State(true);
      //--- Pisca para indicar que o limite foi atingido
      HighlightLimit();
     }
   if(corrected_value>m_max_value)
     {
      //--- Define o valor máximo
      corrected_value=m_max_value;
      //--- Define o estado para On (ligado)
      m_spin_inc.State(true);
      //--- Pisca para indicar que o limite foi atingido
      HighlightLimit();
     }
//--- Se o valor tiver sido alterado
   if(m_edit_value!=corrected_value)
     {
      m_edit_value=corrected_value;
      m_edit.Color(m_edit_text_color);
      return(true);
     }
//--- Valor inalterado
   return(false);
  }
//+------------------------------------------------------------------+
//| Destacando o limite                                              |
//+------------------------------------------------------------------+
void CSpinEdit::HighlightLimit(void)
  {
//--- Muda a cor do texto temporariamente
   m_edit.Color(m_edit_text_color_highlight);
//--- Atualiza
   ::ChartRedraw();
//--- Atrasa antes de voltar para a cor inicial
   ::Sleep(100);
//--- Muda a cor do texto para o inicial
   m_edit.Color(m_edit_text_color);
  }

O método CSpinEdit::SetValue() é designado apenas para ajustar o valor no caso do limite estabelecido for excedido. O método CSpinEdit::ChangeValue() é usado para alterar o valor do campo de edição:

class CSpinEdit : public CElement
  {
private:
   //--- A alteração do valor no campo de edição
   void              ChangeValue(const double value);
  };
//+------------------------------------------------------------------+
//| A alteração do valor no campo de edição                          |
//+------------------------------------------------------------------+
void CSpinEdit::ChangeValue(const double value)
  {
//--- Verifica, ajusta e armazena o novo valor
   SetValue(value);
//--- Define o novo valor no campo de edição
   m_edit.Description(::DoubleToString(GetValue(),m_digits));
  }


Semelhante aos outros elementos, vamos precisar de um método para gerenciar a disponibilidade do controle de edição, como mostrado no código abaixo:

class CSpinEdit : public CElement
  {
private:
   //--- Estado da caixa de seleção(disponível/bloqueado)
   bool              m_spin_edit_state;
   //---
public:
   //--- Retorna/define o estado da disponibilidade do campo de edição
   bool              SpinEditState(void)                      const { return(m_spin_edit_state);          }
   void              SpinEditState(const bool state);
  };
//+------------------------------------------------------------------+
//| Define o estado do controle                                      |
//+------------------------------------------------------------------+
void CSpinEdit::SpinEditState(const bool state)
  {
   m_spin_edit_state=state;
//--- Cor do rótulo de texto
   m_label.Color((state)? m_label_color : m_label_color_locked);
//--- Cor do campo de edição
   m_edit.Color((state)? m_edit_text_color : m_edit_text_color_locked);
   m_edit.BackColor((state)? m_edit_color : m_edit_color_locked);
   m_edit.BorderColor((state)? m_edit_border_color : m_edit_border_color_locked);
//--- Ícones das chaves
   m_spin_inc.BmpFileOn((state)? "::"+m_inc_bmp_file_on : "::"+m_inc_bmp_file_locked);
   m_spin_dec.BmpFileOn((state)? "::"+m_dec_bmp_file_on : "::"+m_dec_bmp_file_locked);
//--- Define em relação ao estado atual
   if(!m_spin_edit_state)
     {
      //--- Prioridades
      m_edit.Z_Order(-1);
      m_spin_inc.Z_Order(-1);
      m_spin_dec.Z_Order(-1);
      //--- Edita no modo somente leitura
      m_edit.ReadOnly(true);
     }
   else
     {
      //--- Prioridades
      m_edit.Z_Order(m_edit_zorder);
      m_spin_inc.Z_Order(m_spin_zorder);
      m_spin_dec.Z_Order(m_spin_zorder);
      //--- O controle campo de edição no modo de edição
      m_edit.ReadOnly(false);
     }
  }

Agora, nós vamos considerar os métodos para lidar com os eventos do controle campo de edição. O clique em cima do rótulo de texto irá gerar um evento personalizado com (1) o identificador de evento ON_CLICK_LABEL, (2) o identificador de controle, (3) o índice de controle e (4) a descrição do rótulo de texto. O modo de resetar o valor no campo de edição para o seu mínimo foi mencionado anteriormente. Este modo é desativado por padrão (false). Ele pode ser ativado com o método CSpinEdit::ResetMode(). Para isso, você só precisa definir como true em seu único argumento. Se o modo para resetar o valor estiver ativado, então, ao pressionar o rótulo de texto, será chamado o método para definir o valor mínimo no campo de edição.

O código do método CSpinEdit::OnClickLabel() para lidar com o clique sobre o rótulo de texto será como é mostrado abaixo:

class CSpinEdit : public CElement
  {
private:
   //--- Manipulando o pressionamento do rótulo de texto
   bool              OnClickLabel(const string clicked_object);
  };
//+------------------------------------------------------------------+
//| Clique no rótulo do elemento                                     |
//+------------------------------------------------------------------+
bool CSpinEdit::OnClickLabel(const string clicked_object)
  {
//--- Sai se o nome for diferente
   if(m_area.Name()!=clicked_object)
      return(false);
//--- Se o modo de resetar o valor está habilitado
   if(m_reset_mode)
     {
      //--- Define o valor mínimo
      ChangeValue(MinValue());
     }
//--- Envia uma mensagem sobre ele
   ::EventChartCustom(m_chart_id,ON_CLICK_LABEL,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }

O usuário pode alterar o valor no controle campo de edição, inserindo o novo valor manualmente ou usando os botões de incremento e decremento. Nós vamos precisar de novos identificadores de eventos personalizados. Adicione-os no arquivo Defines.mqh:

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#define ON_END_EDIT               (18) // Edição final do valor no campo de edição
#define ON_CLICK_INC              (19) // Altera o contador para cima
#define ON_CLICK_DEC              (20) // Altera o contador para baixo

Para lidar com a entrada manual do novo valor, nós vamos escrever o método CSpinEdit::OnEndEdit(). Ele será chamado no manipulador comum CSpinEdit::OnEvent() ao receber um evento com o identificador CHARTEVENT_OBJECT_ENDEDIT. O novo valor pode ser ajustado se necessário. No final do método, um evento personalizado será gerado com (1) o identificador de evento ON_END_EDIT, (2) o identificador do elemento, (3) o índice do elemento e (4) a descrição do rótulo de texto, como é mostrado no código abaixo. 

class CSpinEdit : public CElement
  {
private:
   //--- Manipulação do valor inserido no campo de edição
   bool              OnEndEdit(const string edited_object);
  };
//+------------------------------------------------------------------+
//| Manipulação do valor inserido no campo de edição                 |
//+------------------------------------------------------------------+
bool CSpinEdit::OnEndEdit(const string edited_object)
  {
//--- Sai se o nome for diferente
   if(m_edit.Name()!=edited_object)
      return(false);
//--- Obter o valor inserido
   double entered_value=::StringToDouble(m_edit.Description());
//--- Verifica, ajusta e armazena o novo valor
   ChangeValue(entered_value);
//--- Envia uma mensagem sobre ele
   ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }

Para lidar com o pressionamento sobre os botões de incremento e decremento, nós precisamos criar dois métodos distintos, o CSpinEdit::OnClickSpinInc() e o CSpinEdit::OnClickSpinDec(). Eles são bem simples. Depois de um objeto gráfico ser pressionado, há uma verificação pelo seu nome, se for um botão de nosso controle. Em seguida, nós obtemos o valor atual no campo de edição e aumentamos/diminuímos o seu passo definido nas propriedades do controle. No final dos métodos, um evento personalizado é gerado com (1) o identificador de evento ON_CLICK_INC/ON_CLICK_DEC, (2) o identificador do elemento, (3) o índice do elemento e (4) a descrição do rótulo de texto, como é mostrado no código abaixo.

class CSpinEdit : public CElement
  {
private:
   //--- Manipulação do clique do botão do campo de edição
   bool              OnClickSpinInc(const string clicked_object);
   bool              OnClickSpinDec(const string clicked_object);
  };
//+------------------------------------------------------------------+
//| Pressionando na chave de incremento                              |
//+------------------------------------------------------------------+
bool CSpinEdit::OnClickSpinInc(const string clicked_object)
  {
//--- Sai se o nome for diferente
   if(m_spin_inc.Name()!=clicked_object)
      return(false);
//--- Obtém o valor atual
   double value=GetValue();
//--- Aumenta em um passo e verifica se excedeu o limite
   ChangeValue(value+m_step_value);
//--- Define o estado para On (ligado)
   m_spin_inc.State(true);
//--- Envia uma mensagem sobre ele
   ::EventChartCustom(m_chart_id,ON_CLICK_INC,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }
//+------------------------------------------------------------------+
//| Pressionando na chave de decremento                              |
//+------------------------------------------------------------------+
bool CSpinEdit::OnClickSpinDec(const string clicked_object)
  {
//--- Sai se o nome for diferente
   if(m_spin_dec.Name()!=clicked_object)
      return(false);
//--- Obtém o valor atual
   double value=GetValue();
//--- Diminui em um passo e verifica se excedeu o limite
   ChangeValue(value-m_step_value);
//--- Define o estado para On (ligado)
   m_spin_dec.State(true);
//--- Envia uma mensagem sobre ele
   ::EventChartCustom(m_chart_id,ON_CLICK_DEC,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }

Todos estes métodos de manipulação devem ser chamados no método principal para o tratamento de eventos, como é mostrado no código abaixo. O acesso ao corpo de métodos de manipulação é controlado pela disponibilidade atual do controle.

//+------------------------------------------------------------------+
//| Manipulador de evento                                            |
//+------------------------------------------------------------------+
void CSpinEdit::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Manipula o clique do botão esquerdo do mouse sobre o objeto
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Sai, se o controle está bloqueado
      if(!m_spin_edit_state)
         return;
      //--- Manipulando o pressionamento do rótulo de texto
      if(OnClickLabel(sparam))
         return;
      //--- Manipulação do clique do botão do campo de edição
      if(OnClickSpinInc(sparam))
         return;
      if(OnClickSpinDec(sparam))
         return;
      //---
      return;
     }
//--- Manipulando a alteração do valor no evento do campo de edição
   if(id==CHARTEVENT_OBJECT_ENDEDIT)
     {
      //--- Sai, se o controle está bloqueado
      if(!m_spin_edit_state)
         return;
      //--- Manipula o valor de entrada
      if(OnEndEdit(sparam))
         return;
     }
  }

Para uma rolagem mais rápida dos valores quando o botão esquerdo do mouse é pressionado sobre os botões chaves do controle, crie o método CSpinEdit::FastSwitching() que será chamado no timer do controle. Nós discutimos esse método quando falamos sobre a classe CListView para a criar a lista com uma barra de rolagem. Considerando que esse método foi necessário para a rolagem da lista, aqui ele vai ter uma função de aumentar ou diminuir os valores do campo de edição. Mais detalhes do código CSpinEdit::FastSwitching() é apresentado abaixo. 

class CSpinEdit : public CElement
  {
private:
   //--- Rolagem rápida dos valores do campo de edição
   void              FastSwitching(void);
  };
//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void CSpinEdit::OnEventTimer(void)
  {
//--- Se o elemento é suspenso
   if(CElement::IsDropdown())
     {
      ChangeObjectsColor();
      FastSwitching();
     }
   else
     {
      //--- Acompanha a mudança da cor e a rolagem mais rápida dos valores 
      //    se o formulário não está bloqueado
      if(!m_wnd.IsLocked())
        {
         ChangeObjectsColor();
         FastSwitching();
        }
     }
  }
//+------------------------------------------------------------------+
//| Rolagem rápida dos valores do campo de edição                    |
//+------------------------------------------------------------------+
void CSpinEdit::FastSwitching(void)
  {
//--- Sai, se o foco não está no controle
   if(!CElement::MouseFocus())
      return;
//--- Reseta o contador para o valor inicial quando o botão do mouse for liberado
   if(!m_mouse_state)
      m_timer_counter=SPIN_DELAY_MSC;
//--- Se o botão do mouse é pressionado para baixo
   else
     {
      //--- Aumenta o contador pelo passo definido
      m_timer_counter+=TIMER_STEP_MSC;
      //--- Sai, se menor que zero
      if(m_timer_counter<0)
         return;
      //--- Obtém o valor atual no campo de edição
      double current_value=::StringToDouble(m_edit.Description());
      //--- Se aumentar 
      if(m_spin_inc.State())
         SetValue(current_value+m_step_value);
      //--- Se diminuir
      else if(m_spin_dec.State())
         SetValue(current_value-m_step_value);
      //--- Altera o valor se o botão chaveado ainda estiver pressionado para baixo
      if(m_spin_inc.State() || m_spin_dec.State())
         m_edit.Description(::DoubleToString(GetValue(),m_digits));
     }
  }

 

Teste do Controle Campo de Edição

Todos os métodos do controle campo de edição foram implementadas. Vamos testá-lo no programa que nós preparamos antes. Na classe personalizada CProgram do aplicativo, crie uma instância da classe CSpinEdit e declare um método para criar o controle campo de edição.

//+------------------------------------------------------------------+
//| Classe para a criação de um aplicativo                           |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
   //--- Campos de Edição
   CSpinEdit         m_spin_edit1;
   //---
private:
   //--- Campos de Edição
#define SPINEDIT1_GAP_X       (150)
#define SPINEDIT1_GAP_Y       (75)
   bool              CreateSpinEdit1(const string text);
  };

Vamos fazer a primeira caixa de seleção para gerenciar a disponibilidade desse controle, da mesma maneira que foi feito em relação à segunda caixa de seleção. Portanto, após este controle ser criado, sua disponibilidade dependerá do estado da primeira caixa de seleção como é mostrado no código abaixo.

//+------------------------------------------------------------------+
//| Cria o campo de edição 1                                         |
//+------------------------------------------------------------------+
bool CProgram::CreateSpinEdit1(string text)
  {
//--- Armazena o ponteiro da janela
   m_spin_edit1.WindowPointer(m_window1);
//--- Coordenadas
   int x=m_window1.X()+SPINEDIT1_GAP_X;
   int y=m_window1.Y()+SPINEDIT1_GAP_Y;
//--- Valor
   double v=(m_spin_edit1.GetValue()==WRONG_VALUE) ? 4 : m_spin_edit1.GetValue();
//--- Define as propriedades antes da criação
   m_spin_edit1.XSize(150);
   m_spin_edit1.YSize(18);
   m_spin_edit1.EditXSize(76);
   m_spin_edit1.MaxValue(1000);
   m_spin_edit1.MinValue(-1000);
   m_spin_edit1.StepValue(1);
   m_spin_edit1.SetDigits(0);
   m_spin_edit1.SetValue(v);
   m_spin_edit1.ResetMode(true);
   m_spin_edit1.AreaColor(clrWhiteSmoke);
   m_spin_edit1.LabelColor(clrBlack);
   m_spin_edit1.LabelColorLocked(clrSilver);
   m_spin_edit1.EditColorLocked(clrWhiteSmoke);
   m_spin_edit1.EditTextColor(clrBlack);
   m_spin_edit1.EditTextColorLocked(clrSilver);
   m_spin_edit1.EditBorderColor(clrSilver);
   m_spin_edit1.EditBorderColorLocked(clrSilver);
//--- Cria o controle
   if(!m_spin_edit1.CreateSpinEdit(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- A disponibilidade irá depender do estado atual da primeira caixa de seleção
   m_spin_edit1.SpinEditState(m_checkbox1.CheckButtonState());
//--- Adiciona o objeto para o array comum dos grupos de objetos
   CWndContainer::AddToElementsArray(0,m_spin_edit1);
   return(true);
  }

Semelhante aos outros controles, o método CProgram::CreateSpinEdit1() deve ser chamado no método principal para criar a interface gráfica do programa. Abaixo está uma versão resumida do método:

//+------------------------------------------------------------------+
//| Cria o painel de negociação                                      |
//+------------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Criação do formulário 1 para os controles
//--- Criação dos controles:
//    Menu principal
//--- Menus de contexto
//--- Criando a barra de status
//--- Caixas de seleção
//--- Campos de Edição
   if(!CreateSpinEdit1("Spin Edit 1:"))
      return(false);
//--- Redesenha o gráfico
   m_chart.Redraw();
   return(true);
  }

No manipulador de eventos CProgram::OnEvent(), adicione o código para o testar a escuta dos eventos a partir dos controles campo de edição e também especifique que o primeiro campo de edição depende do estado da primeira caixa de seleção

//+------------------------------------------------------------------+
//| Manipulador de eventos                                           |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- O evento clique no rótulo de texto
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Se o clique foi na primeira caixa de seleção
      if(lparam==m_checkbox1.Id())
        {
         //--- Define o estado para a segunda caixa de seleção e o primeiro campo de edição
         m_checkbox2.CheckBoxState(m_checkbox1.CheckButtonState());
         m_spin_edit1.SpinEditState(m_checkbox1.CheckButtonState());
        }
     }
//--- O evento fim do valor de entrada no campo de edição
   if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
//--- O evento clique dos botões chaveados do campo de edição
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC || id==CHARTEVENT_CUSTOM+ON_CLICK_DEC)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
  }

Compile o programa e carregue-o ao gráfico. Você pode ver que a interface gráfica da aplicação está igual a imagem abaixo:

Fig. 4. Testando o controle campo de edição.

Fig. 4. Testando o controle campo de edição.

 


Outros Controles com as Caixas de Seleção

Foi mencionado no início deste artigo, que além dos controles da caixa de seleção e campo de edição, nós poderíamos considerar o campo de edição com caixa de seleção e a lista combinada. O campo de edição com o caixa de seleção é uma versão estendida da classe CSpinEdit, enriquecida com campos e métodos da classe CCheckBox que consideramos neste artigo. 

 Fig. 5. Partes integrantes do controle campo de edição com a caixa de seleção.

Fig. 5. Partes integrantes do controle campo de edição com a caixa de seleção.


A caixa de seleção com a lista combinada é uma combinação semelhante às classes CComboBox e CCheckBox:

 Fig. 6. Partes integrantes do controle caixa de seleção com a lista combinada.

Fig. 6. Partes integrantes do controle caixa de seleção com a lista combinada.


Você pode encontrar a implementação do CCheckBoxEdit (campo de edição com caixa de seleção) e o CCheckComboBox (caixa de seleção com a lista combinada) nos arquivos anexados neste artigo para estudar por conta própria. Como o controle do tipo CCheckComboBox contém uma lista suspensa, as adições relevantes precisam ser introduzidas no arquivo WndContainer.mqh semelhante aos outros elementos que possuem partes suspensas. Neste caso, o ponteiro da lista suspensa deve entrar no array privado de ponteiros m_drop_lists[]. Uma descrição detalhada de como fazer isso pode ser encontrada no artigo Interfaces Gráficas V: O Controle ComboBox (Capítulo 3).

Por uma questão de exemplo, nós vamos adicionar o aplicativo de teste com esses controles para que você possa ver como ele funciona. Vamos adicionar duas caixas de seleção do tipo CCheckBox e um do CCheckBoxEdit e CCheckComboBox. A disponibilidade do controle do tipo CCheckBoxEdit vai depender do estado da terceira caixa de seleção e a disponibilidade do controle do tipo CCheckComboBox vai depender do estado da quarta lista combinada.

 Fig. 7. Testando os controles de tipos mistos.

Fig. 7. Testando os controles de tipos mistos.

 


Conclusão

Neste artigo, nós desenvolvemos os controles amplamente utilizados em muitas interfaces gráficas em diferentes ambientes: caixa de seleção, campo de edição, campo de edição com caixa de seleção e a lista combinada com a caixa de seleção. No segundo capítulo, nós vamos desenvolver os controles deslizante e deslizante duplo. 

Você pode baixar o material da parte VI e testar o seu funcionamento. 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 sexta parte:

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

Arquivos anexados |
Expert Advisor multiplataforma: Introdução Expert Advisor multiplataforma: Introdução
Este artigo descreve um método que permite desenvolver rápida e facilmente um Expert Advisor multiplataforma. O método proposto combina as características, comuns para ambas as versões, numa classe e desenvolve a implementação para funções incompatíveis nas classes herdadas.
Aprimorando o Testador de Estratégia para Otimizar Indicadores Exclusivamente nos Exemplos dos Mercados Lateral e de Tendência Aprimorando o Testador de Estratégia para Otimizar Indicadores Exclusivamente nos Exemplos dos Mercados Lateral e de Tendência
É essencial detectar se um mercado é lateral ou se o mesmo não está para muitas estratégias. Usando o conhecido ADX, demonstraremos como podemos usar o Testador de Estratégia, tanto para otimizar esse indicador quanto ao nosso objetivo específico, como também podemos decidir se este indicador irá satisfazer as nossas necessidades quanto a variação média dos mercados lateral e de tendência, que são muito importantes para determinar os stops e os alvos dos mercados.
Expert Advisor multiplataforma: reutilização de componentes a partir da Biblioteca padrão MQL5 Expert Advisor multiplataforma: reutilização de componentes a partir da Biblioteca padrão MQL5
Na biblioteca padrão MQL5, existem alguns componentes que podem ser úteis em versões de EAs MQL4 multiplataforma. Este artigo descreve um método para a criação de alguns componentes da biblioteca padrão MQL5 compatíveis com o compilador MQL4.
Usando arquivos de texto para armazenar parâmetros de entrada dos Expert Advisors, indicadores e scripts Usando arquivos de texto para armazenar parâmetros de entrada dos Expert Advisors, indicadores e scripts
O artigo descreve a aplicação de arquivos de texto para armazenar objetos dinâmicos, arrays e outras variáveis, as quais são ​​utilizadas como propriedades dos Expert Advisors, indicadores e scripts. Os arquivos servem como um complemento útil para a funcionalidade das ferramentas padrão oferecidas pelas linguagens MQL.