English Русский 中文 Español Deutsch 日本語
Interfaces Gráficas V: O Controle Combobox (Capítulo 3)

Interfaces Gráficas V: O Controle Combobox (Capítulo 3)

MetaTrader 5Exemplos | 19 setembro 2016, 16:15
1 120 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.   

Nos dois primeiros capítulos da quinta parte da série, nós desenvolvemos as classes para criar uma barra de rolagem e uma lista. Lá, nós não demonstramos como anexar uma barra de rolagem ao elemento se os dados não se encaixam na área designada. Neste capítulo, nós falaremos sobre a criação de uma classe para o controle combobox. Este é também um controle composto que contém, entre outros, os elementos considerados nos capítulos anteriores desta quinta parte.


O controle ComboBox

Um combobox é um controle composto, as partes principais dele são: (1) um botão e (2) uma lista. A lista, neste caso, é um elemento suspenso e é chamado quando o botão é pressionado. Depois de selecionar uma lista de elementos, o texto é exibido no botão e a lista é oculta. Quando um programa contém muitos parâmetros multi-opcionais, utilizar um combobox permitirá criar uma interface gráfica compacta.

A seguir estão os objetos primitivos para compor o controle combobox.

  1. O elemento de fundo
  2. Rótulo (descrição do elemento)
  3. Botão
  4. Indicação de uma lista suspensa


Fig. 1. Partes integrantes do controle combobox


Na próxima parte do artigo, nós vamos escrever uma classe para criar esse controle.

Escrevendo uma Classe para Criar o Controle Combobox

Nós vamos considerar todas as fases do desenvolvimento do controle combobox de modo que, no futuro, este artigo poderá ser utilizado como um exemplo para escrever classes semelhantes. No início, crie um arquivo mqh chamado (ComboBox.mqh) e inclua nele todos os arquivos necessários com as classes que exigidas para criar uma combobox. Em nosso caso, estes serão três arquivos com as seguintes classes:

  • CElement — classe base para criar o controle.
  • CWindow — classe do formulário que este controle será anexado.
  • CListView — classe da lista cuja visibilidade será gerenciada pela combobox.
//+------------------------------------------------------------------+
//|                                                     ComboBox.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
#include "ListView.mqh"

Em seguida, crie a classe CComboBox e os métodos padrão para cada elemento da biblioteca no arquivo ComboBox.mqh:

//+------------------------------------------------------------------+
//| Classe para criar um menu de contexto                            |
//+------------------------------------------------------------------+
class CComboBox : public CElement
  {
private:
   //--- Ponteiro para o formulário que este elemento está anexado
   CWindow          *m_wnd;
   //---
public:
                     CComboBox(void);
                    ~CComboBox(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);
   //--- Reseta a cor
   virtual void      ResetColors(void);
  };
//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CComboBox::CComboBox(void)
  {
//--- Armazena o nome da classe do elemento na classe base
   CElement::ClassName(CLASS_NAME);
  }
//+------------------------------------------------------------------+
//| Destrutor                                                        |
//+------------------------------------------------------------------+
CComboBox::~CComboBox(void)
  {
  }

O usuário deve ter a oportunidade de escolher o seu próprio esquema de cores para a interface gráfica. Para isso, ele deve ter acesso às configurações das propriedades dos objetos que se compõem o controle. A seguir estão as propriedades que se podem ajustar antes do controle ser criado:

  • Cor de fundo do controle
  • A descrição exibida no combobox (rótulo de texto)
  • Margens para o rótulo de texto ao longo do eixo X e Y
  • Cores do rótulo de texto em diferentes estados
  • Texto do botão (texto do elemento selecionado da lista)
  • Tamanho do botão
  • Cores do botão em diferentes estados
  • Cores do quadro do botão em diferentes estados
  • Cores do texto do botão em diferentes estados
  • Ícones para a seta - a indicação de uma lista suspensa para o modo ativo e bloqueado
  • Margens para os ícones da seta ao longo do eixo X e Y

O código a seguir contém os campos e métodos para instalar as propriedades listadas acima: 

class CComboBox : public CElement
  {
private:
   //--- Propriedades do combobox:
   //    Cor do fundo geral
   color             m_area_color;
   //--- Texto e margens do rótulo de texto
   string            m_label_text;
   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_array[];
   //--- (1) Texto do botão e (2) o seu tamanho
   string            m_button_text;
   int               m_button_x_size;
   int               m_button_y_size;
   //--- Cores do botão em diferentes estados
   color             m_button_color;
   color             m_button_color_off;
   color             m_button_color_hover;
   color             m_button_color_pressed;
   color             m_button_color_array[];
   //--- Cores do quadro de botão em diferentes estados
   color             m_button_border_color;
   color             m_button_border_color_off;
   //--- Cor do botão de texto em diferentes estados
   color             m_button_text_color;
   color             m_button_text_color_off;
   //--- Margens do rótulo
   int               m_drop_arrow_x_gap;
   int               m_drop_arrow_y_gap;
   //--- Rótulos dos botões com um menu suspenso nos estado ativo e bloqueado
   string            m_drop_arrow_file_on;
   string            m_drop_arrow_file_off;
   //--- Prioridades do clique do botão esquerdo do mouse
   int               m_area_zorder;
   int               m_button_zorder;
   int               m_zorder;
   //---
public:
   //--- (1) A cor de fundo, (2) define e (3) retorna o valor do rótulo de texto
   void              AreaColor(const color clr)                       { m_area_color=clr;                                }
   void              LabelText(const string label_text)               { m_label_text=label_text;                         }
   string            LabelText(void)                            const { return(m_label_text);                            }
   //--- 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;                             }
   //--- (1) Retorna o texto do botão (2), definindo o tamanho do botão
   string            ButtonText(void)                           const { return(m_button_text);                           }
   void              ButtonXSize(const int x_size)                    { m_button_x_size=x_size;                          }
   void              ButtonYSize(const int y_size)                    { m_button_y_size=y_size;                          }
   //--- (1) cor de fundo, (2) cores do rótulo de texto
   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;                         }
   //--- Cores dos botões
   void              ButtonBackColor(const color clr)                 { m_button_color=clr;                              }
   void              ButtonBackColorOff(const color clr)              { m_button_color_off=clr;                          }
   void              ButtonBackColorHover(const color clr)            { m_button_color_hover=clr;                        }
   void              ButtonBackColorPressed(const color clr)          { m_button_color_pressed=clr;                      }
   //--- Cores do quadro de botão
   void              ButtonBorderColor(const color clr)               { m_button_border_color=clr;                       }
   void              ButtonBorderColorOff(const color clr)            { m_button_border_color_off=clr;                   }
   //--- Cores do texto do botão
   void              ButtonTextColor(const color clr)                 { m_button_text_color=clr;                         }
   void              ButtonTextColorOff(const color clr)              { m_button_text_color_off=clr;                     }
   //--- Ícones configuração para o botão com um menu suspenso no estado ativo e bloqueado
   void              DropArrowFileOn(const string file_path)          { m_drop_arrow_file_on=file_path;                  }
   void              DropArrowFileOff(const string file_path)         { m_drop_arrow_file_off=file_path;                 }
   //--- Margens do rótulo
   void              DropArrowXGap(const int x_gap)                   { m_drop_arrow_x_gap=x_gap;                        }
   void              DropArrowYGap(const int y_gap)                   { m_drop_arrow_y_gap=y_gap;                        }
  };

A inicialização de todas as propriedades listadas acima por valores padrão estão no construtor da classe: 

//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CComboBox::CComboBox(void) : m_area_color(C'15,15,15'),
                             m_label_text("combobox: "),
                             m_label_x_gap(0),
                             m_label_y_gap(2),
                             m_label_color(clrWhite),
                             m_label_color_off(clrGray),
                             m_label_color_hover(C'85,170,255'),
                             m_button_text(""),
                             m_button_y_size(18),
                             m_button_text_color(clrBlack),
                             m_button_text_color_off(clrDarkGray),
                             m_button_color(clrGainsboro),
                             m_button_color_off(clrLightGray),
                             m_button_color_hover(C'193,218,255'),
                             m_button_color_pressed(C'153,178,215'),
                             m_button_border_color(clrWhite),
                             m_button_border_color_off(clrWhite),
                             m_drop_arrow_x_gap(16),
                             m_drop_arrow_y_gap(1),
                             m_drop_arrow_file_on(""),
                             m_drop_arrow_file_off("")
  {
//--- Define as prioridades do botão esquerdo do mouse
   m_zorder        =0;
   m_area_zorder   =1;
   m_button_zorder =2;
  }

O combobox será criado com cinco métodos privados, que serão chamados no método público e principal CComboBox::CreateComboBox(). Para obter acesso à configuração da lista e as propriedades da barra de rolagem, crie os métodos para obter os ponteiros destes elementos: 

class CComboBox : public CElement
  {
private:
   //--- Objetos para criar um combobox
   CRectLabel        m_area;
   CLabel            m_label;
   CEdit             m_button;
   CBmpLabel         m_drop_arrow;
   CListView         m_listview;
   //---
public:
   //--- Métodos para criar um combobox
   bool              CreateComboBox(const long chart_id,const int subwin,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateLabel(void);
   bool              CreateButton(void);
   bool              CreateDropArrow(void);
   bool              CreateList(void);
   //---
public:
   //--- Retorna os ponteiros para (1) a lista e (2) a barra de rolagem
   CListView        *GetListViewPointer(void)                         { return(::GetPointer(m_listview));                }
   CScrollV         *GetScrollVPointer(void)                          { return(m_listview.GetScrollVPointer());          }
  };

Fora dos métodos apresentados no código acima, nós vamos considerar apenas o método CComboBox::CreateList() para criar uma lista em detalhes. Outros métodos não possuem nada que nós já não estudamos nos artigos anteriores desta série. Antes disso, no entanto, nós devemos introduzir algumas alterações à classe da lista CListView

A lista suspensa é sempre uma parte componente de um outro elemento. Isso significa que seu manipulador de eventos pode exigir o monitoramento do foco sobre o elemento que está anexado. No nosso caso, é o combobox. Adicione um campo e um método para a classe CListView para armazenar o ponteiro para o combobox para o qual a lista será anexada. 

class CListView : public CElement
  {
private:
   //--- Ponteiro para o elemento que gerencia a visibilidade da lista
   CElement         *m_combobox;
   //---
public:
   //--- Armazena o ponteiro combobox
   void              ComboBoxPointer(CElement &object)                   { m_combobox=::GetPointer(object); }
  };

Se a lista é suspensa, adicione uma verificação ao ponteiro para o método principal (público) para a criação de uma lista. Se durante a criação da lista acontecer de não haver nenhum ponteiro, então, a criação da interface gráfica será encerrada e uma mensagem relevante será impressa no registro.

Abaixo está uma versão resumida do método CListView::CreateListView(): 

//+------------------------------------------------------------------+
//| Cria uma lista                                                   |
//+------------------------------------------------------------------+
bool CListView::CreateListView(const long chart_id,const int window,const int x,const int y)
  {
//--- Retorna se não há nenhum ponteiro do formulário

//--- Se a lista é suspensa, será necessário haver um ponteiro para o combobox para o qual ele será anexado
   if(CElement::IsDropdown())
     {
      //--- Sai, se não houver nenhum ponteiro para a combobox
      if(::CheckPointer(m_combobox)==POINTER_INVALID)
        {
         ::Print(__FUNCTION__," > Antes de criar a lista suspensa, a classe deve ser passada "
                 "para o ponteiro do combobox: CListView::ComboBoxPointer(CElement &object)");
         return(false);
        }
     }
//--- Inicializa as variáveis​
//--- Margens da borda
//--- Cria um botão
//--- Oculta o elemento se ele for uma janela de diálogo ou ela está minimizada
//---
   return(true);
  }

Agora, nós vamos voltar para o desenvolvimento da classe combobox (CComboBox). A propriedade indicando que a lista será suspensa terá que ser definida em uma fase muito precoce, que está no construtor da classe: 

CComboBox::CComboBox(void)
  {
//--- Modo da lista suspensa
   m_listview.IsDropdown(true);
  }

Ao criar uma lista, os ponteiros para o formulário e o combobox em que a lista será ligada tem de ser armazenada no início do método. Por favor note que a lista e o combobox devem ter o identificador em comum como neste caso, eles compõem um controle. Após a lista ser criada, ela deve ser oculta

//+------------------------------------------------------------------+
//| Cria uma lista                                                   |
//+------------------------------------------------------------------+
bool CComboBox::CreateList(void)
  {
//--- Armazena os ponteiros para o formulário e o combobox
   m_listview.WindowPointer(m_wnd);
   m_listview.ComboBoxPointer(this);
//--- Coordenadas
   int x=CElement::X2()-m_button_x_size;
   int y=CElement::Y()+m_button_y_size;
//--- Define as propriedades
   m_listview.Id(CElement::Id());
   m_listview.XSize(m_button_x_size);
//--- Cria o controle
   if(!m_listview.CreateListView(m_chart_id,m_subwin,x,y))
      return(false);
//--- Oculta a lista
   m_listview.Hide();
   return(true);
  }

Para definir o número de elementos da lista e preencher a lista com os valores, adicione os métodos relevantes para a classe CComboBox

class CListView : public CElement
  {
public:
   //--- Define (1) o tamanho da lista (número de elementos) e (2) a sua parte visível
   void              ItemsTotal(const int items_total)                { m_listview.ListSize(items_total);                }
   void              VisibleItemsTotal(const int visible_items_total) { m_listview.VisibleListSize(visible_items_total); }
   
   //--- Armazena o valor passado na lista pelo índice especificado
   void              ValueToList(const int item_index,const string item_text);
  };
//+------------------------------------------------------------------+
//| Armazena o valor passado da lista pelo índice especificado       |
//+------------------------------------------------------------------+
void CComboBox::ValueToList(const int item_index,const string item_text)
  {
   m_listview.ValueToList(item_index,item_text);
  }

Para selecionar (destacar) o elemento da lista, crie o método CComboBox::SelectedItemByIndex(). O índice do elemento que deve ser destacado é o único argumento que tem de ser passado para este método. Então, realiza-se o destaque do elemento no método de mesmo nome da lista (CListView), onde o índice é ajustado, se o intervalo for excedido. Depois disso, o texto do elemento é armazenado e definido no botão combobox. 

class CListView : public CElement
  {
public:
   //--- Destacando o elemento pelo índice especificado
   void              SelectedItemByIndex(const int index);
  };
//+------------------------------------------------------------------+
//| Destacando o elemento pelo índice especificado                   |
//+------------------------------------------------------------------+
void CComboBox::SelectedItemByIndex(const int index)
  {
//--- Destaca o elemento na lista
   m_listview.SelectedItemByIndex(index);
//--- Armazena e definir o texto do botão
   m_button_text=m_listview.SelectedItemText();
   m_button.Description(m_listview.SelectedItemText());
  }

Nós também vamos precisar de um método para bloquear e desbloquear o elemento e também de um para obter o seu estado atual. Dependendo do novo estado do elemento, as cores correspondentes a este estado são definidas para seus objetos. Alguns exemplos serão mostrados mais adiante no artigo. 

class CListView : public CElement
  {
public:
   //--- Obter e definir o estado do elemento
   bool              ComboBoxState(void)                        const { return(m_combobox_state);                        }
   void              ComboBoxState(const bool state);
  };
//+------------------------------------------------------------------+
//| Alterando o estado do combobox                                   |
//+------------------------------------------------------------------+
void CComboBox::ComboBoxState(const bool state)
  {
   m_combobox_state=state;
//--- Define as cores correspondentes ao estado atual para o objeto
   m_label.Color((state)? m_label_color : m_label_color_off);
   m_button.Color((state)? m_button_text_color : m_button_text_color_off);
   m_button.BackColor((state)? m_button_color : m_button_color_off);
   m_button.BorderColor((state)? m_button_border_color : m_button_border_color_off);
   m_drop_arrow.State(state);
  }

Quando o cursor do mouse está sobre os objetos do elemento, será possível mudar sua cor usando o método CComboBox::ChangeObjectsColor() quando este elemento estiver disponível

class CListView : public CElement
  {
public:
   //--- Mudando a cor do objeto quando o cursor estiver sobre ele
   void              ChangeObjectsColor(void);
  };
//+------------------------------------------------------------------+
//| Alterar a cor do objeto quando o cursor estiver pairando sobre ele|
//+------------------------------------------------------------------+
void CComboBox::ChangeObjectsColor(void)
  {
//--- Sai, se o elemento está bloqueado
   if(!m_combobox_state)
      return;
//--- Muda a cor do objeto
   CElement::ChangeObjectColor(m_label.Name(),CElement::MouseFocus(),OBJPROP_COLOR,m_label_color,m_label_color_hover,m_label_color_array);
   CElement::ChangeObjectColor(m_button.Name(),CElement::MouseFocus(),OBJPROP_BGCOLOR,m_button_color,m_button_color_hover,m_button_color_array);
  }

O método CComboBox::ChangeObjectsColor() deve ser chamado no timer do controle CComboBox::OnEventTimer(). Seguindo em frente, deve-se mencionar que um combobox pode ser parte de um elemento composto mais complexo, que também é suspenso. Em um dos artigos futuros, nós vamos falar de um calendário suspenso - um exemplo de tal elemento. A parte composto dela é um combobox. As condições para alterar a cor do timer para tal elemento será formado como é mostrado no código abaixo:

  1. Se este for um elemento suspenso e a lista estiver oculta.
  2. Se a primeira condição não for cumprida, verifique a disponibilidade do formulário e do próprio elemento. 
//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void CComboBox::OnEventTimer(void)
  {
//--- Se este for um elemento suspenso e a lista estiver oculta.
   if(CElement::IsDropdown() && !m_listview.IsVisible())
      ChangeObjectsColor();
   else
     {
      //--- Se o formulário e o elemento não estiverem bloqueados
      if(!m_wnd.IsLocked() && m_combobox_state)
         ChangeObjectsColor();
     }
  }

Vamos criar o método CComboBox::ChangeComboboxListState() para gerenciar a visibilidade da lista do combobox. Este método irá alterar o estado atual da combobox para a uma oposta. No início do método, haverá uma verificação para a disponibilidade do elemento. Se a combobox for bloqueada, o programa irá sair do método. Em seguida, o código será dividido em dois ramos:

  1. Se a visualização da lista já for visível, ela será ocultada aqui e as cores correspondentes serão definidas para o botão da combobox. Depois disso, se este não for um elemento suspenso, o formulário deve ser desbloqueado e o identificador do elemento ativo deve ser redefinido. 
  2. Se a lista está oculta, ela deve voltar a ser visível e as cores correspondentes a este estado devem ser definidas para o botão do combobox. No final do ramo, a formulário deve ser bloqueado e o identificador do elemento de ativação deve ser armazenado. 
class CListView : public CElement
  {
public:
   //--- Altera o estado atual da combobox para o oposto
   void              ChangeComboBoxListState(void);
  };
//+------------------------------------------------------------------+
//| Altera o estado atual da combobox para o oposto                  |
//+------------------------------------------------------------------+
void CComboBox::ChangeComboBoxListState(void)
  {
//--- Sai, se o elemento está bloqueado
   if(!m_combobox_state)
      return;
//--- Se a lista é visível
   if(m_listview.IsVisible())
     {
      //--- Oculta a lista
      m_listview.Hide();
      //--- Define as cores
      m_label.Color(m_label_color_hover);
      m_button.BackColor(m_button_color_hover);
      //--- Se este não for um elemento suspenso
      if(!CElement::IsDropdown())
        {
         //--- Desbloqueia o formulário
         m_wnd.IsLocked(false);
         m_wnd.IdActivatedElement(WRONG_VALUE);
        }
     }
//--- Se a lista está oculta
   else
     {
      //--- Mostra a lista
      m_listview.Show();
      //--- Define as cores
      m_label.Color(m_label_color_hover);
      m_button.BackColor(m_button_color_pressed);
      //--- Bloqueia o formulário
      m_wnd.IsLocked(true);
      m_wnd.IdActivatedElement(CElement::Id());
     }
  }



Métodos para Manipular os Eventos do Controle

Nós podemos seguir definindo o controle de manipulação de eventos CComboBox::OnEvent(). Para isso, nós precisaremos de mais dois métodos privados auxiliares:

  • CComboBox::OnClickButton() - o evento de pressionar o botão do combobox será monitorado neste método.
  • CComboBox::CheckPressedOverButton() - o estado do botão esquerdo do mouse sobre o botão combobox será rastreado aqui.
class CListView : public CElement
  {
private:
   //--- Manipulando o pressionamento de um botão
   bool              OnClickButton(const string clicked_object);
   //--- Verifica o pressionamento do botão esquerdo do mouse sobre o botão combobox
   void              CheckPressedOverButton(void);
  };

O código do método CComboBox::OnClickButton() é muito simples. Ele irá conter apenas uma verificação do nome do objeto em que ocorreu o pressionamento e uma chamada do método CComboBox::ChangeComboBoxListState() discutido anteriormente, na qual irá gerir a visibilidade da lista combobox, como é mostrado no código abaixo. 

//+------------------------------------------------------------------+
//| Pressionando o botão combobox                                    |
//+------------------------------------------------------------------+
bool CComboBox::OnClickButton(const string clicked_object)
  {
//--- Sai, se o nome do objeto for diferente  
   if(clicked_object!=m_button.Name())
      return(false);
//--- Altera o estado de exibição da lista
   ChangeComboboxListState();
   return(true);
  }

O código do método CComboBox::CheckPressedOverButton() é apresentado abaixo. Uma verificação para a disponibilidade do formulário e o identificador do elemento ativo é realizado no início do método. O programa irá deixar o método se o formulário for bloqueado e os identificadores não corresponderem. 

Então, se não há foco sobre o elemento, nós verificamos a presença do foco sobre a lista e o estado da barra de rolagem. Se o foco acontecer de não ser sobre a lista ou a barra de rolagem está no modo do movimento do deslizador, então o programa irá deixar o método. Já é de seu conhecimento que o deslizador da barra de rolagem, se estiver no modo de movimento, ele pode ser movido mesmo se o cursor sair da área do mesmo. Se nenhuma dessas condições forem atendidas, então:

(1) a lista está oculta,

(2) as cores dos objetos do elemento foram restaurados,

e no final deste bloco de código, se os identificadores não forem iguais e o elemento não for suspenso, (3) o formulário terá de ser desbloqueado. Deixe-me lembrá-lo que um formulário pode ser desbloqueado apenas pelo elemento que o bloqueou.

No caso, quando há um foco sobre o elemento, em primeiro lugar, é realizado a verificação da lista. Se a lista é visível, então não há nenhum ponto em continuar e o programa deixará o método. Se a lista está oculta, então, as cores correspondentes são definidas de acordo com o foco sobre o botão combobox. 

//+------------------------------------------------------------------+
//| Verifica o pressionamento do botão esquerdo do mouse sobre um botão |
//+------------------------------------------------------------------+
void CComboBox::CheckPressedOverButton(void)
  {
//--- Sai, se o formulário for bloqueado e seus identificadores não corresponderem
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return;
//--- Se não houver foco
   if(!CElement::MouseFocus())
     {
      //--- Sai, se o foco não estiver sobre a lista ou a barra de rolagem estiver ativada
      if(m_listview.MouseFocus() || m_listview.ScrollState())
         return;
      //--- Oculta a lista
      m_listview.Hide();
      //--- Restaura as cores
      ResetColors();
      //--- Se os identificadores corresponderem e o elemento não é suspenso
      if(m_wnd.IdActivatedElement()==CElement::Id() && !CElement::IsDropdown())
         //--- Desbloqueia o formulário
         m_wnd.IsLocked(false);
     }
//--- Se houver foco
   else
     {
      //--- Sai, se a lista é visível
      if(m_listview.IsVisible())
         return;
      //--- Define a cor considerando o foco
      if(m_button.MouseFocus())
         m_button.BackColor(m_button_color_pressed);
      else
         m_button.BackColor(m_button_color_hover);
     }
  }

A chamada do método CComboBox::OnClickButton() deve ser passado no bloco de manipulação do evento de pressionar o objecto gráfico, que pode ser identificado pelo identificador CHARTEVENT_OBJECT_CLICK

//+------------------------------------------------------------------+
//| Manipulador de eventos                                           |
//+------------------------------------------------------------------+
void CComboBox::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)
     {
      //--- Pressionando o botão combobox
      if(OnClickButton(sparam))
         return;
     }
  }

Antes de chamar o método CComboBox::CheckPressedOverButton(), as seguintes verificações devem ser passadas ​​no bloco de manipulação de evento do movimento do cursor do mouse CHARTEVENT_MOUSE_MOVE:

  • a visibilidade do elemento;
  • a disponibilidade do elemento;
  • estado do botão esquerdo do mouse. 
//+------------------------------------------------------------------+
//| Manipulador de eventos                                           |
//+------------------------------------------------------------------+
void CComboBox::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 elemento está oculto
      if(!CElement::IsVisible())
         return;
      //--- Coordenadas
      int  x=(int)lparam;
      int  y=(int)dparam;
      //--- Verificando o foco sobre os elementos
      CElement::MouseFocus(x>CElement::X() && x<CElement::X2() && 
                           y>CElement::Y() && y<CElement::Y2());
      m_button.MouseFocus(x>m_button.X() && x<m_button.X2() && 
                          y>m_button.Y() && y<m_button.Y2());
      //--- Sai, se o elemento está bloqueado
      if(!m_combobox_state)
         return;
      //--- Sai, se o botão esquerdo do mouse for liberado
      if(sparam=="0")
         return;
      //--- Verifica o pressionamento do botão esquerdo do mouse sobre um botão de divisão
      CheckPressedOverButton();
      return;
     }
  }

No momento do pressionamento sobre um dos elementos da lista, o evento personalizado ON_CLICK_LIST_ITEM é gerado, como é mostrado no código abaixo. Esta mensagem deve ser recebido no manipulador de eventos combobox. Se os identificadores do elemento corresponderem, devemos receber a mensagem que veio da lista anexado ao combobox, em seguida, armazenar o texto do elemento destacado da lista e ocultar a lista usando o método CComboBox::ChangeComboBoxListState().

Para garantir a conexão com o aplicativo em desenvolvimento, esta mensagem com o identificador ON_CLICK_LIST_ITEM pode ser recebida na classe personalizada CProgram. A mensagem também poderá ser enviada a partir da combobox com o seu (1) identificador de evento exclusivo, (2) o identificador de elemento (3) e a descrição combobox. Para ampliar a capacidade de identificação do evento dos controles, nós vamos usar esta opção também. Adicione um identificador exclusivo para o controle combobox ao arquivo Defines.mqh

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#define ON_CLICK_COMBOBOX_ITEM    (17) // Selecionando um elemento na lista combobox

Neste caso, adicione uma linha destacada no código abaixo em azul para o manipulador de evento do controle: 

//+------------------------------------------------------------------+
//| Manipulador de eventos                                           |
//+------------------------------------------------------------------+
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Manipulando o evento de pressionar um elemento da lista
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
     {
      //--- Se os identificadores forem iguais
      if(lparam==CElement::Id())
        {
         //--- Armazena e definir o texto do botão
         m_button_text=m_listview.SelectedItemText();
         m_button.Description(m_listview.SelectedItemText());
         //--- Altera o estado de exibição da lista
         ChangeComboBoxListState();
         //--- Envia uma mensagem sobre ele
         ::EventChartCustom(m_chart_id,ON_CLICK_COMBOBOX_ITEM,CElement::Id(),0,m_label_text);
        }
      //---
      return;
     }
  }

Nós também podemos definir para ocultar a lista quando as propriedades do gráfico são alteradas. Para isso, um evento com o identificador CHARTEVENT_CHART_CHANGE deve ser tratado como é mostrado no código abaixo: 

//+------------------------------------------------------------------+
//| Manipulador de eventos                                           |
//+------------------------------------------------------------------+
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Manipulando o evento de alteração das propriedades do gráfico
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- Sai, se o elemento está bloqueado
      if(!m_combobox_state)
         return;
      //--- Oculta a lista
      m_listview.Hide();
      //--- Restaura as cores
      ResetColors();
      //--- Desbloqueia o formulário
      m_wnd.IsLocked(false);
      m_wnd.IdActivatedElement(WRONG_VALUE);
      return;
     }
  }

A classe para criar o controle combobox está pronta para o teste, mas antes disso ela deve ser conectada com o motor da biblioteca para o seu funcionamento correto. 


Conexão da Classe de Controle com o Motor da Biblioteca

A conexão de um controle com o motor de biblioteca é realizada apenas com algumas ações simples:

1.Inclua o arquivo com a classe de controle no arquivos raiz da biblioteca WndContainer.mqh.

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

2. Se necessário, crie um array privado para o elemento e um método para criar o tamanho deste array. No nosso caso, será necessário um array privado para as listas suspensas. 

class CWndContainer
  {
protected:
   //--- Estrutura dos arrays de elementos
   struct WindowElements
     {
      //--- Array comum de todos os objetos
      //--- Array comum de todos os elementos

      //---Arrays privados de Elementos
      //    Array dos menus de contexto
      //--- Array dos menus principais
      //--- Dicas de contexto
      //--- Array da lista suspensa de diferentes tipos
      CElement         *m_drop_lists[];
     };
   //--- Array dos arrays de elemento para cada janela
   WindowElements    m_wnd[];
   //---
public:
   //--- Número da lista suspensa
   int               DropListsTotal(const int window_index);
  };
//+------------------------------------------------------------------+
//| Retorna o número da lista suspensa pelo índice da janela especificada |
//+------------------------------------------------------------------+
int CWndContainer::DropListsTotal(const int window_index)
  {
   if(window_index>=::ArraySize(m_wnd))
     {
      ::Print(PREVENTING_OUT_OF_RANGE);
      return(WRONG_VALUE);
     }
//---
   return(::ArraySize(m_wnd[window_index].m_drop_lists));
  }

3.Cria um método privado para adicionar os ponteiros ao array privado. Neste caso, nós precisamos obter um ponteiro da lista do controle combobox e adicioná-lo ao array privado. Além disso, os ponteiros do objeto da lista e a barra de rolagem da lista devem ser adicionados ao array comum de objetos. O código do método CWndContainer::AddComboBoxElements() é apresentado abaixo. 

class CWndContainer
  {
private:
   //--- Armazena os ponteiros para os elementos do menu de contexto na base
   //--- Armazena os ponteiros para os elementos do menu principal na base
   //--- Armazena os ponteiros aos elementos do botão de divisão na base
   //--- Armazena os ponteiros aos elementos dicas de contexto na base
   //--- Armazena os ponteiros para a lista de objetos na base

   //--- Armazena os ponteiros para os elementos da lista suspensa na base
   bool              AddComboBoxElements(const int window_index,CElement &object);
  };
//+------------------------------------------------------------------+
//| Armazena os ponteiros para os elementos da lista suspensa no array privado |
//+------------------------------------------------------------------+
bool CWndContainer::AddComboBoxElements(const int window_index,CElement &object)
  {
//--- Retorna, se este não for uma dica de contexto
   if(object.ClassName()!="CComboBox")
      return(false);
//--- Obtém o ponteiro combobox
   CComboBox *cb=::GetPointer(object);
//---
   for(int i=0; i<2; i++)
     {
      //--- Incrementa o array de elementos
      int size=::ArraySize(m_wnd[window_index].m_elements);
      ::ArrayResize(m_wnd[window_index].m_elements,size+1);
      //--- Adiciona a lista para a base
      if(i==0)
        {
         CListView *lv=cb.GetListViewPointer();
         m_wnd[window_index].m_elements[size]=lv;
         AddToObjectsArray(window_index,lv);
         //--- Adiciona o ponteiro para o array privado
         AddToRefArray(lv,m_wnd[window_index].m_drop_lists);
        }
      //--- Adiciona a barra de rolagem para a base
      else if(i==1)
        {
         CScrollV *sv=cb.GetScrollVPointer();
         m_wnd[window_index].m_elements[size]=sv;
         AddToObjectsArray(window_index,sv);
        }
     }
//---
   return(true);
  }

4.Se forem necessárias as ações do item 3, não se esqueça de chamar o método CWndContainer::AddComboBoxElements() no método principal CWndContainer::AddToElementsArray() onde as chamadas de tais métodos devem ser localizadas.

//+------------------------------------------------------------------+
//| Adiciona um ponteiro ao array de elemento                        |
//+------------------------------------------------------------------+
void CWndContainer::AddToElementsArray(const int window_index,CElement &object)
  {
//--- Se a base não contém formulários para os controles
/ --- Se a solicitação for para um formulário que não existe
//--- Adiciona ao array comum de elementos
//--- Adiciona os objetos do elemento para o array comum de objetos
//--- Armazena o ID do último elemento em todos os formulários
//--- Aumenta o contador de identificadores do elemento

//--- Armazena os ponteiros para os objetos do menu de contexto na base
//--- Armazena os ponteiros para os objetos do menu principal na base
//--- Armazena os ponteiros aos elementos do botão de divisão na base
//--- Armazena os ponteiros aos elementos dicas de contexto na base
//--- Armazena os ponteiros para a lista de objetos na base

//--- Armazena os ponteiros para os objetos de controle combobox na base
   if(AddComboBoxElements(window_index,object))
      return;
  }

Quando um elemento é suspenso, às vezes ele pode exceder os limites do formulário, dependendo da localização deste elemento no formulário. A localização do cursor do mouse deve ser controlada em todos os momentos e a rolagem do gráfico deve ser desativada se o gráfico for mais de um desses elementos. Isso permitirá evitar rolar o gráfico quando o botão esquerdo do mouse for pressionado sobre o elemento suspenso. Para isso, nós já escrevemos o método CWndEvents::SetChartState() na classe CWndEvents. Agora, ele tem de ser enriquecido com a verificação da lista suspensa. No código abaixo, esta parte é destacada em amarelo

//+------------------------------------------------------------------+
//| Define o estado do gráfico                                       |
//+------------------------------------------------------------------+
void CWndEvents::SetChartState(void)
  {
   int awi=m_active_window_index;
//--- Para identificar o evento quando a gestão deve ser desativada
   bool condition=false;
//--- Verifica a janela
   int windows_total=CWndContainer::WindowsTotal();
   for(int i=0; i<windows_total; i++)
     {
      //--- Move para o próximo, se este formulário está oculto
      if(!m_windows[i].IsVisible())
         continue;
      //--- Verifica as condições no manipulador interno do formulário
      m_windows[i].OnEvent(m_id,m_lparam,m_dparam,m_sparam);
      //--- Se houver um foco, marque-o
      if(m_windows[i].MouseFocus())
        {
         condition=true;
         break;
        }
     }
//--- Verifica a lista suspensa
   if(!condition)
     {
      //--- Obtém o total das listas suspensas
      int drop_lists_total=CWndContainer::DropListsTotal(awi);
      for(int i=0; i<drop_lists_total; i++)
        {
         //--- Obtém o ponteiro para a exibição da lista suspensa
         CListView *lv=m_wnd[awi].m_drop_lists[i];
         //--- Se a lista é ativada (visível)
         if(lv.IsVisible())
           {
            //--- Verifica a focagem através da lista e o estado da sua barra de rolagem
            if(m_wnd[awi].m_drop_lists[i].MouseFocus() || lv.ScrollState())
              {
               condition=true;
               break;
              }
           }
        }
     }
//--- Verifica o foco dos menus de contexto
   if(!condition)
     {
      //--- Verifique o total de menus de contexto suspensos
      int context_menus_total=CWndContainer::ContextMenusTotal(awi);
      for(int i=0; i<context_menus_total; i++)
        {
         //--- Se o foco está sobre o menu de contexto
         if(m_wnd[awi].m_context_menus[i].MouseFocus())
           {
            condition=true;
            break;
           }
        }
     }
//--- Define o estado do gráfico em todas os formulários
   for(int i=0; i<windows_total; i++)
      m_windows[i].CustomEventChartState(condition);
  }

Nós temos tudo pronto para testar o controle combobox. 

Testando o Controle ComboBox na Interface Gráfica do Aplicativo Personalizado

Vamos testar tudo o que foi implementado na interface gráfica do aplicativo personalizado na quinta parte da série. O teste no artigo anterior foi finalizado com três modos da lista. Vamos manter a lista e adicionar quatro combobox para a interface gráfica da aplicação. Coloque duas combobox de forma que nos permitirá testar o impacto da lista suspensa sobre a lista estática que será localizada abaixo dela. Além disso, nós temos que testar o funcionamento do método CWndEvents::SetChartState(). Para isso, nós vamos colocar as combobox para que quando as listas suspensa serem visíveis, elas ultrapassem os limites do formulário que eles estão ligados.

Na classe personalizada CProgram da aplicação do teste, a classe da combobox já está disponível através das classes base. Crie quatro instâncias da classe do tipo CComboBox e declare quatro métodos para cada um deles especificando as margens a partir do ponto superior esquerdo do formulário como é mostrado no código abaixo.

//+------------------------------------------------------------------+
//| Classe para a criação de um aplicativo                           |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
   //--- Combobox
   CComboBox         m_combobox1;
   CComboBox         m_combobox2;
   CComboBox         m_combobox3;
   CComboBox         m_combobox4;
   //---
private:
   //--- Combobox 1
#define COMBOBOX1_GAP_X       (7)
#define COMBOBOX1_GAP_Y       (50)
   bool              CreateComboBox1(const string text);
   //--- Combobox 2
#define COMBOBOX2_GAP_X       (160)
#define COMBOBOX2_GAP_Y       (50)
   bool              CreateComboBox2(const string text);
   //--- Combobox 3
#define COMBOBOX3_GAP_X       (7)
#define COMBOBOX3_GAP_Y       (202)
   bool              CreateComboBox3(const string text);
   //--- Combobox 4
#define COMBOBOX4_GAP_X       (160)
#define COMBOBOX4_GAP_Y       (202)
   bool              CreateComboBox4(const string text);
  };

Consideremos um destes métodos já que todos eles são idênticos com exceção das propriedades definidas pelo utilizador. Por exemplo, nós vamos bloquear a quarta combobox logo após a sua criação. Abaixo está a sequência de ações para criar o controle combobox.

  • Armazene o ponteiro do formulário na classe de controle.
  • Calcule as coordenadas.
  • Declare e inicialize imediatamente o array de texto para os elementos da lista.
  • Defina as propriedades do controle. A maioria deles são inicializados por valores padrão. Os valores podem ser redefinidos antes de criar o controle, se for necessário.
  • Armazene os valores dos elementos na lista combobox.
  • Se necessário, defina as propriedades para a exibição da lista e a barra de rolagem.
  • Destaque o elemento na lista. O primeiro elemento (0) será destacado por padrão.
  • Cria o controle.
  • O controlo pode ser bloqueado, se necessário. Nós vamos bloquear a quarta combobox em nosso aplicativo de teste, como um exemplo.
  • No final do método, passe o objeto para a classe base para armazenar o ponteiro.

A sequência de ações pode ser diferente. O importante é manter a sequência das três ações principais:

  1. Adicionando o ponteiro do formulário para a classe do controle. Caso contrário, a criação da interface gráfica será encerrada. A razão da falha pode ser encontrada a partir das mensagens no registro.
  2. Criando o controle.
  3. Armazenando o ponteiro de controle na base do objeto.
//+------------------------------------------------------------------+
//| Cria o combobox 1                                                |
//+------------------------------------------------------------------+
bool CProgram::CreateComboBox1(const string text)
  {
//--- Número total de elementos de exibição da lista
#define ITEMS_TOTAL1 8
//--- Passa o objeto do formulário
   m_combobox1.WindowPointer(m_window1);
//--- Coordenadas
   int x=m_window1.X()+COMBOBOX1_GAP_X;
   int y=m_window1.Y()+COMBOBOX1_GAP_Y;
//--- Array dos valores de elementos da lista
   string items_text[ITEMS_TOTAL1]={"FALSE","item 1","item 2","item 3","item 4","item 5","item 6","item 7"};
//--- Define as propriedades antes da criação
   m_combobox1.XSize(140);
   m_combobox1.YSize(18);
   m_combobox1.LabelText(text);
   m_combobox1.ButtonXSize(70);
   m_combobox1.AreaColor(clrWhiteSmoke);
   m_combobox1.LabelColor(clrBlack);
   m_combobox1.LabelColorHover(clrCornflowerBlue);
   m_combobox1.ButtonBackColor(C'206,206,206');
   m_combobox1.ButtonBackColorHover(C'193,218,255');
   m_combobox1.ButtonBorderColor(C'150,170,180');
   m_combobox1.ButtonBorderColorOff(C'178,195,207');
   m_combobox1.ItemsTotal(ITEMS_TOTAL1);
   m_combobox1.VisibleItemsTotal(5);
//--- Armazena os valores dos elementos na lista combobox.
   for(int i=0; i<ITEMS_TOTAL1; i++)
      m_combobox1.ValueToList(i,items_text[i]);
//--- Obtém o ponteiro de exibição da lista
   CListView *lv=m_combobox1.GetListViewPointer();
//--- Define as propriedades da lista
   lv.LightsHover(true);
   lv.SelectedItemByIndex(lv.SelectedItemIndex()==WRONG_VALUE ? 2 : lv.SelectedItemIndex());
//--- Cria o controle
   if(!m_combobox1.CreateComboBox(m_chart_id,m_subwin,x,y))
      return(false);
//--- Adiciona o objeto para o array comum dos grupos de objetos
   CWndContainer::AddToElementsArray(0,m_combobox1);
   return(true);
  }

Para criar a interface gráfica, a chamada dos métodos para a criação dos controles deve ser colocada no método principal. No nosso caso, este é o CProgram::CreateTradePanel(). 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

//--- Combobox
   if(!CreateComboBox1("Combobox 1:"))
      return(false);
   if(!CreateComboBox2("Combobox 2:"))
      return(false);
   if(!CreateComboBox3("Combobox 3:"))
      return(false);
   if(!CreateComboBox4("Combobox 4:"))
      return(false);

//--- Lista

//--- Redesenho do gráfico
   m_chart.Redraw();
   return(true);
  }

Adicione o bloco de identificação de mensagens a partir das combobox com o identificador ON_CLICK_COMBOBOX_ITEM para o manipulador de eventos da classe personalizada CProgram. Vamos garantir que, se uma mensagem a partir do terceiro combobox for recebida, então, dependendo de qual lista foi selecionada, o estado do quarto combobox irá mudar. No nosso caso, a seleção de qualquer elemento da lista, exceto o primeiro (0) fará com que a quarta combobox esteja disponível. Selecionando o primeiro elemento irá bloqueá-lo. 

//+------------------------------------------------------------------+
//| Manipulador de eventos                                           |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Seleção do elemento no evento combobox
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM)
     {
      if(sparam==m_combobox1.LabelText())
         ::Print(__FUNCTION__," > Esta mensagem é do combobox 1 > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      else if(sparam==m_combobox2.LabelText())
         ::Print(__FUNCTION__," > Esta mensagem é do combobox 2 > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Manipula a mensagem a partir do terceiro combobox
      else if(sparam==m_combobox3.LabelText())
        {
         ::Print(__FUNCTION__," > Esta mensagem é do combobox 3 > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
         //--- Se o valor especificado for selecionado, desativa o combobox 4
         if(m_combobox3.ButtonText()=="FALSE")
            m_combobox4.ComboBoxState(false);
         //--- Se outro valor tiver sido selecionado, ativa o combobox 4
         else
            m_combobox4.ComboBoxState(true);
        }
      else if(sparam==m_combobox4.LabelText())
         ::Print(__FUNCTION__," > Esta mensagem é do combobox 4 > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
  }

Se compilarmos o programa e carregarmos ao gráfico, o resultado será como na imagem abaixo:

 Fig. 2. Testando o controle combobox.

Fig. 2. Testando o controle combobox.

Nós completamos o desenvolvimento da classe CComboBox para a criação do combobox.


Conclusão

Neste artigo nós consideramos o controle composto combobox. A esquemática da biblioteca para a criação das interfaces gráficas no atual estágio de desenvolvimento é parecido com a imagem abaixo:

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

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

O próximo artigo daremos início a sexta parte da série dedicada ao desenvolvimento da biblioteca para a criação das interfaces gráficas. Lá, nós vamos escrever as classes para criar os controles da caixa de seleção, de edição e seus tipos mistos.

Você pode baixar o material da parte V 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 da quinta parte:

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

Arquivos anexados |
Como copiar sinais pelas suas regras usando um EA ? Como copiar sinais pelas suas regras usando um EA ?
Ao assinar um sinal, a seguinte situação pode ocorrer: sua conta de negociação tem uma alavancagem de 1:100, o provedor tem uma alavancagem de 1:500 e as negociações usam um lote mínimo, seus saldos são praticamente iguais - porém o coeficiente de cópia irá abranger somente de 10% a 15%. Este artigo descreve como aumentar a taxa de cópia em tais casos.
Criação de estratégias de negociação manuais usando lógica fuzzy Criação de estratégias de negociação manuais usando lógica fuzzy
No artigo é considerada a possibilidade de melhorar as estratégias de negociação manuais usando a teoria dos conjuntos difusos (fuzzy). Como exemplo, é descrito passo a passo o motor de busca de estratégias e a seleção de seus parâmetros, o uso de lógica fuzzy para diluir os critérios demasiado formais de entrada no mercado. Assim, Depois da modificação da estratégia, nós obtemos condições flexíveis de abertura de posição que respondem melhor à situação de mercado.
Dicas para o trader: indicadores de saldo, drawdown, carregamento e ticks durante o teste Dicas para o trader: indicadores de saldo, drawdown, carregamento e ticks durante o teste
Como tornar o teste mais claro? A resposta é simples: no testador, você precisa usar um ou mais indicadores, a saber: os indicadores de ticks, saldo e eqüidade, drawdown e carga de depósito. Isso permitirá monitorar visualmente quer a natureza dos ticks, quer as alterações de saldo e eqüidade, quer o drawdown e a carga de depósito.
Proteção contra falsos positivos do robô de negociação Proteção contra falsos positivos do robô de negociação
A rentabilidade dos sistemas de negociação é determinada não só pela lógica e precisão da dinâmica dos instrumentos financeiros, mas também pela qualidade do algoritmo de execução dessa lógica. Os falsos positivos são uma manifestação característica da má execução da lógica fundamental do robô de negociação. Neste artigo trataremos várias opções para resolver esse problema.