English Русский 中文 Español Deutsch 日本語
Interfaces Gráficas V: A Barra de Rolagem Vertical e Horizontal (Capítulo 1)

Interfaces Gráficas V: A Barra de Rolagem Vertical e Horizontal (Capítulo 1)

MetaTrader 5Exemplos | 14 setembro 2016, 08:39
1 647 0
Anatoli Kazharski
Anatoli Kazharski

Conteúdo



Introdução

Nos artigos anteriores da série sobre as interfaces gráficas no ambiente do MetaTrader, nós discutimos as principais partes da biblioteca em desenvolvimento e criamos também vários elementos de interface: O menu principal, o menu de contexto, a barra de status, botões, grupos de botões e as dicas de contexto. A quinta parte da série será dedicada aos controles como a barra de rolagem e a lista. No primeiro capítulo, nós vamos escrever as classes para criar uma barra de rolagem vertical e horizontal. No segundo capítulo, nós vamos desenvolver o elemento de interface composto chamado lista. Este elemento será composto pois uma barra de rolagem fará parte dele, desse modo, nós vamos começar criando ela. 

 


O Controle Barra de Rolagem

A barra de rolagem é usada em diferentes visualizações de listas e tabelas quando o conjunto de dados não cabe na área designada. Os principais objetos da barra de rolagem são os botões para mover os dados em um passo e o deslizador que movimenta os dados de forma rápida através de seu arrastamento com o botão esquerdo do mouse pressionado.

Nós vamos compor a barra de rolagem com cinco objetos gráficos.

  1. Fundo principal.
  2. Fundo da área do deslizador.
  3. Dois botões para mover os dados em um passo.
  4. Deslizador para realizar um movimento rápido dos dados.

 

Fig. 1. Partes integrantes do controle barra de rolagem.

Como podemos ter dois tipos de barra de rolagem - as horizontais e verticais, será conveniente criarmos uma classe separada para cada tipo. Estas serão classes derivadas, que servem para refletir as propriedades únicas de cada tipo de barra de rolagem. 

  • CScrollV – Classe derivada para barra de rolagem vertical.
  • CScrollH - Classe derivada para a barra de rolagem horizontal.

A classe base para elas será a CScroll. Ela irá conter os campos e métodos comuns para cada tipo. Todas as três classes serão colocadas no arquivo Scrolls.mqh. O esquema para o controle barra de rolagem será o seguinte:

 Fig. 2. Esquema do controle barra de rolagem.

Fig. 2. Esquema do controle barra de rolagem.


Agora, nós vamos considerar o desenvolvimento da classe base para esse controle - CScroll

 


Classe Base do Controle

O controle de deslocamento não é um elemento independente da interface gráfica. Ele é um elemento auxiliar que será ligado a outros elementos que exigem o deslocamento de dados na área de trabalho. Isso significa que o arquivo Scrolls.mqh não precisa ser diretamente incluído no arquivo Arquivo WndContainer.mqh. As classes da barra de rolagem estarão disponíveis na biblioteca, através da inclusão nos arquivos com as classes de outros elementos.

Crie a classe CScroll no arquivo Scrolls.mqh com os métodos padrão para todos os elementos da interface:

//+------------------------------------------------------------------+
//|                                                      Scrolls.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
//+------------------------------------------------------------------+
//| Classe base para a criação da barra de rolagem                   |
//+------------------------------------------------------------------+
class CScroll : public CElement
  {
protected:
   //--- Ponteiro para o formulário ao qual o elemento está anexado
   CWindow          *m_wnd;
   //---
public:
   //--- Armazena o ponteiro do formulário
   void              WindowPointer(CWindow &object)           { m_wnd=::GetPointer(object);       }
   //---
public:
   //--- Manipulador de eventos do gráfico
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Timer
   virtual void      OnEventTimer(void) {}
   //--- Move o elemento
   virtual void      Moving(const int x,const int y);
   //--- (1) Exibe, (2) oculta, (3) reseta, (4) remove
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- (1) Definir (2), resetar as prioridades para o clique esquerdo do mouse
   virtual void      SetZorders(void);
   virtual void      ResetZorders(void);
   //--- Resetar a cor
   virtual void      ResetColors(void) {}
  };
//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CScroll::CScroll(void)
  {
  }
//+------------------------------------------------------------------+
//| Destrutor                                                        |
//+------------------------------------------------------------------+
CScroll::~CScroll(void)
  {
  }

Seguindo em frente, deve-se mencionar que as classes derivadas devem ser criada no mesmo arquivo, como é mostrado no código abaixo. O elemento recebe um nome correspondente no construtor da classe de acordo com a classe que será utilizada.  

//+------------------------------------------------------------------+
//| Classe para a gestão da barra de rolagem vertical                |
//+------------------------------------------------------------------+
class CScrollV : public CScroll
  {
public:
                     CScrollV(void);
                    ~CScrollV(void);
  };
//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CScrollV::CScrollV(void)
  {
//--- Armazena o nome da classe do elemento na classe base
   CElement::ClassName(CLASS_NAME);
  }
//+------------------------------------------------------------------+
//| Destrutor                                                        |
//+------------------------------------------------------------------+
CScrollV::~CScrollV(void)
  {
  }
//+------------------------------------------------------------------+
//| Classe para a gestão da barra de rolagem horizontal              |
//+------------------------------------------------------------------+
class CScrollH : public CScroll
  {
public:
                     CScrollH(void);
                    ~CScrollH(void);
  };
//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CScrollH::CScrollH(void)
  {
//--- Armazena o nome da classe do elemento na classe base
   CElement::ClassName(CLASS_NAME);
  }
//+------------------------------------------------------------------+
//| Destrutor                                                        |
//+------------------------------------------------------------------+
CScrollH::~CScrollH(void)
  {
  }

Como mencionado anteriormente, vamos fazer com que haja a possibilidade de personalização da aparência da barra de rolagem. Para isso, na classe base CScroll crie os campos e métodos para definir os seguintes parâmetros dos objetos de elemento:

  • Largura da barra de rolagem
  • Cor do quadro do fundo geral
  • Cor do fundo e do quadro da área onde o deslizador da barra de rolagem está localizada
  • Cor do fundo e do quadro do deslizador em diferentes estados
  • Ícones para diferentes estados dos botões, com o qual os dados serão deslocados

Deve-se notar que a largura da barra de rolagem vertical e seus objetos serão do tamanho do eixo X e para a horizontal será do tamanho do eixo Y. A largura padrão será de 15 pixels. Os ícones padrão para os botões são selecionados para corresponderem a este tamanho. Eles estão localizados dentro do do fundo geral com a margem de 1 pixel de modo que eles não cubram o quadro de fundo. Seu tamanho é de 13x13 pixels. Portanto, se você alterar a largura da barra de rolagem, você precisará alterar o botão de ícones. Vamos criar os métodos relevantes.

A largura de outros objetos da barra de rolagem (área interna e o deslizador) serão calculados automaticamente em relação à largura do fundo geral. O comprimento também será calculado automaticamente já que este parâmetro depende do número de itens na lista e do seu tamanho ao longo do exio Y. Sua implementação será descrita posteriormente no artigo. 

class CScroll : public CElement
  {
protected:
   //--- Propriedades da área geral da barra de rolagem
   int               m_area_width;
   int               m_area_length;
   color             m_area_color;
   color             m_area_border_color;
   //--- Propriedades do fundo do deslizador
   int               m_bg_length;
   color             m_bg_border_color;
   //--- Ícones de botão
   string            m_inc_file_on;
   string            m_inc_file_off;
   string            m_dec_file_on;
   string            m_dec_file_off;
   //--- Cores do deslizador em diferentes estados
   color             m_thumb_color;
   color             m_thumb_color_hover;
   color             m_thumb_color_pressed;
   color             m_thumb_border_color;
   color             m_thumb_border_color_hover;
   color             m_thumb_border_color_pressed;
   //--- (1) Largura da barra, (2) comprimento do deslizador (3) e o seu comprimento mínimo
   int               m_thumb_width;
   int               m_thumb_length;
   int               m_thumb_min_length;
   //--- (1) Passo do deslizador e (2) o número de passos
   double            m_thumb_step_size;
   double            m_thumb_steps_total;
   //--- Prioridades do clique do botão esquerdo do mouse
   int               m_area_zorder;
   int               m_bg_zorder;
   int               m_arrow_zorder;
   int               m_thumb_zorder;
   //---
public:
   //--- Largura da barra do deslizador
   void              ScrollWidth(const int width)             { m_area_width=width;               }
   int               ScrollWidth(void)                  const { return(m_area_width);             }
   //--- (1) Cor do fundo, (2) do quadro de fundo e (3) o quadro interna do fundo
   void              AreaColor(const color clr)               { m_area_color=clr;                 }
   void              AreaBorderColor(const color clr)         { m_area_border_color=clr;          }
   void              BgBorderColor(const color clr)           { m_bg_border_color=clr;            }
   //--- Definindo os ícones para os botões
   void              IncFileOn(const string file_path)        { m_inc_file_on=file_path;          }
   void              IncFileOff(const string file_path)       { m_inc_file_off=file_path;         }
   void              DecFileOn(const string file_path)        { m_dec_file_on=file_path;          }
   void              DecFileOff(const string file_path)       { m_dec_file_off=file_path;         }
   //--- (1) Cor do fundo do deslizador e (2) o quadro de fundo do deslizador
   void              ThumbColor(const color clr)              { m_thumb_border_color=clr;         }
   void              ThumbColorHover(const color clr)         { m_thumb_border_color_hover=clr;   }
   void              ThumbColorPressed(const color clr)       { m_thumb_border_color_pressed=clr; }
   void              ThumbBorderColor(const color clr)        { m_thumb_border_color=clr;         }
   void              ThumbBorderColorHover(const color clr)   { m_thumb_border_color_hover=clr;   }
   void              ThumbBorderColorPressed(const color clr) { m_thumb_border_color_pressed=clr; }
  };
//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CScroll::CScroll(void) : m_area_width(15),
                         m_area_length(0),
                         m_inc_file_on(""),
                         m_inc_file_off(""),
                         m_dec_file_on(""),
                         m_dec_file_off(""),
                         m_thumb_width(0),
                         m_thumb_length(0),
                         m_thumb_min_length(15),
                         m_area_color(C'210,210,210'),
                         m_area_border_color(C'240,240,240'),
                         m_bg_border_color(C'210,210,210'),
                         m_thumb_color(C'190,190,190'),
                         m_thumb_color_hover(C'180,180,180'),
                         m_thumb_color_pressed(C'160,160,160'),
                         m_thumb_border_color(C'170,170,170'),
                         m_thumb_border_color_hover(C'160,160,160'),
                         m_thumb_border_color_pressed(C'140,140,140')
  {
//--- Define as prioridades do botão esquerdo do mouse
   m_area_zorder  =8;
   m_bg_zorder    =9;
   m_arrow_zorder =10;
   m_thumb_zorder =11;
  }

Vamos considerar os métodos para a criação do elemento da barra de rolagem. Cada parte dele é criada por um método privado individual. O tamanho da lista e o tamanho da parte visível da lista deve ser passado como os dois últimos parâmetros do método principal. Estes parâmetros serão usados no cálculo do número de passos para o deslizador da barra de rolagem. 

class CScroll : public CElement
  {
protected:
   //--- Objetos para criar a barra de rolagem
   CRectLabel        m_area;
   CRectLabel        m_bg;
   CBmpLabel         m_inc;
   CBmpLabel         m_dec;
   CRectLabel        m_thumb;
   //---
public:
   //--- Métodos para criar a barra de rolagem
   bool              CreateScroll(const long chart_id,const int subwin,const int x,const int y,const int items_total,const int visible_items_total);
   //---
private:
   bool              CreateArea(void);
   bool              CreateBg(void);
   bool              CreateInc(void);
   bool              CreateDec(void);
   bool              CreateThumb(void);
  };

Como exemplo nós vamos mostrar o código de apenas alguns desses métodos, pois no resto dos métodos são utilizados princípios semelhantes, que deve ser fácil de acompanhar. Dê uma olhada no código do método CScroll::CreateBg() abaixo. Note que a formação do nome do objeto depende do tipo da barra de rolagem e também se o índice deste elemento foi especificado. Pode ser necessário especificar o índice para o desenvolvimento dos controles compostos onde pode ser utilizado várias barras de rolagem de um tipo. Tais exemplos serão ilustradas em um dos seguintes artigos.

O tipo da barra de rolagem também define os cálculos de tais parâmetros como as (1) coordenadas, (2) comprimento da área do deslizador e (3) o seu tamanho. Esta parte é destacada em azul no código abaixo. 

//+------------------------------------------------------------------+
//| Cria o fundo da barra de rolagem                                 |
//+------------------------------------------------------------------+
bool CScroll::CreateBg(void)
  {
//--- Elaborando o nome do objeto
   string name      ="";
   string name_part =(CElement::ClassName()=="CScrollV")? "_scrollv_bg_" : "_scrollh_bg_";
//--- Se o índice não foi especificado
   if(CElement::Index()==WRONG_VALUE)
      name=CElement::ProgramName()+name_part+(string)CElement::Id();
//--- Se o índice foi especificado
   else
      name=CElement::ProgramName()+name_part+(string)CElement::Index()+"__"+(string)CElement::Id();
//--- Coordenadas
   int x=0;
   int y=0;
//--- Tamanho
   int x_size=0;
   int y_size=0;
//--- Define as propriedades, considerando o tipo da barra de rolagem
   if(CElement::ClassName()=="CScrollV")
     {
      m_bg_length =CElement::YSize()-(m_thumb_width*2)-2;
      x           =CElement::X()+1;
      y           =CElement::Y()+m_thumb_width+1;
      x_size      =m_thumb_width;
      y_size      =m_bg_length;
     }
   else
     {
      m_bg_length =CElement::XSize()-(m_thumb_width*2)-2;
      x           =CElement::X()+m_thumb_width+1;
      y           =CElement::Y()+1;
      x_size      =m_bg_length;
      y_size      =m_thumb_width;
     }
//--- Cria um objeto
   if(!m_bg.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size))
      return(false);
//--- Definindo as propriedades
   m_bg.BackColor(m_area_color);
   m_bg.Color(m_bg_border_color);
   m_bg.BorderType(BORDER_FLAT);
   m_bg.Corner(m_corner);
   m_bg.Selectable(false);
   m_bg.Z_Order(m_bg_zorder);
   m_bg.Tooltip("\n");
//--- Armazena as coordenadas
   m_bg.X(x);
   m_bg.Y(y);
//--- Armazena as margens
   m_bg.XGap(x-m_wnd.X());
   m_bg.YGap(y-m_wnd.Y());
//--- Armazena o tamanho
   m_bg.XSize(x_size);
   m_bg.YSize(y_size);
//--- Armazena o ponteiro de objeto
   CElement::AddToArray(m_bg);
   return(true);
  }

Ao criar o objeto gráfico que atuará como o deslizador da barra de rolagem, nós vamos precisar de um método para calcular o seu comprimento. O tamanho depende do número de itens da lista e o número de itens em sua parte visível. Vamos criar tal método e chamá-lo de CScroll::CalculateThumbSize(). 

No início deste método, há uma verificação para o tamanho da área do deslizador. Se o comprimento deste espaço for menor que o comprimento mínimo do deslizador, então, o cálculo não é necessário. O método retornará false e o deslizador não será criado uma vez que ele não é necessário neste caso. Se ele passou na verificação, então o cálculo terá várias etapas:

  • Cálculo do deslizador. 
  • Se o valor obtido for inferior que 1, então, deixe-o igual a 1.
  • Cálculo da área de trabalho para mover o deslizador. 
  • Se o tamanho da área de trabalho for menor do que o tamanho de toda a área de movimento do deslizador, então, calcula-se o comprimento do mesmo. Caso contrário, define-se um comprimento mínimo que por padrão é igual a 15 pixels.
  • A verificação do comprimento calculado do deslizador, que envolve a conversão para o tipo inteiro (int) é realizada no final do método, bem como o seu ajustamento no caso do comprimento calculado ser menor que o mínimo. 

O código detalhado do método CScroll::CalculateThumbSize() é exibido abaixo.

class CScroll : public CElement
  {
protected:

public:
   //--- Cálculo do comprimento do deslizador
   bool              CalculateThumbSize(void);
  };
//+------------------------------------------------------------------+
//|Cálculo do comprimento do deslizador                              |
//+------------------------------------------------------------------+
bool CScroll::CalculateThumbSize(void)
  {
//--- O cálculo não é necessário se o comprimento da área para mover o deslizador for menor do que o comprimento mínimo dela
   if(m_bg_length<m_thumb_min_length)
      return(false);
//--- Calcula o tamanho do deslizador
   m_thumb_step_size=(double)(m_bg_length-m_thumb_min_length)/m_thumb_steps_total;
//--- O tamanho do passo não pode ser inferior a 1
   m_thumb_step_size=(m_thumb_step_size<1)? 1 : m_thumb_step_size;
//--- Calcula o tamanho da área de trabalho para mover o deslizador
   double work_area=m_thumb_step_size*m_thumb_steps_total;
//--- Se o tamanho da área de trabalho for menos do que o tamanho de toda a área, obtém o tamanho do deslizador, caso contrário, define o tamanho mínimo
   double thumb_size=(work_area<m_bg_length)? m_bg_length-work_area+m_thumb_step_size : m_thumb_min_length;
//--- Verifica o tamanho do deslizador usando a conversão do tipo
   m_thumb_length=((int)thumb_size<m_thumb_min_length)? m_thumb_min_length :(int)thumb_size;
   return(true);
  }

A chamada do método CScroll::CalculateThumbSize() deve ser realida no método CScroll::CreateThumb() antes de criar o objeto. Mais tarde, nós ilustraremos outro caso, quando o comprimento da barra de deslocamento deve ser calculada no processo de utilização do controle. Nós vamos considerar isso quando estivermos desenvolvendo o controle.

//+------------------------------------------------------------------+
//| Cria o deslizador da barra de rolagem                            |
//+------------------------------------------------------------------+
bool CScroll::CreateThumb(void)
  {
//--- Elaborando o nome do objeto  
   string name      ="";
   string name_part =(CElement::ClassName()=="CScrollV")? "_scrollv_thumb_" : "_scrollh_thumb_";
//--- Se o índice não foi especificado
   if(CElement::Index()==WRONG_VALUE)
      name=CElement::ProgramName()+name_part+(string)CElement::Id();
//--- Se o índice foi especificado
   else
      name=CElement::ProgramName()+name_part+(string)CElement::Index()+"__"+(string)CElement::Id();
//--- Coordenadas
   int x=0;
   int y=0;
//--- Tamanho
   int x_size=0;
   int y_size=0;
//--- Calcula o tamanho da barra de rolagem
   if(!CalculateThumbSize())
      return(true);
//--- Define a propriedade considerando o tipo da barra de rolagem
   if(CElement::ClassName()=="CScrollV")
     {
      x      =(m_thumb.X()>0) ? m_thumb.X() : m_x+1;
      y      =(m_thumb.Y()>0) ? m_thumb.Y() : m_y+m_thumb_width+1;
      x_size =m_thumb_width;
      y_size =m_thumb_length;
     }
   else
     {
      x      =(m_thumb.X()>0) ? m_thumb.X() : m_x+m_thumb_width+1;
      y      =(m_thumb.Y()>0) ? m_thumb.Y() : m_y+1;
      x_size =m_thumb_length;
      y_size =m_thumb_width;
     }
//--- Cria um objeto
   if(!m_thumb.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size))
      return(false);
//--- Definindo as propriedades
   m_thumb.BackColor(m_thumb_color);
   m_thumb.Color(m_thumb_border_color);
   m_thumb.BorderType(BORDER_FLAT);
   m_thumb.Corner(m_corner);
   m_thumb.Selectable(false);
   m_thumb.Z_Order(m_thumb_zorder);
   m_thumb.Tooltip("\n");
//--- Armazena as coordenadas
   m_thumb.X(x);
   m_thumb.Y(y);
//--- Armazena as margens
   m_thumb.XGap(x-m_wnd.X());
   m_thumb.YGap(y-m_wnd.Y());
//--- Armazena o tamanho
   m_thumb.XSize(x_size);
   m_thumb.YSize(y_size);
//--- Armazena o ponteiro de objeto
   CElement::AddToArray(m_thumb);
   return(true);
  }

Os outros métodos para a criação dos objetos da barra de rolagem são voltados para o estudo individual. Eles podem ser encontrados no arquivo anexado neste artigo.

Adicione a verificação para o tipo de classe no método principal (público) para criar a barra de rolagem. O nome da classe não será armazenado na classe base do elemento CScroll. É por isso que, ao tentar criar uma barra de rolagem usando a classe base, a criação da interface gráfica será encerrada. O registro receberá uma mensagem de que as classes derivadas do tipo CScrollV ou da CScrollH devem ser usadas. Por favor, note como alguns parâmetros do elemento são inicializados. Tal abordagem permite automatizar ao máximo todos os cálculos, livrando o usuário de toda aquela rotina e proporcionando a possibilidade de especificar um número mínimo de propriedades ao criar os controles com uma barra de rolagem. 

//+------------------------------------------------------------------+
//| Creates the scrollbar                                            |
//+------------------------------------------------------------------+
bool CScroll::CreateScroll(const long chart_id,const int subwin,const int x,const int y,const int items_total,const int visible_items_total)
  {
//--- Retorna se não há nenhum ponteiro do formulário
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
     {
      ::Print(__FUNCTION__," > Antes de criar a barra de rolagem, a classe deve ser passada "
              "o ponteiro do formulário: CScroll::WindowPointer(CWindow &object)");
      return(false);
     }
//--- Sai, se houver uma tentativa de usar a classe base da barra de rolagem
   if(CElement::ClassName()=="")
     {
      ::Print(__FUNCTION__," > Use as classes derivadas da barra de rolagem (CScrollV ou CScrollH).");
      return(false);
     }
//--- Inicializa as variáveis​
   m_chart_id          =chart_id;
   m_subwin            =subwin;
   m_x                 =x;
   m_y                 =y;
   m_area_width        =(CElement::ClassName()=="CScrollV")? CElement::XSize() : CElement::YSize();
   m_area_length       =(CElement::ClassName()=="CScrollV")? CElement::YSize() : CElement::XSize();
   m_thumb_width       =m_area_width-2;
   m_thumb_steps_total =items_total-visible_items_total+1;
//--- Margens da borda
   CElement::XGap(m_x-m_wnd.X());
   CElement::YGap(m_y-m_wnd.Y());
//--- Criando o botão
   if(!CreateArea())
      return(false);
   if(!CreateBg())
      return(false);
   if(!CreateInc())
      return(false);
   if(!CreateDec())
      return(false);
   if(!CreateThumb())
      return(false);
//--- Oculta o elemento se ela for uma janela de diálogo ou está minimizada
   if(m_wnd.WindowType()==W_DIALOG || m_wnd.IsMinimized())
      Hide();
//---
   return(true);
  }

Para identificar o estado do botão esquerdo do mouse em relação ao deslizador da barra de rolagem, crie a enumeração ENUM_THUMB_MOUSE_STATE no arquivo Enums.mqh.

//+------------------------------------------------------------------+
//| Enumeração de estados do botão esquerdo do mouse para a barra de rolagem |
//+------------------------------------------------------------------+
enum ENUM_THUMB_MOUSE_STATE
  {
   THUMB_NOT_PRESSED     =0,
   THUMB_PRESSED_OUTSIDE =1,
   THUMB_PRESSED_INSIDE  =2
  };

Para isso, nós precisamos criar os campos e métodos apropriados. O método CScroll::CheckMouseButtonState() é necessário para identificar qual foi a área em que o botão esquerdo do mouse foi pressionado. O método CScroll::ZeroThumbVariables() é usado para zerar as variáveis ​​relacionadas com o movimento do deslizador, sendo este chamado no método CScroll::CheckMouseButtonState() quando o botão esquerdo do mouse é liberado.

Tenha em mente que, quando a barra de rolagem está no modo de mover o deslizador, o formulário se torna bloqueado apenas se o elemento não for do tipo suspenso. Isso é necessário para excluir o destacamento de outros elementos quando o cursor estiver sobre eles, o deslizador da barra de rolagem está no modo de movimento e o cursor está fora de sua área. Quando o modo de movimento do deslizador está desativado, o formulário deve ser desbloqueado no método CScroll::ZeroThumbVariables()

class CScroll : public CElement
  {
protected:
   //--- Variáveis ​​relacionadas com o movimento do deslizador
   bool              m_scroll_state;
   int               m_thumb_size_fixing;
   int               m_thumb_point_fixing;
   //--- Para identificar a área em que o botão esquerdo do mouse foi pressionado
   ENUM_THUMB_MOUSE_STATE m_clamping_area_mouse;
   //---
public:
   //--- Identifica a área em que o botão esquerdo do mouse foi pressionado
   void              CheckMouseButtonState(const bool mouse_state);
   //--- Zerando as variáveis
   void              ZeroThumbVariables(void);
  };
//+------------------------------------------------------------------+
//| Identifica a área em que o botão esquerdo do mouse foi pressionado|
//+------------------------------------------------------------------+
void CScroll::CheckMouseButtonState(const bool mouse_state)
  {
//--- Identifica o estado do botão do mouse:
//    Se foi solto
   if(!mouse_state)
     {
      //--- Zerando as variáveis
      ZeroThumbVariables();
      return;
     }
//--- Se pressionado
   if(mouse_state)
     {
      //--- Sai, se o botão for pressionado em outra área
      if(m_clamping_area_mouse!=THUMB_NOT_PRESSED)
         return;
      //--- Fora da área do deslizador
      if(!m_thumb.MouseFocus())
         m_clamping_area_mouse=THUMB_PRESSED_OUTSIDE;
      //--- Dentro da área do deslizador
      else
        {
         m_clamping_area_mouse=THUMB_PRESSED_INSIDE;
         //--- Se este não for um elemento suspenso
         if(!CElement::IsDropdown())
           {
            //--- Bloqueia o formulário e armazena o identificador do elemento ativo
            m_wnd.IsLocked(true);
            m_wnd.IdActivatedElement(CElement::Id());
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Zera as variáveis ​​relacionadas com o movimento do deslizador     |
//+------------------------------------------------------------------+
void CScroll::ZeroThumbVariables(void)
  {
//--- Se este não for um elemento suspenso
   if(!CElement::IsDropdown())
     {
      //--- Desbloqueia o formulário e redefine o identificador de elemento ativo
      m_wnd.IsLocked(false);
      m_wnd.IdActivatedElement(WRONG_VALUE);
     }
   m_thumb_size_fixing   =0;
   m_clamping_area_mouse =THUMB_NOT_PRESSED;
  }

Para alterar a cor dos objetos da barra de rolagem, dependendo da localização do cursor do mouse e o estado do seu botão esquerdo, crie o método CScroll::ChangeObjectsColor(). No início deste método, há uma verificação se o formulário é bloqueado e se o identificador da barra de rolagem difere do identificador armazenado na memória do formulário. Se essas duas condições forem satisfeitas, eles recebem um estado que corresponde ao modo atual da barra de rolagem e do foco sobre os seus botões. A barra de rolagem pode ter dois modos: (1) livre e (2) no processo de mover o deslizador. Depois disso, dependendo da localização do cursor e da área onde o botão esquerdo do mouse foi pressionado, o deslizador recebe uma cor relevante. O modo da barra de rolagem é definida aqui também.

class CScroll : public CElement
  {
public:
   //--- A mudança da cor dos objetos na barra de rolagem
   void              ChangeObjectsColor(void);
  };
//+------------------------------------------------------------------+
//| Altera a cor dos objetos da barra de rolagem da lista            |
//+------------------------------------------------------------------+
void CScroll::ChangeObjectsColor(void)
  {
//--- Sai, se o formulário está bloqueado e o identificador do elemento ativo neste momento não coincidir.
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return;
//--- Cores dos botões da barra de rolagem da lista
   if(!m_scroll_state)
     {
      m_inc.State(m_inc.MouseFocus());
      m_dec.State(m_dec.MouseFocus());
     }
//--- Se o cursor estiver na área da barra de rolagem
   if(m_thumb.MouseFocus())
     {
      //--- Se o botão esquerdo do mouse foi liberado
      if(m_clamping_area_mouse==THUMB_NOT_PRESSED)
        {
         m_scroll_state=false;
         m_thumb.BackColor(m_thumb_color_hover);
         m_thumb.Color(m_thumb_border_color_hover);
        }
      //--- O botão esquerdo do mouse foi pressionado no deslizador
      else if(m_clamping_area_mouse==THUMB_PRESSED_INSIDE)
        {
         m_scroll_state=true;
         m_thumb.BackColor(m_thumb_color_pressed);
         m_thumb.Color(m_thumb_border_color_pressed);
        }
     }
//--- Se o cursor estiver fora da área da barra de rolagem
   else
     {
      //--- O botão esquerdo do mouse foi liberado
      if(m_clamping_area_mouse==THUMB_NOT_PRESSED)
        {
         m_scroll_state=false;
         m_thumb.BackColor(m_thumb_color);
         m_thumb.Color(m_thumb_border_color);
        }
     }
  }

Para o desenvolvimento dos elementos de interface com a barra de rolagem, será necessário termos os métodos para obtenção dos nomes e estados de seus botões. Além disso, nós vamos precisar dos métodos para definir e identificar o estado do deslocamento do deslizador da barra de rolagem e sua localização atual em relação a lista na qual ele está anexado. 

class CScroll : public CElement
  {
protected:
   //--- Definindo o estado da barra de rolagem
   bool              m_scroll_state;
   //--- Localização atual do deslizador
   int               m_current_pos;
   //---
public:
   //--- Nomes dos objetos do botão
   string            ScrollIncName(void)                const { return(m_inc.Name());             }
   string            ScrollDecName(void)                const { return(m_dec.Name());             }
   //--- Estado dos botões
   bool              ScrollIncState(void)               const { return(m_inc.State());            }
   bool              ScrollDecState(void)               const { return(m_dec.State());            }
   //--- Estado da barra de rolagem
   void              ScrollState(const bool scroll_state)     { m_scroll_state=scroll_state;      }
   bool              ScrollState(void)                  const { return(m_scroll_state);           }
   //--- Localização atual do deslizador
   void              CurrentPos(const int pos)                { m_current_pos=pos;                }
   int               CurrentPos(void)                   const { return(m_current_pos);            }
  };

Nós completamos o desenvolvimento da classe base da barra de rolagem. Agora, nós vamos preencher as classes derivadas desse controle. 

 


Classes Derivadas do Controle

Se a classe base da barra de rolagem está preenchida com os métodos gerais para a criação dos objetos como a definição dos parâmetros e a obtenção de seus valores, as classes derivadas são destinados para gerir este controle. Nós criamos anteriormente as classes derivadas CScrollV e CScrollH no arquivo Scrolls.mqh. Nós vamos discutir os métodos de apenas um deles - a classe da barra de rolagem vertical (CScrollV). Na segunda classe (CScrollH), tudo será o mesmo com apenas um ajuste para o tipo da barra de rolagem. Na classe da barra de rolagem horizontal nós estaremos trabalhando com a coordenada X, ao contrário da classe da barra de rolagem vertical, onde trabalhamos com as coordenadas Y.

Num primeiro momento, nós vamos considerar o código dos métodos CScrollV::OnDragThumb() e CScrollV::UpdateThumb() projetados para deslocar o deslizador da barra de rolagem. Eles precisam ser declarados na seção privada da classe já que eles serão utilizados apenas dentro da classe CScrollV.

//+------------------------------------------------------------------+
//| Classe para a gestão da barra de rolagem vertical                |
//+------------------------------------------------------------------+
class CScrollV : public CScroll
  {
private:
   //--- Deslocando o deslizador
   void              OnDragThumb(const int y);
   //--- Atualizando a localização do cursor
   void              UpdateThumb(const int new_y_point);
  };

O método CScrollV::OnDragThumb() é necessário para identificar a tentativa do usuário de mover os deslizador. Se o botão esquerdo do mouse foi pressionado sobre o deslizador da barra de rolagem e o cursor foi movido nesse estado ao longo do eixo Y, isto significa que o processo de movimento foi iniciado e o objeto tem de ser transferido. A atualização das coordenadas do deslizador é realizada com o método CScrollV::UpdateThumb().  

//+------------------------------------------------------------------+
//| Movendo o deslizador                                             |
//+------------------------------------------------------------------+
void CScrollV::OnDragThumb(const int y)
  {
//--- Para identificar a nova coordenada Y
   int new_y_point=0;
//--- Se a barra de rolagem está inativa, ...
   if(!CScroll::ScrollState())
     {
      //--- ...zera as variáveis ​​auxiliares para mover o deslizador
      CScroll::m_thumb_size_fixing  =0;
      CScroll::m_thumb_point_fixing =0;
      return;
     }
//--- Se o ponto de fixação é zero, armazena as coordenadas atuais do cursor
   if(CScroll::m_thumb_point_fixing==0)
      CScroll::m_thumb_point_fixing=y;
//--- Se a distância da extremidade do deslizador para a coordenada atual do cursor é zero, calcula ele
   if(CScroll::m_thumb_size_fixing==0)
      CScroll::m_thumb_size_fixing=m_thumb.Y()-y;
//--- Se o limite é ultrapassado para baixo no estado pressionado para baixo
   if(y-CScroll::m_thumb_point_fixing>0)
     {
      //--- Calcula a coordenada Y
      new_y_point=y+CScroll::m_thumb_size_fixing;
      //--- Atualiza a localização do deslizador
      UpdateThumb(new_y_point);
      return;
     }
//--- Se o limite é ultrapassado para cima no estado pressionado para baixo
   if(y-CScroll::m_thumb_point_fixing<0)
     {
      //--- Calcula a coordenada Y
      new_y_point=y-::fabs(CScroll::m_thumb_size_fixing);
      //--- Atualiza a localização do deslizador
      UpdateThumb(new_y_point);
      return;
     }
  }

Abaixo nós encontramos o código detalhado do método CScrollV::UpdateThumb(). A coordenada Y calculada no método CScrollV::OnDragThumb() e passada para ele. Lá, é feito a sua verificação. Se ele verificar que foi excedido os limites da área de trabalho designada para mover o cursor, os valores são ajustados. Só depois disso que as coordenadas são atualizadas e armazenada nos campos das classes base. 

//+------------------------------------------------------------------+
//| Atualizando a localização do deslizador                          |
//+------------------------------------------------------------------+
void CScrollV::UpdateThumb(const int new_y_point)
  {
   int y=new_y_point;
//--- Zerando o ponto de fixação
   CScroll::m_thumb_point_fixing=0;
//--- Verifica se o valor excedeu a área de trabalho para baixo e ajusta-o
   if(new_y_point>m_bg.Y2()-CScroll::m_thumb_length)
     {
      y=m_bg.Y2()-CScroll::m_thumb_length;
      CScroll::CurrentPos(int(CScroll::m_thumb_steps_total));
     }
//--- Verifica se o valor excedeu a área de trabalho para cima e ajusta-o
   if(new_y_point<=m_bg.Y())
     {
      y=m_bg.Y();
      CScroll::CurrentPos(0);
     }
//--- Atualiza as coordenadas e margens
   m_thumb.Y(y);
   m_thumb.Y_Distance(y);
   m_thumb.YGap(m_thumb.Y()-(CElement::Y()-CElement::YGap()));
  }

Nós vamos precisar de mais um método privado para corrigir a posição atual do deslizador em relação a sua coordenada Y. Vamos nomeá-lo de CScrollV::CalculateThumbPos(). O código é apresentado a seguir. 

class CScrollV : public CScroll
  {
private:
   //--- Corrige o valor da posição do deslizador
   void              CalculateThumbPos(void);
  };
//+------------------------------------------------------------------+
//| Corrige o valor da posição do deslizador                         |
//+------------------------------------------------------------------+
void CScrollV::CalculateThumbPos(void)
  {
//--- Sai, se a etapa é igual a zero
   if(CScroll::m_thumb_step_size==0)
      return;
//--- Corrige o valor da posição da barra de rolagem
   CScroll::CurrentPos(int((m_thumb.Y()-m_bg.Y())/CScroll::m_thumb_step_size));
//--- Verifica se o valor excedeu a área de trabalho para baixo/cima
   if(m_thumb.Y2()>=m_bg.Y2()-1)
      CScroll::CurrentPos(int(CScroll::m_thumb_steps_total-1));
   if(m_thumb.Y()<m_bg.Y())
      CScroll::CurrentPos(0);
  }

Agora, vamos criar o método público CScrollV::ScrollBarControl() para gerir o deslizador. Todos os métodos privados considerados acima será chamados neste método. Ele terá de ser chamado no manipulador de evento OnEvent() desses elementos contendo uma barra de rolagem. Nós vamos trazer um exemplo detalhado no segundo capítulo, onde nós iremos desenvolver uma classe para criar o controle lista. 

O código do método CScrollV::ScrollBarControl() é apresentado abaixo. As coordenadas do cursor e o estado do botão esquerdo do mouse são passados ​​a ele como argumentos. No início, nós vamos verificar o foco sobre a barra de rolagem. Em seguida, nós verificaremos qual a área em que o botão esquerdo do mouse foi pressionado. Dependendo da localização do cursor e o estado do botão esquerdo do mouse, a cor da barra de rolagem é alterada. Depois disso, se o gerenciamento é passado para a barra de rolagem, ela é movida de acordo com a nova coordenada Y calculada. O número do elemento da lista é calculado em relação a ele. 

class CScrollV : public CScroll
  {
public:
   //--- Gerenciando a barra de rolagem
   bool              ScrollBarControl(const int x,const int y,const bool mouse_state);
  };
//+------------------------------------------------------------------+
//| Gerenciando a barra de rolagem                                   |
//+------------------------------------------------------------------+
bool CScrollV::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- Verificando o foco sobre a barra de rolagem
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() && 
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- Verifica e armazena o estado do botão do mouse
   CScroll::CheckMouseButtonState(mouse_state);
//--- Muda a cor da barra de rolagem
   CScroll::ChangeObjectsColor();
//--- Se o gerenciamento é passado para a barra de rolagem, identifica a localização da barra de rolagem
   if(CScroll::ScrollState())
     {
      //--- Deslocando o deslizador
      OnDragThumb(y);
      //--- Altera o valor de localização da barra de rolagem
      CalculateThumbPos();
      return(true);
     }
//---
   return(false);
  }

O método CScrollV::CalculateThumbPos() converte a coordenada Y em um número do elemento da lista. Nós também precisamos de um método para fazer a conversão inversa, que é o de calcular coordenada Y em relação a posição atual da barra de rolagem. Aqui, existem também as verificações caso ocorra de exceder a área de trabalho e seu devido ajuste. No final do método, as coordenadas e as margens do objeto são atualizados. 

class CScrollV : public CScroll
  {
public:
   //--- Cálculo da coordenada Y da barra de rolagem
   void              CalculateThumbY(void);
  };
//+------------------------------------------------------------------+
//| Cálculo da coordenada Y da barra de rolagem                      |
//+------------------------------------------------------------------+
void CScrollV::CalculateThumbY(void)
  {
//--- Identifica a coordenada Y atual da barra de rolagem
   int scroll_thumb_y=int(m_bg.Y()+(CScroll::CurrentPos()*CScroll::m_thumb_step_size));
//--- Se a superfície de trabalho foi excedida para cima
   if(scroll_thumb_y<=m_bg.Y())
      scroll_thumb_y=m_bg.Y();
//--- Se a superfície de trabalho foi excedida para baixo
   if(scroll_thumb_y+CScroll::m_thumb_length>=m_bg.Y2() || 
      CScroll::CurrentPos()>=CScroll::m_thumb_steps_total-1)
     {
      scroll_thumb_y=int(m_bg.Y2()-CScroll::m_thumb_length);
     }
//--- Atualiza a coordenada e a margem ao longo do eixo Y
   m_thumb.Y(scroll_thumb_y);
   m_thumb.Y_Distance(scroll_thumb_y);
   m_thumb.YGap(m_thumb.Y()-m_wnd.Y());
  }

O método CScrollV::CalculateThumbY() será chamado nos métodos que manipulam o pressionamento sobre os botões na barra de rolagem, como é mostrado no código abaixo. O nome do objeto é o único argumento que é passado para os métodos CScrollV::OnClickScrollInc() e CScrollV::OnClickScrollDec(). Os seguintes parâmetros são controlados no início do método.

  • Se este botão foi pressionado. Verifique pelo nome do objeto.
  • Estado da barra de rolagem. Para ser passado na verificação, o modo deve ser livre.
  • O número de passos deve ser definido e este valor não pode ser inferior a um.

Se foi passado em todas as verificações, então a posição é alterada por um passo, considerando que a faixa de trabalho não pode ser ultrapassada. Depois disso, no método CScrollV::CalculateThumbY() a coordenada Y é calculada e atualizada, bem como as margens a partir da borda do formulário. O botão deve ficar no estado ligado após ter sido pressionado.

class CScrollV : public CScroll
  {
public:
   //--- Manipulando o pressionamento dos botões de barra de rolagem
   bool              OnClickScrollInc(const string clicked_object);
   bool              OnClickScrollDec(const string clicked_object);
  };
//+------------------------------------------------------------------+
//| Manipulando o pressionamento dos botões de barra de rolagem      |
//+------------------------------------------------------------------+
bool CScrollV::OnClickScrollInc(const string clicked_object)
  {
//--- Sai, se o pressionamento não foi neste objeto ou a barra de rolagem está inativa ou o número de passos não foi identificado
   if(m_inc.Name()!=clicked_object || CScroll::ScrollState() || CScroll::m_thumb_steps_total<1)
      return(false);
//--- Diminui o valor da posição da barra de rolagem
   if(CScroll::CurrentPos()>0)
      CScroll::m_current_pos--;
//--- Cálculo da coordenada Y da barra de rolagem
   CalculateThumbY();
//--- Define o estado ligado
   m_inc.State(true);
   return(true);
  }
//+------------------------------------------------------------------+
//| Manipulando o pressionamento para direita esquerda               |
//+------------------------------------------------------------------+
bool CScrollV::OnClickScrollDec(const string clicked_object)
  {
//--- Sai, se o pressionamento não foi neste objeto ou a barra de rolagem está inativa ou o número de passos não foi identificado
   if(m_dec.Name()!=clicked_object || CScroll::ScrollState() || CScroll::m_thumb_steps_total<1)
      return(false);
//--- Aumenta o valor da posição da barra de rolagem
   if(CScroll::CurrentPos()<CScroll::m_thumb_steps_total-1)
      CScroll::m_current_pos++;
//--- Cálculo da coordenada Y da barra de rolagem
   CalculateThumbY();
//--- Define o estado ligado
   m_dec.State(true);
   return(true);
  }

Terminamos o desenvolvimento dos métodos necessários para gerenciar a barra de rolagem vertical. Os mesmos métodos são utilizados para o tipo horizontal, com exceção dos cálculos que são feitos na coordenada X

 


Conclusão

Neste capítulo, nós discutimos as barras de rolagem vertical e horizontal. No artigo a seguir, estaremos desenvolvendo um outro elemento da interface gráfica - a lista. O número dos elementos da lista pode não caber no espaço disponível e, nesse caso, será necessário o controle barra de rolagem que nós desenvolvemos neste artigo.

Você pode baixar o material da parte V e testar o seu funcionamento. Se você tiver dúvidas sobre a utilização do material a partir desses arquivos, você poderá consultar a descrição detalhada do desenvolvimento da biblioteca em um dos artigos da lista abaixo ou fazer sua pergunta nos comentários deste artigo.

Lista de artigos da quinta parte:

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

Arquivos anexados |
Avaliação da eficácia dos sistemas de negociação pela análise de seus componentes Avaliação da eficácia dos sistemas de negociação pela análise de seus componentes
Este artigo explora a eficácia dos sistemas de negociação complexos pela análise da eficiência de seus componentes individuais. Qualquer análise é um dos componentes-chave de sucesso em negociação nos mercados financeiros, seja gráfica, com base em indicadores, ou qualquer outro. Portanto, de certa maneira, este arquivo é uma pesquisa sobre alguns sistemas de negociação simples e independentes, no qual podemos analisar a sua eficácia em conjunto com a utilidade da aplicação.
Expressões regulares para traders Expressões regulares para traders
As expressões regulares são uma linguagem especial para manipulação de textos de acordo com uma regra definida, às vezes, chamada de padrão ou máscara de expressão regular. Este artigo mostrará como manipular o relatório de negociação usando a biblioteca RegularExpressions para MQL5 e demostrará seus resultados de otimização.
Módulo de sinais de negociação utilizando o sistema Bill Williams Módulo de sinais de negociação utilizando o sistema Bill Williams
O artigo descreve as regras do sistema de negociação Bill Williams, o procedimento da aplicação de um módulo MQL5 desenvolvido com o objetivo de procurar e marcar padrões deste sistema no gráfico, as negociações automatizadas de acordo com os padrões encontrados e por fim, apresenta os resultados dos testes em vários instrumentos de negociação.
Expert Advisor Universal: Integração com os Módulos de Sinais Padrão do MetaTrader (parte 7) Expert Advisor Universal: Integração com os Módulos de Sinais Padrão do MetaTrader (parte 7)
Esta parte do artigo descreve as possibilidades de integração do motor CStrategy com os módulos de sinais incluídos na biblioteca padrão no MetaTrader. O artigo descreve como trabalhar com sinais, assim como demonstra uma forma de criar estratégias personalizadas com base nas mesmas.