English Русский 中文 Español Deutsch 日本語
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)

MetaTrader 5Exemplos | 9 novembro 2016, 13:29
1 324 0
Anatoli Kazharski
Anatoli Kazharski

Conteúdo


Introdução

O primeiro artigo Interfaces gráficas I: Preparação da Estrutura da Biblioteca (Capítulo 1) considera em detalhes a finalidade desta biblioteca. A lista completa dos links para os artigos da primeira parte se encontram 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.

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.

A partir desta versão, a biblioteca só será desenvolvida para a plataforma MetaTrader 5. Isto está relacionado com algumas diferenças fundamentais de arquitetura e limitações no MetaTrader 4. No entanto, se houver uma necessidade urgente de suporte da biblioteca para uma versão anterior a da plataforma, é possível emitir um pedido no serviço Freelance dirigindo-se ao autor ou qualquer outro desenvolvedor, dispostos e capazes de fazer o trabalho. 

 

Atualizações

1. Até agora, as aplicações em MQL nos artigos anteriores demonstraram como implementar uma interface gráfica na sub-janela do indicador. Naturalmente, esta abordagem seria suficiente para algumas aplicações simples. Mas também seria interessante ter a possibilidade de criar uma interface gráfica em uma sub-janela para um programa do tipo "Expert". Dessa forma, seria possível criar os painéis de negociação completamente funcionais e que estariam separados da janela principal do gráfico. Trabalhando neste modo será mais conveniente: o gráfico de preços e quaisquer dados importantes sobre o gráfico estaria sempre aberto e organizado pela interface gráfica da aplicação. A implementação desta ideia com a biblioteca Easy And Fast será descrita posteriormente.

A tarefa era fazer com que o modo "Expert na sub-janela" seja ativada pela inclusão do recurso com o indicador vazio (SubWindow.ex5) no arquivo principal da aplicação MQL. O espaço reservado é apenas uma sub-janela sem a parte de cálculos das séries. Mas já que não há atualmente nenhuma maneira de saber se o indicador está incluído como um recurso usando os meios MQL, adicione temporariamente a diretiva com o identificador da constante EXPERT_IN_SUBWINDOW ao arquivo Defines.mqh. Ela é necessária para eliminar o erro do registro que ocorre quando se tenta obter o identificador de um indicador que não está disponível no diretório especificado.

O valor padrão é false, significando que o modo está desativado e a interface gráfica será criada na janela do gráfico principal (veja o código abaixo).

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
//--- Modo "Expert na sub-janela"
#define EXPERT_IN_SUBWINDOW false
...

Se for necessário criar a interface gráfica em uma sub-janela, defina o valor para true e inclua o recurso com o indicador vazio no arquivo principal da aplicação MQL

//+------------------------------------------------------------------+
//|                                                TestLibrary01.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2016, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//--- Incluindo o indicador no modo "Expert na sub-janela"
#resource \\Indicators\\SubWindow.ex5
...

Em seguida, considere o indicador SubWindow.ex5 e como ele está ligado ao EA. O código completo do indicador SubWindow.ex5 foi fornecido abaixo. As propriedades do programa especificam que o indicador é uma sub-janela do gráfico, o número de buffers e séries é zero, escala vertical máxima e o mínima também são zero. 

O indicador e o expert trocarão mensagens um com o outro. Acontece que o indicador "não sabe" quais os modos para traçar a interface gráfica que foi selecionada no expert. É preciso ser passado uma mensagem, se o desenvolvedor decidiu fazer com que a sub-janela tenha uma altura fixa, bem como os valores da altura em pixels. Será necessário de outro identificador do evento ON_SUBWINDOW_CHANGE_HEIGHT para criar a mensagem. Este identificador também deve ser colocado no arquivo Defines.mqh, para que ele esteja disponível nas aplicações que usam esta biblioteca para a criação das interfaces gráficas. 

Para compreender quando o EA necessita gerar o evento para alterar a altura da subjanela: após uma inicialização bem sucedida do indicador, durante a primeira chamada automática da função ::OnCalculate() (quando o argumento prev_calculated é zero), será passado uma mensagem para o EA. Para determinar de forma inequívoca de que a mensagem foi proveniente do indicador SubWindow.ex5, além do identificador de evento ON_SUBWINDOW_CHANGE_HEIGHT, o nome do programa será enviado como um parâmetro string (sparam). A mensagem será monitorada no manipulador da classe CWindow. Se todas as condições forem atendidas lá, o indicador enviará uma resposta com o mesmo identificador (1) (ON_SUBWINDOW_CHANGE_HEIGHT), (2) o valor da altura como parâmetro long do evento (lparam) e (3) o nome do expert. Uma vez que esta mensagem é recebida, ela será processada na função ::OnChartEvent(). Após verificar o nome, a altura da sub-janela é definida de acordo com o valor passado.  

//+------------------------------------------------------------------+
//|                                                    SubWindow.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2016, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property indicator_separate_window
#property indicator_plots   0
#property indicator_buffers 0
#property indicator_minimum 0.0
#property indicator_maximum 0.0
//--- Nome do programa
#define PROGRAM_NAME ::MQLInfoString(MQL_PROGRAM_NAME)
//--- Identificador do evento para alterar a altura da sub-janela do expert
#define ON_SUBWINDOW_CHANGE_HEIGHT (25)
//+------------------------------------------------------------------+
//| Função de inicialização do indicador personalizado               |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//--- Nome abreviado do indicador
   ::IndicatorSetString(INDICATOR_SHORTNAME,PROGRAM_NAME);
//--- Inicialização bem sucedida
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Desinicialização                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Função de iteração do indicador personalizado                    |
//+------------------------------------------------------------------+
int OnCalculate(const int    rates_total,
                const int    prev_calculated,
                const int    begin,
                const double &price[])
  {
//--- Se a inicialização teve êxito
   if(prev_calculated<1)
      //--- Envia a mensagem para o expert para obter o tamanho da sub-janela a partir dele
      ::EventChartCustom(0,ON_SUBWINDOW_CHANGE_HEIGHT,0,0.0,PROGRAM_NAME);
//---
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Função ChartEvent                                                |
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Manipulação do evento para alterar a altura da sub-janela do expert
   if(id==CHARTEVENT_CUSTOM+ON_SUBWINDOW_CHANGE_HEIGHT)
     {
      //--- Aceita as mensagens apenas do nome do expert
      if(sparam==PROGRAM_NAME)
         return;
      //--- Alterar a altura da sub-janela
      ::IndicatorSetInteger(INDICATOR_HEIGHT,(int)lparam);
     }
  }
//+------------------------------------------------------------------+

Além disso no manipulador de eventos da classe CWindow deve-se adicionar um bloco de código como é exibido abaixo. Quando chega um evento com o identificador ON_SUBWINDOW_CHANGE_HEIGHT, será necessário realizar várias verificações. O programa deixa o método se:

  • a mensagem foi enviada do expert para o indicador;
  • este programa não é um expert;
  • o modo da altura fixa da sub-janela do expert não foi definida. 
//+------------------------------------------------------------------+
//| Manipulador de eventos do gráfico                                |
//+------------------------------------------------------------------+
void CWindow::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
...
//--- Manipulação do evento para alterar a altura da sub-janela do expert
   if(id==CHARTEVENT_CUSTOM+ON_SUBWINDOW_CHANGE_HEIGHT)
     {
      //--- Sai, se a mensagem era do expert
      if(sparam==PROGRAM_NAME)
         return;
      //--- Sai, se este programa não é do expert
      if(CElement::ProgramType()!=PROGRAM_EXPERT)
         return;
      //--- Sai, se o modo da altura fixa da sub-janela não está definida
      if(!m_height_subwindow_mode)
         return;
      //--- Calcula e altera a altura da sub-janela
      m_subwindow_height=(m_is_minimized)? m_caption_height+3 : m_bg_full_height+3;
      ChangeSubwindowHeight(m_subwindow_height);
      return;
     }
  }

Se todas as verificações são passados, então a altura para a sub-janela é calculada levando em consideração o estado atual da janela (minimizada/maximizada). Após isso, o método CWindow::ChangeSubwindowHeight() é chamado, que também sofreu uma ligeira modificação (veja o código abaixo). A sua finalidade é que se o tipo do programa for um «Expert», então, uma mensagem é gerada pelo indicador SubWindow.ex5

//+------------------------------------------------------------------+
//| Altera a altura da sub-janela do indicador                       |
//+------------------------------------------------------------------+
void CWindow::ChangeSubwindowHeight(const int height)
  {
//--- Se a interface gráfica não está na sub-janela ou o programa é do tipo "Script"
   if(CElement::m_subwin<=0 || CElement::m_program_type==PROGRAM_SCRIPT)
      return;
//--- Se a altura da sub-janela precisar ser alterada
   if(height>0)
     {
      //--- Se o programa é do tipo indicador
      if(CElement::m_program_type==PROGRAM_INDICATOR)
        {
         if(!::IndicatorSetInteger(INDICATOR_HEIGHT,height))
            ::Print(__FUNCTION__," > Falha ao alterar a altura do indicador! Código do erro: ",::GetLastError());
        }
      //--- Se o programa é do tipo "Expert"
      else
        {
         //--- Envia a mensagem para o indicador SubWindow.ex5, informando que o tamanho da janela deve ser alterado
         ::EventChartCustom(m_chart_id,ON_SUBWINDOW_CHANGE_HEIGHT,(long)height,0,PROGRAM_NAME);
        }
     }
  }

O motor da biblioteca (classe CWndEvents) também exige certos complementos a fim de determinar, verificar e ajustar o número da sub-janela, onde a interface gráfica da aplicação MQL do tipo "Expert" deve ser colocada. O código para o modo "Expert na sub-janela" deve ser adicionado ao método CWndEvents::DetermineSubwindow(). O código a seguir mostra a versão resumida deste método. A entrada para o bloco é feita na condição de que o tipo do programa seja um "Expert". Em seguida, vem a verificação se o modo "Expert na sub-janela" está ativada. Se ativado, obtém o identificador do indicador SubWindow.ex5. E se não houver problemas com isso, então, é determinado primeiro o número atual de sub-janelas na janela do gráfico. O valor obtido define o número de sub-janelas do indicador SubWindow.ex5, que é definido pela função ::ChartIndicatorAdd(). Então, se não houver erros ao definir a sub-janela, ele armazena (1) o número de sub-janelas do expert, (2) o número atual de sub-janelas e (3) o nome abreviado do indicador SubWindow.ex5.  

//+------------------------------------------------------------------+
//| Classe para a manipulação de eventos                             |
//+------------------------------------------------------------------+
class CWndEvents : public CWndContainer
  {
protected:
   //--- Manipula a sub-janela do expert
   int               m_subwindow_handle;
   //--- Nome da sub-janela do expert
   string            m_subwindow_shortname;
   //--- O número de sub-janelas no gráfico depois de definir a sub-janela do expert
   int               m_subwindows_total;
  };
//+------------------------------------------------------------------+
//| Identificando o número da sub-janela                             |
//+------------------------------------------------------------------+
void CWndEvents::DetermineSubwindow(void)
  {
//--- Sai, se o tipo do programa é um "Script"
//--- Reseta o último erro

//--- Se o tipo do programa é um "Expert"
   if(PROGRAM_TYPE==PROGRAM_EXPERT)
     {
      //--- Sai, se é preciso ter a interface gráfica do expert na janela principal
      if(!EXPERT_IN_SUBWINDOW)
         return;
      //--- Obtém o identificador do indicador vazio (sub-janela vazia)
      m_subwindow_handle=iCustom(Symbol(),Period(),"::Indicators\\SubWindow.ex5");
      //--- Se não existe tal indicador, relata o erro ao registro
      if(m_subwindow_handle==INVALID_HANDLE)
         ::Print(__FUNCTION__," > Erro em obter o manipulador do indicador no diretório ::Indicators\\SubWindow.ex5 !");
      //--- Se o identificador é obtido, então o indicador existe, inclua-o na aplicação como um recurso,
      //    e isso significa que a interface gráfica da aplicação deve ser colocada na sub-janela.
      else
        {
         //--- Obtém o número de sub-janelas no gráfico
         int subwindows_total=(int)::ChartGetInteger(m_chart_id,CHART_WINDOWS_TOTAL);
         //--- Define a sub-janela para a interface gráfica do expert
         if(::ChartIndicatorAdd(m_chart_id,subwindows_total,m_subwindow_handle))
           {
            //--- Armazena o número da sub-janela e o número atual de subjanelas no gráfico
            m_subwin           =subwindows_total;
            m_subwindows_total =subwindows_total+1;
            //--- Obtém e armazena o nome abreviado da sub-janela do expert
            m_subwindow_shortname=::ChartIndicatorName(m_chart_id,m_subwin,0);
           }
         //--- Se a sub-janla não foi definida
         else
            ::Print(__FUNCTION__," > Erro ao definir a sub-janela do expert! Código do erro: ",::GetLastError());
        }
      //---
      return;
     }
//--- Identifica a janela do indicador
//--- Sai, se não conseguiu identificar o número
//--- Se esta não é a janela principal do gráfico
...
  }

Também é necessário ter certeza de que o número da sub-janela do expert seja ajustada para o funcionamento correto da interface gráfica quando se adiciona e remover outros indicadores nas sub-janelas do gráfico. Além disso, vamos fazê-lo de modo que se o usuário excluir a sub-janela do expert, o expert é removido também, deixando uma mensagem de registro na guia "Experts" da janela "caixa de ferramentas", indicando a razão da remoção do gráfico. O método CWndEvents::CheckExpertSubwindowNumber() é aplicado para esta finalidade. A admissão a este método é realizada sob a condição de que o programa deve ser do tipo "Expert". Se a verificação foi satisfeita, será calculado o número de sub-janelas na janela do gráfico. Se acontecer do número de sub-janelas não serem alteradas, o programa sairá do método. 

Em seguida, é necessário encontrar a sub-janela do expert em um loop, e se ela existe - verifica se o número da sua sub-janela foi alterada. O número da sub-janela poderia ter sido alterada devido à adição ou remoção de um indicador que também foi localizado em uma sub-janela separada. Se o número da sub-janela tiver sido alterada, é necessário armazenar seu número e atualizar o valor em todos os controles da janela principal

Se a sub-janela não foi encontrada, pode haver apenas uma razão: ela foi excluída. Nesse caso, o expert também será removido do gráfico

class CWndEvents : public CWndContainer
  {
private:
   //--- Verifica e atualiza o número de sub-janelas do expert
   void              CheckExpertSubwindowNumber(void);
  };
//+------------------------------------------------------------------+
//|Verifica e atualiza o número de sub-janelas do expert             |
//+------------------------------------------------------------------+
void CWndEvents::CheckExpertSubwindowNumber(void)
  {
//--- Sai, se isso não for um expert
   if(PROGRAM_TYPE!=PROGRAM_EXPERT)
      return;
//--- Obtém o número de sub-janelas no gráfico
   int subwindows_total=(int)::ChartGetInteger(m_chart_id,CHART_WINDOWS_TOTAL);
//--- Sai, se o número de sub-janelas e o número de indicadores não foram alterados
   if(subwindows_total==m_subwindows_total)
      return;
//--- Armazena o número atual de sub-janelas
   m_subwindows_total=subwindows_total;
//--- Para verificar se a sub-janela do expert está presente
   bool is_subwindow=false;
//--- Encontra o expert da sub-janela
   for(int sw=0; sw<subwindows_total; sw++)
     {
      //--- Parar o ciclo, se a sub-janela do expert foi encontrada
      if(is_subwindow)
         break;
      //--- O número de indicadores nesta janela/sub-janela
      int indicators_total=::ChartIndicatorsTotal(m_chart_id,sw);
      //--- Iterar sobre todos os indicadores na janela 
      for(int i=0; i<indicators_total; i++)
        {
         //--- Obtém o nome abreviado do indicador
         string indicator_name=::ChartIndicatorName(m_chart_id,sw,i);
         //--- Se este não é a sub-janela do expert, vá para a próxima
         if(indicator_name!=m_subwindow_shortname)
            continue;
         //--- Marca que o expert possui uma sub-janela
         is_subwindow=true;
         //--- Se o número o número de sub-janelas foi alterado, então 
         //    é necessário armazenar o novo número em todos os controles do formulário principal
         if(sw!=m_subwin)
           {
            //--- Armazena o número da sub-janela
            m_subwin=sw;
            //--- Guarde-o em todos os controles do formulário principal da interface
            int elements_total=CWndContainer::ElementsTotal(0);
            for(int e=0; e<elements_total; e++)
               m_wnd[0].m_elements[e].SubwindowNumber(m_subwin);
           }
         //---
         break;
        }
     }
//--- Se a sub-janela do expert não foi encontrada, remova o expert
   if(!is_subwindow)
     {
      ::Print(__FUNCTION__," > Removendo a sub-janela do expert causa a remoção do mesmo!");
      //--- Removendo o EA a partir do gráfico
      ::ExpertRemove();
     }
  }

 

2. A versão anterior da biblioteca introduziu a possibilidade de alternar a alteração automática da largura do formulário. Vamos adicionar um recurso semelhante para a altura. O identificador ON_WINDOW_CHANGE_SIZE para o evento de alterar o tamanho do formulário não é adequado para resolver esta tarefa, já que a alteração da largura e da altura será tratada com eventos separados. Portanto, o arquivo Defines.mqh terá dois identificadores separados, em vez do ON_WINDOW_CHANGE_SIZE, como é exibido no código abaixo. A substituição correspondente do identificador tem sido realizada em outros arquivos da biblioteca.  

#define ON_WINDOW_CHANGE_XSIZE     (3)  // Altera o tamanho da janela ao longo do eixo X
#define ON_WINDOW_CHANGE_YSIZE     (4)  // Altera o tamanho da janela ao longo do eixo y

O método CWindow::ChangeWindowHeight() foi adicionado para alterar a altura do formulário. Ao chamar o método após a alteração do tamanho do formulário, a mensagem sobre a ação realizada é gerada no final. 

//+------------------------------------------------------------------+
//| Classe para criar um formulário de controles                     |
//+------------------------------------------------------------------+
class CWindow : public CElement
  {
public:
   //--- Gerenciamento do tamanho
   void              ChangeWindowHeight(const int height);
  };
//+------------------------------------------------------------------+
//| Altera a altura da janela                                        |
//+------------------------------------------------------------------+
void CWindow::ChangeWindowHeight(const int height)
  {
//--- Se a altura não mudar, sai
   if(height==m_bg.YSize())
      return;
//--- Sai se a janela é minimizada
   if(m_is_minimized)
      return;
//--- Atualiza a altura do fundo
   CElement::YSize(height);
   m_bg.YSize(height);
   m_bg.Y_Size(height);
   m_bg_full_height=height;
//--- Uma mensagem de que os tamanhos da janela foram alterados
   ::EventChartCustom(m_chart_id,ON_WINDOW_CHANGE_YSIZE,(long)CElement::Id(),0,"");
  }

Para a altura do formulário ser alterada automaticamente, o usuário desenvolvedor da aplicação MQL deve definir o modo correspondente, utilizando o método CElement::AutoYResizeMode(): 

//+------------------------------------------------------------------+
//| Classe base do controle                                          |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- Modo de redimensionamento automático do controle
   bool              m_auto_yresize_mode;
   //---
public:
   //--- (1) Modo da alteração automática do controle de altura
   bool              AutoYResizeMode(void)                     const { return(m_auto_yresize_mode);          }
   void              AutoYResizeMode(const bool flag)                { m_auto_yresize_mode=flag;             }
  };

Agora, se os modos de redimensionamento automático do formulário está habilitado, então, se o tamanho da janela do gráfico ser alterada, o manipulador de eventos do formulário ajusta os tamanhos do formulário com base no evento CHARTEVENT_CHART_CHANGE. Isto irá funcionar tanto na sub-janela do indicador quanto na janela do gráfico. É possível habilitar qualquer um dos modos, ou ambos ao mesmo tempo. 

//--- O evento de alteração das propriedades do gráfico
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- Se o botão é solto
      if(m_clamping_area_mouse==NOT_PRESSED)
        {
         //--- Obter o tamanho da janela do gráfico
         SetWindowProperties();
         //--- Ajuste das coordenadas
         UpdateWindowXY(m_x,m_y);
        }
      //--- Altera a largura se o modo está habilitado
      if(CElement::AutoXResizeMode())
         ChangeWindowWidth(m_chart.WidthInPixels()-2);
      //--- Altera a altura, se o modo está habilitado
      if(CElement::AutoYResizeMode())
         ChangeWindowHeight(m_chart.HeightInPixels(m_subwin)-3);
      //---
      return;
     }

 

3. O modo de alteração automática da altura também se aplica a todos os controles da biblioteca. Mas, na versão atual, isso irá funcionar apenas nos controles relacionados abaixo:

  • CTabs – guias simples.
  • CIconTabs – guias com imagens.
  • CCanvasTable – tabela renderizada.
  • CLineGraph – gráfico de linha.

Semelhante à adição anterior do método virtual CElement::ChangeWidthByRightWindowSide() para alterar a largura do controle para a classe CElement, vamos adicionar o método para a alteração da altura automática. Além disso, nós vamos criar os métodos para definir o deslocamento a partir da borda inferior do formulário, semelhante aos deslocamentos adicionados anteriormente da borda direita do formulário ao mudar a sua largura. 

class CElement
  {
protected:
   //--- Deslocamento da margem direita/inferior do formulário no modo de controle automático da alteração da largura/altura
   int               m_auto_xresize_right_offset;
   int               m_auto_yresize_bottom_offset;
   //---
public:
   //--- Obtém/define o deslocamento a partir da borda inferior do formulário
   int               AutoYResizeBottomOffset(void)             const { return(m_auto_yresize_bottom_offset); }
   void              AutoYResizeBottomOffset(const int offset)       { m_auto_yresize_bottom_offset=offset;  }
   //---
public:
   //--- Altera a altura na borda inferior da janela
   virtual void      ChangeHeightByBottomWindowSide(void) {}
  };

Cada controle terá a sua própria implementação do método ChangeWidthByRightWindowSide(), que considera as características únicas e modos. Como um exemplo, o código abaixo mostra o método CCanvasTable na classe: 

//+------------------------------------------------------------------+
//| Altera a altura da borda inferior da janela                      |
//+------------------------------------------------------------------+
void CCanvasTable::ChangeHeightByBottomWindowSide(void)
  {
//--- Sai, se o modo de ancoragem para a parte inferior do formulário está habilitada  
   if(m_anchor_bottom_window_side)
     return;
//--- Coordenadas
   int y=0;
//--- Tamanho
   int x_size=(m_auto_xresize_mode)? m_wnd.X2()-m_area.X()-m_auto_xresize_right_offset : m_x_size;
   int y_size=m_wnd.Y2()-m_area.Y()-m_auto_yresize_bottom_offset;
//--- Sai se o tamanho é menor do que o especificado
   if(y_size<60)
     return;
//--- Define o novo tamanho do fundo da tabela
   ChangeMainSize(x_size,y_size);
//--- Calcula o tamanho da tabela
   CalculateTableSize();
//--- Verifica a presença de uma barra de rolagem
   bool is_scrollh=!(m_table_visible_x_size>=m_table_x_size);
   bool is_scrollv=!(m_table_visible_y_size>=m_table_y_size);
//--- Deslocamento relativo à presença da barra de rolagem
   int offset=(is_scrollh || (!is_scrollh && !is_scrollv))? 0 : 2;
//--- Calcula e define a nova coordenada para a barra de rolagem horizontal
   y=m_area.Y2()-m_scrollh.ScrollWidth();
   m_scrollh.YDistance(y);
//--- Inicializa a barra de rolagem horizontal para o novo tamanho
   m_scrollh.Reinit(m_table_x_size,m_table_visible_x_size);
//--- Calcula e altera a altura da barra de rolagem vertical
   m_scrollv.Reinit(m_table_y_size,m_table_visible_y_size-offset);
   m_scrollv.ChangeYSize((is_scrollh)? m_table_visible_y_size+2 : m_table_visible_y_size);
//--- Se a barra de rolagem vertical não é necessária
   if(!is_scrollv)
     {
      //--- Ocultar a barra de rolagem vertical
      m_scrollv.Hide();
      //--- Altera a largura da barra de rolagem horizontal
      m_scrollh.ChangeXSize(m_area.XSize());
     }
   else
     {
      //--- Mostra a barra de rolagem vertical
      if(CElement::IsVisible())
         m_scrollv.Show();
      //--- Calcula e altera a largura da barra de rolagem horizontal
      m_scrollh.ChangeXSize(m_area.XSize()-m_scrollv.ScrollWidth()+1);
     }
//--- Gerencia a visibilidade da barra de rolagem horizontal
   if(CElement::IsVisible())
     {
      if(!is_scrollh) m_scrollh.Hide();
      else m_scrollh.Show();
     }
//--- Redimensiona a tabela
   ChangeTableSize(m_table_x_size,m_table_y_size,m_table_visible_x_size,m_table_visible_y_size-offset);
/ --- Desenhar a tabela
   DrawTable();
//--- Atualiza a posição dos objetos
   Moving(m_wnd.X(),m_wnd.Y());
  }

Para que tudo isso funcione, algumas adições e mudanças devem ser feitas para na classe CWndEvents. Já que os eventos de redimensionamento (largura e altura) são gerados agora com os identificadores únicos, dois métodos separados são necessários para o seu tratamento. 

//+------------------------------------------------------------------+
//| Classe para a manipulação de eventos                             |
//+------------------------------------------------------------------+
class CWndEvents : public CWndContainer
  {
private:
   //--- Manipula a alteração do tamanho da janela
   bool              OnWindowChangeXSize(void);
   bool              OnWindowChangeYSize(void);
  };
//+------------------------------------------------------------------+
//| Evento ON_WINDOW_CHANGE_XSIZE                                    |
//+------------------------------------------------------------------+
bool CWndEvents::OnWindowChangeXSize(void)
  {
//--- Se o sinal for para "redimensionar os controles"
   if(m_id!=CHARTEVENT_CUSTOM+ON_WINDOW_CHANGE_XSIZE)
      return(false);
//--- Índice da janela ativa
   int awi=m_active_window_index;
//--- Se a janela de identificadores correspondem entre si
   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++)
     {
      //--- Se for uma janela, vai para o próximo
      if(m_wnd[awi].m_elements[e].ClassName()=="CWindow")
         continue;
      //--- Se o modo estiver habilitado, ajusta a largura
      if(m_wnd[awi].m_elements[e].AutoXResizeMode())
         m_wnd[awi].m_elements[e].ChangeWidthByRightWindowSide();
     }
//---
   return(true);
  }
//+------------------------------------------------------------------+
//| Evento ON_WINDOW_CHANGE_YSIZE                                    |
//+------------------------------------------------------------------+
bool CWndEvents::OnWindowChangeYSize(void)
  {
//--- Se o sinal for para "redimensionar os controles"
   if(m_id!=CHARTEVENT_CUSTOM+ON_WINDOW_CHANGE_YSIZE)
      return(false);
//--- Índice da janela ativa
   int awi=m_active_window_index;
//--- Se a janela de identificadores correspondem entre si
   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++)
     {
      //--- Se for uma janela, vai para o próximo
      if(m_wnd[awi].m_elements[e].ClassName()=="CWindow")
         continue;
      //--- Se o modo estiver habilitado, ajusta a altura
      if(m_wnd[awi].m_elements[e].AutoYResizeMode())
         m_wnd[awi].m_elements[e].ChangeHeightByBottomWindowSide();
     }
//---
   return(true);
  }

Os métodos CWndEvents::OnWindowChangeXSize() e CWndEvents::OnWindowChangeYSize() são chamados no método comum CWndEvents::ChartEventCustom() para lidar com os eventos personalizados. O código a seguir mostra a versão resumida deste método. 

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

//--- Se o sinal for para redimensionar os controles ao longo do eixo X
   if(OnWindowChangeXSize())
      return;
//--- Se o sinal for para redimensionar os controles ao longo do eixo Y
   if(OnWindowChangeYSize())
      return;

//--- Se o sinal é para ocultar os menus de contexto abaixo do elemento inicial
//--- Se o sinal for para esconder todos os menus de contexto

//--- Se o sinal é para abrir uma janela de diálogo
//--- Se o sinal é para fechar uma janela de diálogo
//--- Se o sinal estiver é para resetar as cores de todos os elementos na formulário especificado
//--- Se o sinal for para resetar as prioridades do clique do botão esquerdo do mouse
//--- Se o sinal for para restaurar as prioridades do clique do botão esquerdo do mouse
  }

Agora, ao redimensionar a janela do gráfico, se o modo de redimensionamento do formulário e os controles especificados em que ele está habilitado, eles também serão automaticamente redimensionados. 

As imagens abaixo mostram um exemplo de uma interface gráfica em um aplicativo MQL, que foi criado na janela do gráfico principal. Para a janela do aplicativo (CWindow), os modos da largura e altura automática ajustam a altura da janela do gráfico. Para os controles «menu principal» (CMenuBar) e a «barra de estado» (CStatusBar), é definido o modo da largura automática e o ajuste de altura na janela da aplicação MQL. Para os controles «Guias» (CTabs) e a «tabela renderizada» (CCanvasTable), é definido o modo da largura automática e o ajuste de altura do tamanho do formulário e especificado os deslocamentos a partir da borda inferior da aplicação MQL.

Fig. 1. Tamanho mínimo da janela do terminal. Interface gráfica de uma aplicação MQL com os modos de redimensionamento automático ativado. 

Fig. 1. Tamanho mínimo da janela do terminal. Interface gráfica de uma aplicação MQL com os modos de redimensionamento automático ativado.


Se o tamanho da janela do terminal foi alterado, quando os modos acima mencionados são habilitados, a interface gráfica da aplicação MQL também será redimensionada.

Fig. 2. Quando os tamanhos da janela do terminal forem alterados, a interface gráfica da aplicação MQL também será redimensionada. 

Fig. 2. Quando os tamanhos da janela do terminal forem alterados, a interface gráfica da aplicação MQL também será redimensionada.


4. Muitas vezes, quando a concepção da interface gráfica em que os tamanhos dos formulários podem se alterar, pode ser necessário que controles sejam posicionados na parte direita ou na parte inferior da janela da aplicação. Anteriormente, havia uma opção para especificar de forma simples as coordenadas para o controle, relativo ao ponto superior esquerdo do formulário que ele está ligado. Agora, existem quatro opções para posicionar o controle em relação ao formulário:

  • Canto superior esquerdo.
  • Canto superior direito.
  • Canto inferior direito.
  • Canto inferior esquerdo.

Para implementar esta ideia, vamos adicionar dois métodos para a classe base de controles (CElement) para configurar/obter os modos de posicionamento do controle na direita e inferior ao formulário: 

class CElement
  {
protected:
   //--- Os pontos de ancoragem do controle a direita e inferior a janela
   bool              m_anchor_right_window_side;
   bool              m_anchor_bottom_window_side;
   //---
public:
   //--- Modo (obter/definir) do ponto de ancoragem do controle para a borda (1) direita e (2) inferior da janela
   bool              AnchorRightWindowSide(void)               const { return(m_anchor_right_window_side);   }
   void              AnchorRightWindowSide(const bool flag)          { m_anchor_right_window_side=flag;      }
   bool              AnchorBottomWindowSide(void)              const { return(m_anchor_bottom_window_side);  }
   void              AnchorBottomWindowSide(const bool flag)         { m_anchor_bottom_window_side=flag;     }
  };

Para que tudo funcione de acordo com estes modos, as mudanças foram feitas para todas as classes dos controles da biblioteca. Como exemplo, segue o código do método para a criação de um rótulo de texto para o controle «caixa de seleção» (CCheckBox). Preste atenção nas linhas que calculam as coordenadas e os deslocamentos para o objeto gráfico. 

//+------------------------------------------------------------------+
//| Cria o rótulo de texto da caixa de seleção                       |
//+------------------------------------------------------------------+
bool CCheckBox::CreateLabel(void)
  {
//--- Elaborando o nome do objeto
   string name=CElement::ProgramName()+"_checkbox_lable_"+(string)CElement::Id();
//--- Coordenadas
   int x =(m_anchor_right_window_side)? m_x-m_label_x_gap : m_x+m_label_x_gap;
   int y =(m_anchor_bottom_window_side)? m_y-m_label_y_gap : m_y+m_label_y_gap;
//--- Cor do texto de acordo com o estado
   color label_color=(m_check_button_state) ? m_label_color : m_label_color_off;
//--- Define o objeto
   if(!m_label.Create(m_chart_id,name,m_subwin,x,y))
      return(false);
//--- Define as propriedades
   m_label.Description(m_label_text);
   m_label.Font(FONT);
   m_label.FontSize(FONT_SIZE);
   m_label.Color(label_color);
   m_label.Corner(m_corner);
   m_label.Anchor(m_anchor);
   m_label.Selectable(false);
   m_label.Z_Order(m_zorder);
   m_label.Tooltip("\n");
//--- Margens da borda
   m_label.XGap((m_anchor_right_window_side)? x : x-m_wnd.X());
   m_label.YGap((m_anchor_bottom_window_side)? y : y-m_wnd.Y());
//--- Inicialização do array de gradiente
   CElement::InitColorArray(label_color,m_label_color_hover,m_label_color_array);
//--- Armazena o ponteiro de objeto
   CElement::AddToArray(m_label);
   return(true);
  }

Os métodos Moving() de todos os controles na biblioteca consideram agora os modos de posicionamento do controle. Como um exemplo, o código abaixo mostra o método CCheckBox::Moving(): 

//+------------------------------------------------------------------+
//| Deslocamento dos controles                                       |
//+------------------------------------------------------------------+
void CCheckBox::Moving(const int x,const int y)
  {
//--- Sai se o elemento está oculto
   if(!CElement::IsVisible())
      return;
//--- Se está ancorado à direita
   if(m_anchor_right_window_side)
     {
      //--- Armazena as coordenadas nos campos do elemento
      CElement::X(m_wnd.X2()-XGap());
      //--- Armazena as coordenadas nos campos dos objetos
      m_area.X(m_wnd.X2()-m_area.XGap());
      m_check.X(m_wnd.X2()-m_check.XGap());
      m_label.X(m_wnd.X2()-m_label.XGap());
     }
   else
     {
      //--- Armazena as coordenadas nos campos dos objetos
      CElement::X(x+XGap());
      //--- Armazena as coordenadas nos campos dos objetos
      m_area.X(x+m_area.XGap());
      m_check.X(x+m_check.XGap());
      m_label.X(x+m_label.XGap());
     }
//--- Se está ancorado no canto inferior
   if(m_anchor_bottom_window_side)
     {
      //--- Armazena as coordenadas nos campos do elemento
      CElement::Y(m_wnd.Y2()-YGap());
      //--- Armazena as coordenadas nos campos dos objetos
      m_area.Y(m_wnd.Y2()-m_area.YGap());
      m_check.Y(m_wnd.Y2()-m_check.YGap());
      m_label.Y(m_wnd.Y2()-m_label.YGap());
     }
   else
     {
      //--- Armazena as coordenadas nos campos dos objetos
      CElement::Y(y+YGap());
      //--- Armazena as coordenadas nos campos dos objetos
      m_area.Y(y+m_area.YGap());
      m_check.Y(y+m_check.YGap());
      m_label.Y(y+m_label.YGap());
     }
//--- Atualizando as coordenadas dos objetos gráficos
   m_area.X_Distance(m_area.X());
   m_area.Y_Distance(m_area.Y());
   m_check.X_Distance(m_check.X());
   m_check.Y_Distance(m_check.Y());
   m_label.X_Distance(m_label.X());
   m_label.Y_Distance(m_label.Y());
  }

Para uma maior clareza, a figura abaixo mostra esquematicamente todas as combinações possíveis dos modos de posicionamento e redimensionamento automático dos controles. Ele é um exemplo abstrato, na qual o formulário (ver a nona coluna «Result») é representado por um retângulo branco com um quadro preto em negrito e o tamanho de 400 x 400 pixels, e o controle é representado por um retângulo cinzento com um tamanho de 200 x 200 pixels. As coordenadas relativas e o tamanho do controle também são exibidos para cada combinação. Os traços indicam os casos que não é obrigatório definir o tamanho (se o modo automático de redimensionamento está habilitado). 

Fig. 3. Tabela listando as diferentes opções em combinação com o posicionamento e o redimensionamento automático do controle. 

Fig. 3. Tabela listando as diferentes opções em combinação com o posicionamento e o redimensionamento automático do controle.


5. Foi adicionado o identificador de evento ON_CLICK_TAB para gerar o evento das alternâncias das guias nas classes CTabs e CIconTabs

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
...
#define ON_CLICK_TAB               (27) // Alternância das guias

Agora o evento com o identificador ON_CLICK_TAB pode ser monitorado no manipulador de uma classe personalizada, oferecendo mais possibilidades para gerir a aparência da interface gráfica. 


6. Foi adicionado a atualização forçada das coordenadas pelos métodos Show() de todos os controles. Como um exemplo, o código abaixo mostra o método da classe CSimpleButton (linha destacada em amarelo):

//+------------------------------------------------------------------+
//| Exibe o botão                                                    |
//+------------------------------------------------------------------+
void CSimpleButton::Show(void)
  {
//--- Retorna, se o elemento já for visível
   if(CElement::IsVisible())
      return;
//--- Faz com que todos os objetos sejam visíveis
   m_button.Timeframes(OBJ_ALL_PERIODS);
//--- Estado de visibilidade
   CElement::IsVisible(true);
//--- Atualiza a posição dos objetos
   Moving(m_wnd.X(),m_wnd.Y());
  }

Em certos casos, o uso ativo da interface gráfica da aplicação MQL pode acontecer de alguns de seus controles ficarem posicionados de forma incorreta. Agora, este problema foi resolvido.


7. Os métodos para obter os ponteiros para os botões foram adicionados a classe CWindow

//+------------------------------------------------------------------+
//| Classe para criar um formulário de controles                     |
//+------------------------------------------------------------------+
class CWindow : public CElement
  {
public:
   //--- Retorna os ponteiros para os botões do formulário
   CBmpLabel        *GetCloseButtonPointer(void)                             { return(::GetPointer(m_button_close));   }
   CBmpLabel        *GetRollUpButtonPointer(void)                            { return(::GetPointer(m_button_unroll));  }
   CBmpLabel        *GetUnrollButtonPointer(void)                            { return(::GetPointer(m_button_rollup));  }
   CBmpLabel        *GetTooltipButtonPointer(void)                           { return(::GetPointer(m_button_tooltip)); }
  };

Agora os usuários da biblioteca possuem a possibilidade de alterar as propriedades destes objetos gráficos em qualquer momento do ciclo de vida da aplicação MQL após a interface gráfica ter sido criada. Por exemplo, se antes as descrições para os botões estavam representados com valores predefinidos, agora o usuário pode definir de forma independente. Isso pode ser útil na criação de aplicações MQL em vários idiomas.


8. Foi corrigido a classe CTable. Adicionado a verificação para o método principal da criação de um controle (Veja o código abaixo). A parte visível não precisa ser mais comum. Agora, se o usuário comete um erro ao configurar as propriedades da tabela, os valores serão corrigidos automaticamente. 

//+------------------------------------------------------------------+
//| Cria tabela com a caixa de edição                                |
//+------------------------------------------------------------------+
bool CTable::CreateTable(const long chart_id,const int subwin,const int x,const int y)
  {
//--- Retorna se não há nenhum ponteiro do formulário
   if(!CElement::CheckWindowPointer(::CheckPointer(m_wnd)))
      return(false);
//--- A parte visível não precisa ser mais comum
   m_visible_rows_total    =(m_visible_rows_total>m_rows_total)? m_rows_total : m_visible_rows_total;
   m_visible_columns_total =(m_visible_columns_total>m_columns_total)? m_columns_total : m_visible_columns_total;
//--- 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_x_size   =(m_x_size<1 || m_auto_xresize_mode)? (m_anchor_right_window_side)? m_wnd.X2()-m_x+m_x_size-(m_wnd.X2()-m_x)+1-m_auto_xresize_right_offset : m_wnd.X2()-m_x-m_auto_xresize_right_offset : m_x_size;
   m_y_size   =m_row_y_size*m_visible_rows_total-(m_visible_rows_total-1)+2;
//--- Margens da borda
   CElement::XGap((m_anchor_right_window_side)? m_x : m_x-m_wnd.X());
   CElement::YGap((m_anchor_bottom_window_side)? m_y : m_y-m_wnd.Y());
//--- Cria a tabela
   if(!CreateArea())
      return(false);
   if(!CreateCells())
      return(false);
   if(!CreateScrollV())
      return(false);
   if(!CreateScrollH())
      return(false);
//--- Oculta o elemento se ele for uma janela de diálogo ou ela está minimizada
   if(m_wnd.WindowType()==W_DIALOG || m_wnd.IsMinimized())
      Hide();
//---
   return(true);
  }


 

Aplicação para Testar as Atualizações

Para o teste, vamos alterar ligeiramente a aplicação do artigo anterior para tornar possível demonstrar tudo o que foi apresentado neste artigo. Crie o EA em uma sub-janela do indicador "SubWindow". O tamanho da janela principal da interface gráfica irá ajustar automaticamente para o tamanho da sub-janela. A altura da sub-janela poderá ser alterada manualmente. Para fazer isso, o argumento "false" deve ser passado (destacado em verde no código abaixo) ao chamar o método CWindow::RollUpSubwindowMode()

O código a seguir também demonstra como obter acesso para gerenciar as propriedades dos botões na janela principal da interface gráfica da aplicação. Neste caso, o exemplo mostra a definição das dicas de ferramentas.

//+------------------------------------------------------------------+
//| Cria um formulário para os controles                             |
//+------------------------------------------------------------------+
bool CProgram::CreateWindow(const string caption_text)
  {
//--- Adiciona o ponteiro da janela para o array de janela
   CWndContainer::AddWindow(m_window);
//--- Coordenadas
   int x=1;
   int y=1;
//--- Propriedades
   m_window.Movable(false);
   m_window.UseRollButton();
   m_window.AutoXResizeMode(true);
   m_window.AutoYResizeMode(true);
   m_window.RollUpSubwindowMode(false,false);
//--- Criando o formulário
   if(!m_window.CreateWindow(m_chart_id,m_subwin,caption_text,x,y))
      return(false);
//--- Defina as dicas de ferramentas
   m_window.GetCloseButtonPointer().Tooltip("Close program");
   m_window.GetUnrollButtonPointer().Tooltip("Unroll");
   m_window.GetRollUpButtonPointer().Tooltip("Roll up");
   return(true);
  }

Na primeira guia, todos os controles serão ancorados ao lado direito do formulário (veja a imagem abaixo). Se a largura do formulário for alterada, eles permanecerão na mesma distância da sua margem direita. 

 Fig. 4. Os controles da primeira guia estão ancorados ao lado direito do formulário.

Fig. 4. Os controles da primeira guia estão ancorados ao lado direito do formulário.


Como exemplo, segue o código para criar o controle "Simple button" (CSimpleButton). A fim de ancorar o controle ao lado direito, é suficiente chamar o método AnchorRightWindowSide(), e passá-lo o valor true

//+------------------------------------------------------------------+
//| Cria um botão simples 1                                          |
//+------------------------------------------------------------------+
bool CProgram::CreateSimpleButton1(const int x_gap,const int y_gap,string button_text)
  {
//--- Armazena o ponteiro da janela
   m_simple_button1.WindowPointer(m_window);
//--- Anexa à primeira guia
   m_tabs.AddToElementsArray(0,m_simple_button1);
//--- Coordenadas
   int x=m_window.X()+x_gap;
   int y=m_window.Y()+y_gap;
//--- Define as propriedades antes da criação
   m_simple_button1.ButtonXSize(140);
   m_simple_button1.BackColor(C'255,140,140');
   m_simple_button1.BackColorHover(C'255,180,180');
   m_simple_button1.BackColorPressed(C'255,120,120');
   m_simple_button1.AnchorRightWindowSide(true);
//--- Cria um botão
   if(!m_simple_button1.CreateSimpleButton(m_chart_id,m_subwin,button_text,x,y))
      return(false);
//--- Adiciona o ponteiro do elemento para a base
   CWndContainer::AddToElementsArray(0,m_simple_button1);
   return(true);
  }

A segunda guia será atribuído apenas uma tabela renderizada (CCanvasTable), que irá ajustar-se aos tamanhos do formulário quando a largura e a altura da sub-janela se alterar.

 Fig. 5. Tabela renderizada que se ajusta conforme os tamanhos do formulário.

Fig. 5. Tabela renderizada que se ajusta conforme os tamanhos do formulário.


Para que tudo funcione como pretendido, é necessário usar os métodos AutoXResizeMode() e AutoYResizeMode() e permitir os modos para redimensionamento horizontal e vertical automática. Com os métodos AutoXResizeRightOffset() e AutoYResizeBottomOffset(), é possível ajustar os deslocamentos da bordas direita e inferior do controle para a extremidade inferior ou da direita do formulário. Nesse caso, o deslocamento da borda direita está definido para 1 pixel, e 25 pixels da parte inferior (Veja o código abaixo). 

//+------------------------------------------------------------------+
//| Cria uma tabela renderizada                                      |
//+------------------------------------------------------------------+
bool CProgram::CreateCanvasTable(const int x_gap,const int y_gap)
  {
#define COLUMNS3_TOTAL 15
#define ROWS3_TOTAL    30
//--- Armazena o ponteiro ao formulário
   m_canvas_table.WindowPointer(m_window);
//--- Anexa para a segunda guia
   m_tabs.AddToElementsArray(1,m_canvas_table);
//--- Coordenadas
   int x=m_window.X()+x_gap;
   int y=m_window.Y()+y_gap;
//--- Array de largura das colunas
   int width[COLUMNS3_TOTAL];
   ::ArrayInitialize(width,70);
   width[0]=100;
   width[1]=90;
//--- Array do alinhamento de texto em colunas
   ENUM_ALIGN_MODE align[COLUMNS3_TOTAL];
   ::ArrayInitialize(align,ALIGN_CENTER);
   align[0]=ALIGN_RIGHT;
   align[1]=ALIGN_RIGHT;
   align[2]=ALIGN_LEFT;
//--- Define as propriedades antes da criação
   m_canvas_table.XSize(400);
   m_canvas_table.YSize(200);
   m_canvas_table.TableSize(COLUMNS3_TOTAL,ROWS3_TOTAL);
   m_canvas_table.TextAlign(align);
   m_canvas_table.ColumnsWidth(width);
   m_canvas_table.GridColor(clrLightGray);
   m_canvas_table.AutoXResizeMode(true);
   m_canvas_table.AutoYResizeMode(true);
   m_canvas_table.AutoXResizeRightOffset(1);
   m_canvas_table.AutoYResizeBottomOffset(25);
//--- Preenche a tabela com os dados
   for(int c=0; c<COLUMNS3_TOTAL; c++)
      for(int r=0; r<ROWS3_TOTAL; r++)
         m_canvas_table.SetValue(c,r,string(c)+":"+string(r));
//--- Cria o controle
   if(!m_canvas_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- Adiciona o objeto ao array comum dos grupos de objetos
   CWndContainer::AddToElementsArray(0,m_canvas_table);
   return(true);
  }

O gráfico de linha (CLineGraph) será colocado sobre a terceira guia, com o ajuste automático dos tamanhos do formulário:

Fig. 6. O controle «gráfico de linha» que se ajusta aos tamanhos do formulário. 

Fig. 6. O controle «gráfico de linha» que se ajusta aos tamanhos do formulário.


A quarta e quinta guia demonstram a ancoragem da borda direita de muitos outros controles da biblioteca:

Fig. 7. Controles na quarta guia. 

Fig. 7. Controles na quarta guia.


Fig. 8. Controles na quinta guia. 

Fig. 8. Controles na quinta guia.


O aplicativo de teste apresentado no artigo pode ser baixado usando o link abaixo para estudá-lo ainda mais. 

 


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. 9. Estrutura da biblioteca no atual estágio de desenvolvimento. 

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


Na próxima versão, a biblioteca será expandido com os controles adicionais, que podem ser necessários ao desenvolvimento das aplicações MQL. Os controles existentes sofrerão melhorias e será adicionado novas funcionalidades.

Abaixo, você pode baixar a terceira versão da biblioteca Easy And Fast. Se você tiver dúvidas sobre a utilização de material a partir desses arquivos, você poderá consultar a descrição detalhada desta série de artigos ou realizar uma pergunta nos comentários deste artigo. 


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

Arquivos anexados |
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.
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)
Desde a publicação do artigo anterior da 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.
MQL5 Programações Básicas: Arquivos MQL5 Programações Básicas: Arquivos
Este artigo de orientação prática se concentra em trabalhar com arquivos no MQL5. Ele oferece uma série de tarefas simples, o qual nos permite compreender os conceitos básicos e aprimorar suas habilidades.
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.