English Русский 中文 Español Deutsch 日本語
Interfaces gráficas X: Atualizações para a Biblioteca Easy And Fast (Build 2)

Interfaces gráficas X: Atualizações para a Biblioteca Easy And Fast (Build 2)

MetaTrader 5Exemplos | 9 novembro 2016, 13:26
1 232 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) explica 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.

Desde a publicação do artigo anterior desta série, a biblioteca Easy And Fast tem recebido algumas funcionalidades novas. A estrutura e o código da biblioteca foram parcialmente otimizados, reduzindo ligeiramente a carga da CPU. Alguns métodos recorrentes em muitas classes de controle foram transferidos para a classe base CElement. Além disso, foram adicionadas algumas melhorias visuais pequenas e correções. Vamos examinar tudo isso em detalhes.

 

Atualizações

1. Alterado o esquema de cores padrão. Agora, ele está em tons claros em conformidade com qualquer fundo do gráfico. Usando o esquema de cores padrão permite especificar a quantidade mínima de propriedades no desenvolvimento de métodos para a criação de controles em uma classe personalizada. 

As imagens seguintes mostram os exemplos de uma interface gráfica em uma aplicação MQL contra os fundos claros e escuros:

 Fig. 1. Amostra da interface gráfica com o esquema de cores padrão contra um fundo claro

Fig. 1. Amostra da interface gráfica com o esquema de cores padrão contra um fundo claro


 Fig. 2. Amostra da interface gráfica com o esquema de cores padrão contra um fundo escuro

Fig. 2. Amostra da interface gráfica com o esquema de cores padrão contra um fundo escuro


 

2. Implementado a primeira versão da classe CMouse para armazenar os parâmetros do mouse e de seu cursor. Vamos analisar ele com mais cuidado.

A classe CMouse pode ser encontrada no arquivo Mouse.mqh localizado no diretório de todos os arquivos da biblioteca: “<diretório do terminal>\MQLX\Include\EasyAndFastGUI\Controls ”. Aqui nós precisamos da instância da classe CChart da biblioteca padrão. O método CChart::SubwindowY() é para ser usado a partir dessa classe para calcular a coordenada Y em relação à sub-janela onde o cursor do mouse está localizado atualmente. A Vinculação do gráfico é realizada no construtor da classe, enquanto que a desvinculação é feita no processo do destrutor.

A classe CChart estará disponível para todas as classes das bibliotecas básicas a partir daqui. Portanto, foram implementadas as alterações apropriadas. 

//+------------------------------------------------------------------+
//|                                                        Mouse.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Charts\Chart.mqh>
//+------------------------------------------------------------------+
//| Classe para receber os parâmetros de mouse                       |
//+------------------------------------------------------------------+
class CMouse
  {
private:
   //--- Instância de classe para gerenciar o gráfico
   CChart            m_chart;
   //---
public:
                     CMouse(void);
                    ~CMouse(void);
  };
//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CMouse::CMouse(void)
  {
//--- Recebe o ID do gráfico atual
   m_chart.Attach();
  }
//+------------------------------------------------------------------+
//| Destrutor                                                        |
//+------------------------------------------------------------------+
CMouse::~CMouse(void)
  {
//--- Desvincula do gráfico
   m_chart.Detach();
  }

A lista dos parâmetros do mouse e do cursor, que pode ser utilizado em quase todas as classes da biblioteca é fornecida abaixo.

  • As coordenadas atuais do cursor.
  • Número da sub-janela que atualmente contém o cursor.
  • Tempo correspondente a coordenada X do cursor no gráfico.
  • Nível correspondente a coordenada Y do cursor no gráfico.
  • Estado do botão esquerdo do mouse (pressionado/liberado).

Os campos e métodos relevantes para o armazenamento e o recebimento dos valores dos parâmetros são implementadas no corpo da classe CMouse

class CMouse
  {
private:
   //--- Coordenadas
   int               m_x;
   int               m_y;
   //--- Número da janela, em que o cursor está localizado
   int               m_subwin;
   //--- Tempo correspondente à coordenada X
   datetime          m_time;
   //--- Nível (preço), correspondente à coordenada Y
   double            m_level;
   //--- Estado do botão esquerdo do mouse (pressionado/liberado)
   bool              m_left_button_state;
   //---
public:
   //--- Retorna as coordenadas
   int               X(void)               const { return(m_x);                 }
   int               Y(void)               const { return(m_y);                 }
   //--- Retorna o (1) número da janela onde o cursor está localizado atualmente, (2) o tempo correspondente à coordenada X, 
   //    (3) nível (preço), correspondente à coordenada Y
   int               SubWindowNumber(void) const { return(m_subwin);            }
   datetime          Time(void)            const { return(m_time);              }
   double            Level(void)           const { return(m_level);             }
   //--- Retorna o estado do botão esquerdo do mouse (pressionado/liberado)
   bool              LeftButtonState(void) const { return(m_left_button_state); }
  };

Claro, nós precisamos que o manipulador de eventos monitore a ocorrência do evento CHARTEVENT_MOUSE_MOVE. Os campos da classe CMouse são preenchidos no bloco do processamento de eventos. Nós já encontramos esse código em todos os manipuladores de eventos do controle. Agora, ele está presente apenas na classe CMouse tornando o código das classes do controle mais intuitivas. Além disso, agora os parâmetros do mouse e do cursor são recebidos apenas uma vez dentro de toda a passagem ao longo de todos os elementos, reduzindo, assim, a carga da CPU.  

class CMouse
  {
   / --- Manipulador de eventos
   void              OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
  };
//+------------------------------------------------------------------+
//| Manipulador de eventos do movimento do cursor do mouse           |
//+------------------------------------------------------------------+
void CMouse::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Manipulador de eventos do movimento do cursor
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Coordenadas e o estado do botão esquerdo do mouse
      m_x                 =(int)lparam;
      m_y                 =(int)dparam;
      m_left_button_state =(bool)int(sparam);
      //--- Recebe a localização do cursor
      if(!::ChartXYToTimePrice(0,m_x,m_y,m_subwin,m_time,m_level))
         return;
      //--- Recebe a coordenada Y relativa
      if(m_subwin>0)
         m_y=m_y-m_chart.SubwindowY(m_subwin);
     }
  }

A instância da classe CMouse é declarada na classe base do motor da biblioteca (CWndContainer):

//+------------------------------------------------------------------+
//| Classe para armazenar todos os objetos da interface              |
//+------------------------------------------------------------------+
class CWndContainer
  {
protected:
   //--- Instância da classe para receber os parâmetros do mouse
   CMouse            m_mouse;
  };

A instância da classe CMouse também é declarada na classe do controle base CElement para armazenar o ponteiro ao objeto desse tipo, que por sua vez é declarado na classe CWndContainer. Além disso, os métodos para salvar e receber o ponteiro estão localizados aqui. 

//+------------------------------------------------------------------+
//| Classe base do controle                                          |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- Instância da classe para receber os parâmetros do mouse
   CMouse           *m_mouse;
   //---
public:
   //--- (1) Salve e (2) retorna o ponteiro do mouse
   void              MousePointer(CMouse &object)                   { m_mouse=::GetPointer(object);       }
   CMouse           *MousePointer(void)                       const { return(::GetPointer(m_mouse));      }
  };

O ponteiro para o objeto CMouse é passado automaticamente para todos os controles ao criar a interface gráfica da biblioteca. Para fazer isso, o objeto CMouse deve ser passado no método CWndContainer::AddToObjectsArray() onde os ponteiros de todos os objetos gráficos que formam parte dos controles são enviados ao array comum, tal como encontramos no código abaixo. 

//+------------------------------------------------------------------+
//| Adiciona os ponteiros de objetos de controle ao array comum      |
//+------------------------------------------------------------------+
template<typename T>
void CWndContainer::AddToObjectsArray(const int window_index,T &object)
  {
   int total=object.ObjectsElementTotal();
   for(int i=0; i<total; i++)
      AddToArray(window_index,object.Object(i));
//--- Salva o cursor do mouse na classe base do controle
   object.MousePointer(m_mouse);
  }

Agora, cada classe do controle tem acesso aos parâmetros do mouse e do cursor, que estão armazenados em um único objeto em toda a biblioteca. A fim de receber os novos valores no manipulador ChartEvent() da classe CWndEvents, o manipulador do objeto CMouse deve ser chamado, enviando-lhe os parâmetros atuais do evento. Desde que a chamada seja realizada antes do manipulador de eventos de todos os controles, os valores atuais dos parâmetros do mouse e do cursor estarão disponíveis posteriormente para todos os controles sem a necessidade de realizar novamente a conversão dos tipos, atribuir os valores aos campos de classe e calcular a coordenada Y.

//+------------------------------------------------------------------+
//| Manipulação dos eventos do programa                              |
//+------------------------------------------------------------------+
void CWndEvents::ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Sai se o array está vazio
//--- Inicialização dos campos dos parâmetros de eventos

//--- Recebe os parâmetros do mouse
   m_mouse.OnEvent(id,lparam,dparam,sparam);

//--- Eventos personalizados
//--- Verifica os eventos do controle da interface
//--- Evento do movimento do mouse
//--- Evento da alteração das propriedades do gráfico
  }

Como exemplo, nós vamos mostrar uma parte do código do manipulador do controle CSimpleButton. Abaixo é exibido a versão resumida do método CSimpleButton::OnEvent(). A cor amarela é usado para realçar as linhas que contém a chamada dos métodos do objeto CMouse para obter (1) o número da sub-janela, que se encontra o cursor do mouse, (2) as coordenadas do cursor e (3) o estado do botão esquerdo do mouse.  

//+------------------------------------------------------------------+
//| Manipulador de eventos                                           |
//+------------------------------------------------------------------+
void CSimpleButton::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Manipulação do evento do movimento do cursor
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Sai, se o controle está oculto
      if(!CElement::IsVisible())
         return;
      //--- Sai se o formulário está bloqueado
      if(m_wnd.IsLocked())
         return;
      //--- Sai se os números da sub-janela não corresponderem
      if(CElement::m_subwin!=CElement::m_mouse.SubWindowNumber())
         return;
      //--- Sai se o botão está bloqueado
      if(!m_button_state)
         return;
      //--- Define o foco
      CElement::MouseFocus(CElement::m_mouse.X()>X() && CElement::m_mouse.X()<X2() && 
                           CElement::m_mouse.Y()>Y() && CElement::m_mouse.Y()<Y2());
      //--- Sai se o botão do mouse foi liberado
      if(!CElement::m_mouse.LeftButtonState())
         return;
      //--- 
      ...
      return;
     }
//...
  }

As correções correspondentes foram implementadas em todas as classes dos controles da biblioteca.  


3. Anteriormente, os métodos para a obtenção do ID de um controle e o índice do nome do objeto gráfico dele se repetiam em muitas classes do controle da biblioteca. Agora, estes métodos foram colocados na classe base CElement para evitar repetições.  

//+------------------------------------------------------------------+
//| Classe base do controle                                          |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- Recebe um ID do nome do objeto.
   int               IdFromObjectName(const string object_name);
   //--- Recebe o índice do nome do elemento do menu
   int               IndexFromObjectName(const string object_name);
  };

 

4. Este métodos foram adicionados na classe CWindow para habilitar o botão de minimizar/maximizar a janela e o posicionar o rótulo de texto no cabeçalho.  

//+------------------------------------------------------------------+
//| Classe para a criação do formulário para os controles            |
//+------------------------------------------------------------------+
class CWindow : public CElement
  {
private:
   //--- Margens do rótulo de texto do cabeçalho
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Presença do botão para minimizar/maximizar a janela
   bool              m_roll_button;
   //---
public:
   //--- 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;                }
   //--- Usa o botão dica da ferramenta
   void              UseRollButton(void)                                     { m_roll_button=true;                 }
  };

 

5. Foi adicionado o método CheckWindowPointer() para a classe CElement, a fim de verificar a presença do ponteiro da janela (CWindow). A verificação é feita através do envio do tipo do ponteiro pelo método CheckPointer(). Anteriormente, o mesmo código era repetido em todas as classes do controle dentro do método de criação do controle principal, antes de sua criação. O método CElement::CheckWindowPointer() simplifica o processo, reduz a quantidade de código e faz com que o mesmo seja mais versátil. 

//+------------------------------------------------------------------+
//| Classe base do controle                                          |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- Verifica se o ponteiro para o formulário está presente
   bool              CheckWindowPointer(ENUM_POINTER_TYPE pointer_type);
  };
//+------------------------------------------------------------------+
//| Verifica se o ponteiro para o formulário está presente            |
//+------------------------------------------------------------------+
bool CElement::CheckWindowPointer(ENUM_POINTER_TYPE pointer_type)
  {
//--- Se não existe o ponteiro para a formulário
   if(pointer_type==POINTER_INVALID)
     {
      //--- Gera a mensagem
      string message=__FUNCTION__+" > Antes de criar o controle, deve-se passar o ponteiro ao formulário: "+ClassName()+"::WindowPointer(CWindow &object)";
      //--- Envia a mensagem ao registro do terminal
      ::Print(message);
      //--- Interrompe a criação da interface gráfica da aplicação
      return(false);
     }
//--- Envia o indício da presença do ponteiro
   return(true);
  }

Agora, para verificar a presença do ponteiro ao formulário na qual o controle deve ser ligado, basta chamar o método CElement::CheckWindowPointer(), como é mostrado no código abaixo (tomando de exemplo a criação do botão simples na classe CSimpleButton). As correções correspondentes foram implementadas em todas as classes dos controles da biblioteca. 

//+------------------------------------------------------------------+
//| Cria o controle "um botão simples"                               |
//+------------------------------------------------------------------+
bool CSimpleButton::CreateSimpleButton(const long chart_id,const int subwin,const string button_text,const int x,const int y)
  {
//--- Sai se o ponteiro para o formulário está ausente
   if(!CElement::CheckWindowPointer(::CheckPointer(m_wnd)))
      return(false);
//--- Inicializa as variáveis
   m_id          =m_wnd.LastId()+1;
   m_chart_id    =chart_id;
   m_subwin      =subwin;
   m_x           =x;
   m_y           =y;
   m_button_text =button_text;
//--- Recortes do ponto da borda
   CElement::XGap(m_x-m_wnd.X());
   CElement::YGap(m_y-m_wnd.Y());
//--- Cria o botão
   if(!CreateButton())
      return(false);
//--- Oculta o controle, se este é uma janela de diálogo ou ele está minimizado
   if(m_wnd.WindowType()==W_DIALOG || m_wnd.IsMinimized())
      Hide();
//---
   return(true);
  }

 

6. Foi adicionado o modo para a alteração automática da largura do controles na classe base CElement, se foi alterado a largura do formulário, a qual o controle está ligado. O método CElement::AutoXResizeMode() é usado para definir o modo. Agora, a borda direita do controle neste modo está vinculada a borda direita do formulário. Além disso, foi adicionado o método CElement::AutoXResizeRightOffset() para definir e obter a margem (em pixels) da borda direita do formulário. 

//+------------------------------------------------------------------+
//| Classe base do controle                                          |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- Modo de alteração automática da largura do controle
   bool              m_auto_xresize_mode;
   //--- Margem da borda direita do formulário no modo de alteração automática da largura do controle
   int               m_auto_xresize_right_offset;
   //---
public:
   //--- (1) Modo de alteração automática da largura do controle, (2) definir/obter a margem da borda direita do formulário
   bool              AutoXResizeMode(void)                    const { return(m_auto_xresize_mode);         }
   void              AutoXResizeMode(const bool flag)               { m_auto_xresize_mode=flag;            }
   int               AutoXResizeRightOffset(void)             const { return(m_auto_xresize_right_offset); }
   void              AutoXResizeRightOffset(const int offset)       { m_auto_xresize_right_offset=offset;  }
  };

Por padrão, o modo de vincular a borda direita do controle com a borda direita do formulário está desativado (false) e a margem é igual a 0. A inicialização é realizada no construtor da classe CElement (veja o código abaixo): 

//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CElement::CElement(void) : m_auto_xresize_mode(false),
                           m_auto_xresize_right_offset(0)
  {
  }

Anteriormente, o método CWindow::ChangeWindowWidth() já foi criado na classe CWindow para alterar a largura do formulário. Agora, se o modo está ativado, a largura do formulário é automaticamente alterada somente se a interface gráfica foi implementada na sub-janela do indicador. Em outras palavras, se a largura da janela de gráfico é alterada no manipulador de eventos do formulário devido ao evento CHARTEVENT_CHART_CHANGE, a largura do formulário é alterada. 

//--- Evento da alteração das propriedades do gráfico
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- Se o botão foi liberado
      if(m_clamping_area_mouse==NOT_PRESSED)
        {
         //--- Receba o tamanho da janela do gráfico
         SetWindowProperties();
         //--- Corrige as coordenadas
         UpdateWindowXY(m_x,m_y);
        }
      //--- Altera o tamanho se o modo está habilitado
      if(CElement::AutoXResizeMode())
         ChangeWindowWidth(m_chart.WidthInPixels()-2);
      //---
      return;
     }

O novo identificador foi adicionado à lista de eventos da biblioteca - ON_WINDOW_CHANGE_SIZE. Este ID é utilizado para gerar a mensagem de alteração do tamanho do formulário. 

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
...
//--- Identificadores de evento
#define ON_WINDOW_CHANGE_SIZE     (3)  // Altera o tamanho da janela
...

A geração de tal mensagem foi adicionada ao método CWindow::ChangeWindowWidth(). A versão resumida do método é mostrada abaixo: 

//+------------------------------------------------------------------+
//| Altera a largura da janela                                       |
//+------------------------------------------------------------------+
void CWindow::ChangeWindowWidth(const int width)
  {
//--- Sair se a largura não foi alterada
//--- Atualiza a largura de fundo e do cabeçalho
//--- Atualiza as coordenadas e as margens para todos os botões:
//    Botão de fechamento
//--- Botão de maximizar
//--- Botão de minimizar
//--- Botão dica da ferramenta (se habilitado)

//--- Mensagem sobre a alteração do tamanho da janela
   ::EventChartCustom(m_chart_id,ON_WINDOW_CHANGE_SIZE,(long)CElement::Id(),0,””);
  }

A mensagem é processada no motor da biblioteca (classe CWndEvents). Adicionado o método virtual ChangeWidthByRightWindowSide() para a classe base dos controles CElement. Além disso, foi alterado a implementação do método em muitos classes derivadas (onde a largura do controle deve ser alterada).  

//+------------------------------------------------------------------+
//| Classe base do controle                                          |
//+------------------------------------------------------------------+
class CElement
  {
public:
   //--- Altera a largura da borda direita da janela
   virtual void      ChangeWidthByRightWindowSide(void) {}
  };

Após a chegada do evento ON_WINDOW_CHANGE_SIZE na classe CWndEvents, é possível alterar a largura dos controles que foram ativados no modo correspondente. O método CWndEvents::OnWindowChangeSize() foi implementado para esta finalidade. 

//+------------------------------------------------------------------+
//| Classe para a manipulação de eventos                             |
//+------------------------------------------------------------------+
class CWndEvents : public CWndContainer
  {
private:
   //--- Manipula a alteração do tamanho da janela
   bool              OnWindowChangeSize(void);
  };
//+------------------------------------------------------------------+
//| Evento ON_WINDOW_CHANGE_SIZE                                     |
//+------------------------------------------------------------------+
bool CWndEvents::OnWindowChangeSize(void)
  {
//--- No caso do sinal "Alteração do tamanho do controle"
   if(m_id!=CHARTEVENT_CUSTOM+ON_WINDOW_CHANGE_SIZE)
      return(false);
//--- Índice da janela ativa
   int awi=m_active_window_index;
//--- Se os IDs das janelas corresponderam
   if(m_lparam!=m_windows[awi].Id())
      return(true);
//--- Altera a largura de todos os controles, exceto do formulário
   int elements_total=CWndContainer::ElementsTotal(awi);
   for(int e=0; e<elements_total; e++)
     {
      if(m_wnd[awi].m_elements[e].ClassName()=="CWindow")
         continue;
      //---
      if(m_wnd[awi].m_elements[e].AutoXResizeMode())
         m_wnd[awi].m_elements[e].ChangeWidthByRightWindowSide();
     }
//---
   return(true);
  }

O método é chamado no método principal do processamento de eventos da biblioteca CWndEvents::ChartEventCustom(). 

//+------------------------------------------------------------------+
//| Evento CHARTEVENT_CUSTOM                                         |
//+------------------------------------------------------------------+
void CWndEvents::ChartEventCustom(void)
  {
//--- Sinal para minimizar o formulário
//--- Sinal para maximizar o formulário

//--- Sinal para alterar o tamanho do controle
   if(OnWindowChangeSize())
      return;

//--- Sinal para ocultar os menus de contexto do elemento inicializador
//--- Sinal para ocultar todos os menus de contexto
//--- Sinal para abrir a janela de diálogo
//--- Sinal para fechar a janela de diálogo
//--- Sinal para resetar a cor do controle no formulário especificado
//--- Sinal para resetar as prioridades do clique do botão esquerdo do mouse
//--- Sinal para resetar as prioridades do clique do botão esquerdo do mouse
  }

Atualmente, o método ChangeWidthByRightWindowSide() para alterar a largura do controle em relação à largura do formulário em que eles estão associadas está presente nas seguintes classes:

  • CTabs – guias simples.
  • CIconTabs – guias com imagens.
  • CStatusBar – barra de estado.
  • CMenuBar – menu principal.
  • CLabelsTable – tabela com o rótulo de texto.
  • CTable – tabela com o caixa de edição.
  • CCanvasTable – tabela renderizada.
  • CProgressBar – barra de progresso.
  • CTreeView – lista hierárquica.
  • CFileNavigator – navegador de arquivos.
  • CLineGraph – gráfico de linha.

Como exemplo, o código do método para o controle do tipo CLabelsTable é exibido abaixo. 

//+------------------------------------------------------------------+
//| Altera a largura para a borda direita da margem                  |
//+------------------------------------------------------------------+
void CLabelsTable::ChangeWidthByRightWindowSide(void)
  {
//--- Coordenadas
   int x=0;
//--- Tamanho
   int x_size=0;
//--- Calcula e define o novo tamanho do fundo da tabela
   x_size=m_wnd.X2()-m_area.X()-m_auto_xresize_right_offset;
   CElement::XSize(x_size);
   m_area.XSize(x_size);
   m_area.X_Size(x_size);
//--- Calcula e define a nova coordenada para a barra de rolagem vertical
   x=m_area.X2()-m_scrollv.ScrollWidth();
   m_scrollv.XDistance(x);
//--- Calcula e altera a largura da barra de rolagem horizontal
   x_size=CElement::XSize()-m_scrollh.ScrollWidth()+1;
   m_scrollh.ChangeXSize(x_size);
//--- Atualiza a posição dos objetos
   Moving(m_wnd.X(),m_wnd.Y());
  }


7. Foi adicionado a possibilidade de alternar programaticamente as guias após a sua criação. O método SelectTab() foi implementado nas classes CTabs e CIconTabs. Como exemplo, o código a seguir mostra o método da classe CTabs:

//+------------------------------------------------------------------+
//| Classe para a criação das guias                                  |
//+------------------------------------------------------------------+
class CTabs : public CElement
  {
public:
   //--- Destaca a guia especificada
   void              SelectTab(const int index);
  };
//+------------------------------------------------------------------+
//| Destaca a guia especificada                                      |
//+------------------------------------------------------------------+
void CTabs::SelectTab(const int index)
  {
   for(int i=0; i<m_tabs_total; i++)
     {
      //--- Se a guia é selecionada
      if(index==i)
        {
         //--- Coordenadas
         int x=0;
         int y=0;
         //--- Tamanho
         int x_size=0;
         int y_size=0;
         //--- Salva o índice da guia selecionada
         SelectedTab(index);
         //--- Define as cores
         m_tabs[i].Color(m_tab_text_color_selected);
         m_tabs[i].BackColor(m_tab_color_selected);
         //--- Cálculo relativo ao posicionamento da guia
         CalculatingPatch(x,y,x_size,y_size);
         //--- Atualiza o valor
         m_patch.X_Size(x_size);
         m_patch.Y_Size(y_size);
         m_patch.XGap(x-m_wnd.X());
         m_patch.YGap(y-m_wnd.Y());
         //--- Atualiza a localização dos objetos
         Moving(m_wnd.X(),m_wnd.Y());
        }
      else
        {
         //--- Define as cores para as guias não ativas
         m_tabs[i].Color(m_tab_text_color);
         m_tabs[i].BackColor(m_tab_color);
        }
     }
//--- Exibe somente os controles da guia selecionada
   ShowTabElements();
  }

 

8. Foi adicionado a possibilidade de desfazer a seleção de uma linha no campo de edição da tabela (CTable) através do clique sobre ela novamente

9. O formato da string "column_row_text" é enviado em um evento gerado como um parâmetro de string (sparam) ao clicar em uma célula da tabela (CTable) com o modo de edição da célula desativado.

10. Foram corrigidos a enumeração e os métodos para definir a área do clique do botão do mouse. Agora a enumeração ENUM_MOUSE_STATE é usada para monitorar a área do clique esquerdo do botão do mouse em todos os controles.

11. Foram renomeados alguns arquivos de imagem usados ​​como recurso (resource) na biblioteca devido as limitações do tamanho do nome do arquivo nas aplicações do tipo Indicator.

12. Além disso, foi adicionado algumas melhorias visuais pequenas e corrigido alguns erros. Alguns erros detectados ocorreram apenas no MetaTrader 4


Aplicação para Testar as Atualizações

Vamos desenvolver uma aplicação que lhe permita testar todas as alterações mencionadas acima. Nós vamos criar duas versões do aplicação — "Expert" e "Indicator". A interface gráfica do indicador estará localizada na sub-janela do gráfico tornando possível o teste do encaixe automático da largura da janela para a largura da sub-janela do gráfico, bem como o ajuste da largura dos elementos que estão vinculados a ela. 

Para realizar um teste completo, todos os tipos de controle existentes na biblioteca serão incluídos na interface gráfica. Os controles devem estar localizados em diferentes guias (CTabs) para otimizar ao máximo o espaço da interface gráfica. Já que a lista de controles é bem grande, seria conveniente colocarmos a implementação dos métodos para a sua criação em um arquivo separado. Vamos chamar o arquivo de MainWindow.mqh. Ele será armazenado na pasta com os demais arquivos do projeto. Ele deve ser incluído logo após o corpo da classe personalizada, conforme mostrado no código a seguir:

//+------------------------------------------------------------------+
//|                                                      Program.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <EasyAndFastGUI\Controls\WndEvents.mqh>
//+------------------------------------------------------------------+
//| Classe para a criação de um aplicativo                           |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {

//...

  };
//+------------------------------------------------------------------+
//| Cria os controles:                                               |
//+------------------------------------------------------------------+
#include "MainWindow.mqh"

Program.mqh should be connected to MainWindow.mqh

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

No arquivo Program.mqh, é conveniente deixar apenas o arquivo principal para criar a interface gráfica do programa, onde são chamados todos os métodos da criação dos controles. 

A aplicação de teste da interface gráfica irá conter oito guias no total. As imagens abaixo mostram a posição dos controles. A primeira guia contém todos os tipos de botões (incluindo os grupos de botões) e a lista com a barra de rolagem vertical. O "Simple Button 3" possui dois modos. Se ativado, aparecerá o elemento barra de progresso simulando a execução de algum processo.  

 Fig. 3. Grupo de controles para a primeira guia da interface gráfica

Fig. 3. Grupo de controles para a primeira guia da interface gráfica


Quando o "Simple Button 3" estiver ativado, a barra de progresso é exibida na área da barra de estado (veja a imagem abaixo):

 Fig. 4. Controle barra de progresso

Fig. 4. Controle barra de progresso


A segunda, terceira e quarta guia irão conter as tabelas de diferentes tipos:

 Fig. 5. Grupo de controles da segunda guia da interface gráfica

Fig. 5. Grupo de controles da segunda guia da interface gráfica

 

 Fig. 6. Grupo de controles da terceira guia da interface gráfica

Fig. 6. Grupo de controles da terceira guia da interface gráfica

 

Fig. 7. Grupo de controles da quarta guia da interface gráfica 

Fig. 7. Grupo de controles da quarta guia da interface gráfica


A quinta guia contém o controle do gráfico de linha. Os métodos para trabalhar com ela são declarados e implementados na classe CProgram. O timer CProgram::OnTimerEvent() gera a série aleatória a cada 300 milissegundos:

 Fig. 8. Grupo de controles da quinta guia da interface gráfica

Fig. 8. Grupo de controles da quinta guia da interface gráfica


A sexta e sétima guia contêm a a lista hierárquica e o navegador de arquivos, bem como vários tipos de caixas de combinação, campos de entrada e caixas de seleção:

 Fig. 9. Grupo de controles da sexta guia da interface gráfica

Fig. 9. Grupo de controles da sexta guia da interface gráfica

 

Fig. 10. Grupo de controles da sétima guia da interface gráfica 

Fig. 10. Grupo de controles da sétima guia da interface gráfica


A oitava guia contém os seguintes controles: calendário, calendário suspenso, controle deslizante, controle deslizante duplo, separador e botão de seleção da paleta de cores:

 Fig. 11. Grupo de controles da oitava guia da interface gráfica

Fig. 11. Grupo de controles da oitava guia da interface gráfica


Se quiser que a janela da paleta de cores seja criada na janela do gráfico principal, deve-se indicar o índice zero no método de criação, tanto para o formulário quanto para os controles que estão vinculados neste formulário. Aqui, apenas um controle (paleta de cores) é vinculado ao formulário. A imagem abaixo mostra o resultado final:

 Fig. 12. Controle paleta de cores na janela principal do gráfico

Fig. 12. Controle paleta de cores na janela principal do gráfico


Como já foi mencionado, nós criamos uma outra aplicação (Expert) contendo a mesma interface gráfica:

 Fig. 13. Teste da aplicação do tipo Expert

Fig. 13. Teste da aplicação do tipo Expert


Ambos os tipos da aplicação (Expert e Indicador) foram implementados para as duas plataformas - MetaTrader 4 e MetaTrader 5. Todos os arquivos do teste estão anexados abaixo.

 

 


Conclusão

A biblioteca para a criação de interfaces gráficas no atual estágio de desenvolvimento se parece com o esquema abaixo.

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

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


Muitas correções e atualizações foram aplicadas nas solicitações dos usuários interessados. Se lhe faltar alguma coisa ou você detectar algum um erro relacionado a biblioteca ao desenvolver uma aplicação, por favor escreva um comentário no artigo ou me envie uma mensagem privada. Eu estarei contente em ajudá-lo. Eu já estou trabalhando na próxima versão da biblioteca (build 3). Ela terá muitos recursos adicionais que levará a biblioteca para um novo nível. 

Além das aplicações de teste descritas no artigo, os arquivos a seguir contêm as versões atualizadas dos EAs de teste e dos indicadores de todos os artigos anteriores da série.

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

Arquivos anexados |
Interfaces gráficas X: Atualizações para a Biblioteca Easy And Fast(Build 3) Interfaces gráficas X: Atualizações para a Biblioteca Easy And Fast(Build 3)
Apresentamos neste artigo a próxima versão da biblioteca Easy And Fast (build 3). Foi corrigido certas falhas e adicionado novos recursos. Para maiores informações leia a continuação do artigo.
Interfaces Gráficas IX: Os Controles Barra de Progresso e Gráfico de Linha (Capítulo 2) Interfaces Gráficas IX: Os Controles Barra de Progresso e Gráfico de Linha (Capítulo 2)
O segundo capítulo da parte nove é dedicado aos controles barra de progresso e gráfico de linha. Como sempre, teremos exemplos detalhados para revelar como esses controles podem ser utilizados nas aplicações MQL personalizadas.
ZigZag universal ZigZag universal
O Zigzag é um dos indicadores mais populares entre os usuários MetaTrader 5. No artigo, foram analisadas as possibilidades de criar diferentes variações do ZigZag. Como resultado, obtivemos um indicador universal com amplas possibilidades para estender recursos de fácil uso durante o desenvolvimento de Expert Advisor e outros indicadores.
Sistema de negociação 'Turtle Soup' e sua modificação 'Turtle Soup Plus One' Sistema de negociação 'Turtle Soup' e sua modificação 'Turtle Soup Plus One'
No artigo regras de estratégias de negociação formalizadas e programadas Turtle Soup e Turtle Soup Plus One a partir do livro de Linda Raschke e Laurence Connors Street Smarts: High Probability Short-Term Trading Strategies. As estratégias descritas no livro receberam uma ampla acolhida, no entanto é importante entender que os autores conceberam suas ideias com base no comportamento do mercado de há 15-20 anos.