Interfaces Gráficas IX: O Controle Seletor de Cores (Capítulo 1)
Conteúdo
Introdução
Por favor, leia o primeiro artigo chamado Interfaces Gráficas I: Preparação da Estrutura da Biblioteca (Capítulo 1) para obter uma melhor compreensão da finalidade desta biblioteca. No final dos artigos de cada parte há uma lista de capítulos com os links, e você poderá baixar também uma versão completa da biblioteca no atual estágio de seu desenvolvimento. Os arquivos devem estar localizados nas mesmas pastas que o arquivo baixado.
A parte IX desta série irá descrever os seguintes elementos de controle e interface:
1. Primeiro capítulo:
- Controle seletor de cores (classe CColorPicker).
- Controle botão do seletor de cores (classe CColorButton).
2. Segundo capítulo:
- Controle barra de progresso (classe CProgressBar).
- Controle gráfico de linha (classe CLineGraph).
Haverá exemplos detalhados para todos os controlos mencionados acima, mostrando como eles poderão ser aplicados em uma aplicação personalizada.
Controle seletor de cores
Uma paleta de cores pode ser encontrada em várias aplicações que possuem uma opção para escolher a cor do objeto. Nos terminais de negociação MetaTrader, a paleta de cor pode ser usada para alterar rapidamente a cor dos controles em sua aplicação MQL. Por exemplo, ao criar um estúdio visual para as interfaces gráficas e as cores precisam ser definidas para cada controle, seria muito inconveniente fazê-la sem uma paleta de cores.
A paleta de cores é um elemento composto complexo do controle, que além da paleta atual exibir o modelo de cor selecionado, há também outros objetos e grupos de controles. As partes integrantes deste controle estão listadas abaixo.
- Fundo
- Paleta de cor que exibe um modelo de cor especificado
- Marcador da cor definida
- Marcador da cor selecionada
- Marcador da cor quando o mouse estiver sobre ela
- Grupo de botões de rádio com as caixas de edição para uma configuração manual dos componentes do modelo de cor
- Botão para cancelar a cor selecionada
- Botão para configurar (correção) a cor especificada no segundo marcador
Fig. 1. Partes componente do seletor de cor.
A imagem acima mostra que o grupo de botões de radio é dividido em três subgrupos, possuindo três botões de radio cada um. Cada subgrupo é um modelo de cor, e cada botão de radio é um componente deste modelo (coordenada da área de cores). A lista abaixo fornece a decifração das abreviações de todos os modelos de cores que serão utilizados durante a criação de uma paleta de cores para a biblioteca desenvolvida.
1. HSL modelo de cor:
- H - matiz. Faixa de valores a partir do 0 até 360.
- S - saturação. Faixa de valores a partir do 0 até 100.
- L - Luminosidade. Faixa de valores a partir do 0 até 100.
2. RGB modelo de cor:
- R - cor vermelha. Faixa de valores do 0 até 255.
- G - cor verde. Faixa de valores do 0 até 255.
- B - cor azul. Faixa dos valores do 0 até 255.
3. Lab modelo de cor:
- L - Luminância. Faixa de valores a partir do 0 até 100.
- a - Primeira coordenada cromática que define o tom de cor de verde para roxo. Faixa de valores de 128 até 127.
- b - Segunda coordenada cromática que define o tom de cor de azul para amarelo. Faixa de valores de 128 até 127.
Além disso, nós vamos analisar a classe CColorPicker para criar a paleta de cor.
Desenvolvimento da classe CColorPicker
Nós vamos criar o arquivo ColorPicker.mqh no mesmo diretório onde os arquivos dos controles restantes estão mantidos atualmente (<pasta de dados>\MQLX\Include\EasyAndFastGUI\Controls). Neste arquivo nós devemos criar a classe CColorPicker com os membros padrão como é mostrado no código abaixo:
//+------------------------------------------------------------------+ //| ColorPicker.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "Element.mqh" #include "Window.mqh" //+------------------------------------------------------------------+ //| Classe para a criação do seletor de cores | //+------------------------------------------------------------------+ class CColorPicker : public CElement { private: //--- Ponteiro para o formulário ao qual o controle será anexado CWindow *m_wnd; //--- public: CColorPicker(void); ~CColorPicker(void); //--- 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); //--- Mover o controle 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) Define (2), reseta as prioridades para o clique esquerdo do mouse virtual void SetZorders(void); virtual void ResetZorders(void); //--- Resetar a cor virtual void ResetColors(void) {} };
As seguintes propriedades estarão disponíveis para definir os objetos gráficos do controle:
- Cor de fundo do controle
- Cor da borda de fundo do controle
- Cor da borda da paleta de cores e dos marcadores
As propriedades dos objetos gráficos de outros controles podem ser alteradas após o recebimento do ponteiro.
class CColorPicker : public CElement { private: //--- Cor da (1) área e (2) da borda da área color m_area_color; color m_area_border_color; //--- Cor da borda da paleta color m_palette_border_color; //--- public: //--- Definição da cor (1) da área e (2) da borda da área (3), paleta da borda void AreaBackColor(const color clr) { m_area_color=clr; } void AreaBorderColor(const color clr) { m_area_border_color=clr; } void PaletteBorderColor(const color clr) { m_palette_border_color=clr; } };
Já que outros controles serão utilizadas como partes integrantes da paleta de cores, é necessário conectar os arquivos com as classes destes controles para o arquivo ColorPicker.mqh. Serão necessários de 17 métodos privados e um público para a criação da paleta de cores.
//+------------------------------------------------------------------+ //| ColorPicker.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "Element.mqh" #include "Window.mqh" #include "SpinEdit.mqh" #include "SimpleButton.mqh" #include "RadioButtons.mqh" //+------------------------------------------------------------------+ //| Classe para a criação das paleta de cores | //+------------------------------------------------------------------+ class CColorPicker : public CElement { private: //--- Objetos para criar o controle CRectLabel m_area; CRectCanvas m_canvas; CRectLabel m_current; CRectLabel m_picked; CRectLabel m_hover; //--- CRadioButtons m_radio_buttons; CSpinEdit m_hsl_h_edit; CSpinEdit m_hsl_s_edit; CSpinEdit m_hsl_l_edit; //--- CSpinEdit m_rgb_r_edit; CSpinEdit m_rgb_g_edit; CSpinEdit m_rgb_b_edit; //--- CSpinEdit m_lab_l_edit; CSpinEdit m_lab_a_edit; CSpinEdit m_lab_b_edit; //--- CSimpleButton m_button_ok; CSimpleButton m_button_cancel; //--- public: //--- Métodos para criar o controle bool CreateColorPicker(const long chart_id,const int subwin,const int x,const int y); //--- private: bool CreateArea(void); bool CreatePalette(void); bool CreateCurrentSample(void); bool CreatePickedSample(void); bool CreateHoverSample(void); bool CreateRadioButtons(void); bool CreateHslHEdit(void); bool CreateHslSEdit(void); bool CreateHslLEdit(void); bool CreateRgbREdit(void); bool CreateRgbGEdit(void); bool CreateRgbBEdit(void); bool CreateLabLEdit(void); bool CreateLabAEdit(void); bool CreateLabBEdit(void); bool CreateButtonOK(const string text); bool CreateButtonCancel(const string text); };
Alterando o botão de radio ao lado da paleta de cores, será exibido dois cortes dimensionais nas áreas de cor de acordo com o valor indicado do componente selecionado. Em outras palavras, para desenhar cada corte, primeiro você precisa fazer o cálculo em relação ao valor atual de seu componente. Portanto, nós vamos escrever três métodos distintos para cada modelo de cor. O índice do botão de radio selecionado será enviado para todos estes métodos (índice selecionado).
Para alterar a cor, nós usamos os métodos da instância da classe CColors que é declarado na classe base do controle (CElement). Não há um método apropriado na classe CColors para a conversão do formato RGB para Lab. Portanto, onde a conversão RGB->Lab é necessária, será preciso aplicar uma correção dupla através do modelo mestre de cor XYZ: RGB->XYZ->Lab. Para calcular e armazenar os valores dos componentes de todos os modelos de cores na classe CColorPicker, será necessário definir campos relevantes.
class CColorPicker : public CElement { private: //--- Valores dos componentes em modelos de cores diferentes: // HSL double m_hsl_h; double m_hsl_s; double m_hsl_l; //--- RGB double m_rgb_r; double m_rgb_g; double m_rgb_b; //--- Lab double m_lab_l; double m_lab_a; double m_lab_b; //--- XYZ double m_xyz_x; double m_xyz_y; double m_xyz_z; //--- private: //--- Desenha a paleta com base no modelo de cor HSL (0: H, 1: S, 2: L) void DrawHSL(const int index); //--- Desenha a paleta com base no modelo de cor RGB (3: R, 4: G, 5: B) void DrawRGB(const int index); //--- Desenha a paleta com base no modelo de cor LAB (6: G, 7: A, 8: b) void DrawLab(const int index); };
Como um exemplo, nós vamos fornecer aqui um código de apenas um destes métodos - CColorPicker::DrawHSL(), já que a única diferença entre eles é o cálculo preliminar do valor componente antes da alteração. O código de outros métodos está disponível a partir dos arquivos anexados neste artigo.
Os cálculos e desenhos são realizados para cada pixel da exibição. Por favor note que os cálculos são realizados em relação ao tamanho da paleta de cores. Ou seja, usando esse código você poderá criar um controle semelhante onde a paleta de cores pode ter um tamanho ou forma diferente (não necessariamente um quadrado).
Fig. 2. Exemplo da paleta de cores no tamanho de 500x255 pixels.
//+------------------------------------------------------------------+ //| Desenha a paleta HSL | //+------------------------------------------------------------------+ void CColorPicker::DrawHSL(const int index) { switch(index) { //--- Matiz (H) - tom de cor que varia de 0 a 360 case 0 : { //--- Cálculo do componente H m_hsl_h=m_hsl_h_edit.GetValue()/360.0; //--- for(int ly=0; ly<m_canvas.YSize(); ly++) { //--- Calculo do componente L m_hsl_l=ly/(double)m_canvas.YSize(); //--- for(int lx=0; lx<m_canvas.XSize(); lx++) { //--- Cálculo do componente S m_hsl_s=lx/(double)m_canvas.XSize(); //--- Conversão do componente HSL para o RGB m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b); //--- Liga os canais uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b); m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color); } } break; } //--- Saturação (S) - saturação na faixa de 0 a 100 case 1 : { //--- Cálculo do componente S m_hsl_s=m_hsl_s_edit.GetValue()/100.0; //--- for(int ly=0; ly<m_canvas.YSize(); ly++) { //--- Calculo do componente L m_hsl_l=ly/(double)m_canvas.YSize(); //--- for(int lx=0; lx<m_canvas.XSize(); lx++) { //--- Cálculo do componente H m_hsl_h=lx/(double)m_canvas.XSize(); //--- Conversão do componente HSL para o RGB m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b); //--- Liga os canais uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b); m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color); } } break; } //--- Luminosidade (L) - luminosidade no intervalo de 0 a 100 case 2 : { //--- Calculo do componente L m_hsl_l=m_hsl_l_edit.GetValue()/100.0; //--- for(int ly=0; ly<m_canvas.YSize(); ly++) { //--- Cálculo do componente S m_hsl_s=ly/(double)m_canvas.YSize(); //--- for(int lx=0; lx<m_canvas.XSize(); lx++) { //--- Cálculo do componente H m_hsl_h=lx/(double)m_canvas.XSize(); //--- Conversão do componente HSL para o RGB m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b); //--- Liga os canais uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b); m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color); } } break; } } }
Nós vamos escrever o método CColorPicker::DrawPaletteBorder() desenhar uma borda sobre a tela da paleta de cores:
class CColorPicker : public CElement { private: //--- Desenha a borda da paleta void DrawPaletteBorder(void); }; //+------------------------------------------------------------------+ //| Desenha a borda da paleta | //+------------------------------------------------------------------+ void CColorPicker::DrawPaletteBorder(void) { //--- Tamanho da paleta int x_size=m_canvas.XSize()-1; int y_size=m_canvas.YSize()-1; //--- Desenha a borda m_canvas.Line(0,0,x_size,0,m_palette_border_color); m_canvas.Line(0,y_size,x_size,y_size,m_palette_border_color); m_canvas.Line(0,0,0,y_size,m_palette_border_color); m_canvas.Line(x_size,0,x_size,y_size,m_palette_border_color); }
Todos os métodos acima mencionados para o desenho serão chamados eventualmente no método principal para desenhar a paleta de cores CColorPicker::DrawPalette()
class CColorPicker : public CElement { private: //--- Desenha a paleta void DrawPalette(const int index); }; //+------------------------------------------------------------------+ //| Desenha a paleta | //+------------------------------------------------------------------+ void CColorPicker::DrawPalette(const int index) { switch(index) { //--- HSL (0: H, 1: S, 2: L) case 0 : case 1 : case 2 : { DrawHSL(index); break; } //--- RGB (3: R, 4: G, 5: B) case 3 : case 4 : case 5 : { DrawRGB(index); break; } //--- LAB (6: L, 7: a, 8: b) case 6 : case 7 : case 8 : { DrawLab(index); break; } } //--- Desenha a borda da paleta DrawPaletteBorder(); //--- Atualiza a paleta m_canvas.Update(); }
Ao selecionar a cor da paleta ou configurar um componente de qualquer modelo de cor apresentado em um controle, os valores em todas as caixas de edição serão automaticamente recalculados. Nós exigimos os métodos que podem ser utilizados para calcular os componentes de todos os modelos de cores do controle em relação aquele cujo corte (botão de radio selecionado) é apresentado na paleta no momento atual.
Primeiramente, serão exigidos os métodos para corrigir os componentes RGB e os modelos HSL, que serão chamados em muitos outros métodos da classe:
class CColorPicker : public CElement { private: //--- Correção dos componentes RGB void AdjustmentComponentRGB(void); //--- Correção dos componentes HSL void AdjustmentComponentHSL(void); }; //+------------------------------------------------------------------+ //| Correção dos componentes RGB | //+------------------------------------------------------------------+ void CColorPicker::AdjustmentComponentRGB(void) { m_rgb_r=::fmin(::fmax(m_rgb_r,0),255); m_rgb_g=::fmin(::fmax(m_rgb_g,0),255); m_rgb_b=::fmin(::fmax(m_rgb_b,0),255); } //+------------------------------------------------------------------+ //| Correção dos componentes HSL | //+------------------------------------------------------------------+ void CColorPicker::AdjustmentComponentHSL(void) { m_hsl_h*=360; m_hsl_s*=100; m_hsl_l*=100; }
Após o cálculo de todos os componentes, nós precisamos definir os novos valores na caixa de edição. Em alguns casos, pode ser necessário (1) definir os valores de todos os componentes, e ocasionalmente (2) para todos além daquele selecionado no momento. Para essas situações, nós vamos escrever o método CColorPicker::SetControls() que pode funcionar em dois modos.
class CColorPicker : public CElement { private: //--- Definindo os parâmetros atuais nas caixas de edição void SetControls(const int index,const bool fix_selected); }; //+------------------------------------------------------------------+ //| Define os parâmetros atuais nas caixas de edição | //+------------------------------------------------------------------+ void CColorPicker::SetControls(const int index,const bool fix_selected) { //--- Se o valor precisar ser corrigido na caixa de edição do botão de radio selecionado if(fix_selected) { //--- Componentes HSL if(index!=0) m_hsl_h_edit.ChangeValue(m_hsl_h); if(index!=1) m_hsl_s_edit.ChangeValue(m_hsl_s); if(index!=2) m_hsl_l_edit.ChangeValue(m_hsl_l); //--- Componentes RGB if(index!=3) m_rgb_r_edit.ChangeValue(m_rgb_r); if(index!=4) m_rgb_g_edit.ChangeValue(m_rgb_g); if(index!=5) m_rgb_b_edit.ChangeValue(m_rgb_b); //--- Componentes Lab if(index!=6) m_lab_l_edit.ChangeValue(m_lab_l); if(index!=7) m_lab_a_edit.ChangeValue(m_lab_a); if(index!=8) m_lab_b_edit.ChangeValue(m_lab_b); return; } //--- Se for necessário corrigir os valores nas caixas de edição de todos os modelos de cores m_hsl_h_edit.ChangeValue(m_hsl_h); m_hsl_s_edit.ChangeValue(m_hsl_s); m_hsl_l_edit.ChangeValue(m_hsl_l); //--- m_rgb_r_edit.ChangeValue(m_rgb_r); m_rgb_g_edit.ChangeValue(m_rgb_g); m_rgb_b_edit.ChangeValue(m_rgb_b); //--- m_lab_l_edit.ChangeValue(m_lab_l); m_lab_a_edit.ChangeValue(m_lab_a); m_lab_b_edit.ChangeValue(m_lab_b); }
Para calcular os componentes de todos os modelos de cores do controle sobre aquele cujo corte (botão de radio selecionado) é exibido na paleta no momento atual, nós vamos escrever três métodos separados: CColorPicker::SetHSL(), CColorPicker::SetRGB() e CColorPicker::SetLab(). Já que estes métodos têm um conteúdo muito semelhante, apenas um código será fornecido aqui - CColorPicker::setRGB(). No início deste método nós obtemos os valores das caixas de edição do modelo RGB nos campos da classe. Os valores obtidos são convertidos para o formato HSL e Lab. No final nós chamamos o método CColorPicker::SetControls() no modo de definição dos valores para todos os modelos de cores do controle (false).
class CColorPicker : public CElement { private: //--- Definição dos parâmetros dos modelos de cores em relação ao (1) HSL, (2) RGB, (3) Lab void SetHSL(void); void SetRGB(void); void SetLab(void); }; //+------------------------------------------------------------------+ //| Definição dos parâmetros dos modelos de cores em relação ao RGB | //+------------------------------------------------------------------+ void CColorPicker::SetRGB(void) { //--- Obtém os valores atuais dos componentes RGB m_rgb_r=m_rgb_r_edit.GetValue(); m_rgb_g=m_rgb_g_edit.GetValue(); m_rgb_b=m_rgb_b_edit.GetValue(); //--- Conversão do componente RGB para os componentes HSL m_clr.RGBtoHSL(m_rgb_r,m_rgb_g,m_rgb_b,m_hsl_h,m_hsl_s,m_hsl_l); //--- Correção dos componentes HSL AdjustmentComponentHSL(); //--- Conversão do componente RGB para o componente Lab m_clr.RGBtoXYZ(m_rgb_r,m_rgb_g,m_rgb_b,m_xyz_x,m_xyz_y,m_xyz_z); m_clr.XYZtoCIELab(m_xyz_x,m_xyz_y,m_xyz_z,m_lab_l,m_lab_a,m_lab_b); //--- Definindo os parâmetros atuais nas caixas de edição SetControls(0,false); }
E, finalmente, o principal método é exigido quando todos os métodos mencionados acima para os cálculos, desenho e definição dos valores dos componentes são chamados na caixa de edição do controle. Aqui, ele é o método CColorPicker::SetComponents(). Ela também opera em dois modos. No caso do argumento fix_selected ser igual a true, então, os componentes serão calculados em relação à cor selecionada e a configuração dos valores na caixa de edição serão em relação ao botão de radio selecionado do componente. Se o argumento fix_selected ser igual a false, então o cálculo é feito em relação ao modelo da cor indicada. A paleta de cores é redesenhada após todos os cálculos.
class CColorPicker : public CElement { private: //--- Cálculo e definição dos componentes da cor void SetComponents(const int index,const bool fix_selected); }; //+------------------------------------------------------------------+ //| Cálculo e definição dos componentes da cor | //+------------------------------------------------------------------+ void CColorPicker::SetComponents(const int index=0,const bool fix_selected=true) { //--- Se for necessário corrigir as cores em relação ao botão de radio selecionado do componente if(fix_selected) { //--- Decomposição da cor selecionada para os componentes em RGB m_rgb_r=m_clr.GetR(m_picked_color); m_rgb_g=m_clr.GetG(m_picked_color); m_rgb_b=m_clr.GetB(m_picked_color); //--- Converte os componentes em RGB para os componentes em HSL m_clr.RGBtoHSL(m_rgb_r,m_rgb_g,m_rgb_b,m_hsl_h,m_hsl_s,m_hsl_l); //--- Correção dos componentes HSL AdjustmentComponentHSL(); //--- Converte os componentes em RGB para os componentes em LAB m_clr.RGBtoXYZ(m_rgb_r,m_rgb_g,m_rgb_b,m_xyz_x,m_xyz_y,m_xyz_z); m_clr.XYZtoCIELab(m_xyz_x,m_xyz_y,m_xyz_z,m_lab_l,m_lab_a,m_lab_b); //--- Define as cores nas caixas de edição SetControls(m_radio_buttons.SelectedButtonIndex(),true); return; } //--- Definição dos parâmetros dos modelos de cores switch(index) { case 0 : case 1 : case 2 : SetHSL(); break; case 3 : case 4 : case 5 : SetRGB(); break; case 6 : case 7 : case 8 : SetLab(); break; } //--- Desenha a paleta em relação ao botão de radio selecionado DrawPalette(m_radio_buttons.SelectedButtonIndex()); }
Para definir a cor atual da paleta que será atribuída a todos os objetos de marcador, nós escrevemos o método CColorPicker::CurrentColor(). O artigo revela ainda onde ele irá ser utilizado.
class CColorPicker : public CElement { public: //--- Definindo a cor selecionada pelo usuário a partir da paleta void CurrentColor(const color clr); }; //+------------------------------------------------------------------+ //| Definindo a cor atual | //+------------------------------------------------------------------+ void CColorPicker::CurrentColor(const color clr) { m_hover_color=clr; m_hover.Color(clr); m_hover.BackColor(clr); m_hover.Tooltip(::ColorToString(clr)); //--- m_picked_color=clr; m_picked.Color(clr); m_picked.BackColor(clr); m_picked.Tooltip(::ColorToString(clr)); //--- m_current_color=clr; m_current.BackColor(clr); m_current.Tooltip(::ColorToString(clr)); }
Todos os métodos de cálculos estão prontos. Procede com os métodos de manipulação de eventos do controle.
Métodos para a manipulação de eventos do controle
Serão necessários os seguintes métodos para a manipulação de eventos e gerenciamento das paletas de cores:
- O método CColorPicker::OnHoverColor() — obtém a cor (sobre a paleta) do cursor do mouse. O programa sai do método se o cursor do mouse estiver além da área da paleta. Se o cursor estiver em sua área, então, nós vamos definir suas coordenadas sobre ele e obter a cor do cursor do mouse. Imediatamente após isto, uma nova cor é definida para o marcador correspondente, e através do método ColorToString(), é estabelecido a dica de ferramentas nos objetos gráficos do marcador e da paleta de cores - string colorida no formato RGB.
//+------------------------------------------------------------------+ //| Obtém a cor do cursor do mouse | //+------------------------------------------------------------------+ bool CColorPicker::OnHoverColor(const int x,const int y) { //--- Sai se o foco não está na paleta if(!m_canvas.MouseFocus()) return(false); //--- Define a cor na paleta do cursor do mouse int lx =x-m_canvas.X(); int ly =y-m_canvas.Y(); m_hover_color=(color)::ColorToARGB(m_canvas.PixelGet(lx,ly),0); //--- Define a cor e a dica da ferramenta na amostra relevante (marcador) m_hover.Color(m_hover_color); m_hover.BackColor(m_hover_color); m_hover.Tooltip(::ColorToString(m_hover_color)); //--- Define a dica da ferramenta para a paleta m_canvas.Tooltip(::ColorToString(m_hover_color)); return(true); }
- O método CColorPicker::OnClickPalette() — lida com o clique na paleta de cores. No início do método o nome do objeto é verificado. Se o clique ocorre na paleta, então a cor do cursor do mouse e a dica para o marcador relevante são salvos e definido. Bem no final, o método CColorPicker::SetComponents() é chamado para calcular e configurar os componentes dos modelos de cores em relação ao botão de radio selecionado do componente.
//+------------------------------------------------------------------+ //| Manipula o clique na paleta de cores | //+------------------------------------------------------------------+ bool CColorPicker::OnClickPalette(const string clicked_object) { //--- Sai se o nome do objeto não corresponder if(clicked_object!=m_canvas.Name()) return(false); //--- Define a cor e a dica da ferramenta na amostra relevante (marcador) m_picked_color=m_hover_color; m_picked.Color(m_picked_color); m_picked.BackColor(m_picked_color); m_picked.Tooltip(::ColorToString(m_picked_color)); //--- Calcula e define os componentes da cor em relação ao botão de radio selecionado SetComponents(); return(true); }
- O método CColorPicker::OnClickRadioButton() — lida com o clique no botão de radio. Primeiramente, duas verificações devem ser realizadas: (1) pelo identificador do elemento e (2) pelo texto exibido do botão de radio. Se as verificações são passados, então, a paleta de cor é redesenhada em relação ao componente selecionado do modelo de cor na qual ele pertence.
//+------------------------------------------------------------------+ //| Manipula o clique no botão de radio | //+------------------------------------------------------------------+ bool CColorPicker::OnClickRadioButton(const long id,const int button_index,const string button_text) { //--- Sai se os identificadores não correspondem if(id!=CElement::Id()) return(false); //--- Sai se o texto do botão de radio não corresponde if(button_text!=m_radio_buttons.SelectedButtonText()) return(false); //--- Atualiza a paleta levando em consideração das últimas alterações DrawPalette(button_index); return(true); }
- O método CColorPicker::OnEndEdit() — lida com a entrada de um novo valor na caixa de edição. É suficiente ter uma única verificação pelo elemento do identificador, e após sua conclusão, os componentes de todos os modelos de cor são calculados em relação àquele que tem um componente do botão de radio selecionado.
//+------------------------------------------------------------------+ //| Lida com a entrada de um novo valor na caixa de edição | //+------------------------------------------------------------------+ bool CColorPicker::OnEndEdit(const long id,const int button_index) { //--- Sai se os identificadores não correspondem if(id!=CElement::Id()) return(false); //--- Calcula e define os componentes de cor para todos os modelos de cores SetComponents(button_index,false); return(true); }
- O método CColorPicker::OnClickButtonOK() — lida com o clique no botão 'OK'. Esta não é uma versão final do método, e ele ainda será alterado no artigo. A única coisa que nós precisamos saber no momento, é que ao clicar no botão, a cor selecionada é salva como a atual.
//+------------------------------------------------------------------+ //| Manipula o clique no botão "OK" | //+------------------------------------------------------------------+ bool CColorPicker::OnClickButtonOK(const string clicked_object) { //--- Sai se o nome do objeto não corresponder if(clicked_object!=m_button_ok.Text()) return(false); //--- Salva a cor selecionada m_current_color=m_picked_color; m_current.BackColor(m_current_color); m_current.Tooltip(::ColorToString(m_current_color)); return(true); }
- O método CColorPicker::OnClickButtonCancel() — lida com o clique no botão "Cancel". Há uma única verificação do nome do objeto neste método. Então, se a formulário que o controle é ligado possui um tipo de janela de diálogo, então ela é fechada.
//+------------------------------------------------------------------+ //| Manipula o clique no botão "Cancel" | //+------------------------------------------------------------------+ bool CColorPicker::OnClickButtonCancel(const string clicked_object) { //--- Sai se o nome do objeto não corresponder if(clicked_object!=m_button_cancel.Text()) return(false); //--- Fecha a janela se é uma janela de diálogo if(m_wnd.WindowType()==W_DIALOG) m_wnd.CloseDialogBox(); //--- return(true); }
Há um total de seis blocos no manipulador de eventos da paleta de cores CColorPicker::OnEvent(). Cada método da lista acima será chamado até a chegada do identificador de evento ser destinado a ele. Todo o código do manipulador de eventos estará disponível no código a seguir:
//+------------------------------------------------------------------+ //| Manipulador de evento do gráfico | //+------------------------------------------------------------------+ void CColorPicker::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Manipula o evento de mover o mouse if(id==CHARTEVENT_MOUSE_MOVE) { //--- Sai se o controle está oculto if(!CElement::IsVisible()) return; //--- Coordenadas e o estado do botão esquerdo do mouse int x=(int)lparam; int y=(int)dparam; m_mouse_state=(bool)int(sparam); CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2()); m_canvas.MouseFocus(x>m_canvas.X() && x<m_canvas.X2()-1 && y>m_canvas.Y() && y<m_canvas.Y2()-1); //--- Obtém a cor do cursor do mouse if(OnHoverColor(x,y)) return; //--- return; } //--- Manipula o evento de clicar no botão esquerdo do mouse sobre o objeto if(id==CHARTEVENT_OBJECT_CLICK) { //--- Se a paleta foi clicada if(OnClickPalette(sparam)) return; //--- return; } //--- Manipula a entrada de valores na caixa de edição if(id==CHARTEVENT_CUSTOM+ON_END_EDIT) { //--- Verifica a entrada do novo valor if(OnEndEdit(lparam,(int)dparam)) return; //--- return; } //--- Manipula o clique do controle if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL) { //--- Se botão foi clicado if(OnClickRadioButton(lparam,(int)dparam,sparam)) return; //--- return; } //--- Manipula o clique de alteração das caixas de edição if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC || id==CHARTEVENT_CUSTOM+ON_CLICK_DEC) { //--- Verifica a entrada do novo valor if(OnEndEdit(lparam,(int)dparam)) return; //--- return; } //--- Manipula o clique do botão do controle if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON) { //--- Sai se os identificadores não correspondem if(lparam!=CElement::Id()) return; //--- Se clicou no botão "OK" if(OnClickButtonOK(sparam)) return; //--- Se clicou no botão "Cancel" if(OnClickButtonCancel(sparam)) return; //--- return; } }
Muitos controles de biblioteca que foram desenvolvidos possuem o método FastSwitching(). Ele é normalmente utilizado para a troca rápida dos valores nas caixas de edição, barras de rolagem das listas ou tabelas. No entanto, aqui ele é necessário para redesenhar a paleta de cores quando a alteração rápida do contador do componente caixa de edição foi ativada. O código do método CColorPicker::FastSwitching() está disponível a partir dos arquivos ligados ao artigo.
Botão do seletor de cores
A classe para a criação da paleta de cores está pronto, mas ainda está faltando um elemento para a sua utilização plena. Nós precisamos de um botão que irá ser usado para chamar a janela com a paleta de cores. O botão deve ter uma opção para ver a cor definida no momento atual. Nós vamos escrever a classe para a criação de tal botão. A lista abaixo mostra as suas partes compostas.
- Área do controle
- Rótulo de texto com a descrição
- Indicador de cor selecionado
- Área do botão
- Descrição da cor selecionada no formato RGB
Fig. 3. Partes integrantes do botão para chamar uma paleta de cores.
Nos artigos anteriores nós já consideramos os controles semelhantes, por isso nós não iremos fornecer aqui uma descrição desta classe de código. Em vez disso, nós vamos avançar para a parte de interação entre o botão e a paleta de cores. Por favor, encontre o arquivo ColorButton.mqh com a classe CColorButton no arquivo anexado ao artigo para saber mais.
Nós precisamos conectar a paleta de cores com o botão para chamá-lo. Nós vamos fazer isso através do ponteiro do botão que irá ser armazenado na classe CColorPicker. Para este propósito nós conectamos o arquivo ColorButton.mqh para o arquivo ColorPicker.mqh e declaramos a instância da classe CColorButton onde o ponteiro para o botão para chamar a paleta de cores é armazenado.
//+------------------------------------------------------------------+ //| ColorPicker.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "Element.mqh" #include "Window.mqh" #include "SpinEdit.mqh" #include "SimpleButton.mqh" #include "RadioButtons.mqh" #include "ColorButton.mqh" //+------------------------------------------------------------------+ //| Classe para a criação do seletor de cores | //+------------------------------------------------------------------+ class CColorPicker : public CElement { private: //--- Ponteiro ao botão que chama o controle para a seleção da cor CColorButton *m_color_button; };
Será necessário também de um método público para armazenar o ponteiro para o botão. A fim de simplificar a interação entre o botão de chamada e a paleta, todos os marcadores da paleta serão atribuídos a uma cor atual do botão no envio do objeto do botão para armazenar seu ponteiro. Uma janela que tem uma paleta de cores conectada será aberta, então (veja o código abaixo).
class CColorPicker : public CElement { public: //--- Armazena o ponteiro para o botão que chama a paleta de cores void ColorButtonPointer(CColorButton &object); }; //+------------------------------------------------------------------+ //| Armazena o ponteiro para o botão que chama a paleta de cores e | //| a janela aberta que a paleta está ligada | //+------------------------------------------------------------------+ void CColorPicker::ColorButtonPointer(CColorButton &object) { //--- Armazena o ponteiro para o botão m_color_button=::GetPointer(object); //--- Define a cor do botão enviada a todos os marcadores da paleta CurrentColor(object.CurrentColor()); //--- Abre a janela que a paleta está ligada m_wnd.Show(); }
Além disso, nós iremos exigir os métodos para definir e obter a cor do botão. A cor definida aparecerá no marcador (indicador) do botão, e para obter informações adicionais no texto do botão, é exibido uma apresentação da string colorida no formato RGB.
class CColorButton : public CElement { public: //--- Retorna/define a cor atual do parâmetro color CurrentColor(void) const { return(m_current_color); } void CurrentColor(const color clr); }; //+------------------------------------------------------------------+ //| Altera a cor atual do parâmetro | //+------------------------------------------------------------------+ void CColorButton::CurrentColor(const color clr) { m_current_color=clr; m_button_icon.BackColor(clr); m_button_label.Description(::ColorToString(clr)); }
E uma pequena adição do método CColorPicker::OnClickButtonOK(). Se um ponteiro para o botão é definido em seguida:
- uma cor selecionada na paleta é definida para o botão;
- a janela que a paleta de cores está ligada pode ser fechada;
- a mensagem de que uma nova cor, selecionada na paleta, foi gerada. Um novo identificador do evento ON_CHANGE_COLOR contido no arquivo Defines.mqh é necessário aqui. Esta mensagem também irá conter (1) o Identificador do controle, (2) o índice do elemento e (3) o texto do botão que chamou paleta de cores. Dessa forma, você será capaz de entender qual botão esta mensagem refere-se no manipulador de eventos, e irá nos ajudar a lidar com o evento corretamente;
- o ponteiro para o botão é zerado.
Se não houver um ponteiro para o botão, então, haverá uma mensagem com uma dica de ferramenta exibida pelo desenvolvedor do aplicativo em MQL no log do terminal.
//+------------------------------------------------------------------+ //| Manipula o clique no botão "OK" | //+------------------------------------------------------------------+ bool CColorPicker::OnClickButtonOK(const string clicked_object) { //--- Sai se o nome do objeto não corresponder if(clicked_object!=m_button_ok.Text()) return(false); //--- Salva a cor selecionada m_current_color=m_picked_color; m_current.BackColor(m_current_color); m_current.Tooltip(::ColorToString(m_current_color)); //--- Se existe um ponteiro para o botão de chamada da janela para a seleção das cores if(::CheckPointer(m_color_button)!=POINTER_INVALID) { //--- Define uma cor selecionada para o botão m_color_button.CurrentColor(m_current_color); //--- Fecha a janela m_wnd.CloseDialogBox(); //--- Envia uma mensagem sobre ele ::EventChartCustom(m_chart_id,ON_CHANGE_COLOR,CElement::Id(),CElement::Index(),m_color_button.LabelText()); //--- Reseta o ponteiro m_color_button=NULL; } else { //--- Se não há nenhum ponteiro e é uma janela de diálogo, // exibe uma mensagem que não há nenhum ponteiro para o botão chamar o controle if(m_wnd.WindowType()==W_DIALOG) ::Print(__FUNCTION__," > Ponteiro inválido para a chamada do controle(CColorButton)."); } //--- return(true); }
Agora está tudo em ordem para prosseguirmos com o teste da paleta de cores.
Teste dos controles
Qualquer Expert Advisor do artigo anterior pode ser usado para o teste. Vamos fazer uma cópia e manter lá somente o menu principal e uma string de estado. Na janela principal (W_MAIN) da interface gráfica, nós criamos cinco botões para chamar a janela de diálogo (W_DIALOG) com a paleta de cores. Em outras palavras, é suficiente criar uma paleta de cores para toda a aplicação MQL. Toda vez que ao clicar no botão para chamar a janela de diálogo com uma paleta de cores, a mesma janela será chamada. Mas o ponteiro do botão no ponto da chamada deve ser enviada para a classe CColorPicker de forma independente. Será ainda mostrado como este deve ser implementado na classe na aplicação personalizada.
Na classe personalizada chamada CProgram, nós precisamos declarar as instâncias de classes para a criação de uma janela adicional (CWindow), cinco botões para chamar as paletas de cores CColorButton e CColorPicker, e também os métodos para a sua criação com os deslocamentos do ponto extremo do formulário.
class CProgram : public CWndEvents { private: //--- Formulário 2 - janela com a paleta de cores para seleção da cor CWindow m_window2; //--- Botões para chamar a janela com a paleta de cores CColorButton m_color_button1; CColorButton m_color_button2; CColorButton m_color_button3; CColorButton m_color_button4; CColorButton m_color_button5; //--- Paleta de cores CColorPicker m_color_picker; //--- private: //--- Formulário 2 bool CreateWindow2(const string text); //--- Botões para chamar a paleta de cores #define COLORBUTTON1_GAP_X (7) #define COLORBUTTON1_GAP_Y (50) bool CreateColorButton1(const string text); #define COLORBUTTON2_GAP_X (7) #define COLORBUTTON2_GAP_Y (75) bool CreateColorButton2(const string text); #define COLORBUTTON3_GAP_X (7) #define COLORBUTTON3_GAP_Y (100) bool CreateColorButton3(const string text); #define COLORBUTTON4_GAP_X (7) #define COLORBUTTON4_GAP_Y (125) bool CreateColorButton4(const string text); #define COLORBUTTON5_GAP_X (7) #define COLORBUTTON5_GAP_Y (150) bool CreateColorButton5(const string text); //--- Paleta de cores #define COLORPICKER_GAP_X (1) #define COLORPICKER_GAP_Y (20) bool CreateColorPicker(void); };
Os códigos do métodos de criação dos botões para chamar a paleta de cores são praticamente idênticos, portanto, nós iremos fornecer aqui somente um exemplo. A diferença pode ser apenas na definição da cor inicial que será exibida no indicador do botão após a definição, e também o texto na descrição.
//+------------------------------------------------------------------+ //| Cria o botão para chamar a paleta de cores 1 | //+------------------------------------------------------------------+ bool CProgram::CreateColorButton1(const string text) { //--- Armazena o ponteiro para a janela m_color_button1.WindowPointer(m_window1); //--- Coordenadas int x=m_window1.X()+COLORBUTTON1_GAP_X; int y=m_window1.Y()+COLORBUTTON1_GAP_Y; //--- Define as propriedades antes da criação m_color_button1.XSize(195); m_color_button1.YSize(18); m_color_button1.ButtonXSize(100); m_color_button1.ButtonYSize(18); m_color_button1.AreaColor(clrWhiteSmoke); m_color_button1.LabelColor(clrBlack); m_color_button1.BackColor(C'220,220,220'); m_color_button1.BorderColor(clrSilver); m_color_button1.CurrentColor(clrRed); //--- Cria o elemento if(!m_color_button1.CreateColorButton(m_chart_id,m_subwin,text,x,y)) return(false); //--- Adiciona o ponteiro para controlar na base CWndContainer::AddToElementsArray(0,m_color_button1); return(true); }
O código do método usado para criar a formulário da janela de diálogo para uma paleta de cores difere da janela principal apenas por ter o tipo da janela (W_DIALOG) indicada. Em adição a isto, nós vamos definir uma imagem única para esta janela que indica o seu propósito. Todas as imagens são anexadas no arquivo no final do artigo.
//+------------------------------------------------------------------+ //| Cria o formulário 2 para a paleta de cores | //+------------------------------------------------------------------+ #resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\color_picker.bmp" //--- bool CProgram::CreateWindow2(const string caption_text) { //--- Armazena o ponteiro para a janela CWndContainer::AddWindow(m_window2); //--- Coordenadas int x=(m_window2.X()>0) ? m_window2.X() : 30; int y=(m_window2.Y()>0) ? m_window2.Y() : 30; //--- Propriedades m_window2.Movable(true); m_window2.XSize(350); m_window2.YSize(286); m_window2.WindowType(W_DIALOG); m_window2.WindowBgColor(clrWhiteSmoke); m_window2.WindowBorderColor(clrLightSteelBlue); m_window2.CaptionBgColor(clrLightSteelBlue); m_window2.CaptionBgColorHover(clrLightSteelBlue); m_window2.IconFile("Images\\EasyAndFastGUI\\Icons\\bmp16\\color_picker.bmp"); //--- Criação de um formulário if(!m_window2.CreateWindow(m_chart_id,m_subwin,caption_text,x,y)) return(false); //--- return(true); }
A lista abaixo tem o código do método CProgram::CreateColorPicker() para a criação de uma paleta de cores. É importante guardar um ponteiro para a janela de diálogo que um controlo será ligado. Ao adicionar um ponteiro do controle na base de controles, Índice da janela que o elemento está ligado precisa ser enviada. Neste caso, é um índice de janela de diálogo [1].
//+------------------------------------------------------------------+ //| Cri a paleta de cores para a seleção de cor | //+------------------------------------------------------------------+ bool CProgram::CreateColorPicker(void) { //--- Armazena o ponteiro para a janela m_color_picker.WindowPointer(m_window2); //--- Coordenadas int x=m_window2.X()+COLORPICKER_GAP_X; int y=m_window2.Y()+COLORPICKER_GAP_Y; //--- Cria o controle if(!m_color_picker.CreateColorPicker(m_chart_id,m_subwin,x,y)) return(false); //--- Adiciona o ponteiro para controlar na base CWndContainer::AddToElementsArray(1,m_color_picker); return(true); }
Nós precisamos garantir que, ao clicar no botão, o ponteiro é enviado para a paleta de cores. Pode ser feito no processador de eventos da classe personalizada CProgram::OnEvent(). Ao clicar no botão, uma mensagem com o identificador ON_CLICK_BUTTON é gerado. A mensagem também contém o texto da descrição do botão usado para definir qual objeto do tipo CColorButton necessita ser enviado para a paleta de cores. Logo após o envio do objeto do botão, uma janela com a paleta de cores será aberta, e a cor do botão cujo objeto foi enviado será exibido em todos os seus marcadores. Isto é demonstrado no código a seguir:
//+------------------------------------------------------------------+ //| Manipulador de eventos | //+------------------------------------------------------------------+ void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Evento clique do botão if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON) { //--- Se o botão 1 foi clicado if(sparam==m_color_button1.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button1); return; } //--- Se o botão 2 foi clicado if(sparam==m_color_button2.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button2); return; } //--- Se o botão 3 foi clicado if(sparam==m_color_button3.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button3); return; } //--- Se o botão 4 foi clicado if(sparam==m_color_button4.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button4); return; } //--- Se o botão 5 foi clicado if(sparam==m_color_button5.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button5); return; } } }
Após a seleção das cores serem confirmadas clicando no botão "ОК" na paleta de cores, uma mensagem com o identificador ON_CHANGE_COLOR será tratada como é exibido na listagem do código.
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Evento para mudar a cor usando a paleta de cores if(id==CHARTEVENT_CUSTOM+ON_CHANGE_COLOR) { //--- Se os identificadores de controles corresponder if(lparam==m_color_picker.Id()) { //--- Se a resposta é a partir do botão 1 if(sparam==m_color_button1.LabelText()) { //--- Altera a cor do objeto que se refere ao botão 1... return; } //--- Se a resposta é do botão 2 if(sparam==m_color_button2.LabelText()) { //--- Altera a cor do objeto que se refere ao botão 2... return; } //--- Se a resposta é do botão 3 if(sparam==m_color_button3.LabelText()) { //--- Altera a cor do objeto que se refere a tecla 3 ... return; } //--- Se a resposta é do botão 4 if(sparam==m_color_button4.LabelText()) { //--- Mude a cor do objeto que se refere a tecla 4... return; } / --- Se a resposta é do botão 5 if(sparam==m_color_button5.LabelText()) { //--- Altera a cor do objeto que se refere a tecla 5... return; } } return; } }
Compile o programa e carregue-o na parada do terminal. O resultado aparece na imagem abaixo:
Fig. 4. Teste dos botões para chamar uma paleta de cores.
Ao clicar no botão para chamar uma paleta de cores a partir dos cinco botões coloridos na apresentados na janela principal, a janela do seletor de cores será aberta como é mostrado na imagem a seguir:
Fig. 5. Teste do elemento de cor selecionado.
Agora tudo funciona como era de se esperar.
Conclusão
Foi apresentado um controle composto e complexo da interface chamada seletor de cor foi apresentado neste artigo (primeiro capítulo da parte 9 da série de artigos). Um botão especial para chamar a paleta de cores foi criado como um controle adicional. Agora, os usuários da biblioteca desenvolvida possuem a oportunidade de gerenciar as cores de objetos usando uma interface gráfica de sua aplicação MQL.
O seguinte artigo irá conter uma descrição das classes de códigos dos controles, como a barra de progresso e o gráfico de linhas.
A seguir estão os materiais da parte nove da série de artigos que você pode baixar no seu PC, a fim de testar como tudo funciona. Para qualquer dúvida relacionadas com a utilização do material fornecido nestes arquivos, você pode referir-se a descrição detalhada do processo de desenvolvimento da biblioteca em um dos artigos da lista abaixo ou fazer perguntas nos comentários do artigo.
Lista de artigos (capítulos) da parte nove:
- Interfaces Gráficas IX: O Controle Seletor de Cores (Capítulo 1)
- Interfaces Gráficas IX: Os Controles Barra de Progresso e Gráfico de Linha (Capítulo 2)
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/2579
- 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