Interfaces Gráficas X: Caixa de Edição de Texto, Slider de Imagens e Controles Simples (build 5)
Conteúdo
- Introdução
- O Controle Caixa de Edição de Texto
- Classe para a criação do controle Caixa de Edição de Texto
- O Controle Slider de Imagem
- Classe para a criação do controle Slider de Imagem
- Os Controles Rótulo de Texto e Imagem
- Classe CFonts para trabalhar com as fontes de texto
- Lista de atualizações adicionais da biblioteca
- Aplicação para testar os controles
- Conclusão
Introdução
A fim de obter uma melhor compreensão do propósito desta biblioteca, leia por favor o primeiro artigo: Interfaces Gráficas I: Preparação da Estrutura da Biblioteca (Capítulo 1). Você irã encontrar uma lista de artigos com os links no final de cada capítulo. Lá, você também pode encontrar e baixar a versão completa da biblioteca, no estágio de desenvolvimento atual. Os arquivos devem estar localizados nas mesmas pastas que o arquivo baixado.
Este artigo irá considerar novos controles: A Caixa de Edição de Texto, o Slider de Imagem, bem como os controles simples adicionais: Rótulo de Texto e Imagem, que poderá ser útil em vários casos. A biblioteca continua a crescer, e, além da introdução de novos controles, aqueles que foram criados anteriormente também estão sendo melhorados. Como, atualmente, a biblioteca é utilizada por um grande número de pessoas, várias observações e sugestões foram recebidas. Muitos dessas solicitações foram implementadas na nova versão da biblioteca. Além disso, alguns algoritmos foram otimizados. Isso reduziu ainda mais a carga da CPU. Mais detalhes sobre isto se encontrará mais adiante no artigo.
O Controle Caixa de Edição de Texto
Até agora, a biblioteca desenvolvida já contém um controle Caixa de edição (a classe CSpinEdit), mas ela foi projetada para entrar apenas com os valores numéricos. Agora, a biblioteca será complementada com um outro controle, na qual permitiria que qualquer texto seja inserido no campo. O controle Caixa de Edição de Texto pode ser necessário em diferentes situações. Por exemplo, é possível criar uma string de pesquisa nos arquivos do "ambiente protegido" do terminal. Outra opção consiste em proporcionar ao usuário final da aplicação MQL a capacidade de inserir um array de símbolos para a negociação. Em suma, este pode ser qualquer dado de texto necessário para o trabalho.
Vamos enumerar todos os componentes do controle Caixa de Edição de Texto:
- Fundo
- Ícone
- Descrição
- Caixa de edição
Fig. 1. Componentes do controle Caixa de Edição de texto.
Vamos dar uma olhada mais a fundo na classe deste controle.
Classe para a criação do controle Caixa de Edição de Texto
Cria o arquivo TextEdit.mqh com a classe CTextEdit que tem os métodos padrão para todos os controles e inclui ele no motor da biblioteca (o arquivo WndContainer.mqh). Abaixo estão as propriedades do controle que estão disponíveis ao usuário para personalização:
- Cor de fundo do controle
- Ícones do controle para os estados ativo e bloqueado
- Margens do ícone ao longo dos dois eixos (x, y)
- Descrição de texto do controle
- Margens para o rótulo de texto ao longo dos dois eixos (x, y)
- Cor do texto em diferentes estados do controle
- Tamanho da Caixa de Edição
- Margens para a Caixa de Edição ao longo dos dois eixos (x, y)
- Cores da Caixa de Edição e do texto da Caixa de Edição em estados diferentes
- Alinhamento do texto na Caixa de Edição (esquerda/direita/centro)
- Modo de exibição do cursor de seleção de texto
- Modo de resetar o valor na Caixa de Edição
//| Classe para a criação de caixa de edição de texto |
//+------------------------------------------------------------------+
class CTextEdit : public CElement
{
private:
//--- Cor de fundo do controle
color m_area_color;
//--- Ícones da caixa de seleção nos estados ativo e bloqueado
string m_icon_file_on;
string m_icon_file_off;
//--- Margens do ícone
int m_icon_x_gap;
int m_icon_y_gap;
//--- Texto da descrição da Caixa de Edição
string m_label_text;
//--- Margens do rótulo de texto
int m_label_x_gap;
int m_label_y_gap;
//--- Cor do texto em diferentes estados
color m_label_color;
color m_label_color_hover;
color m_label_color_locked;
color m_label_color_array[];
//--- Valor atual da Caixa de Edição
string m_edit_value;
//--- Tamanho da Caixa de Edição
int m_edit_x_size;
int m_edit_y_size;
//--- Margem para o Campo de Edição
int m_edit_x_gap;
int m_edit_y_gap;
//--- Cores da Caixa de Edição e do texto da Caixa de Edição em diferentes estados
color m_edit_color;
color m_edit_color_locked;
color m_edit_text_color;
color m_edit_text_color_locked;
color m_edit_text_color_highlight;
//--- Cores do quadro do campo de edição em diferentes estados
color m_edit_border_color;
color m_edit_border_color_hover;
color m_edit_border_color_locked;
color m_edit_border_color_array[];
//--- Modo de resetar o valor (string vazia)
bool m_reset_mode;
//--- Modo de exibição do ponteiro de seleção de texto
bool m_show_text_pointer_mode;
//--- Modo de alinhamento do texto
ENUM_ALIGN_MODE m_align_mode;
//---
public:
//--- Margens do ícone
void IconXGap(const int x_gap) { m_icon_x_gap=x_gap; }
void IconYGap(const int y_gap) { m_icon_y_gap=y_gap; }
//--- (1) Cor de fundo, (2) texto da descrição do caixa de edição, (3) margens do rótulo de texto
void AreaColor(const color clr) { m_area_color=clr; }
string LabelText(void) const { return(m_label.Description()); }
void LabelText(const string text) { m_label.Description(text); }
void LabelXGap(const int x_gap) { m_label_x_gap=x_gap; }
void LabelYGap(const int y_gap) { m_label_y_gap=y_gap; }
//--- Cores do rótulo de texto em diferentes estados
void LabelColor(const color clr) { m_label_color=clr; }
void LabelColorHover(const color clr) { m_label_color_hover=clr; }
void LabelColorLocked(const color clr) { m_label_color_locked=clr; }
//--- (1) Tamanho do campo de edição, (2) margem do campo de edição do lado direito
void EditXSize(const int x_size) { m_edit_x_size=x_size; }
void EditYSize(const int y_size) { m_edit_y_size=y_size; }
//--- Margins for the Edit box
void EditXGap(const int x_gap) { m_edit_x_gap=x_gap; }
void EditYGap(const int y_gap) { m_edit_y_gap=y_gap; }
//--- Cores da caixa de edição em diferentes estados
void EditColor(const color clr) { m_edit_color=clr; }
void EditColorLocked(const color clr) { m_edit_color_locked=clr; }
//--- Cores do texto do campo de edição em diferentes estados
void EditTextColor(const color clr) { m_edit_text_color=clr; }
void EditTextColorLocked(const color clr) { m_edit_text_color_locked=clr; }
void EditTextColorHighlight(const color clr) { m_edit_text_color_highlight=clr; }
//--- Cores do quadro do campo de edição em diferentes estados
void EditBorderColor(const color clr) { m_edit_border_color=clr; }
void EditBorderColorHover(const color clr) { m_edit_border_color_hover=clr; }
void EditBorderColorLocked(const color clr) { m_edit_border_color_locked=clr; }
// --- (1) Modo de resete ao pressionar o rótulo de texto, (2) o modo do ponteiro de seleção do texto de exibição
bool ResetMode(void) { return(m_reset_mode); }
void ResetMode(const bool mode) { m_reset_mode=mode; }
void ShowTextPointerMode(const bool mode) { m_show_text_pointer_mode=mode; }
//--- Modo de alinhamento do texto
void AlignMode(ENUM_ALIGN_MODE mode) { m_align_mode=mode; }
//--- Definir os ícones para o botão nos estados ativo e bloqueado
void IconFileOn(const string file_path);
void IconFileOff(const string file_path);
};
O modo de exibição do ponteiro de seleção de texto significa que o cursor do mouse será complementado por um ícone adicional quando se passa sobre a Caixa de Edição, indicando que o texto pode ser digitado lá. Para que isto funcione, foi adicionado mais um identificador (MP_TEXT_SELECT) à enumeração ENUM_MOUSE_POINTER.
//| Enumeração dos tipos de ponteiros |
//+------------------------------------------------------------------+
enum ENUM_MOUSE_POINTER
{
MP_CUSTOM =0,
MP_X_RESIZE =1,
MP_Y_RESIZE =2,
MP_XY1_RESIZE =3,
MP_XY2_RESIZE =4,
MP_X_SCROLL =5,
MP_Y_SCROLL =6,
MP_TEXT_SELECT =7
};
A adição correspondente foi feita na classe CPointer (veja o código abaixo). A imagem para o ícone do cursor de seleção do texto está disponível no arquivo do final do artigo.
//| Pointer.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
//--- Recursos
...
#resource "\\Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp"
//+------------------------------------------------------------------+
//| Define as imagens do cursor com base no tipo do cursor|
//+------------------------------------------------------------------+
void CPointer::SetPointerBmp(void)
{
switch(m_type)
{
case MP_X_RESIZE :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_x_rs_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_x_rs.bmp";
break;
case MP_Y_RESIZE :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_y_rs_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_y_rs.bmp";
break;
case MP_XY1_RESIZE :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_xy1_rs_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_xy1_rs.bmp";
break;
case MP_XY2_RESIZE :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_xy2_rs_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_xy2_rs.bmp";
break;
case MP_X_SCROLL :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_x_scroll_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_x_scroll.bmp";
break;
case MP_Y_SCROLL :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_y_scroll_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_y_scroll.bmp";
break;
case MP_TEXT_SELECT :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp";
break;
}
//--- Se o tipo personalizado (MP_CUSTOM) é especificado
if(m_file_on=="" || m_file_off=="")
::Print(__FUNCTION__," > Both icons must be set for the cursor!");
}
Para criar o controle Caixa de Edição de Texto, vamos precisar de cinco métodos privados e um público:
{
private:
//--- Objetos para a criação da Caixa de Edição
CRectLabel m_area;
CBmpLabel m_icon;
CLabel m_label;
CEdit m_edit;
CPointer m_text_select;
//---
public:
// --- Métodos para criar a Caixa de Edição de Texto
bool CreateTextEdit(const long chart_id,const int subwin,const string label_text,const int x,const int y);
//---
private:
bool CreateArea(void);
bool CreateIcon(void);
bool CreateLabel(void);
bool CreateEdit(void);
bool CreateTextSelectPointer(void);
};
O resto da classe CTextEdit não possui nada que nós já não estudamos nos artigos anteriores desta série. Portanto, você pode examinar suas capacidades por si próprio. A versão atual da Caixa de Edição de Texto tem um limite de 63 caracteres.
O Controle Slider de Imagem
O Slider de Imagem pertence aos controles de informação da interface gráfica. Ele é útil para criar um guia de referência rápida, onde as ilustrações mostram certas situações no gráfico de preços ou uma breve explicação sobre o propósito de um controle específico da interface gráfica na aplicação MQL utilizada.
Vamos enumerar todos os componentes do controle Slider de Imagem:
- Fundo
- Botões de seta do Slider
- Grupo de botões de radio
- Grupo de imagens associadas ao grupo de botões de radio
Fig. 2. Componentes do controle Slider de Imagem.
Classe para a criação do controle Slider de Imagem
Cria o arquivo PicturesSlider.mqh com os métodos convencionais presentes em outras classes e inclui ele no arquivo WndContainer.mqh. A seguir estão as propriedades do controle que podem ser personalizadas pelos usuários da biblioteca.
- Cor de fundo do controle
- Cor do controle quadro de fundo
- Margem para as imagens ao longo do eixo Y
- Margens para os botões do slider ao longo dos dois eixos (x, y)
- Margens para os botões de radio ao longo dos dois eixos (x, y)
- Margem entre os botões de radio
//| Classe para criar o Slider de Imagem |
//+------------------------------------------------------------------+
class CPicturesSlider : public CElement
{
private:
//--- Cor de fundo do controle e do quadro
color m_area_color;
color m_area_border_color;
//--- Margem para as imagens ao longo do eixo Y
int m_pictures_y_gap;
//--- Margens para os botões
int m_arrows_x_gap;
int m_arrows_y_gap;
//--- Margens para os botões de radio
int m_radio_buttons_x_gap;
int m_radio_buttons_y_gap;
int m_radio_buttons_x_offset;
//---
public:
//--- (1) Cor do fundo e (2) do fundo do quadro
void AreaColor(const color clr) { m_area_color=clr; }
void AreaBorderColor(const color clr) { m_area_border_color=clr; }
//--- Margens para os botões de seta
void ArrowsXGap(const int x_gap) { m_arrows_x_gap=x_gap; }
void ArrowsYGap(const int y_gap) { m_arrows_y_gap=y_gap; }
//--- Margem para as imagens ao longo do eixo Y
void PictureYGap(const int y_gap) { m_pictures_y_gap=y_gap; }
//--- (1) Margens dos botões de radio, (2) distância entre os botões de radio
void RadioButtonsXGap(const int x_gap) { m_radio_buttons_x_gap=x_gap; }
void RadioButtonsYGap(const int y_gap) { m_radio_buttons_y_gap=y_gap; }
void RadioButtonsXOffset(const int x_offset) { m_radio_buttons_x_offset=x_offset; }
};
Para criar o controle de Slider de Imagem, vamos precisar de cinco métodos privados e um público:
{
private:
//--- Objetos para criar o controle
CRectLabel m_area;
CBmpLabel m_pictures[];
CRadioButtons m_radio_buttons;
CIconButton m_left_arrow;
CIconButton m_right_arrow;
//---
public:
//--- Métodos para criar o Slider de Imagem
bool CreatePicturesSlider(const long chart_id,const int subwin,const int x,const int y);
//---
private:
bool CreateArea(void);
bool CreatePictures(void);
bool CreateRadioButtons(void);
bool CreateLeftArrow(void);
bool CreateRightArrow(void);
};
A largura do controle será calculada automaticamente, com base nos parâmetros definidos pelo usuário. Esses parâmetros incluem as margens do grupo de botões de radio a partir da borda esquerda do controle, que também se calcula a coordenada para o botão de seta para a direita do Slider de Imagem. A altura do controle depende também do tamanho das imagens. Supõe-se que os tamanhos da imagem serão o mesmo, de modo que os cálculos usam o tamanho da primeira imagem do grupo.
Antes de chamar o método principal para criar o controle, é necessário adicionar as imagens para um array usando o método CPicturesSlider::AddPicture(). Se o caminho para a imagem não está definida como um único argumento deste método, o caminho padrão será aplicado.
//| PicturesSlider.mqh |
//| Copyright 2016, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
...
//--- Imagem padrão
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp"
//+------------------------------------------------------------------+
//| Classe para criar a imagem Slider |
//+------------------------------------------------------------------+
class CPicturesSlider : public CElement
{
private:
//--- Array de imagens (caminho para fotos)
string m_file_path[];
<//--- Caminho padrão para a imagem
string m_default_path;
//---
public:
<//--- Adicionar imagem
void AddPicture(const string file_path="");
};
//+------------------------------------------------------------------+
//| Construtor |
//+------------------------------------------------------------------+
CPicturesSlider::CPicturesSlider(void) : m_default_path("Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp"),
m_area_color(clrNONE),
m_area_border_color(clrNONE),
m_arrows_x_gap(2),
m_arrows_y_gap(2),
m_radio_button_width(12),
m_radio_buttons_x_gap(25),
m_radio_buttons_y_gap(1),
m_radio_buttons_x_offset(20),
m_pictures_y_gap(25)
{
//--- Guarda o nome da classe do controle na classe base
CElement::ClassName(CLASS_NAME);
//--- Define as prioridades do botão esquerdo do mouse
m_zorder=0;
}
//+------------------------------------------------------------------+
//| Adiciona uma imagem |
//+------------------------------------------------------------------+
void CPicturesSlider::AddPicture(const string file_path="")
{
//--- Aumenta o tamanho do array por um elemento
int array_size=::ArraySize(m_pictures);
int new_size=array_size+1;
::ArrayResize(m_pictures,new_size);
::ArrayResize(m_file_path,new_size);
//--- Armazena os valores dos parâmetros passados
m_file_path[array_size]=(file_path=="")? m_default_path : file_path;
}
Para exibir uma imagem do grupo, utilize o método CPicturesSlider::SelectPicture(). Este método será chamado ao pressionar as teclas de setas e botões de radio no manipulador da classe CPicturesSlider.
{
public:
//--- Muda a imagem no índice especificado
void SelectPicture(const uint index);
};
//+------------------------------------------------------------------+
//| Especifica a imagem a ser exibida |
//+------------------------------------------------------------------+
void CPicturesSlider::SelectPicture(const uint index)
{
//--- Obtém o número de imagens
uint pictures_total=PicturesTotal();
//--- Se não houver nenhuma imagem no grupo, reporta
if(pictures_total<1)
{
::Print(__FUNCTION__," > This method is to be called, "
"if a group contains at least one picture! Use the CPicturesSlider::AddPicture() method");
return;
}
//--- Ajusta o valor do índice, se o tamanho do array for excedido
uint correct_index=(index>=pictures_total)? pictures_total-1 : index;
//--- Seleciona o botão de radio neste índice
m_radio_buttons.SelectRadioButton(correct_index);
//--- Muda para a imagem
for(uint i=0; i<pictures_total; i++)
{
if(i==correct_index)
m_pictures[i].Timeframes(OBJ_ALL_PERIODS);
else
m_pictures[i].Timeframes(OBJ_NO_PERIODS);
}
}
Ao pressionar os botões de seta, o manipulador de eventos do controle chama os métodos CPicturesSlider::OnClickLeftArrow() e CPicturesSlider::OnClickRightArrow(). A lista abaixo mostra o código se o método for para o botão esquerdo do mouse. Os eventos de clique nos botões do Slider de Imagem podem ser rastreados na classe personalizada da aplicação em MQL, se necessário.
{
public:
private:
//--- Manipulação do clique do botão esquerdo
bool OnClickLeftArrow(const string clicked_object);
//--- Manipulação do clique do botão direito
bool OnClickRightArrow(const string clicked_object);
};
//+------------------------------------------------------------------+
//| Clique no botão esquerdo do mouse |
//+------------------------------------------------------------------+
bool CPicturesSlider::OnClickLeftArrow(const string clicked_object)
{
//--- Sai, se o clique não estiver no botão
if(::StringFind(clicked_object,CElement::ProgramName()+"_icon_button_",0)<0)
return(false);
//--- Obtém o identificador do controle a partir do nome do objeto
int id=CElement::IdFromObjectName(clicked_object);
//--- Obtém o índice do controle do nome do objeto
int index=CElement::IndexFromObjectName(clicked_object);
//--- Sai, se os identificadores de controle não corresponderem
if(id!=CElement::Id())
return(false);
//--- Sai, se os índices do controle não corresponderem
if(index!=0)
return(false);
//--- Obtém o índice atual do botão de radio selecionado
int selected_radio_button=m_radio_buttons.SelectedButtonIndex();
//--- Muda a imagem
SelectPicture(--selected_radio_button);
//--- Envia uma mensagem sobre isso
::EventChartCustom(m_chart_id,ON_CLICK_BUTTON,CElement::Id(),CElement::Index(),"");
return(true);
}
Abaixo é exibido o código menor do manipulador de eventos para o Slider de Imagem. É evidente que os eventos de clique nos botões de radio do controle Slider são rastreados aqui também. É possível entender que um botão de radio em um grupo local foi clicado usando o identificador de controle, que é igual ao identificador do Slider de Imagem.
//| Manipulador de eventos |
//+------------------------------------------------------------------+
void CPicturesSlider::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Manipulação do evento de movimento do cursor
...
//--- Manipulação do evento de clique no botão de radio
if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
{
//--- Se este é um botão de radio do controle Slider, muda a imagem
if(lparam==CElement::Id())
SelectPicture(m_radio_buttons.SelectedButtonIndex());
//---
return;
}
//--- Manipulação do botão esquerdo do mouse sobre o objeto
if(id==CHARTEVENT_OBJECT_CLICK)
{
//--- Se um botão de seta do controle Slider for clicado, muda a imagem
if(OnClickLeftArrow(sparam))
return;
if(OnClickRightArrow(sparam))
return;
//---
return;
}
}
Os Controles Rótulo de Texto e Imagem
Como um suplemento, a biblioteca inclui agora duas novas classes CTextLabel e cPicture para a criação do rótulo de texto simples e controles de imagem. Eles podem ser utilizados como objetos separados, sem liga-los a qualquer outro controle. Seu conteúdo é muito simples. Na classe cPicture, os usuários podem alterar apenas uma propriedade - o caminho para a imagem. O método CPicture::Path() é utilizado para este objetivo. A menos que um caminho personalizado não seja especificado, então, será usado uma imagem padrão. A imagem pode ser alterada de forma programática a qualquer momento, mesmo depois de criar a interface gráfica da aplicação MQL.
//| Picture.mqh |
//| Copyright 2016, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
//--- Recursos
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp"
//+------------------------------------------------------------------+
//| Classe para a criação da imagem |
//+------------------------------------------------------------------+
class CPicture : public CElement
{
private:
//--- Caminho para a imagem
string m_path;
//---
public:
//--- Obtém/define o caminho para a imagem
string Path(void) const { return(m_path); }
void Path(const string path);
};
//+------------------------------------------------------------------+
//| Construtor |
//+------------------------------------------------------------------+
CPicture::CPicture(void) : m_path("Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp")
{
//--- Armazena o nome da classe de controle na classe base
CElement::ClassName(CLASS_NAME);
//--- Define as prioridades do botão esquerdo do mouse
m_zorder=0;
}
//+------------------------------------------------------------------+
//| Define a imagem |
//+------------------------------------------------------------------+
void CPicture::Path(const string path)
{
m_path=path;
m_picture.BmpFileOn("::"+path);
m_picture.BmpFileOff("::"+path);
}
Quanto ao controle do rótulo de texto, tudo é bastante simples e apenas quatro propriedades podem ser definidas pelo usuário:
- Texto do rótulo
- Cor do texto
- Fonte
- Tamanho da fonte
//| Classe para a criação de um rótulo de texto |
//+------------------------------------------------------------------+
class CTextLabel : public CElement
{
public:
//--- Obtém/define o texto do rótulo
string LabelText(void) const { return(m_label.Description()); }
void LabelText(const string text) { m_label.Description(text); }
//--- Define a (1) cor, (2) a fonte e (3) o tamanho da fonte do rótulo de texto
void LabelColor(const color clr) { m_label.Color(clr); }
void LabelFont(const string font) { m_label.Font(font); }
void LabelFontSize(const int size) { m_label.FontSize(size); }
};
Classe CFonts para trabalhar com as fontes de texto
Para facilitar a seleção da fonte, foi implementado uma classe adicional - CFonts. Ela contém 187 fontes. Essas são as fontes do sistema do terminal, que você provavelmente já viu listados nas configurações de certos objetos gráficos.
Fig. 3. Fontes do sistema do terminal.
O arquivo com as fontes (Fonts.mqh) está localizado na pasta "MetaTrader 5\MQL5\Include\EasyAndFastGUI\Fonts.mqh". Ele foi incluído no arquivo Objects.mqh para permitir o acesso total ao longo de todo o esquema da biblioteca:
//| Objects.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Enums.mqh"
#include "Defines.mqh"
#include "..\Fonts.mqh"
#include "..\Canvas\Charts\LineChart.mqh"
#include <ChartObjects\ChartObjectSubChart.mqh>
#include <ChartObjects\ChartObjectsBmpControls.mqh>
#include <ChartObjects\ChartObjectsTxtControls.mqh>
A classe CFonts contém apenas dois métodos públicos para obter o tamanho do array de fontes e obter o nome da fonte pelo índice. O array de fontes é inicializado no construtor da classe.
//| Fonts.mqh |
//| Copyright 2016, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Classe para trabalhar com a fonte |
//+------------------------------------------------------------------+
class CFonts
{
private:
//--- Array de fontes
string m_fonts[];
//---
public:
CFonts(void);
~CFonts(void);
//--- Retorna o número de tipos de fontes
int FontsTotal(void) const { return(::ArraySize(m_fonts)); }
//--- Retorna a fonte pelo índice
string FontsByIndex(const uint index);
//---
private:
//--- Inicializa o array de fontes
void InitializeFontsArray(void);
};
//+------------------------------------------------------------------+
//| Construtor |
//+------------------------------------------------------------------+
CFonts::CFonts(void)
{
//--- Inicializa o array de fontes
InitializeFontsArray();
}
//+------------------------------------------------------------------+
//| Destrutor |
//+------------------------------------------------------------------+
CFonts::~CFonts(void)
{
::ArrayFree(m_fonts);
}
A Chamada do método CFonts::FontsByIndex() recorre ao ajuste que impede que o tamanho do array exceda:
//| Retorna a fonte pelo índice |
//+------------------------------------------------------------------+
string CFonts::FontsByIndex(const uint index)
{
//--- Tamanho do array
uint array_size=FontsTotal();
//--- Ajuste no caso do tamanho ter excedido
uint i=(index>=array_size)? array_size-1 : index;
//--- Retorna a fonte
return(m_fonts[i]);
}
Lista de atualizações adicionais da biblioteca
1. Corrigido a exibição incorreta das dicas de ferramentas nas caixas de diálogo. Agora, o estado pressionado do botão dicas de ferramentas na janela principal se aplica a todas as janelas da interface gráfica. Ao pressionar o botão, ele gera uma mensagem com o novo identificador de evento ON_WINDOW_TOOLTIPS (consulte o arquivo Defines.mqh).
//| Defines.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
...
#define ON_WINDOW_TOOLTIPS (29) // Clique no botão dicas de ferramentas
Por conseguinte, o método OnClickTooltipsButton() foi adicionado a classe CWindow para lidar com o botão de dicas de ferramentas:
//| Classe para criar um formulário para os controles |
//+------------------------------------------------------------------+
class CWindow : public CElement
{
private:
//--- Manipulação do evento de clique no botão dicas de ferramentas
bool OnClickTooltipsButton(const string clicked_object);
};
//+------------------------------------------------------------------+
//| Manipulador de eventos do gráfico |
//+------------------------------------------------------------------+
void CWindow::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Manipulação de eventos do clique em um objeto
if(id==CHARTEVENT_OBJECT_CLICK)
{
//--- Se o botão de dicas de ferramentas foi clicado
if(OnClickTooltipsButton(sparam))
return;
}
}
//+------------------------------------------------------------------+
//| Manipulação do evento de clique no botão dicas de ferramentas |
//+------------------------------------------------------------------+
bool CWindow::OnClickTooltipsButton(const string clicked_object)
{
//--- Este botão não é necessário, se a janela for uma caixa de diálogo
if(m_window_type==W_DIALOG)
return(false);
//--- Sai, se o clique não estiver no botão de radio
if(::StringFind(clicked_object,CElement::ProgramName()+"_window_tooltip_",0)<0)
return(false);
//--- Obtém o identificador do controle a partir do nome do objeto
int id=CElement::IdFromObjectName(clicked_object);
//--- Sai, se os identificadores do controle não corresponderem
if(id!=CElement::Id())
return(false);
//--- Armazena o estado no campo da classe
m_tooltips_button_state=m_button_tooltip.State();
//--- Envia uma mensagem sobre ele
::EventChartCustom(m_chart_id,ON_WINDOW_TOOLTIPS,CElement::Id(),CElement::Index(),"");
return(true);
}
Por que tudo isto funcione no motor da biblioteca (classe CWndEvents), o método OnWindowTooltips() para tratamento de eventos com o identificador ON_WINDOW_TOOLTIPS foi adicionado:
{
private:
//--- Ativar/desativar as dicas de ferramentas
bool OnWindowTooltips(void);
};
//+------------------------------------------------------------------+
//| 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
//--- Se o sinal for para redimensionar os controles ao longo do eixo Y
//--- Se o sinal for para ativar/desativar as dicas de ferramentas
if(OnWindowTooltips())
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
}
//+------------------------------------------------------------------+
//| Evento ON_WINDOW_TOOLTIPS |
//+------------------------------------------------------------------+
bool CWndEvents::OnWindowTooltips(void)
{
//--- Se o sinal for para "Ativar/desativar as dicas de ferramentas"
if(m_id!=CHARTEVENT_CUSTOM+ON_WINDOW_TOOLTIPS)
return(false);
//--- Se a janela de identificadores correspondem entre si
if(m_lparam!=m_windows[0].Id())
return(true);
//--- Sincroniza o modo de dicas de ferramentas em todas as janelas
int windows_total=WindowsTotal();
for(int w=0; w<windows_total; w++)
{
if(w>0)
m_windows[w].TooltipButtonState(m_windows[0].TooltipButtonState());
}
//---
return(true);
}
2. Adicionado a capacidade de mudar o texto na descrição dos seguintes controles adicionados depois de terem sido criados:
Fig. 4. Lista de controles com a capacidade de alterar o texto depois de terem sido criados.
3. Agora o ícone pode ser definido em todos os controles, onde ele pode ser necessário (veja a tabela abaixo). Além disso, foi adicionado a capacidade de alterar os ícones do controle após eles terem sido criados:
Fig. 5. Lista de controles com a capacidade de alterar o ícone, após eles terem sido criados.
Para substituir o ícone em todos os controlos listados na tabela acima, há os métodos IconFileOn() e IconFileOff().
4. Adicionado a capacidade de gerenciar de forma programática o estado de todos os tipos de botões e guias (pressionado/solto) depois de terem sido criados. A tabela abaixo mostra os controles que incluem esta adição:
Fig. 6. Lista de controles com a capacidade de alterar o estado (pressionado/solto) depois de terem sido criados.
5. Otimizado o algoritmo para destacar os itens quando o cursor está pairando sobre eles nos seguintes controles:
Fig. 7. Controles com o algoritmo otimizado para destacar os itens de controle.
Anteriormente, o programa iterava todos os itens nas listas dos controles acima, verificando a localização do cursor do mouse por cima deles. Assim, o item sob o cursor foi destacado em uma cor diferente, enquanto a cor padrão foi definida para o restante dos itens. Mas este método exige um recurso muito intensivo, de modo que havia uma necessidade para otimiza-lo. Agora, em vez dele ficar iterando em todo o conjunto de itens, apenas dois itens participam da mudança de cor. A pesquisa no ciclo só ocorre quando houver uma transição para outro item, ou seja, o foco foi alterado.
Além disso, como um exemplo, considere como este foi implementado na classe CListView. A Implementação acima requer a adição do campo da classe (1) m_prev_item_index_focus para armazenar o índice do último item focado, (2) o método CListView::CheckItemFocus() para verificar o foco sobre o item e (3) para alterar o algoritmo no método CListView::ChangeItemsColor().
//| Classe para criar uma lista |
//+------------------------------------------------------------------+
class CListView : public CElement
{
private:
//--- Para determinar o momento de transição do cursor do mouse de um item para o outro
int m_prev_item_index_focus;
//---
private:
//--- Mudando a cor dos itens da lista quando o cursor está pairando sobre eles
void ChangeItemsColor(void);
//--- Verificando o foco da lista dos itens da lista quando o cursor está pairado
void CheckItemFocus(void);
};
O método CListView::CheckItemFocus() é chamado somente quando o cursor do mouse entra na área de controle (neste caso - CListView), e também quando o cursor do mouse se move de um item para o outro (veja o código abaixo). Uma vez que o item com o mouse pairando nele for encontrado, o seu índice é armazenado.
//| Verifica o foco da lista de itens da lista quando o cursor está pairado |
//+------------------------------------------------------------------+
void CListView::CheckItemFocus(void)
{
//--- Obtém a posição atual do controle deslizante da barra de rolagem
int v=m_scrollv.CurrentPos();
//--- Identifica sobre qual item o cursor está e destaca-o
for(int i=0; i<m_visible_items_total; i++)
{
//--- Aumenta o contador se o tamanho da lista não for excedido
if(v>=0 && v<m_items_total)
v++;
//--- Pula o elemento selecionado
if(m_selected_item_index==v-1)
{
m_items[i].BackColor(m_item_color_selected);
m_items[i].Color(m_item_text_color_selected);
continue;
}
//--- Se o cursor está sobre este elemento, destaca-o
if(m_mouse.X()>m_items[i].X() && m_mouse.X()<m_items[i].X2() &&
m_mouse.Y()>m_items[i].Y() && m_mouse.Y()<m_items[i].Y2())
{
m_items[i].BackColor(m_item_color_hover);
m_items[i].Color(m_item_text_color_hover);
//--- Lembrando do elemento
m_prev_item_index_focus=i;
break;
}
}
}
O método CListView::CheckItemFocus() é chamado de dentro do método CListView::ChangeItemsColor() nos casos descritos no parágrafo anterior (veja o código abaixo):
//| Mudando a cor da lista de itens da lista quando o cursor está pairado |
//+------------------------------------------------------------------+
void CListView::ChangeItemsColor(void)
{
//--- Sai, se o realce do item quando o cursor está pairando sobre ele está desativado ou a barra de rolagem está ativa
if(!m_lights_hover || m_scrollv.ScrollState())
return;
//--- Sai, se não for um elemento suspenso e o formulário está bloqueado
if(!CElement::IsDropdown() && m_wnd.IsLocked())
return;
//--- Se entrou na lista novamente
if(m_prev_item_index_focus==WRONG_VALUE)
{
//--- Verifica o foco no item atual
CheckItemFocus();
}
else
{
//--- Verifica o foco na linha atual
int i=m_prev_item_index_focus;
bool condition=m_mouse.X()>m_items[i].X() && m_mouse.X()<m_items[i].X2() &&
m_mouse.Y()>m_items[i].Y() && m_mouse.Y()<m_items[i].Y2();
//--- Se mudou para outro item
if(!condition)
{
//--- Reseta a cor do elemento de menu
m_items[i].BackColor(m_item_color);
m_items[i].Color(m_item_text_color);
m_prev_item_index_focus=WRONG_VALUE;
//--- Verifica o foco no item atual
CheckItemFocus();
}
}
}
No manipulador de evento CListView::OnEvent(), o método CListView::ChangeItemsColor() é chamado somente quando o cursor do mouse está localizado dentro da área do controle. Assim que o cursor sair da área de controle, as cores padrão são definidas, e o valor do índice do item é resetado. A versão curta do manipulador de eventos é mostrada abaixo.
//| Manipulador de eventos |
//+------------------------------------------------------------------+
void CListView::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Manipulação do evento de movimento do cursor
if(id==CHARTEVENT_MOUSE_MOVE)
{
//--- Sai se o elemento está oculto
//--- Sai, se os números das sub-janelas não corresponderem
//--- Verificando o foco sobre os elementos
//--- Se esta é uma lista suspensa e o botão do mouse foi pressionado
//--- Mova a lista se a gestão do controle slider for habilitado
//--- Reseta a cor do elemento, se não estiver em foco
if(!CElement::MouseFocus())
{
//--- Se o item já está em foco
if(m_prev_item_index_focus!=WRONG_VALUE)
{
//--- Reseta a cor da lista
ResetColors();
m_prev_item_index_focus=WRONG_VALUE;
}
return;
}
//--- Muda a cor dos itens da lista quando o cursor está pairando sobre ele
ChangeItemsColor();
return;
}
}
O mesmo princípio foi aplicado nas classes CTable, CCalendar e CTreeView, mas com algumas diferenças que levam em conta as peculiaridades de cada controle.
6. Pressionando um botão do tipo CIconButton no modo de dois estados (quando o botão não é liberado após o clique), ele mostra um ícone diferente, se estiver definido. O ícone para o botão pressionado pode ser definido usando os métodos CIconButton::IconFilePressedOn() e CIconButton::IconFilePressedOff().
//| Classe para criar um botão de Ícone |
//+------------------------------------------------------------------+
class CIconButton : public CElement
{
private:
//--- Ícones para o botão em estados ativos, bloqueados e pressionados
string m_icon_file_on;
string m_icon_file_off;
string m_icon_file_pressed_on;
string m_icon_file_pressed_off;
//---
public:
//--- Definindo os ícones para o botão nos estados pressionados, ativos e bloqueados
void IconFileOn(const string file_path);
void IconFileOff(const string file_path);
void IconFilePressedOn(const string file_path);
void IconFilePressedOff(const string file_path);
};
//+------------------------------------------------------------------+
//| Define o ícone para o estado pressionado "ON" |
//+------------------------------------------------------------------+
void CIconButton::IconFilePressedOn(const string file_path)
{
//--- Sai, se o modo de dois estados estiver desativado para o botão
if(!m_two_state)
return;
//--- Armazena o caminho para a imagem
m_icon_file_pressed_on=file_path;
//--- Determina imediatamente se o botão é pressionado
if(m_button.State())
m_icon.BmpFileOn("::"+file_path);
}
//+------------------------------------------------------------------+
//| Define o ícone para o estado pressionado "OFF" |
//+------------------------------------------------------------------+
void CIconButton::IconFilePressedOff(const string file_path)
{
//--- Sai, se o modo de dois estados estiver desativado para o botão
if(!m_two_state)
return;
//--- Armazena o caminho para a imagem
m_icon_file_pressed_off=file_path;
//--- Determina imediatamente se o botão é pressionado
if(m_button.State())
m_icon.BmpFileOff("::"+file_path);
}
7. Adicionado a capacidade de selecionar programaticamente uma linha na tabela (CTable). Para fazer isso, use o método CTable::SelectRow(). Especificando o índice de uma linha já selecionada, ela é desmarcada.
//| Classe para a criação de uma tabela da caixa de edição |
//+------------------------------------------------------------------+
class CTable : public CElement
{
public:
//--- Escolha uma linha específica da tabela
void SelectRow(const uint row_index);
};
//+------------------------------------------------------------------+
//| Seleciona a linha especificada da tabela |
//+------------------------------------------------------------------+
void CTable::SelectRow(const uint row_index)
{
//--- Ajuste no caso do tamanho ser excedido
uint index=(row_index>=(uint)m_rows_total)? m_rows_total-1 : row_index;
//--- Se esta linha estiver selecionada, desmarque-a
bool is_selected=(index==m_selected_item);
//--- Armazena o índice de linha
m_selected_item=(is_selected)? WRONG_VALUE : (int)index;
//--- Armazena a linha da célula
m_selected_item_text=(is_selected)? "" : m_vcolumns[0].m_vrows[index];
//--- Gera uma string com os parâmetros da célula
string cell_params=string(0)+"_"+string(index)+"_"+m_vcolumns[0].m_vrows[index];
//--- Reseta o foco
m_prev_item_index_focus=WRONG_VALUE;
//--- Atualiza a tabela
UpdateTable();
//--- Destaca uma linha selecionada
HighlightSelectedItem();
}
8. Corrigido um problema com a exibição dos elementos em uma guia selecionada do controle CIconTabs. O problema ocorria ao abrir e maximizando um formulário com este tipo de guias.
Aplicação para testar os controles
Vamos escrever um aplicativo de teste, onde você pode testar todos os novos controles e praticar por si próprio, avaliando os seus diferentes modos. Na interface gráfica da aplicação, crie um controle Tabs (classe CTabs), que conterá quatro guias com o seguinte conteúdo:
1. A primeira guia:
- Barra de progresso (CProgressBar).
- Caixa de edição de texto(CTextEdit).
- Combobox com uma lista suspensa (CComboBox).
- Campo de edição para valores numéricos (CSpinEdit).
- Botão para chamar o seletor de cores (CColorButton).
- Rótulo de texto (CTextLabel).
Define um ícone para todos os controles, exceto o rótulo de texto. As descrições dos controles barra de progresso e da caixa de edição de texto serão alterados em intervalos de tempo regulares, a fim de demonstrar que tal recurso já está disponível. Coloque o nome de todas as fontes da classe CFonts para a lista da caixa de combinação. O modelo de evento da aplicação de teste MQL será construída de tal forma que a seleção de uma fonte na caixa de combinação é refletida no rótulo de texto. Da mesma forma, o rótulo de texto será ligado a caixa de edição numérica para mudar o tamanho da fonte e a seleção de cor no seletor.
O manipulador de eventos para gerenciar os parâmetros do controle Rótulo de texto ficará da seguinte forma:
//| Chart event handler |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Evento de seleção da lista combobox
if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM)
{
//--- Se os identificadores de controle correspondem entre si
if(lparam==m_combobox1.Id())
{
//--- Altera a fonte
m_text_label1.LabelFont(m_combobox1.ButtonText());
}
//---
return;
}
//--- Evento do clique nos botões caixa de edição
if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC ||
id==CHARTEVENT_CUSTOM+ON_CLICK_DEC)
{
//--- Se os identificadores de controle correspondem entre si
if(lparam==m_spin_edit1.Id())
{
//--- Altera o tamanho da fonte
m_text_label1.LabelFontSize(int(m_spin_edit1.GetValue()));
}
//---
return;
}
//--- Evento de mudar a cor usando o seletor de cores
if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
{
//--- Se os identificadores do controle correspondem entre si
if(lparam==m_spin_edit1.Id())
{
//--- Altera o tamanho da fonte
m_text_label1.LabelFontSize(int(m_spin_edit1.GetValue()));
}
//---
return;
}
//--- Evento de mudar a cor usando o seletor de cores
if(id==CHARTEVENT_CUSTOM+ON_CHANGE_COLOR)
{
//--- Se os identificadores de controle correspondem entre si
if(lparam==m_color_picker.Id())
{
//--- Se a resposta é a partir do primeiro botão
if(sparam==m_color_button1.LabelText())
{
//--- Muda a cor do objeto
m_text_label1.LabelColor(m_color_button1.CurrentColor());
return;
}
}
return;
}
//--- O evento de pressionamento do botão
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
{
//--- Se o primeiro botão para chamar o seletor de cores foi pressionado
if(sparam==m_color_button1.LabelText())
{
//--- Passa o ponteiro do botão, que abre automaticamente a janela com o seletor de cores
m_color_picker.ColorButtonPointer(m_color_button1);
return;
}
//---
return;
}
}
A imagem abaixo mostra como a visualização do texto pode ser configurada usando a interface gráfica.
Fig. 8. Grupo de controles na primeira guia.
2. Apenas um controle - o Slider de Imagem (classe CPicturesSlider) será colocada na segunda aba. Apenas três imagens padrão serão adicionadas ao grupo, de modo que você pode testar rapidamente esse controle por si próprio. Para o controle funcionar corretamente, prepare as imagens com o mesmo tamanho.
Fig. 9. O controle Slider de Imagem na segunda guia.
Para alternar programaticamente as imagens, use o método CPicturesSlider::SelectPicture().
3. A terceira guia irá conter uma tabela do tipo CTable. Para programaticamente selecionar uma linha, use o método CTable::SelectRow().
Fig. 10. O controle Table na terceira guia.
4. Três controles serão localizados na quarta guia: (1) calendário, (2) calendário suspenso e (3) um botão com dois ícones diferentes para os estados pressionado/liberado.
Fig. 11. Grupo de controles sobre a quarta 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. 12. Estrutura da biblioteca no atual estágio de desenvolvimento.
Na próxima versão, a biblioteca será expandida com controles adicionais. Além disso, os controles existentes continuarão a serem desenvolvidos e ampliados com novas funcionalidades.
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.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/2829
- 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