EA com interface gráfica: Criação do painel (Parte I)
Sumário
- Introdução
- Elementos da interface gráfica
- Montagem da interface gráfica do usuário
- Formulário para controles
- Barra de Status
- Grupo de guias
- Campo inserido
- Botão
- Caixa de combinação com lista suspensa
- Caixa de verificação
- Tabela
- Gráfico padrão
- Barra de progresso
- Atualizações da biblioteca EasyAndFast
- Fim do artigo
Introdução
Apesar do desenvolvimento ativo do algo-trading, muitos traders ainda preferem negociar manualmente, porém, há poucas hipóteses de fazer o trabalho sem automatizar as operações de rotina.
Este artigo mostra a criação de um EA multissímbolo de sinal para negociação manual. Como exemplo, vamos examinar os sinais do indicador Stochastic fornecido com o terminal. Este código pode ser usado para criar seus próprios EAs com uma interface gráfica, pois você pode conectar a ele qualquer outro indicador ou usar os resultados de certos cálculos para tomar decisões.
Para aqueles que atendem encomendas no serviço Freelance, este artigo pode exemplificar uns termos de referência para mostrar aos clientes. É possível que este exemplo ajude a reduzir o tempo que leva redigir os termos de referência de um programa com interface gráfica.
Listemos os assuntos que serão discutidos em detalhes neste artigo:
- Criação de uma interface gráfica.
- Obtenção de uma lista de símbolos com as propriedades especificadas.
- Controles de operações de negociação.
- Alternância rápida de símbolos e timeframes em gráficos sem reinicialização do EA.
- Gerenciamento das propriedades dos gráficos através da interface do usuário.
- Obtenção dos sinais do indicador a partir de um conjunto de símbolos com indicação de cor.
- Trabalho com posições abertas.
- Atualizações da biblioteca EasyAndFast.
O artigo será publicado em duas partes. Neste artigo, será considerada a criação de um painel; no próximo, será descrita a parte de sua funcionalidade.
Elementos da interface gráfica
O desenvolvimento do EA começará com a construção de uma interface gráfica, através da qual será implementada a interação com o usuário e com a visualização dos dados. Pode-se criar uma interface gráfica, usando os recursos da biblioteca padrão, mas, no meu exemplo, ela será implementada com base na biblioteca EasyAndFast. Seus ricos recursos permitem concentrar-se na funcionalidade do próprio programa, sem se distrair com a revisão e melhoramento de sua parte gráfica.
Primeiro, vamos delinear o esquema geral da interface gráfica. O esquema abaixo mostra que há um grupo de duas guias na janela da interface gráfica do usuário. As listas mostram as funções que precisam ser colocadas nelas. Este é um exemplo simplificado, mas o cliente e o desenvolvedor podem trabalhá-lo com mais detalhes durante a discussão da tarefa.
Fig. 1. Esquema geral da interface gráfica com esclarecimentos.
Pode haver muitos controles de interface gráfica do usuário, por isso, primeiro, simplesmente os listamos de forma hierárquica:
- Formulário para controles
- Barra de status para mostrar informações adicionais finais
- Grupo de guias:
- Trade:
- Campo inserido com caixa de verificação para filtrar a lista de símbolos
- Botão de solicitação para começar a coletar a lista de símbolos
- Botão para a operação de negociação SELL
- Botão para a operação de negociação BUY
- Campo inserido para definir o volume do trade
- Botão para fechar todas as posições abertas
- Campo inserido para definir o nível do sinal de venda
- Campo inserido para definir o nível do sinal de compra
- Tabela de símbolos de negociação
- Gráfico para visualizar estes símbolos. Por conveniência, vamos fazer com que algumas propriedades do gráfico possam ser controladas com a ajuda do seguinte grupo de elementos:
- Caixa de combinação com lista suspensa para selecionar a alternância de timeframe
- Caixa de verificação para habilitar/desabilitar a escala de tempo
- Caixa de verificação para habilitar/desabilitar a escala de preços
- Campo inserido para controlar a escala
- Botão para ativar o recuo
- Caixa de verificação para exibição do indicador
- Positions:
- Tabela de posições
- Indicador para o processo de reprodução de quadros
Na classe principal do programa (CProgram), declare os métodos e instâncias das classes dos elementos acima. O código dos métodos para criação destes elementos é colocado num arquivo separado e é conectado a um arquivo com a classe do programa MQL:
//+----------´--------------------------------------------------------+ //| Classe para criar o aplicativo | //+----------´--------------------------------------------------------+ class CProgram : public CWndEvents { private: //--- Janela CWindow m_window1; //--- Barra de Status CStatusBar m_status_bar; //--- Guias CTabs m_tabs1; //--- Campo inserido CTextEdit m_symb_filter; CTextEdit m_lot; CTextEdit m_up_level; CTextEdit m_down_level; CTextEdit m_chart_scale; //--- Botões CButton m_request; CButton m_chart_shift; CButton m_buy; CButton m_sell; CButton m_close_all; //--- Caixas de combinação CComboBox m_timeframes; //--- Caixas de verificação CCheckBox m_date_scale; CCheckBox m_price_scale; CCheckBox m_show_indicator; //--- Tabelas CTable m_table_positions; CTable m_table_symb; //--- Gráfico padrão CStandardChart m_sub_chart1; //--- Barra de progresso CProgressBar m_progress_bar; //--- public: //--- Cria uma interface gráfica bool CreateGUI(void); //--- private: //--- Formulário bool CreateWindow(const string text); //--- Barra de Status bool CreateStatusBar(const int x_gap,const int y_gap); //--- Guias bool CreateTabs1(const int x_gap,const int y_gap); //--- Campo inserido bool CreateSymbFilter(const int x_gap,const int y_gap,const string text); bool CreateLot(const int x_gap,const int y_gap,const string text); bool CreateUpLevel(const int x_gap,const int y_gap,const string text); bool CreateDownLevel(const int x_gap,const int y_gap,const string text); bool CreateChartScale(const int x_gap,const int y_gap,const string text); //--- Botões bool CreateRequest(const int x_gap,const int y_gap,const string text); bool CreateChartShift(const int x_gap,const int y_gap,const string text); bool CreateBuy(const int x_gap,const int y_gap,const string text); bool CreateSell(const int x_gap,const int y_gap,const string text); bool CreateCloseAll(const int x_gap,const int y_gap,const string text); //--- Caixa de combinação bool CreateComboBoxTF(const int x_gap,const int y_gap,const string text); //--- Caixas de verificação bool CreateDateScale(const int x_gap,const int y_gap,const string text); bool CreatePriceScale(const int x_gap,const int y_gap,const string text); bool CreateShowIndicator(const int x_gap,const int y_gap,const string text); //--- Tabelas bool CreatePositionsTable(const int x_gap,const int y_gap); bool CreateSymbolsTable(const int x_gap,const int y_gap); //--- Gráfico padrão bool CreateSubChart1(const int x_gap,const int y_gap); //--- Barra de progresso bool CreateProgressBar(const int x_gap,const int y_gap,const string text); }; //+----------´--------------------------------------------------------+ //| Métodos para criar controles | //+----------´--------------------------------------------------------+ #include "CreateGUI.mqh" //+----------´--------------------------------------------------------+
Em seguida, damos uma olhada mais de perto à montagem da interface gráfica do usuário, os métodos para criar seus elementos e suas propriedades.
Montagem da interface gráfica do usuário
A interface gráfica do aplicativo a ser desenvolvido utilizará elementos de dez tipos diferentes:
- Formulário para controles (CWindow)
- Barra de Status (CStatusBar)
- Grupo de guias (CTabs)
- Campo inserido (CTextEdit)
- Botão (CButton)
- Caixa de combinação com lista suspensa (CComboBox)
- Caixa de verificação (CCheckBox)
- Tabela (CTable)
- Gráfico padrão (CStandardChart)
- Barra de progresso (CProgressBar)
Nesta lista, haverá vários elementos, portanto considere apenas um de cada grupo. Na mesma sequência, considere os métodos para criá-los.
Formulário para controles
Abaixo está o código do método para criar um formulário no qual serão localizados todos os outros elementos. No começo, você precisa adicionar o formulário à lista de elementos da interface gráfica do usuário do programa. Para fazer isso, você precisa chamar o método CWndContainer::AddWindow(), passando para ele o objeto de um elemento do tipo CWindow. Logo, antes de criar o formulário, defina suas propriedades. Defina as seguintes propriedades (na mesma ordem que na listagem abaixo):
- Dimensões do formulário (largura e altura)
- Tamanho da fonte no cabeçalho
- Modo de deslocamento do formulário (dentro do gráfico)
- Modo de redimensionamento manual do formulário (arrastando bordas)
- Botões do formulário. A visibilidade de cada botão é ativada separadamente. Nesse caso, estão envolvidos os seguintes:
- Encerramento do formulário. No formulário principal do programa, quando você clica neste botão, aparece uma caixa de diálogo perguntando sobre o encerramento do programa.
- Recolher e expandir o formulário.
- Dica de balão de elementos. Este botão também tem dois estados. Se for pressionado, serão exibidas dicas de balão (desde que tenham sido definidas).
- Expandir o formulário em toda a área do gráfico do terminal. Expandido o formulário, ele poderá ser retornado às dimensões anteriores clicando neste botão novamente.
- Para cada botão de formulário, você pode definir uma dica de balão.
Depois que as propriedades estiverem definidas, você precisará chamar o método de criação de formulário CWindow::CreateWindow() e transferir para ele:
- o identificador do gráfico,
- o número da subjanela do gráfico,
- o texto do cabeçalho,
- as coordenadas iniciais de localização para o formulário.
//+----------´--------------------------------------------------------+ //| Criando o formulário para os controles | //+----------´--------------------------------------------------------+ bool CProgram::CreateWindow(const string caption_text) { //--- Adicione o ponteiro da janela para a matriz de janelas CWndContainer::AddWindow(m_window1); //--- Propriedades m_window1.XSize(750); m_window1.YSize(450); m_window1.FontSize(9); m_window1.IsMovable(true); m_window1.ResizeMode(true); m_window1.CloseButtonIsUsed(true); m_window1.CollapseButtonIsUsed(true); m_window1.TooltipsButtonIsUsed(true); m_window1.FullscreenButtonIsUsed(true); //--- Defina as dicas de balão m_window1.GetCloseButtonPointer().Tooltip("Close"); m_window1.GetTooltipButtonPointer().Tooltip("Tooltips"); m_window1.GetFullscreenButtonPointer().Tooltip("Fullscreen"); m_window1.GetCollapseButtonPointer().Tooltip("Collapse/Expand"); //--- Criação do formulário if(!m_window1.CreateWindow(m_chart_id,m_subwin,caption_text,1,1)) return(false); //--- return(true); }
Sempre que adicionando ao código um novo elemento da interface gráfica do usuário, é desejável compilar o programa e ver qual é o resultado:
Fig. 2. Formulário para controles.
Abaixo estão as capturas de tela de todos os resultados intermediários.
Barra de Status
O código do método para criar a barra de status começa com a definição do elemento principal. A partir dele serão calculados o posicionamento e o alinhamento de acordo com o tamanho dos elementos associados a ele. Isso ajuda a poupar tempo, pois todo um grupo de elementos relacionados pode ser movido, alterando as coordenadas apenas para o elemento principal. Para associar um elemento, seu ponteiro é passado para o método CElement::MainPointer(). Neste exemplo, ligamos a barra de status a um formulário, por isso, transfira o objeto do formulário para o método.
Em seguida, defina as propriedades da barra de status. Nela, você fará três itens em que serão exibidas as informações para o usuário.
- Para não especificar dimensões relativas à forma, indique que a largura deve mudar automaticamente quando a largura do formulário for alterada.
- O recuo da borda direita do elemento a partir da borda direita do formulário será de 1 pixel.
- Associe a barra de status à parte inferior do formulário para que, quando a altura mudar, ele se ajuste automaticamente à borda inferior.
- Em seguida, ao adicionar itens, especifique suas larguras.
Depois que as propriedades estiverem definidas, crie o elemento. Agora ele está pronto para trabalhar e você pode alterar o texto em seus itens quando o programa estiver em execução. No nosso exemplo, defina no primeiro item o texto «For Help, press F1».
No final do método, você sempre deve salvar o ponteiro do elemento criado na lista geral de elementos da interface gráfica do usuário. Para fazer isso, chame o método CWndContainer::AddToElementsArray(), transfira para ele o índice do formulário e o objeto do elemento. Como só temos um formulário, seu índice será 0.
//+----------´--------------------------------------------------------+ //| Criando a barra de status | //+----------´--------------------------------------------------------+ bool CProgram::CreateStatusBar(const int x_gap,const int y_gap) { #define STATUS_LABELS_TOTAL 3 //--- Salve o ponteiro para a janela m_status_bar.MainPointer(m_window1); //--- Propriedades m_status_bar.AutoXResizeMode(true); m_status_bar.AutoXResizeRightOffset(1); m_status_bar.AnchorBottomWindowSide(true); //--- Especifique quantas partes devem ser e defina suas propriedades int width[STATUS_LABELS_TOTAL]={0,200,110}; for(int i=0; i<STATUS_LABELS_TOTAL; i++) m_status_bar.AddItem(width[i]); //--- Crie o elemento de controle if(!m_status_bar.CreateStatusBar(x_gap,y_gap)) return(false); //--- Definição do texto para os itens da barra de status m_status_bar.SetValue(0,"For Help, press F1"); //--- Adicione um objeto à matriz comum de grupos de objetos CWndContainer::AddToElementsArray(0,m_status_bar); return(true); }
Outros elementos da biblioteca EasyAndFast são criados seguindo o mesmo princípio. Portanto, consideraremos apenas as propriedades que serão definidas para serem usadas em nosso EA.
Fig. 3. Adição da barra de status.
Grupo de guias
No método para criar um grupo de guias, defina as seguintes propriedades para o elemento:
- Texto nas guias centralizado.
- Guias na parte superior do espaço de trabalho.
- Dimensões que se ajustam automaticamente à área do elemento principal (formulário). Nesse caso, não é necessário especificar o tamanho da área do grupo de guias.
- Recuo a partir das bordas direita e inferior do elemento principal. Ao redimensionar o formulário, esses recuos persistem.
- Ao adicionar as seguintes guias, o nome e a largura da guia também são transferidos para o método.
Veja o código do método:
//+----------´--------------------------------------------------------+ //| Criando um grupo com guias 1 | //+----------´--------------------------------------------------------+ bool CProgram::CreateTabs1(const int x_gap,const int y_gap) { #define TABS1_TOTAL 2 //--- Salve o ponteiro para o elemento principal m_tabs1.MainPointer(m_window1); //--- Propriedades m_tabs1.IsCenterText(true); m_tabs1.PositionMode(TABS_TOP); m_tabs1.AutoXResizeMode(true); m_tabs1.AutoYResizeMode(true); m_tabs1.AutoXResizeRightOffset(3); m_tabs1.AutoYResizeBottomOffset(25); //--- Adicione guias com as propriedades especificadas string tabs_names[TABS1_TOTAL]={"Trade","Positions"}; for(int i=0; i<TABS1_TOTAL; i++) m_tabs1.AddTab(tabs_names[i],100); //--- Crie o elemento de controle if(!m_tabs1.CreateTabs(x_gap,y_gap)) return(false); //--- Adicione um objeto à matriz comum de grupos de objetos CWndContainer::AddToElementsArray(0,m_tabs1); return(true); }
Fig. 4. Adicionando um grupo de guias.
Campo inserido
Por exemplo, consideremos um campo inserido em que o usuário pode especificar moedas e/ou pares de moedas para formar uma lista de símbolos numa tabela. Seu elemento principal será um grupo de guias. Aqui é preciso especificar em qual guia exibir este campo inserido. Para fazer isso, chame o método CTabs::AddToElementsArray(), transfira para ele o índice da guia e o objeto do elemento anexado.
Em seguida, consideramos as propriedades definidas para esse campo inserido.
- Por padrão, no campo inserido será inserido o texto «USD»: o programa coletará na tabela símbolos em que há USD. A moeda e/ou símbolos neste campo inserido devem ser separados por vírgulas. Abaixo, mostrarei o método que permite formar uma lista de símbolos - de acordo com linhas separadas por vírgulas - neste campo inserido.
- O campo inserido será acompanhado por uma caixa de verificação. Se você desativar a caixa de verificação, o texto no campo inserido será ignorado e todos os pares de moedas encontrados serão incluídos na lista de símbolos.
- A largura do campo inserido será toda a largura do elemento principal. Ela também será corrigida se você alterar a largura da área das guias.
- À direita do campo inserido estará o botão Request. Enquanto o programa está em execução, você pode especificar outras moedas e/ou símbolos no campo inserido, e, para que a lista seja formada, você precisará clicar neste botão. Como estão implícitas a alteração automática da largura do campo inserido e a localização do botão Request sempre à direita, é necessário que o lado direito do campo inserido sempre tenha um recuo a partir da borda direita do elemento principal.
O elemento de tipo CTextEdit consiste em vários outros elementos. Portanto, se você precisar alterar suas propriedades, você pode obter ponteiros para eles. Nós precisávamos mudar algumas propriedades do campo inserido (CTextBox). Vamos considerá-las na mesma sequência, conforme implementado na listagem de código abaixo.
- Recuo do campo inserido a partir da borda esquerda do elemento principal (CTextEdit).
- Alteração automática de largura em relação ao elemento principal.
- Ao ativar o campo inserido (clique no botão esquerdo do mouse no campo inserido), o texto é marcado automaticamente como selecionado para uma possível substituição rápida.
- Se não houver texto no campo inserido, será exibida a seguinte infodica: «Example: EURUSD, GBP, NOK».
Por padrão, a caixa de verificação do campo inserido está ativada. Para fazer isso, é preciso ativá-la logo após o elemento ser criado.
//+----------´------------------------------------------------------------------+ //| Criando uma caixa de verificação com o campo inserido "Symbols filter" | //+----------´------------------------------------------------------------------+ bool CProgram::CreateSymbolsFilter(const int x_gap,const int y_gap,const string text) { //--- Salve o ponteiro para o elemento principal m_symb_filter.MainPointer(m_tabs1); //--- Fixe na guia m_tabs1.AddToElementsArray(0,m_symb_filter); //--- Propriedades m_symb_filter.SetValue("USD"); // "EUR,USD" "EURUSD,GBPUSD" "EURUSD,GBPUSD,AUDUSD,NZDUSD,USDCHF" m_symb_filter.CheckBoxMode(true); m_symb_filter.AutoXResizeMode(true); m_symb_filter.AutoXResizeRightOffset(90); m_symb_filter.GetTextBoxPointer().XGap(100); m_symb_filter.GetTextBoxPointer().AutoXResizeMode(true); m_symb_filter.GetTextBoxPointer().AutoSelectionMode(true); m_symb_filter.GetTextBoxPointer().DefaultText("Example: EURUSD,GBP,NOK"); //--- Crie o elemento de controle if(!m_symb_filter.CreateTextEdit(text,x_gap,y_gap)) return(false); //--- Ative a caixa de verificação m_symb_filter.IsPressed(true); //--- Adicione um objeto à matriz comum de grupos de objetos CWndContainer::AddToElementsArray(0,m_symb_filter); return(true); }
Além do campo inserido, haverá numerais na interface gráfica. Por exemplo, o campo inserido Lot (volume para abertura de posições). Para campos inseridos desse tipo, você precisa especificar outras propriedades.
- Largura total do elemento.
- Valor máximo a ser inserido.
- Valor mínimo a ser inserido.
- Incremento ao alternar com os botões de incremento e decremento.
- Número de casas decimais.
- Para que o campo inserido seja numérico, você precisa especificar isso usando o método CTextEdit::SpinEditMode().
- Valor padrão após o carregamento do programa no gráfico do terminal.
- Largura do campo inserido.
- Seleção automática de texto no campo inserido ao clicar nele.
- Acoplagem do campo inserido à borda direita do elemento.
Veja o código para este método:
//+----------´--------------------------------------------------------+ //| Criando o campo inserido "Lot" | //+----------´--------------------------------------------------------+ bool CProgram::CreateLot(const int x_gap,const int y_gap,const string text) { //--- Salve o ponteiro para o elemento principal m_lot.MainPointer(m_tabs1); //--- Fixe na guia m_tabs1.AddToElementsArray(0,m_lot); //--- Propriedades m_lot.XSize(80); m_lot.MaxValue(1000); m_lot.MinValue(0.01); m_lot.StepValue(0.01); m_lot.SetDigits(2); m_lot.SpinEditMode(true); m_lot.SetValue((string)0.1); m_lot.GetTextBoxPointer().XSize(50); m_lot.GetTextBoxPointer().AutoSelectionMode(true); m_lot.GetTextBoxPointer().AnchorRightWindowSide(true); //--- Crie o elemento de controle if(!m_lot.CreateTextEdit(text,x_gap,y_gap)) return(false); //--- Adicione um objeto à matriz comum de grupos de objetos CWndContainer::AddToElementsArray(0,m_lot); return(true); }
Fig. 5. Adicionando campos inseridos.
A imagem não parece muito lógica, mas quando você adiciona os outros elementos, tudo fica certo.
Botão
Adicione alguns botões à interface gráfica do nosso EA. Considere o que tem mais propriedades, isto é, o botão para abrir as posições SELL.
- Largura do botão.
- Texto do botão centrado, tanto na vertical como na horizontal.
- Cor de fundo do botão.
- Cor de fundo ao passar o cursor.
- Cor de fundo ao clicar com o botão esquerdo.
- Cor do texto do botão.
- Cor do texto ao passar o cursor.
- Cor do texto ao clicar com o botão esquerdo.
- Cor da borda do botão.
- Cor da borda ao passar o cursor.
- Cor da borda ao clicar com o botão esquerdo.
No botão BUY são alteradas as mesmas propriedades, porém, existe uma diferença apenas nas cores de plano de fundo especificadas.
//+----------´--------------------------------------------------------+ //| Criando o botão 'Sell' | //+----------´--------------------------------------------------------+ bool CProgram::CreateSell(const int x_gap,const int y_gap,const string text) { //--- Salve o ponteiro para o elemento principal m_sell.MainPointer(m_tabs1); //--- Fixe na guia m_tabs1.AddToElementsArray(0,m_sell); //--- Propriedades m_sell.XSize(80); m_sell.IsCenterText(true); m_sell.BackColor(C'255,51,51'); m_sell.BackColorHover(C'255,100,100'); m_sell.BackColorPressed(C'195,0,0'); m_sell.LabelColor(clrWhite); m_sell.LabelColorHover(clrWhite); m_sell.LabelColorPressed(clrWhite); m_sell.BorderColor(clrBlack); m_sell.BorderColorHover(clrBlack); m_sell.BorderColorPressed(clrBlack); //--- Crie o elemento de controle if(!m_sell.CreateButton(text,x_gap,y_gap)) return(false); //--- Adicione o ponteiro para o elemento na base CWndContainer::AddToElementsArray(0,m_sell); return(true); }
Fig. 6 Adicionando botões.
Caixa de combinação com lista suspensa
Para alterar o timeframe, crie uma caixa de combinação com uma lista suspensa. Liste as propriedades para configurá-la.
- Largura total do elemento.
- Número de itens na lista (no nosso caso 21, conforme o número de timeframes no terminal).
- Elemento ancorado ao lado direito da área das guias.
- Largura do botão da caixa de combinação.
- Botão ancorado ao lado direito do elemento.
Logo, cada item da lista recebe valores e, em seguida, para a lista são definidas algumas propriedades através do ponteiro.
- Realce de itens ao passar o cursor.
- Item realçado. Neste caso, será o item com o índice 18 (timeframe D1).
Veja o código do método para criar esta caixa de combinação:
//+----------´--------------------------------------------------------+ //| Criando uma caixa de combinação para selecionar timeframes | //+----------´--------------------------------------------------------+ bool CProgram::CreateComboBoxTF(const int x_gap,const int y_gap,const string text) { //--- Número total de itens na lista #define ITEMS_TOTAL2 21 //--- Transfira o objeto do painel m_timeframes.MainPointer(m_tabs1); //--- Fixe na guia m_tabs1.AddToElementsArray(0,m_timeframes); //--- Propriedades m_timeframes.XSize(115); m_timeframes.ItemsTotal(ITEMS_TOTAL2); m_timeframes.AnchorRightWindowSide(true); m_timeframes.GetButtonPointer().XSize(50); m_timeframes.GetButtonPointer().AnchorRightWindowSide(true); //--- Salve os valores dos itens na lista da caixa de combinação string items_text[ITEMS_TOTAL2]={"M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30","H1","H2","H3","H4","H6","H8","H12","D1","W1","MN"}; for(int i=0; i<ITEMS_TOTAL2; i++) m_timeframes.SetValue(i,items_text[i]); //--- Obtenha o ponteiro da lista CListView *lv=m_timeframes.GetListViewPointer(); //--- Definia as propriedades da lista lv.LightsHover(true); lv.SelectItem(18); //--- Crie o elemento de controle if(!m_timeframes.CreateComboBox(text,x_gap,y_gap)) return(false); //--- Adicione o ponteiro para o elemento na base CWndContainer::AddToElementsArray(0,m_timeframes); return(true); }
Fig. 7. Adicionando caixa de combinação.
Caixa de verificação
A caixa de verificação é o elemento mais simples. Para ele, basta especificar duas propriedades.
- Largura
- Localização no lado direito do elemento principal.
Após criar um elemento, você pode ativar programaticamente a caixa de verificação.
//+----------´--------------------------------------------------------+ //| Criando a caixa de verificação "Date scale" | //+----------´--------------------------------------------------------+ bool CProgram::CreateDateScale(const int x_gap,const int y_gap,const string text) { //--- Salve o ponteiro para a janela m_date_scale.MainPointer(m_tabs1); //--- Fixe na guia m_tabs1.AddToElementsArray(0,m_date_scale); //--- Propriedades m_date_scale.XSize(70); m_date_scale.AnchorRightWindowSide(true); //--- Crie o elemento de controle if(!m_date_scale.CreateCheckBox(text,x_gap,y_gap)) return(false); //--- Ative a caixa de verificação m_date_scale.IsPressed(true); //--- Adicione um objeto à matriz comum de grupos de objetos CWndContainer::AddToElementsArray(0,m_date_scale); return(true); }
Fig. 8. Adicionando caixas de verificação.
Tabela
A interface gráfica do usuário terá duas tabelas. Considere a que torna visível a lista gerada de símbolos e de sinais para a abertura de posições. Ela é colocada na primeira guia. Primeiro, declare e inicialize as matrizes para definir as propriedades da tabela. Configure as seguintes propriedades.
- Largura do elemento
- Dimensão da tabela (o número de colunas e de linhas).
- Largura da coluna (os valores são transferidos numa matriz).
- Alinhamento do texto (os valores são transferidos numa matriz).
- Recuo do texto a partir das bordas das células.
- Exibição de cabeçalhos.
- Capacidade de selecionar linhas.
- Capacidade de redimensionar as colunas manualmente, arrastando a borda do cabeçalho.
- Exibir com formatação no estilo Zebra.
- Redimensionar automaticamente verticalmente em relação ao elemento principal.
- Recuo a partir da borda inferior do elemento principal.
O texto dos cabeçalhos pode ser especificado após a criação da tabela:
//+----------´--------------------------------------------------------+ //| Criando a tabela de símbolos | //+----------´--------------------------------------------------------+ bool CProgram::CreateSymbolsTable(const int x_gap,const int y_gap) { #define COLUMNS1_TOTAL 2 #define ROWS1_TOTAL 1 //--- Salve o ponteiro para o elemento principal m_table_symb.MainPointer(m_tabs1); //--- Fixe na guia m_tabs1.AddToElementsArray(0,m_table_symb); //--- Matriz de largura de colunas int width[COLUMNS1_TOTAL]={95,58}; //--- Matriz de alinhamento do texto, nas colunas ENUM_ALIGN_MODE align[COLUMNS1_TOTAL]={ALIGN_LEFT,ALIGN_RIGHT}; //--- Matriz de recuo do texto, nas colunas, ao longo do eixo X int text_x_offset[COLUMNS1_TOTAL]={5,5}; //--- Propriedades m_table_symb.XSize(168); m_table_symb.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL); m_table_symb.ColumnsWidth(width); m_table_symb.TextAlign(align); m_table_symb.TextXOffset(text_x_offset); m_table_symb.ShowHeaders(true); m_table_symb.SelectableRow(true); m_table_symb.ColumnResizeMode(true); m_table_symb.IsZebraFormatRows(clrWhiteSmoke); m_table_symb.AutoYResizeMode(true); m_table_symb.AutoYResizeBottomOffset(2); //--- Crie o elemento de controle if(!m_table_symb.CreateTable(x_gap,y_gap)) return(false); //--- Definimos o título do cabeçalho m_table_symb.SetHeaderText(0,"Symbol"); m_table_symb.SetHeaderText(1,"Values"); //--- Adicione um objeto à matriz comum de grupos de objetos CWndContainer::AddToElementsArray(0,m_table_symb); return(true); }
A segunda tabela exibe algumas propriedades das posições abertas. Suas dez colunas exibirão os seguintes dados:
- Símbolo da posição.
- Número de posições.
- Volume total de todas as posições abertas.
- Volume das posições BUY.
- Volume das posições SELL.
- Total atual para todas as posições abertas.
- Total atual para todas as posições BUY abertas.
- Total atual para todas as posições SELL abertas.
- Carga do depósito para cada símbolo separadamente.
- Preço médio.
Na segunda tabela, você também deve configurar as seguintes propriedades:
- Recuo de imagens a partir das bordas direita e superior das células.
- Capacidade de classificar valores.
- Redimensionar automaticamente horizontalmente em relação ao elemento principal.
- Recuo a partir da borda direita do elemento principal.
As imagens nas células da primeira coluna simbolizarão os botões que, ao ser clicados, fecham a posição ou todas as posições, se esta é uma conta de hedge, no símbolo especificado.
//+----------´--------------------------------------------------------+ //| Criando uma tabela de posições | //+----------´--------------------------------------------------------+ bool CProgram::CreatePositionsTable(const int x_gap,const int y_gap) { ... //--- Propriedades m_table_positions.TableSize(COLUMNS2_TOTAL,ROWS2_TOTAL); m_table_positions.ColumnsWidth(width); m_table_positions.TextAlign(align); m_table_positions.TextXOffset(text_x_offset); m_table_positions.ImageXOffset(image_x_offset); m_table_positions.ImageYOffset(image_y_offset); m_table_positions.ShowHeaders(true); m_table_positions.IsSortMode(true); m_table_positions.SelectableRow(true); m_table_positions.ColumnResizeMode(true); m_table_positions.IsZebraFormatRows(clrWhiteSmoke); m_table_positions.AutoXResizeMode(true); m_table_positions.AutoYResizeMode(true); m_table_positions.AutoXResizeRightOffset(2); m_table_positions.AutoYResizeBottomOffset(2); ... return(true); }
Fig. 9. Adicionando uma tabela na primeira guia.
Fig. 10. Adicionando uma tabela na segunda guia.
Numa das próximas seções do artigo, falarei sobre como trabalhar com tabelas no arquivo principal do programa (CProgram).
Gráfico padrão
Para visualizar dados por símbolos, é fornecido um elemento do tipo CStandardChart. Por padrão, será exibido o gráfico EURUSD no timeframe diário. Ele tem as seguintes propriedades.
- Rolagem horizontal.
- Ajuste automático de largura
- Ajuste automático de altura.
- Recuo a partir da borda direita do elemento principal.
- Recuo a partir da borda inferior do elemento principal.
Se necessário, você pode criar uma matriz de gráficos alinhados horizontalmente. Para fazer isso, use o método CStandardChart::AddSubChart(), transferindo para ele o símbolo e o timeframe do gráfico como argumentos. Mas, neste caso, você precisa apenas de um gráfico, enquanto os símbolos e timeframes serão alternados usando outros controles.
//+----------´--------------------------------------------------------+ //| Criando o gráfico padrão 1 | //+----------´--------------------------------------------------------+ bool CProgram::CreateSubChart1(const int x_gap,const int y_gap) { //--- Salve o ponteiro para a janela m_sub_chart1.MainPointer(m_tabs1); //--- Fixe na primeira guia m_tabs1.AddToElementsArray(0,m_sub_chart1); //--- Propriedades m_sub_chart1.XScrollMode(true); m_sub_chart1.AutoXResizeMode(true); m_sub_chart1.AutoYResizeMode(true); m_sub_chart1.AutoXResizeRightOffset(125); m_sub_chart1.AutoYResizeBottomOffset(2); //--- Adicione os gráficos m_sub_chart1.AddSubChart("EURUSD",PERIOD_D1); //--- Crie o elemento de controle if(!m_sub_chart1.CreateStandardChart(x_gap,y_gap)) return(false); //--- Adicione um objeto à matriz comum de grupos de objetos CWndContainer::AddToElementsArray(0,m_sub_chart1); return(true); }
Fig. 11. Adicionando o gráfico.
Barra de progresso
Para que o usuário entenda o que o programa está fazendo agora, adicione uma barra de progresso à interface gráfica. Veja as propriedades do nosso exemplo (na mesma ordem que no código):
- Altura total do elemento.
- Altura do indicador (barra de progresso).
- Recuo do indicador ao longo do eixo X.
- Recuo do indicador ao longo do eixo Y.
- Recuo da etiqueta principal ao longo do eixo X.
- Recuo da etiqueta principal ao longo do eixo Y.
- Recuo da etiqueta de porcentagem ao longo do eixo X.
- Recuo da etiqueta de porcentagem ao longo do eixo Y.
- Atributo do item suspenso (para ocultamento automático).
- Fonte.
- Cor da borda do indicador.
- Cor de fundo do indicador.
- Cor da barra de progresso do indicador.
- Ajuste automático de largura
- Recuo a partir da borda direita do elemento principal.
Abaixo, mostrarei exemplos de uso da barra de progresso
//+----------´--------------------------------------------------------+ //| Criando uma barra de progresso | //+----------´--------------------------------------------------------+ bool CProgram::CreateProgressBar(const int x_gap,const int y_gap,const string text) { //--- Salve o ponteiro para o elemento principal m_progress_bar.MainPointer(m_status_bar); //--- Propriedades m_progress_bar.YSize(17); m_progress_bar.BarYSize(14); m_progress_bar.BarXGap(0); m_progress_bar.BarYGap(1); m_progress_bar.LabelXGap(5); m_progress_bar.LabelYGap(2); m_progress_bar.PercentXGap(5); m_progress_bar.PercentYGap(2); m_progress_bar.IsDropdown(true); m_progress_bar.Font("Consolas"); m_progress_bar.BorderColor(clrSilver); m_progress_bar.IndicatorBackColor(clrWhiteSmoke); m_progress_bar.IndicatorColor(clrLightGreen); m_progress_bar.AutoXResizeMode(true); m_progress_bar.AutoXResizeRightOffset(2); //--- Criação do elemento if(!m_progress_bar.CreateProgressBar(text,x_gap,y_gap)) return(false); //--- Adicione o ponteiro para o elemento na base CWndContainer::AddToElementsArray(0,m_progress_bar); return(true); }
Revimos todos os controles que serão utilizados na interface gráfica do nosso EA. Apesar de, no momento, ser apenas uma interface gráfica, escreveremos todos os métodos necessários para fazer todo funcione de acordo com a idéia original.
Atualizações da biblioteca EasyAndFast
Na biblioteca EasyAndFast, na classe CTable, foi desenvolvido totalmente o método público CTable::SortData(). Agora, como segundo argumento, você pode especificar a direção de classificação de tabela (opcional). Anteriormente, uma nova chamada do método CTable::SortData() iniciava a classificação na direção oposta à atual. Além disso, foram adicionados os métodos para obter a direção da classificação atual e o índice da coluna classificada. Agora, se a tabela for manualmente classificada pelo usuário (clicando no cabeçalho) e, em seguida, os dados na tabela não forem atualizados na mesma sequência, então após descobrir a direção de classificação atual, você poderá restaurá-la.
//+----------´--------------------------------------------------------+ //| Classe para criar uma tabela | //+----------´--------------------------------------------------------+ class CTable : public CElement { public: ... //--- Classificando dados segundo a coluna especificada void SortData(const uint column_index=0,const int direction=WRONG_VALUE); //--- (1) Direção atual da classificação, (2) índice da matriz classificada int IsSortDirection(void) const { return(m_last_sort_direction); } int IsSortedColumnIndex(void) const { return(m_is_sorted_column_index); } ... }; //+----------´--------------------------------------------------------+ //| Classificando dados segundo a coluna especificada | //+----------´--------------------------------------------------------+ void CTable::SortData(const uint column_index=0,const int direction=WRONG_VALUE) { //--- Sair, se você sair das bordas da tabela if(column_index>=m_columns_total) return; //--- Índice a partir do qual é necessário começar a classificação uint first_index=0; //--- Último índice uint last_index=m_rows_total-1; //--- Sem controle de direção do usuário if(direction==WRONG_VALUE) { //--- A primeira vez será classificada em ordem crescente e, em seguida, toda vez na direção oposta if(m_is_sorted_column_index==WRONG_VALUE || column_index!=m_is_sorted_column_index || m_last_sort_direction==SORT_DESCEND) m_last_sort_direction=SORT_ASCEND; else m_last_sort_direction=SORT_DESCEND; } else { m_last_sort_direction=(ENUM_SORT_MODE)direction; } //--- Lembre-se do índice da última coluna classificada de dados m_is_sorted_column_index=(int)column_index; //--- Classificação QuickSort(first_index,last_index,column_index,m_last_sort_direction); }
Outro pequeno complemento adicionado à classe CKeys ao método CKeys::KeySymbol(). Anteriormente, o teclado numérico (o bloco separado de teclas no lado direito do teclado) não era processado. Agora você pode inserir números, assim como caracteres especiais, usando essa parte do teclado.
//+----------´--------------------------------------------------------+ //| Retornando o símbolo da tecla pressionada | //+----------´--------------------------------------------------------+ string CKeys::KeySymbol(const long key_code) { string key_symbol=""; //--- Se você precisar inserir um espaço (a tecla "Space") if(key_code==KEY_SPACE) { key_symbol=" "; } //--- Se você precisar inserir (1) um caractere alfabético ou (2) um caractere de tecla numérica ou (3) um caractere especial else if((key_code>=KEY_A && key_code<=KEY_Z) || (key_code>=KEY_0 && key_code<=KEY_9) || (key_code>=KEY_NUMLOCK_0 && key_code<=KEY_NUMLOCK_SLASH) || (key_code>=KEY_SEMICOLON && key_code<=KEY_SINGLE_QUOTE)) { key_symbol=::ShortToString(::TranslateKey((int)key_code)); } //--- Retornando o caractere return(key_symbol); }
As novas versões das classes CTable e CKeys podem ser baixadas no final do artigo.
Fim do artigo
Você leu a primeira parte do artigo. Nele, analisamos como, sem muito esforço, você pode criar interfaces gráficas de qualquer complexidade para seus programas. Você pode continuar desenvolvendo este programa e usá-lo para seus próprios propósitos. Na segunda parte do artigo, mostrarei como trabalhar com a interface gráfica e, o mais importante, como preenchê-la com funcionalidades.
Abaixo você pode baixar para o seu computador os arquivos de teste e um estudo mais detalhado do código apresentado no artigo.
Nome do arquivo | Comentário |
---|---|
MQL5\Experts\TradePanel\TradePanel.mq5 | EA - para negociação manual - com interface gráfica |
MQL5\Experts\TradePanel\Program.mqh | Arquivo com a classe do programa |
MQL5\Experts\TradePanel\CreateGUI.mqh | Arquivo com a implementação dos métodos para criar uma interface gráfica a partir da classe de programa no arquivo Program.mqh |
MQL5\Include\EasyAndFastGUI\Controls\Table.mqh | Classe atualizada CTable |
MQL5\Include\EasyAndFastGUI\Keys.mqh | Classe atualizada CKeys |
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/4715
- 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