
Interfaces Gráficas V: A Barra de Rolagem Vertical e Horizontal (Capítulo 1)
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.
- Fundo principal.
- Fundo da área do deslizador.
- Dois botões para mover os dados em um passo.
- 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.
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:
- Interfaces Gráficas V: A Barra de Rolagem Vertical e Horizontal (Capítulo 1)
- Interfaces Gráficas V: O Controle Lista (Capítulo 2)
- Interfaces Gráficas V: O Controle Combobox (Capítulo 3)
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/2379





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso