
Interfaces Gráficas VII: O Controle Guias (Capítulo 2)
Conteúdo
- Introdução
- O controle Guias
- Desenvolvimento de uma Classe para a Criação do Controle Guias
- Teste do Controle Guias
- Conclusão
Introdução
O primeiro artigo Interfaces gráficas I: Preparação da Estrutura da Biblioteca (Capítulo 1) considera em detalhes a finalidade desta biblioteca. 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.
Foi introduzido no primeiro capítulo da sétima parte três classes de controles para a criação de tabelas: Tabela com o rótulo de texto (CLabelsTable), tabela com a caixa de edição (CTable) e a tabela renderizada (CCanvasTable). Neste artigo (capítulo dois) nós vamos introduzir o controle Guias. Duas classes serão introduzidas para esse controle - a simples e com a funcionalidade estendida.
O controle Guias
As guias são utilizadas para controlar a exibição de conjuntos predefinidos do controle interface gráfica. Muitas vezes, as aplicações multi-funcionais exigem um grande número de controles para se encaixar em um espaço alocado limitado para a interface gráfica. As guias podem ser usadas para agrupar os controles por categorias e exibir apenas o grupo que é necessário no momento. Isso torna a interface muito mais acessível e intuitiva para o usuário final. Na superfície, as guias são parecidas com um grupo de botões com rótulos (nome do grupo de controles). Ao mesmo tempo, apenas uma delas que poderá ser selecionada (ativa).
Vamos enumerar todos os componentes deste controle.
- Plano de fundo ou a área que encaixa o grupo de controles
- Guias
Fig. 1. Componentes do controle Guias.
Vamos criar quatro modos para posicionar as guias em relação à área, onde outros controles serão colocados: superior, inferior, esquerda e direita.
Desenvolvimento de uma Classe para a Criação do Controle Guias
Crie o arquivo Tabs.mqh e inclua-o no arquivo da biblioteca WndContainer.mqh:
//+------------------------------------------------------------------+ //| WndContainer.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "Tabs.mqh"
A classe CTabs deve ser criada no arquivo Tabs.mqh. Nesta classe, assim como nas classes de outros controles, é necessário a criação dos métodos padrão, bem como os métodos para armazenar o ponteiro para o formulário, ao qual será anexado esse controle.
//+------------------------------------------------------------------+ //| Classe para a criação das guias | //+------------------------------------------------------------------+ class CTabs : public CElement { private: //--- Ponteiro para o formulário ao qual o elemento está anexado CWindow *m_wnd; //--- public: CTabs(void); ~CTabs(void); //--- (1) Armazena o ponteiro do formulário, (2) retorna os ponteiros para as barras de rolagem void WindowPointer(CWindow &object) { m_wnd=::GetPointer(object); } //--- public: //--- Manipulador de eventos do gráfico virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- Timer virtual void OnEventTimer(void); //--- Move o elemento virtual void Moving(const int x,const int y); //--- (1) Exibe, (2) oculta, (3) reseta, (4) remove virtual void Show(void); virtual void Hide(void); virtual void Reset(void); virtual void Delete(void); //--- (1) Definir (2), resetar as prioridades para o clique esquerdo do mouse virtual void SetZorders(void); virtual void ResetZorders(void); //--- Reseta a cor virtual void ResetColors(void) {} }; //+------------------------------------------------------------------+ //| Construtor | //+------------------------------------------------------------------+ CTabs::CTabs(void) { } //+------------------------------------------------------------------+ //| Destrutor | //+------------------------------------------------------------------+ CTabs::~CTabs(void) { }
As propriedades das Guias podem ser divididas em únicas e comuns. Vamos enumerar as duas listas.
Propriedades únicas
- Array de ponteiros para os controles ligados à guia
- Texto
- Largura
Crie a estrutura TElements para as propriedades únicas e declare um array dinâmico com este tipo:
class CTabs : public CElement { private: //--- Estrutura de propriedades e arrays de controles ligados a cada guia struct TElements { CElement *elements[]; string m_text; int m_width; }; TElements m_tab[]; };
Propriedades comuns
- Modo de posicionamento das guias
- Cor de fundo da área
- Tamanho das guias ao longo do eixo Y (altura)
- Cores das guias em diferentes estados
- Cor do texto da guia em diferentes estados
- Cor das bordas da guia
- Prioridades do clique do botão esquerdo do mouse
Para definir o modo de posicionamento da enumeração ENUM_TABS_POSITION deve ser adicionada ao arquivo Enums.mqh:
//+------------------------------------------------------------------+ //| Enumeração das guias de posicionamento | //+------------------------------------------------------------------+ enum ENUM_TABS_POSITION { TABS_TOP =0, TABS_BOTTOM =1, TABS_LEFT =2, TABS_RIGHT =3 };
A declaração dos campos e métodos para definir as propriedades são fornecidas no código a seguir:
class CTabs : public CElement { private: //--- Posicionamento das guias ENUM_TABS_POSITION m_position_mode; //--- Cor de fundo área comum int m_area_color; //--- Tamanho das guias ao longo do eixo Y int m_tab_y_size; //--- Cores das guias em diferentes estados color m_tab_color; color m_tab_color_hover; color m_tab_color_selected; color m_tab_color_array[]; //--- Cor do texto da guia em diferentes estados color m_tab_text_color; color m_tab_text_color_selected; //--- Cor das bordas da guia color m_tab_border_color; //--- Prioridades do clique do botão esquerdo do mouse int m_zorder; int m_tab_zorder; //--- public: //--- (1) Define as posições da guia (superior/inferior/esquerda/direita), (2) define o tamanho da guia ao longo do eixo Y void PositionMode(const ENUM_TABS_POSITION mode) { m_position_mode=mode; } ENUM_TABS_POSITION PositionMode(void) const { return(m_position_mode); } void TabYSize(const int y_size) { m_tab_y_size=y_size; } //--- Cor (1) de fundo comum, (2) cores das abas em diferentes estados, (3) a cor das bordas da guia void AreaColor(const color clr) { m_area_color=clr; } void TabBackColor(const color clr) { m_tab_color=clr; } void TabBackColorHover(const color clr) { m_tab_color_hover=clr; } void TabBackColorSelected(const color clr) { m_tab_color_selected=clr; } void TabBorderColor(const color clr) { m_tab_border_color=clr; } //--- Cor do texto da guia em diferentes estados void TabTextColor(const color clr) { m_tab_text_color=clr; } void TabTextColorSelected(const color clr) { m_tab_text_color_selected=clr; } };
Antes de criar um controle, é necessário adicionar o número necessário de guias com uma indicação do texto exibido e da largura. Vamos escrever o método CTabs::addTab() para isso. Os valores padrão dos argumentos do método são «» (string vazia) e 50 (largura).
class CTabs : public CElement { public: //--- Adiciona uma guia void AddTab(const string tab_text="",const int tab_width=50); }; //+------------------------------------------------------------------+ //| Adiciona uma guia | //+------------------------------------------------------------------+ void CTabs::AddTab(const string tab_text,const int tab_width) { //--- Define o tamanho dos arrays das guias int array_size=::ArraySize(m_tabs); ::ArrayResize(m_tabs,array_size+1); ::ArrayResize(m_tab,array_size+1); //--- Armazena as propriedades passadas m_tab[array_size].m_text =tab_text; m_tab[array_size].m_width =tab_width; //--- Armazena o número de guias m_tabs_total=array_size+1; }
Se uma determinada guia deve ser pré-selecionada ao carregar o aplicativo MQL ao gráfico, então, antes de criar o controle, é necessário especificar o seu índice usando o método CTabs::SelectedTab(). Ele também irá exigir o método privado CTabs::CheckTabIndex() para verificar e ajustar o índice da guia selecionada, no caso de exceder o seu tamanho.
class CTabs : public CElement { private: //--- Índice da guia selecionada int m_selected_tab; //--- public: //--- (1) Armazena e (2) retorna o índice da guia selecionada void SelectedTab(const int index) { m_selected_tab=index; } int SelectedTab(void) const { return(m_selected_tab); } //--- private: //--- Verificação do índice da guia selecionada void CheckTabIndex(void); }; //+------------------------------------------------------------------+ //| Verificação do índice da guia selecionada | //+------------------------------------------------------------------+ void CTabs::CheckTabIndex(void) { //--- Verifica se o tamanho do array não excedeu int array_size=::ArraySize(m_tab); if(m_selected_tab<0) m_selected_tab=0; if(m_selected_tab>=array_size) m_selected_tab=array_size-1; }
Para criar o controle, nós precisaremos de três métodos privados e um público:
class CTabs : public CElement { private: //--- Objetos para criar o elemento CRectLabel m_main_area; CRectLabel m_tabs_area; CEdit m_tabs[]; //--- public: //--- Métodos para criar as guias bool CreateTabs(const long chart_id,const int subwin,const int x,const int y); //--- private: bool CreateMainArea(void); bool CreateTabsArea(void); bool CreateButtons(void); };
Se nenhuma guia foi adicionada antes de colocar o controle, então, a chamada do método público CTabs::CreateTabs() irá parar de criar a interface gráfica enviará a seguinte mensagem para o log:
//--- Se não houver uma guia no grupo, reporta if(m_tabs_total<1) { ::Print(__FUNCTION__," > Este método era para ser chamado, " "se um grupo conter pelo menos uma guia! Utilize o método CTabs::AddTab()"); return(false); }
A determinação e o cálculo das coordenadas para os componentes dos objetos do controle também serão diferentes, dependendo do modo do posicionamento da guia selecionada. Esses cálculos exigem o método CTabs::SumWidthTabs(), que retorna a largura total de todas as guias. Ele irá retornar a largura da primeira guia nos modos de posicionamento da guia na esquerda (TABS_LEFT) e direita (TABS_RIGHT). Para a parte superior (TABS_TOP) e inferior (TABS_BOTTOM) do modos, é somado a largura de todas as abas.
class CTabs : public CElement { private: //--- Posicionamento das guias ENUM_TABS_POSITION m_position_mode; //--- private: //--- Tamanho de todas as guias int SumWidthTabs(void); }; //+------------------------------------------------------------------+ //| Tamanho total de todas as abas | //+------------------------------------------------------------------+ int CTabs::SumWidthTabs(void) { int width=0; //--- Se as guias estão posicionadas à direita ou à esquerda, retorna o tamanho da primeira guia if(m_position_mode==TABS_LEFT || m_position_mode==TABS_RIGHT) return(m_tab[0].m_width); //--- Soma do tamanho de todas as guias for(int i=0; i<m_tabs_total; i++) width=width+m_tab[i].m_width; //--- Com a consideração de uma sobreposição de pixels width=width-(m_tabs_total-1); return(width); }
O método CTabs::CreateMainArea() foi projetado para criar a área onde os grupos de controle serão localizados. O cálculo das coordenadas e tamanhos dos objetos são parecidos com isso (versão resumida do método):
//+------------------------------------------------------------------+ //| Criar o fundo da área comum | //+------------------------------------------------------------------+ bool CTabs::CreateMainArea(void) { //--- Elaborando o nome do objeto string name=CElement::ProgramName()+"_tabs_main_area_"+(string)CElement::Id(); //--- Coordenadas int x=0; int y=0; //--- Tamanho int x_size=0; int y_size=0; //--- Calcula as coordenadas e tamanhos relativos ao posicionamento das guias switch(m_position_mode) { case TABS_TOP : x =CElement::X(); y =CElement::Y()+m_tab_y_size-1; x_size =CElement::XSize(); y_size =CElement::YSize()-m_tab_y_size; break; case TABS_BOTTOM : x =CElement::X(); y =CElement::Y(); x_size =CElement::XSize(); y_size =CElement::YSize()-m_tab_y_size; break; case TABS_RIGHT : x =CElement::X(); y =CElement::Y(); x_size =CElement::XSize()-SumWidthTabs()+1; y_size =CElement::YSize(); break; case TABS_LEFT : x =CElement::X()+SumWidthTabs()-1; y =CElement::Y(); x_size =CElement::XSize()-SumWidthTabs()+1; y_size =CElement::YSize(); break; } //--- Cria um objeto if(!m_main_area.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size)) return(false); //--- Define as propriedades //--- Margens da borda //--- Armazena o tamanho //--- Armazena as coordenadas //--- Armazena o ponteiro de objeto //... return(true); }
A seguir encontramos o cálculo das coordenadas e tamanhos do fundo para as guias, dependendo do modo de posicionamento indicado no método CTabs::CreateTabsArea():
//+------------------------------------------------------------------+ //| Criar o fundo da guia | //+------------------------------------------------------------------+ bool CTabs::CreateTabsArea(void) { //--- Elaborando o nome do objeto string name=CElement::ProgramName()+"_tabs_area_"+(string)CElement::Id(); //--- Coordenadas int x=CElement::X(); int y=CElement::Y(); //--- Tamanho int x_size=SumWidthTabs(); int y_size=0; //--- Calcula as coordenadas e tamanhos relativos ao posicionamento das guias if(m_position_mode==TABS_TOP || m_position_mode==TABS_BOTTOM) { y_size=m_tab_y_size; } else { y_size=m_tab_y_size*m_tabs_total-(m_tabs_total-1); } //--- Ajusta as coordenadas para o posicionamento das guias na parte inferior e à direita if(m_position_mode==TABS_BOTTOM) { y=CElement::Y2()-m_tab_y_size-1; } else if(m_position_mode==TABS_RIGHT) { x=CElement::X2()-x_size; } //--- Cria um objeto if(!m_tabs_area.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size)) return(false); //--- Define as propriedades //--- Margens da borda //--- Armazena o tamanho //--- Armazena as coordenadas //--- Armazena o ponteiro de objeto //... return(true); }
O método CTabs::CreateButtons() requer apenas o cálculo das coordenadas para a criação das guias. A largura é definida na classe personalizada do aplicativo antes que do controle ser criado. Caso contrário, o valor padrão (largura) é usado. Abaixo está uma versão resumida do método:
//+------------------------------------------------------------------+ //| Cria as guias | //+------------------------------------------------------------------+ bool CTabs::CreateButtons(void) { //--- Coordenadas int x =CElement::X(); int y =CElement::Y(); //--- Cálculo da coordena em relação ao posicionamento das guias if(m_position_mode==TABS_BOTTOM) y=CElement::Y2()-m_tab_y_size-1; else if(m_position_mode==TABS_RIGHT) x=CElement::X2()-SumWidthTabs(); //--- Verificação do índice da guia selecionada CheckTabIndex(); //--- Cria as abas for(int i=0; i<m_tabs_total; i++) { //--- Elaborando o nome do objeto string name=CElement::ProgramName()+"_tabs_edit_"+(string)i+"__"+(string)CElement::Id(); //--- Cálculo das coordenadas em relação ao posicionamento das guias para cada guia individual if(m_position_mode==TABS_TOP || m_position_mode==TABS_BOTTOM) x=(i>0) ? x+m_tab[i-1].m_width-1 : CElement::X(); else y=(i>0) ? y+m_tab_y_size-1 : CElement::Y(); //--- Cria um objeto if(!m_tabs[i].Create(m_chart_id,name,m_subwin,x,y,m_tab[i].m_width,m_tab_y_size)) return(false); //--- Define as propriedades //--- Margens da borda do painel //--- Coordenadas //--- Tamanho //--- Inicialização do array de gradiente //--- Armazena o ponteiro de objeto } //--- return(true); }
Para anexar qualquer controle para uma guia específica, nós vamos escrever o método CTabs::AddToElementsArray(). Ele tem dois argumentos: (1) índice da guia, que o controle deverá ser ligado e a (2) referência ao controle, um ponteiro que deve ser armazenado no array de controle da guia.
class CTabs : public CElement { public: //--- Adiciona o controle ao array da guia void AddToElementsArray(const int tab_index,CElement &object); }; //+------------------------------------------------------------------+ //| Adiciona o controle para o array da guia especificada | //+------------------------------------------------------------------+ void CTabs::AddToElementsArray(const int tab_index,CElement &object) { //--- Verifica se o tamanho do array não excedeu int array_size=::ArraySize(m_tab); if(array_size<1 || tab_index<0 || tab_index>=array_size) return; //--- Adiciona o ponteiro do controle passado ao array da guia especificada int size=::ArraySize(m_tab[tab_index].elements); ::ArrayResize(m_tab[tab_index].elements,size+1); m_tab[tab_index].elements[size]=::GetPointer(object); }
Ao alternar as guias, é necessário ocultar os controles da guia anterior e exibir os controles da guia recém-selecionada. Para este efeito, vamos criar o método CTabs::ShowTabElements(). A verificação para a visibilidade do controle está no início do método. Se o controle está oculto, então, o programa sai do método. Em seguida, ele verifica o índice da guia ativa e ajusta ela, se necessário. Em seguida, ele verifica todas as guias em um loop e executa a tarefa principal do método.
class CTabs : public CElement { public: //--- Mostra somente os controles da guia selecionada void ShowTabElements(void); }; //+------------------------------------------------------------------+ //| Mostra somente os controles da guia selecionada | //+------------------------------------------------------------------+ void CTabs::ShowTabElements(void) { //--- Sai, se as abas estão ocultas if(!CElement::IsVisible()) return; //--- Verificação do índice da guia selecionada CheckTabIndex(); //--- for(int i=0; i<m_tabs_total; i++) { //--- Obtém o número de controles ligado à guia int tab_elements_total=::ArraySize(m_tab[i].elements); //--- Se esta guia é selecionada if(i==m_selected_tab) { //--- Exibe os controles da guia for(int j=0; j<tab_elements_total; j++) m_tab[i].elements[j].Show(); } //--- Ocultar os controles das guias inativas else { for(int j=0; j<tab_elements_total; j++) m_tab[i].elements[j].Hide(); } } }
O método CTabs::OnClickTab() será usado para manipular o acionamento de uma guia. Em primeiro lugar, o programa tem de passar por dois controles: (1) com base no nome do objeto pressionado e (2) com base no identificador do controle, obtido a partir do nome do objeto utilizando o método CTabs::IdFromObjectName(). Se as verificações são passadas, então o programa (1) encontra a guia pressionada em um loop, (2) armazena os índices e (3) define as cores correspondentes. No final do método CTabs::ShowTabElements(), apenas os controles da guia ativa são visíveis.
class CTabs : public CElement { private: //--- Manipulando o pressionamento da guia bool OnClickTab(const string pressed_object); //--- Obtém o identificador do nome do objeto int IdFromObjectName(const string object_name); }; //+------------------------------------------------------------------+ //| Pressionando uma guia em um grupo | //+------------------------------------------------------------------+ bool CTabs::OnClickTab(const string clicked_object) { //--- Sai se o pressionamento não foi na célula da tabela if(::StringFind(clicked_object,CElement::ProgramName()+"_tabs_edit_",0)<0) return(false); //--- Obtém o identificador do nome do objeto int id=IdFromObjectName(clicked_object); //--- Retorna, se o tipo definido não corresponder if(id!=CElement::Id()) return(false); //--- for(int i=0; i<m_tabs_total; i++) { //--- Se essa guia é clicada if(m_tabs[i].Name()==clicked_object) { //--- Armazena o índice da guia selecionada SelectedTab(i); //--- Define as cores m_tabs[i].Color(m_tab_text_color_selected); m_tabs[i].BackColor(m_tab_color_selected); } else { //--- Define as cores para as guias inativas m_tabs[i].Color(m_tab_text_color); m_tabs[i].BackColor(m_tab_color); } } //--- Mostra somente os controles da guia selecionada ShowTabElements(); return(true); }
Neste caso, o código para o manipulador de evento principal CTabs::OnEvent() é como mostrado no código abaixo:
//+------------------------------------------------------------------+ //| Manipulador de eventos do gráfico | //+------------------------------------------------------------------+ void CTabs::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Manipulação do evento do movimento do cursor if(id==CHARTEVENT_MOUSE_MOVE) { //--- Sai se o elemento está oculto if(!CElement::IsVisible()) return; //--- Coordenadas int x=(int)lparam; int y=(int)dparam; for(int i=0; i<m_tabs_total; i++) m_tabs[i].MouseFocus(x>m_tabs[i].X() && x<m_tabs[i].X2() && y>m_tabs[i].Y() && y<m_tabs[i].Y2()); //--- return; } //--- Manipula o clique do botão esquerdo do mouse sobre o objeto if(id==CHARTEVENT_OBJECT_CLICK) { //--- Pressionando uma guia if(OnClickTab(sparam)) return; } }
Todos os métodos da classe CTabs classe foram considerados. Agora, vamos testar como tudo isso ira funcionar.
Teste do Controle Guias
Para os testes, vamos usar o EA a partir da parte anterior da série e remover tudo, exceto o menu principal e a barra de estado de sua interface gráfica. Nós vamos fazer com que todos os modos de posicionamento da guia (superior/inferior/esquerda/direita) sejam fáceis de testar, bem como o seu tamanho (altura), que seja fácil de ajustar. Para este fim, adicione os parâmetros externos ao EA no arquivo Program.mqh com a classe personalizada:
//--- Parâmetros externos do Expert Advisor input ENUM_TABS_POSITION TabsPosition =TABS_TOP; // Tabs Position input int TabsHeight =20; // Tabs Height
Em seguida, na classe personalizada (CProgram) do aplicativo, declare uma instância da classe CTabs e o método para a criação do controle Guias recuado dos pontos da borda do formulário:
class CProgram : public CWndEvents { private: //--- Guias CTabs m_tabs; //--- private: //--- Guias #define TABS1_GAP_X (4) #define TABS1_GAP_Y (45) bool CreateTabs(void); };
Haverá quatro guias no total. O texto exibido e a largura das guias podem ser modificadas ao inicializar os arrays, os valores de seus elementos são, em seguida, passado em um loop usando o método CTabs::addTab(). A altura e posicionamento das guias serão definidos pelos parâmetros externos. A segunda aba (índice 1) será selecionada por padrão (quando o programa for carregado ao gráfico pela primeira vez). O código completo do método CProgram::CreateTabs() pode ser visto abaixo:
//+------------------------------------------------------------------+ //| Cria a área com as abas | //+------------------------------------------------------------------+ bool CProgram::CreateTabs(void) { #define TABS1_TOTAL 4 //--- Passa o objeto do painel m_tabs.WindowPointer(m_window1); //--- Coordenadas int x=m_window1.X()+TABS1_GAP_X; int y=m_window1.Y()+TABS1_GAP_Y; //--- Arrays com texto e largura para as guias string tabs_text[]={"Tab 1","Tab 2","Tab 3","Tab 4"}; int tabs_width[]={90,90,90,90}; //--- Define as propriedades antes da criação m_tabs.XSize(596); m_tabs.YSize(243); m_tabs.TabYSize(TabsHeight); m_tabs.PositionMode(TabsPosition); m_tabs.SelectedTab((m_tabs.SelectedTab()==WRONG_VALUE) ? 1 : m_tabs.SelectedTab()); m_tabs.AreaColor(clrWhite); m_tabs.TabBackColor(C'225,225,225'); m_tabs.TabBackColorHover(C'240,240,240'); m_tabs.TabBackColorSelected(clrWhite); m_tabs.TabBorderColor(clrSilver); m_tabs.TabTextColor(clrGray); m_tabs.TabTextColorSelected(clrBlack); //--- Adiciona as guias com as propriedades especificadas for(int i=0; i<TABS1_TOTAL; i++) m_tabs.AddTab(tabs_text[i],tabs_width[i]); //--- Cria o controle if(!m_tabs.CreateTabs(m_chart_id,m_subwin,x,y)) return(false); //--- Adiciona o objeto ao array comum dos grupos de objetos CWndContainer::AddToElementsArray(0,m_tabs); return(true); }
O método deve ser chamado no método principal para criar a interface gráfica da aplicação (ver a versão resumida do método no código abaixo):
//+------------------------------------------------------------------+ //| Cria um painel Expert | //+------------------------------------------------------------------+ bool CProgram::CreateExpertPanel(void) { //--- Criação do formulário 1 para os controles //--- Criação dos controles: // Menu principal //--- Menus de contexto //--- Guias if(!CreateTabs()) return(false); //--- Redesenha o gráfico m_chart.Redraw(); return(true); }
Compile o programa e carregue-o ao gráfico. Os modos de posicionamento da guia será alterada sucessivamente nos parâmetros externos (veja as imagens abaixo):
Fig. 2. Modo de posicionamento das guias - «Superior».
Fig. 3. Modo de posicionamento das guias - «Inferior».
Fig. 4. Modo de posicionamento das guias - «Esquerda».
Fig. 5. Modo de posicionamento das guias - «Direita».
Agora vamos testar como ele funciona com os grupos de controles ligados a cada guia. Para fazer isso, crie uma cópia separada do mesmo EA e exclua os parâmetros externos dele. Aqui, as abas serão posicionadas na parte superior (TABS_TOP) da área de trabalho.
- Uma tabela com o rótulo de texto será anexada na primeira guia.
- Uma tabela com a caixa de edição será anexada à segunda.
- Uma tabela renderizada à terceira.
- O quarto - um grupo de controles, que contém:
- quatro caixas de seleção;
- quatro caixas de seleção com caixas de edição;
- quatro caixas de combinação com as caixas de seleção;
- uma linha de separação.
Na classe personalizada (CProgram) do aplicativo de teste, declare as (1) instâncias desses controles, (2) os métodos para criá-los e (3) as margens das bordas d formulário (ver o código abaixo):
class CProgram : public CWndEvents { private: //--- Tabela com o rótulo de texto CLabelsTable m_labels_table; //--- Tabela com a caixa de edição CTable m_table; //--- Tabela renderizada CCanvasTable m_canvas_table; //--- Caixas de seleção CCheckBox m_checkbox1; CCheckBox m_checkbox2; CCheckBox m_checkbox3; CCheckBox m_checkbox4; //--- Caixas de seleção com as caixas de edição CCheckBoxEdit m_checkboxedit1; CCheckBoxEdit m_checkboxedit2; CCheckBoxEdit m_checkboxedit3; CCheckBoxEdit m_checkboxedit4; //--- Caixas de combinação com as caixas de seleção CCheckComboBox m_checkcombobox1; CCheckComboBox m_checkcombobox2; CCheckComboBox m_checkcombobox3; CCheckComboBox m_checkcombobox4; //--- Linha de separação CSeparateLine m_sep_line; //--- private: //--- Tabela com o rótulo de texto #define TABLE1_GAP_X (5) #define TABLE1_GAP_Y (65) bool CreateLabelsTable(void); //--- Tabela com a caixa de edição #define TABLE2_GAP_X (5) #define TABLE2_GAP_Y (65) bool CreateTable(void); //--- Tabela renderizada #define TABLE3_GAP_X (5) #define TABLE3_GAP_Y (65) bool CreateCanvasTable(void); //--- Linha de separação #define SEP_LINE_GAP_X (300) #define SEP_LINE_GAP_Y (70) bool CreateSepLine(void); //--- Caixas de seleção #define CHECKBOX1_GAP_X (18) #define CHECKBOX1_GAP_Y (75) bool CreateCheckBox1(const string text); #define CHECKBOX2_GAP_X (18) #define CHECKBOX2_GAP_Y (175) bool CreateCheckBox2(const string text); #define CHECKBOX3_GAP_X (315) #define CHECKBOX3_GAP_Y (75) bool CreateCheckBox3(const string text); #define CHECKBOX4_GAP_X (315) #define CHECKBOX4_GAP_Y (175) bool CreateCheckBox4(const string text); //--- Caixas de seleção com as caixas de edição #define CHECKBOXEDIT1_GAP_X (40) #define CHECKBOXEDIT1_GAP_Y (105) bool CreateCheckBoxEdit1(const string text); #define CHECKBOXEDIT2_GAP_X (40) #define CHECKBOXEDIT2_GAP_Y (135) bool CreateCheckBoxEdit2(const string text); #define CHECKBOXEDIT3_GAP_X (337) #define CHECKBOXEDIT3_GAP_Y (105) bool CreateCheckBoxEdit3(const string text); #define CHECKBOXEDIT4_GAP_X (337) #define CHECKBOXEDIT4_GAP_Y (135) bool CreateCheckBoxEdit4(const string text); //--- Caixas de combinação com as caixas de seleção #define CHECKCOMBOBOX1_GAP_X (40) #define CHECKCOMBOBOX1_GAP_Y (205) bool CreateCheckComboBox1(const string text); #define CHECKCOMBOBOX2_GAP_X (40) #define CHECKCOMBOBOX2_GAP_Y (235) bool CreateCheckComboBox2(const string text); #define CHECKCOMBOBOX3_GAP_X (337) #define CHECKCOMBOBOX3_GAP_Y (205) bool CreateCheckComboBox3(const string text); #define CHECKCOMBOBOX4_GAP_X (337) #define CHECKCOMBOBOX4_GAP_Y (235) bool CreateCheckComboBox4(const string text); };
Nos artigos anteriores, foi exibido repetidamente como criar os controles e anexá-los ao formulário. Portanto, o código de apenas um destes métodos será fornecido aqui para mostrar como anexar um controle a uma guia. O mais simples desses controles seria a linha de separação, que é suficiente como um exemplo. No código abaixo, a linha que chama o método CTabs::AddToElementsArray() é destacado em amarelo. O primeiro argumento é o índice da guia, na qual o controle deve ser anexado. Aqui, o índice é 3, ou seja, a quarta guia. O segundo argumento é o objecto do controle que deve ser ligado à guia especificada.
//+------------------------------------------------------------------+ //| Cria uma linha de separação | //+------------------------------------------------------------------+ bool CProgram::CreateSepLine(void) { //--- Armazena o ponteiro da janela m_sep_line.WindowPointer(m_window1); //--- Anexa à quarta página do primeiro grupo de guias m_tabs.AddToElementsArray(3,m_sep_line); //--- Coordenadas int x=m_window1.X()+SEP_LINE_GAP_X; int y=m_window1.Y()+SEP_LINE_GAP_Y; //--- Tamanho int x_size=2; int y_size=210; //--- Define as propriedades antes da criação m_sep_line.DarkColor(C'213,223,229'); m_sep_line.LightColor(clrWhite); m_sep_line.TypeSepLine(V_SEP_LINE); //--- Criação de um elemento if(!m_sep_line.CreateSeparateLine(m_chart_id,m_subwin,0,x,y,x_size,y_size)) return(false); //--- Adiciona o ponteiro do elemento para a base CWndContainer::AddToElementsArray(0,m_sep_line); return(true); }
Uma vez que a interface gráfica do aplicativo foi criada, o método CTabs::ShowTabElements() deve ser chamado para exibir apenas os controles das guias ativas (veja a versão resumida do método no código abaixo). Se não for feito isso, todos os controles de todas as guias serão exibidos.
//+------------------------------------------------------------------+ //| Cria um painel Expert | //+------------------------------------------------------------------+ bool CProgram::CreateExpertPanel(void) { //--- Criação do formulário 1 para os controles //--- Criação dos controles: //--- Menu principal //--- Menus de contexto //--- Barra de status //--- Guias //... //--- Tabela com o rótulo de texto if(!CreateLabelsTable()) return(false); //--- Tabela com a caixa de edição if(!CreateTable()) return(false); //--- Cria a tabela renderizada if(!CreateCanvasTable()) return(false); //--- Linha de separação if(!CreateSepLine()) return(false); //--- Caixas de seleção if(!CreateCheckBox1("Checkbox 1")) return(false); if(!CreateCheckBox2("Checkbox 2")) return(false); if(!CreateCheckBox3("Checkbox 3")) return(false); if(!CreateCheckBox4("Checkbox 4")) return(false); //--- Caixas de seleção com as caixas de edição if(!CreateCheckBoxEdit1("Checkbox Edit 1:")) return(false); if(!CreateCheckBoxEdit2("Checkbox Edit 2:")) return(false); if(!CreateCheckBoxEdit3("Checkbox Edit 3:")) return(false); if(!CreateCheckBoxEdit4("Checkbox Edit 4:")) return(false); //--- Caixas de combinação com as caixas de seleção if(!CreateCheckComboBox1("CheckCombobox 1:")) return(false); if(!CreateCheckComboBox2("CheckCombobox 2:")) return(false); if(!CreateCheckComboBox3("CheckCombobox 3:")) return(false); if(!CreateCheckComboBox4("CheckCombobox 4:")) return(false); //--- Exibe apenas os controles ativos da guia m_tabs.ShowTabElements(); //--- Redesenha o gráfico m_chart.Redraw(); return(true); }
O resultado deve ser igual a imagem abaixo
Fig. 6. Controles da primeira guia.
Fig. 7. Controles da segunda guia.
Fig. 8. Controles da terceira guia.
Fig. 9. Controles da quarta guia.
Tudo está funcionando como pretendido. A sétima parte da série dedicada à biblioteca para criar as interfaces gráficas já pode ser concluída. Como um suplemento, você pode baixar outro código da classe (CIconTabs) para a criação das guias com funcionalidade estendida, que é fornecido nos anexos deste artigo. Ao contrário da classe CTabs, o controle do tipo CIconTabs pode ter ícones ajustáveis para cada guia. Isso pode ajudar a tornar a interface gráfica mais amigável, se necessário.
Os ícones e textos exibidos podem ser colocados com precisão em relação à borda de cada guia, usando os métodos especiais (ver no código abaixo):
//+------------------------------------------------------------------+ //| Classe para a criação do ícone das guias | //+------------------------------------------------------------------+ class CIconTabs : public CElement { private: //--- Margens do rótulo int m_icon_x_gap; int m_icon_y_gap; //--- Margens do rótulo de texto int m_label_x_gap; int m_label_y_gap; //--- public: //--- Margens do rótulo void IconXGap(const int x_gap) { m_icon_x_gap=x_gap; } void IconYGap(const int y_gap) { m_icon_y_gap=y_gap; } //--- Margens do rótulo de texto void LabelXGap(const int x_gap) { m_label_x_gap=x_gap; } void LabelYGap(const int y_gap) { m_label_y_gap=y_gap; } };
Um exemplo da aparência do ícone do controle guias é exibido na imagem abaixo:
Fig. 10. Controle ícone das guias.
O código desse expert também pode ser baixado a partir dos anexos deste artigo.
Conclusão
A esquemática da biblioteca para a criação das interfaces gráficas no atual estágio de desenvolvimento é parecido com a imagem abaixo:
Fig. 11. Estrutura da biblioteca no atual estágio de desenvolvimento.
Os controles tabela e guias foram cobertos na sétima parte da série sobre a criação das interfaces gráficas nos terminais de negociação MetaTrader. Foi fornecido três classes (CLabelsTable, CTable e CCanvasTable) para a criação de tabelas e duas classes (CTabs e CIconTabs) para a criação das guias.
A próxima parte (oitava) da série nós vamos estudar os seguintes controles.
- Calendário estático e suspenso.
- Lista hierárquica.
- Navegador de arquivos.
Você pode encontrar e baixar o material da sétima parte da série nos arquivos anexados para testar o seu funcionamento. Se você tiver dúvidas sobre a utilização do material a partir desses arquivos, você poderá consultar a descrição detalhada do desenvolvimento da biblioteca em um dos artigos da lista abaixo ou fazer sua pergunta nos comentários deste artigo.
Lista de artigos (capítulos) da sétima parte:
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/2503





- 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