
Criando uma Interface Gráfica de Usuário Interativa no MQL5 (Parte 1): Criando o Painel
Introdução
Bem-vindo à primeira parte do nosso guia abrangente sobre a construção de painéis de interface gráfica de usuário (GUI) personalizados na Linguagem MetaQuotes 5 (MQL5)! Como traders e desenvolvedores, entendemos a importância de interfaces eficientes e amigáveis para nossas ferramentas de trading. Nesta série, mergulharemos no mundo do MQL5 e exploraremos como criar painéis GUI poderosos que melhoram sua experiência de trading.
Nesta parte inicial, abordaremos o básico: configurar o projeto, projetar o layout do painel e adicionar controles essenciais. Na próxima parte, tornaremos o painel funcional, interativo e responsivo. Seja você um programador experiente em MQL5 ou esteja apenas começando, este artigo fornecerá instruções passo a passo para ajudá-lo a criar um painel GUI funcional e visualmente atraente. Abordaremos os tópicos a seguir:
- Ilustração dos Elementos
- Montagem do Painel GUI no MQL5
- Conclusão
Nesta jornada, usaremos extensivamente a Linguagem MetaQuotes 5 (MQL5) como nosso ambiente base de codificação IDE (Integrated Development Environment) e executaremos os arquivos no terminal de trading MetaTrader 5 (MT5). Portanto, possuir as versões mencionadas acima será de extrema importância. Vamos começar então.
Ilustração dos Elementos
Vamos criar um painel GUI que inclua as ferramentas utilitárias mais comuns que qualquer trader possa precisar, e, assim, queremos delinear e cobrir tudo nesta série. Portanto, o número de elementos a serem abordados é extenso, mas os organizaremos para facilitar a compreensão. Usaremos 4 elementos para o nosso desenvolvimento GUI e, por meio disso, iremos criá-lo. O painel contará com a criação de botões de trading, retângulos nítidos, atualizações ao vivo, uso de emojis, diferentes estilos de fonte, rótulos, partes móveis do painel e efeitos de destaque (hover). Para ilustrar tudo isso, usamos um exemplo abaixo.
Montagem do Painel GUI no MQL5
Para criar o painel, basearemos em um Expert Advisor. Para criar um Expert Advisor (EA), no seu terminal MetaTrader 5, clique na guia Ferramentas e selecione Editor de Linguagem MetaQuotes, ou simplesmente pressione F4 no teclado. Alternativamente, você pode clicar no ícone IDE (Ambiente de Desenvolvimento Integrado) na barra de ferramentas. Isso abrirá o ambiente MetaQuotes Language Editor, que permite escrever robôs de trading, indicadores técnicos, scripts e bibliotecas de funções.
Uma vez aberto o MetaEditor, na barra de ferramentas, navegue até a guia Arquivo e marque Novo Arquivo, ou simplesmente pressione CTRL + N, para criar um novo documento. Alternativamente, você pode clicar no ícone Novo na guia de ferramentas. Isso resultará em um pop-up do Assistente MQL.
No Assistente que aparece, marque Expert Advisor (template) e clique em Próximo.
Nas propriedades gerais do Expert Advisor, na seção de nome, forneça o nome do arquivo do seu expert. Note que para especificar ou criar uma pasta, se ela não existir, use a barra invertida antes do nome do EA. Por exemplo, aqui temos "Experts" por padrão. Isso significa que nosso EA será criado na pasta Experts e podemos encontrá-lo lá. As outras seções são bastante diretas, mas você pode seguir o link na parte inferior do Assistente para saber como realizar o processo com precisão.
Depois de fornecer o nome do arquivo desejado do Expert Advisor, clique em Próximo, clique em Próximo novamente e, em seguida, clique em Concluir. Depois de realizar tudo isso, estamos prontos para codificar e programar nosso painel GUI.
Primeiramente, precisaremos criar funções para os 4 elementos necessários, ou seja, o rótulo do retângulo, o botão, o campo de edição e os rótulos de texto. Isso será de grande utilidade, pois permitirá reutilizar a mesma função ao criar recursos semelhantes, em vez de repetir todo o processo ao criar objetos similares. Também economizará muito tempo e espaço, tornando o processo rápido, direto e com trechos de código mais curtos.
Para criar o rótulo do retângulo, criaremos uma função que recebe 10 argumentos ou parâmetros.
//+------------------------------------------------------------------+ //| Function to create rectangle label | //+------------------------------------------------------------------+ bool createRecLabel(string objName, int xD, int yD, int xS, int yS, color clrBg, int widthBorder, color clrBorder = clrNONE, ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) { ... }
A assinatura da função ilustra tudo. É uma função booleana chamada "createRecLabel", o que significa que ela retornará dois sinais booleanos: true (verdadeiro) em caso de sucesso e false (falso) em caso de falha. Para entender facilmente seus parâmetros, vamos delineá-los e explicá-los individualmente abaixo.
- objName: Este parâmetro representa o nome exclusivo do objeto rótulo do retângulo. Ele serve como um identificador para o elemento gráfico que está sendo criado.
- xD e yD: Esses parâmetros determinam as distâncias X e Y a partir do canto onde o rótulo do retângulo será posicionado. Considere-os como as coordenadas que definem o canto superior esquerdo do retângulo em relação ao gráfico.
- xS e yS: Esses parâmetros especificam a largura e a altura do retângulo. O valor xS determina quão largo o retângulo será horizontalmente, enquanto yS controla sua altura vertical.
- clrBg: O parâmetro clrBg representa a cor de fundo do rótulo do retângulo. Escolha uma cor que contraste bem com o fundo do gráfico ou complemente outros elementos.
- widthBorder: Este parâmetro define a largura da borda ao redor do retângulo. Se você deseja uma borda, defina um valor positivo; caso contrário, use zero para nenhuma borda.
- clrBorder: Parâmetro opcional para a cor da borda. Se desejar uma borda, especifique uma cor (por exemplo, clrNONE para nenhuma cor de borda).
- borderType: Especifique o tipo de borda para o retângulo. As opções incluem plana, elevada ou outros estilos. Para uma borda simples e plana, use BORDER_FLAT.
- borderStyle: Se você escolher uma borda plana, este parâmetro determina o estilo da linha (por exemplo, sólida, tracejada). Use STYLE_SOLID para uma linha contínua.
Na assinatura da função, você deve ter notado que alguns dos argumentos já estão inicializados com um valor. O valor de inicialização representa o valor padrão que será atribuído a esse parâmetro caso ele seja ignorado durante a chamada da função. Por exemplo, nossa cor de borda padrão é nenhuma, o que significa que se o valor da cor não for especificado durante a chamada da função, nenhuma cor será aplicada à borda do rótulo do retângulo.
Dentro do corpo da função, contido pelas chaves ({}), definimos nossos procedimentos de criação de objetos.
// Create a rectangle label object if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) { Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError); return (false); // Return false if object creation fails }
Começamos usando uma instrução if para verificar se o objeto não foi criado. A função ObjectCreate, uma booleana que aceita 6 argumentos, é usada. Essa função cria um objeto com o nome, tipo e coordenadas iniciais especificados na subjanela do gráfico especificada. Primeiro, especificamos a janela do gráfico, onde 0 significa que o objeto será criado na janela principal. Depois, fornecemos o nome do objeto. Este é o nome que será atribuído exclusivamente a um objeto específico. O tipo de objeto que queremos criar é do tipo "OBJ_RECTANGLE_LABEL", significando um objeto para criar e projetar a interface gráfica personalizada. Em seguida, fornecemos a subjanela, 0 para a subjanela atual. Por fim, fornecemos os valores de tempo e preço como zero (0), já que não os anexaremos ao gráfico, mas sim às coordenadas da janela do gráfico. Os pixels são usados para definir o mapeamento.
Se a criação do objeto falhar, a função "ObjectCreate" retornará false. Nesse caso, informamos o erro, imprimindo-o no diário ao lado do código de erro, e retornamos false. Nesse caso, informamos o erro imprimindo-o no diário ao lado do código de erro e retornando falso. Pode haver um erro anterior e, para obter o erro mais recente, precisamos limpar o erro anterior. Isso é alcançado chamando a função "ResetLastError", que é uma função nativa do MQL5, logo antes da nossa lógica de criação de objeto.
ResetLastError(); // Reset any previous error codes
O objetivo da função é definir o valor da variável pré-definida "_LastError", que armazena o código de erro da última operação que encontrou um erro, para zero. Ao chamá-la, garantimos que quaisquer códigos de erro anteriores sejam limpos antes de prosseguir com as próximas operações. Esse passo é essencial porque permite tratar erros novos de forma independente, sem interferência de estados de erro anteriores.
Se não retornarmos até esse ponto, significa que criamos o objeto e, portanto, podemos continuar com a atualização das propriedades do objeto. Uma função nativa "ObjectSet..." define o valor da propriedade correspondente de um objeto. A propriedade do objeto deve ser do tipo datetime, inteiro, cor, booleano ou caractere.
// Set properties for the rectangle label ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat) ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat) ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat) ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected
Vamos nos concentrar na lógica da primeira propriedade.
ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
Aqui, usamos a função nativa "ObjectSetInteger" e passamos os parâmetros respectivamente. Os parâmetros são descritos abaixo.
- ID do Gráfico: Este é o identificador do gráfico. "0" refere-se ao gráfico atual (ID do gráfico). Estamos ajustando as propriedades de um objeto dentro desse gráfico.
- Nome: Este é o nome do objeto. "objName" representa o nome único atribuído ao objeto de rótulo do retângulo.
- ID da Propriedade: Este é o ID da propriedade do objeto, e seu valor pode ser um dos valores da enumeração "ENUM_OBJECT_PROPERTY_INTEGER". "OBJPROP_XDISTANCE" especifica que estamos modificando a propriedade de distância no eixo X.
- Valor da Propriedade: Este é o valor da propriedade. O valor atribuído a "xD" determina o quão longe à direita (ou à esquerda, se negativo) o canto superior esquerdo do nosso rótulo de retângulo será posicionado horizontalmente a partir da borda esquerda do gráfico.
Da mesma forma, definimos as outras propriedades usando o mesmo formato. "OBJPROP_YDISTANCE" configura a propriedade de distância no eixo Y do rótulo do retângulo. O valor "yD" determina quão longe o canto superior esquerdo do rótulo do retângulo será posicionado verticalmente a partir da borda superior do gráfico. Em outras palavras, controla o posicionamento vertical do rótulo dentro da área do gráfico. Isso define a distância Y a partir do canto. As propriedades "OBJPROP_XSIZE" e "OBJPROP_YSIZE" definem, respectivamente, a largura e a altura do retângulo.
Para posicionar nosso objeto, usamos a propriedade "OBJPROP_CORNER" para determinar o canto em que queremos que nosso objeto esteja na janela do gráfico.
ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
A propriedade só pode ter 4 tipos:
- CORNER_LEFT_UPPER: O centro das coordenadas está no canto superior esquerdo do gráfico.
- CORNER_LEFT_LOWER: O centro das coordenadas está no canto inferior esquerdo do gráfico.
- CORNER_RIGHT_LOWER: O centro das coordenadas está no canto inferior direito do gráfico.
- CORNER_RIGHT_UPPER: O centro das coordenadas está no canto superior direito do gráfico.
Em uma representação fotográfica, é isso que temos.
As demais propriedades são diretas. Adicionamos comentários para facilitar o entendimento. Depois, basta redesenhar o gráfico para que as alterações entrem em vigor automaticamente, sem precisar aguardar mudanças nos preços ou eventos do gráfico.
ChartRedraw(0); // Redraw the chart
Por fim, retornamos true, indicando que a criação e atualização das propriedades do objeto foram bem-sucedidas.
return (true); // Return true if object creation and property settings are successful
A função completa responsável pela criação de um objeto retângulo na janela do gráfico é apresentada abaixo.
bool createRecLabel(string objName, int xD, int yD, int xS, int yS, color clrBg, int widthBorder, color clrBorder = clrNONE, ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) { ResetLastError(); // Reset any previous error codes // Create a rectangle label object if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) { Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError); return (false); // Return false if object creation fails } // Set properties for the rectangle label ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat) ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat) ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat) ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected ChartRedraw(0); // Redraw the chart return (true); // Return true if object creation and property settings are successful }
Para criar um objeto do tipo botão, utiliza-se a mesma abordagem de função. O código para criar uma função personalizada de botão está abaixo.
//+------------------------------------------------------------------+ //| Function to create button | //+------------------------------------------------------------------+ bool createButton(string objName, int xD, int yD, int xS, int yS, string txt = "", color clrTxt = clrBlack, int fontSize = 12, color clrBg = clrNONE, color clrBorder = clrNONE, string font = "Arial Rounded MT Bold") { // Reset any previous errors ResetLastError(); // Attempt to create the button object if (!ObjectCreate(0, objName, OBJ_BUTTON, 0, 0, 0)) { // Print an error message if creation fails Print(__FUNCTION__, ": failed to create the button! Error code = ", _LastError); return (false); } // Set properties for the button ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the button ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the button ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the button ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Button state (not pressed) ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected // Redraw the chart to display the button ChartRedraw(0); return (true); // Button creation successful }
As diferenças no código são que um objeto retângulo não pode conter texto em seu interior, enquanto um botão pode incluir um texto descritivo sobre sua funcionalidade, caso necessário. Portanto, para os parâmetros de entrada, consideramos as propriedades de texto, como o valor do texto, a cor, o tamanho da fonte e o nome da fonte. O tipo de borda para nosso botão é estático; assim, eliminamos suas propriedades e mantemos apenas a cor da borda.
O tipo de objeto que criamos é "OBJ_BUTTON", indicando que estamos criando um objeto gráfico do tipo botão. Seus pontos de ancoragem são definidos em pixels. A propriedade de borda que mantemos é a cor da borda, substituindo o restante pelas propriedades de entrada de texto.
Para criar o botão de campo editável, a mesma lógica é utilizada.
//+------------------------------------------------------------------+ //| Function to create edit field | //+------------------------------------------------------------------+ bool createEdit(string objName, int xD, int yD, int xS, int yS, string txt = "", color clrTxt = clrBlack, int fontSize = 12, color clrBg = clrNONE, color clrBorder = clrNONE, string font = "Arial Rounded MT Bold") { // Reset any previous errors ResetLastError(); // Attempt to create the edit object if (!ObjectCreate(0, objName, OBJ_EDIT, 0, 0, 0)) { // Print an error message if creation fails Print(__FUNCTION__, ": failed to create the edit! Error code = ", _LastError); return (false); } // Set properties for the edit field ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the edit field ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the edit field ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Default text in the edit field ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color ObjectSetInteger(0, objName, OBJPROP_ALIGN, ALIGN_LEFT); // Text alignment (left-aligned) ObjectSetInteger(0, objName, OBJPROP_READONLY, false); // Edit field is not read-only ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Edit field state (not active) ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected // Redraw the chart to display the edit field ChartRedraw(0); return (true); // Edit field creation successful }
A principal diferença no código em relação à criação de uma função de botão é, primeiramente, o tipo de objeto. Utilizamos "OBJ_EDIT" para indicar que queremos criar um botão editável. Em seguida, nas propriedades do campo, adicionamos a propriedade de alinhamento horizontal do texto, que pode ser à direita, à esquerda ou ao centro. No nosso caso, optamos por alinhar o texto horizontalmente à esquerda.
ObjectSetInteger(0, objName, OBJPROP_ALIGN, ALIGN_LEFT); // Text alignment (left-aligned)
A diferença final é a propriedade que habilita a capacidade de editar o texto no objeto. Para habilitar a edição, configuramos o valor da propriedade "OBJPROP_READONLY" como falso.
ObjectSetInteger(0, objName, OBJPROP_READONLY, false); // Edit field is not read-only
Os outros argumentos permanecem os mesmos.
Por fim, precisamos da função do último elemento, que é o rótulo de texto. O rótulo de texto elimina a necessidade de um objeto de plano de fundo, tornando sua implementação mais simples que as demais funções. Precisamos apenas do texto, concentrando-nos, assim, nas propriedades do texto. Seu código está abaixo.
//+------------------------------------------------------------------+ //| Function to create text label | //+------------------------------------------------------------------+ bool createLabel(string objName, int xD, int yD, string txt, color clrTxt = clrBlack, int fontSize = 12, string font = "Arial Rounded MT Bold") { // Reset any previous errors ResetLastError(); // Attempt to create the label object if (!ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0)) { // Print an error message if creation fails Print(__FUNCTION__, ": failed to create the label! Error code = ", _LastError); return (false); } // Set properties for the label ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the label ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Label state (not active) ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected // Redraw the chart to display the label ChartRedraw(0); return (true); // Label creation successful }
As principais diferenças nessa estrutura de código, em relação à função de botão, são o tamanho do objeto e as propriedades da borda. Na assinatura da função, eliminamos os tamanhos do objeto, bem como as propriedades da borda. Definimos nosso tipo de objeto como "OBJ_LABEL" para indicar que desenhamos rótulos conforme as coordenadas definidas para o gráfico. Por fim, eliminamos os parâmetros de tamanho e borda, e é isso. Simples assim.
Agora que temos as funções necessárias para criar uma GUI, vamos utilizá-las para criar o painel. Precisaremos de nomes para os objetos e, para facilitar o gerenciamento da interação dos nomes dos objetos, é muito mais prático definir macros.
#define MAIN_REC "MAIN_REC"
Utilizamos a palavra-chave #define para definir uma macro chamada "MAIN_REC" com o valor "MAIN_REC" para armazenar facilmente o nome base do retângulo principal. Assim, evitamos ter que digitar o nome repetidamente em cada instância em que criamos o nível, economizando tempo e reduzindo as chances de fornecer o nome errado. Basicamente, macros são usadas para substituição de texto durante a compilação.
Nosso código será amplamente baseado na seção de inicialização do especialista, pois queremos criar o painel no momento da inicialização. Assim, o manipulador de eventos OnInit abrigará a maior parte da estrutura do código.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... return(INIT_SUCCEEDED); }
A função OnInit é um manipulador de eventos chamado no momento da inicialização do especialista para realizar as inicializações necessárias, se necessário.
Depois, chamamos a função para criar um rótulo de retângulo digitando seu nome e fornecendo seus parâmetros.
createRecLabel(MAIN_REC,10,30,250,400,clrWhite,1,clrBlack);
Aqui, o nome do nosso retângulo é "MAIN_REC", conforme a definição da macro. A distância no eixo x (escala de tempo e data) a partir do canto superior esquerdo da janela do gráfico é de 10 pixels, e a distância no eixo y (escala de preços) é de 30 pixels. A largura é de 250 pixels e a altura de 400 pixels, respectivamente. Escolhemos a cor de fundo como branca, com uma largura de borda de 1 e uma cor de borda preta. Para aproximar o alcance dos pixels, você pode reduzir o gráfico para 0, e o número de barras entre duas coordenadas de "cross-hair" é igual ao número de pixels na escala horizontal. Como exemplo, veja o que queremos dizer:
Os outros parâmetros foram deixados de fora, o que significa que os valores padrão serão aplicados automaticamente, ou seja, o tipo de borda será plano e o estilo de linha será uma linha sólida contínua. Após a compilação, aqui está o que temos no momento:
Mesmo se tivéssemos todos os parâmetros com os valores padrão, como mostrado abaixo, os resultados seriam sempre os mesmos:
createRecLabel(MAIN_REC,10,30,250,400,clrWhite,1,clrBlack,BORDER_FLAT,STYLE_SOLID);
Para criar um subframe, novamente declaramos explicitamente uma macro para o mesmo.
#define MAIN_SUB_REC "MAIN_SUB_REC"
Em seguida, chamamos a mesma função para criar o subframe. Queremos que nosso frame esteja dentro do frame do painel base e, portanto, será necessário usar uma cor ligeiramente diferente. Para isso, utilizamos uma cor azul clara e uma margem de 5 pixels.
createRecLabel(MAIN_SUB_REC,15,35,240,390,clrLightBlue,1,clrNONE);
Como queremos uma margem de 5 pixels, deslocamos 5 pixels à esquerda e no topo. Assim, a distância no eixo x será o inicial 10, mais a margem de 5, resultando em 15 pixels. O mesmo é feito para a escala no eixo y. Isso significa que o tamanho também precisará ser reduzido em 5 pixels, mas, espere, também precisamos de uma margem de 5 pixels à direita do painel. Portanto, uma redução de 5 pixels de cada lado, para dois lados, é necessária. Assim, o total de pixels necessários é 5 multiplicado por 2, o que equivale a 10 pixels. Portanto, uma redução de 10 pixels nos tamanhos do sub-retângulo resultará em 250 - 10 = 240 pixels de largura e 400 - 10 = 390 pixels de altura do subframe. Aqui está o resultado que obtemos.
A cor azul clara não é tão atraente aos olhos, então optamos por uma cor mais escura. Para ganhar mais controle sobre a cor usada, representamos a cor de fundo em literais. Isso terá o formato "C'000,000,000'", onde os zeros triplos podem ser qualquer número de 0 a 255. O formato adotado é o padrão RGB (Red, Green, Blue). Os três valores representam os componentes vermelho, verde e azul, respectivamente, em uma escala de 0 a 255. Portanto, 245,245,245 traduz-se em um tom quase branco.
createRecLabel(MAIN_SUB_REC,15,35,240,390,C'245,245,245',1,clrNONE);
Definimos a cor da borda como nenhuma para criar uma mistura de cores mais agradável. É sempre recomendado compilar o programa e verificar o resultado cada vez que você adiciona um novo elemento GUI. Abaixo estão os resultados obtidos:
Para criar linhas de limite verticais e horizontais, definimos mais duas macros.
#define MAIN_LINE_UP "MAIN_LINE_UP" #define MAIN_LINE_DN "MAIN_LINE_DN"
A mesma estrutura é usada, mas desta vez utilizamos um tipo de borda elevada. Assim, ignoramos o uso da cor da borda, resultando em uma ilusão de limite.
createRecLabel(MAIN_LINE_UP,15,35,240,1,C'245,245,245',1,clrNONE,BORDER_RAISED); createRecLabel(MAIN_LINE_DN,15,35-1,1,390+1,C'245,245,245',1,clrNONE,BORDER_RAISED);
Aqui está o que obtemos.
Até este ponto, a configuração de nossos frames, margens e limites para o painel GUI está completa. Em seguida, prosseguimos para adicionar outras utilidades ao painel, como botões responsivos, títulos, campos editáveis e rótulos, além de suas propriedades e efeitos.
Se precisar de mais traduções ou ajuda para continuar, é só pedir!
#define LABEL_NAME "LABEL_NAME" ... createLabel(LABEL_NAME,25,35,"DashBoard v1.0",clrBlue,14,"Cooper Black");
Primeiro, definimos uma macro para o nome do título e chamamos a função responsável por criar rótulos, digitando o nome. Em seguida, fornecemos as distâncias no eixo X e Y como 25 e 35 pixels, respectivamente. O texto escolhido é "DashBoard v1.0", indicando o tipo do painel e a versão inicial. Simultaneamente, definimos a cor do texto como azul, o tamanho da fonte como 14 e o tipo da fonte como "Cooper Black". Quanto ao tipo de fonte, o valor não diferencia maiúsculas de minúsculas. Nem maiúsculas nem minúsculas, ou uma mistura de maiúsculas e minúsculas, terão efeito algum. Poderia ser "cooper black" ou "COOPER BLACK" também. Tudo o que importa é fornecer o nome correto da fonte. Ao compilar, obtemos o seguinte resultado:
Você deve ter notado que o tipo de fonte pode ser alterado. Vamos "adicionar açúcar à música" e ver como ela se desenrola. Alguns tipos de fontes contêm ícones e emojis. Agora, o MQL5 aceita e incorpora alguns deles. Exemplos de fontes incluem "Webdings", "Wingdings", "Wingdings 2" e "Wingdings 3". Há muitas outras, mas escolhemos usar as mencionadas. Isso significa que podemos tornar o painel mais interessante usando essas fontes de ícones e emojis. Isso é mostrado abaixo:
Adicionamos três ícones antes do nome do painel: um coração, uma ferramenta e uma ambulância. Claro, você pode escolher conforme sua preferência. Isso requer a definição de três macros novamente para armazenar os nomes dos ícones e, posteriormente, usá-los na criação dos ícones. Aqui está a lógica:
#define ICON_HEART "ICON_HEART" #define ICON_TOOL "ICON_TOOL" #define ICON_CAR "ICON_CAR" ... createLabel(ICON_HEART,190,35,"Y",clrRed,15,"Webdings");
A mesma função é usada, com as distâncias dos eixos, cor e tamanho da fonte. No entanto, você pode notar que o nome da fonte foi alterado para "Webdings", e o valor do texto é a letra maiúscula "Y". Isso não significa que exibiremos "Y" como saída. Exibimos o ícone correspondente ao caractere. Para a fonte, o ícone correspondente ao caractere é o seguinte: o ícone de coração.
O valor do texto é sensível a maiúsculas, pois, como você pode ver, o ícone associado a "y" minúsculo é diferente do de "Y" maiúsculo. Após a compilação, aqui está o resultado:
Os outros dois ícones podem agora ser adicionados da mesma forma que o anterior.
createLabel(ICON_TOOL,210,35,"@",clrBlue,15,"Webdings"); createLabel(ICON_CAR,230,35,"h",clrBlack,15,"Webdings");
A mesma implementação é usada para adicionar os outros objetos utilitários ao gráfico. A lógica está abaixo.
#define LINE1 "LINE1" #define BTN_CLOSE "BTN_CLOSE" #define BTN_MARKET "BTN_MARKET" #define BTN_PROFIT "BTN_PROFIT" #define BTN_LOSS "BTN_LOSS" #define BTN_PENDING "BTN_PENDING" #define LINE2 "LINE2" ... createRecLabel(LINE1,15+10,60,240-10,1,C'245,245,245',1,clrNONE,BORDER_RAISED); createLabel(BTN_CLOSE,25,65,"Close",clrBlack,13,"Impact"); createLabel(BTN_MARKET,70,65,"Market",clrDarkRed,13,"Impact"); createLabel(BTN_PROFIT,125,65,"Profit",clrGreen,13,"Impact"); createLabel(BTN_LOSS,170,65,"Loss",clrRed,13,"Impact"); createLabel(BTN_PENDING,205,65,"Pend'n",clrDarkGray,13,"Impact"); createRecLabel(LINE2,15+10,87,240-10,1,C'245,245,245',1,clrNONE,BORDER_RAISED);
Definimos os nomes das macros dos objetos e chamamos as respectivas funções personalizadas para criar os objetos. Criamos duas linhas de limite verticais que enquadram os botões utilitários de rótulo. Os rótulos são: Close, Market, Profit, Loss e Pending, adaptado para "Pend'n" para acomodar o texto dentro dos limites do frame. Esses botões têm as seguintes finalidades: fechar todas as ordens de mercado e pendentes, fechar apenas as ordens de mercado, fechar as posições que estão com lucro, fechar as posições que estão com prejuízo e deletar ordens pendentes, respectivamente. Após a compilação, temos este resultado:
Até este ponto, criamos com sucesso a seção de cabeçalho do painel. Agora, passamos a criar os botões utilitários. Primeiro, vamos nos concentrar no botão de volume de negociação. Nosso botão terá um rótulo e um ícone de menu suspenso.
#define BTN_LOTS "BTN_LOTS" #define LABEL_LOTS "LABEL_LOTS" #define ICON_DROP_DN1 "ICON_DROP_DN1"
A definição das macros foi feita. Depois, criamos um botão chamando a função de botão.
createButton(BTN_LOTS,25,95,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150');
Mais uma vez, fornecemos as distâncias nos eixos X e Y do botão, com um tamanho de 130 pixels de largura e 25 pixels de altura. Quanto ao texto, optamos por deixá-lo em branco ou nulo, pois queríamos controlar o posicionamento do texto. Representações literais de cores foram usadas para definir o plano de fundo e a borda do botão. Como optamos por omitir o rótulo padrão do botão, criamos um novo rótulo de texto nas proximidades do botão por meio da função abaixo:
createLabel(LABEL_LOTS,25+10,95+5,"LotSize",clrBlack,9);
A função agora já é familiar para você, e você já conhece os parâmetros que são passados. Para o ícone do menu suspenso, usamos um tipo de fonte que fornece o ícone:
createLabel(ICON_DROP_DN1,130,95+5,CharToString(240),C'070,070,070',20,"Wingdings 3");
Você pode notar que no argumento do texto, convertemos um caractere para uma string, que é outra maneira de fornecer o código do caractere correspondente, útil caso você já conheça o código do símbolo. Para criar o botão de campo editável, o mesmo procedimento é adotado.
#define EDIT_LOTS "EDIT_LOTS" #define BTN_P1 "BTN_P1" #define BTN_M1 "BTN_M1" ... createEdit(EDIT_LOTS,165,95,60,25,"0.01",clrBlack,14,clrWhite,C'100,100,100',"Callibri"); createButton(BTN_P1,225,95,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createButton(BTN_M1,225,95+12,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
Definimos os nomes das macros como de costume e chamamos as funções. Para criar o botão de edição, são utilizados os tamanhos de 60 pixels de largura e 25 pixels de altura. O texto padrão é definido como 0.01, com cor de texto preta, tamanho de fonte 14 e tipo de fonte "Callibri". O plano de fundo do botão é branco, com uma cor de borda em tom próximo ao escuro. Para os botões de incremento e decremento de volume de negociação, usamos o tipo de fonte "Webdings" e os valores de texto "5" e "6", respectivamente. Após a compilação, este é o marco que atingimos:
Este é um bom progresso. Para criar os outros botões de stop loss e take profit, aplica-se a mesma lógica por meio do código abaixo:
#define BTN_SL "BTN_SL" #define LABEL_SL "LABEL_SL" #define ICON_DROP_DN2 "ICON_DROP_DN2" #define EDIT_SL "EDIT_SL" #define BTN_P2 "BTN_P2" #define BTN_M2 "BTN_M2" #define BTN_TP "BTN_TP" #define LABEL_TP "LABEL_TP" #define ICON_DROP_DN3 "ICON_DROP_DN3" #define EDIT_TP "EDIT_TP" #define BTN_P3 "BTN_P3" #define BTN_M3 "BTN_M3" ... createButton(BTN_SL,25,95+30,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150'); createLabel(LABEL_SL,35,95+30,"SL Pips",clrBlack,14); createLabel(ICON_DROP_DN2,130,100+30,CharToString(240),C'070,070,070',20,"Wingdings 3"); createEdit(EDIT_SL,165,95+30,60,25,"100.0",clrBlack,13,clrWhite,C'100,100,100',"Callibri"); createButton(BTN_P2,225,95+30,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createButton(BTN_M2,225,107+30,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createButton(BTN_TP,25,95+30+30,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150'); createLabel(LABEL_TP,35,95+30+30,"TP Pips",clrBlack,14); createLabel(ICON_DROP_DN3,130,100+30+30,CharToString(240),C'070,070,070',20,"Wingdings 3"); createEdit(EDIT_TP,165,95+30+30,60,25,"100.0",clrBlack,13,clrWhite,C'100,100,100',"Callibri"); createButton(BTN_P3,225,95+30+30,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createButton(BTN_M3,225,107+30+30,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
Utilitários macros são definidos, e as respectivas funções são chamadas para criá-los. Este código não difere na lógica do inicial que usamos para criar os botões de volume de negociação. Ao compilar, você deve obter este resultado:
#define BTN_BUY "BTN_BUY" #define LABEL_BUY "LABEL_BUY" #define LABEL_BUY_PRICE "LABEL_BUY_PRICE" #define BTN_OVERLAY "BTN_OVERLAY" #define BTN_SPREAD "BTN_SPREAD" #define BTN_SELL "BTN_SELL" #define LABEL_SELL "LABEL_SELL" #define LABEL_SELL_PRICE "LABEL_SELL_PRICE" #define BTN_CONTACT "BTN_CONTACT" ... createRecLabel(BTN_SELL,25,335,105,60,clrRed,1,clrNONE); createLabel(LABEL_SELL,35,335,"Sell",clrWhite,15,"ARIAL black"); createLabel(LABEL_SELL_PRICE,35,335+30,DoubleToString(Bid(),_Digits),clrWhite,13,"ARIAL black"); createRecLabel(BTN_BUY,140,335,105,60,clrGreen,1,clrNONE); createLabel(LABEL_BUY,150+35,335,"Buy",clrWhite,15,"ARIAL black"); createLabel(LABEL_BUY_PRICE,150,335+30,DoubleToString(Ask(),_Digits),clrWhite,13,"ARIAL black"); createRecLabel(BTN_OVERLAY,90,335,90,25,C'245,245,245',0,clrNONE); createButton(BTN_SPREAD,95,335,80,20,(string)Spread(),clrBlack,13,clrWhite,clrBlack); createButton(BTN_CONTACT,25,335+62,230-10,25,"https://t.me/Forex_Algo_Trader",clrBlack,10,clrNONE,clrBlack);
Para criar os botões de comprar, vender, sobreposição, um botão de informações extras e um botão de spread, o código acima é implementado. A única diferença adicional é o texto para os preços de compra (buy) e venda (sell), assim como o valor do spread. Funções personalizadas extras, Bid, Ask e Spread, são chamadas para preencher os valores. As funções de bid e ask retornam um valor do tipo double, e, para converter o double em string, a função nativa DoubleToString é chamada. Para o spread, convertemos o valor inteiro diretamente para string. As funções personalizadas são as seguintes:
double Ask(){return(NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits));} double Bid(){return(NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits));} int Spread(){return((int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD));}
As funções retornam os respectivos tipos de dados de informações do símbolo. Após a compilação, obtemos o seguinte resultado:
Agora, prosseguimos para criar alguns botões extras que utilizaremos para ilustrar como criar um botão com bordas afiadas e um duplicado que usaremos para automatizar o efeito de hover.
#define BTN_SHARP "BTN_SHARP" #define LABEL_SHARP "LABEL_SHARP" #define BTN_HOVER "BTN_HOVER" #define LABEL_HOVER "LABEL_HOVER" ... createRecLabel(BTN_SHARP,25,190,220,35,C'220,220,220',2,C'100,100,100'); createLabel(LABEL_SHARP,25+20,190+5,"Sharp Edged Button",clrBlack,12,"ARIAL black"); //createRecLabel(BTN_HOVER,25,230,220,35,C'220,220,220',3,C'050,050,255'); createRecLabel(BTN_HOVER,25,230,220,35,C'220,220,220',3,C'100,100,100'); createLabel(LABEL_HOVER,25+50,230+5,"Hover Effect",clrBlack,12,"ARIAL black");
Abaixo está o marco atingido:
Há algum espaço extra que pode ser usado para outras utilidades, mas vamos preenchê-lo com alguns emojis e caracteres de ícones.
#define LABEL_EXTRA1 "LABEL_EXTRA1" #define LABEL_EXTRA2 "LABEL_EXTRA2" #define LABEL_EXTRA3 "LABEL_EXTRA3" #define LABEL_EXTRA4 "LABEL_EXTRA4" ... createLabel(LABEL_EXTRA1,25,290,"_",clrBlack,25,"WEBDINGS"); createLabel(LABEL_EXTRA2,25+40,290,"J",clrBlack,25,"WINGDINGS"); createLabel(LABEL_EXTRA3,25+40+40,290,"{",clrBlack,25,"WINGDINGS 2"); createLabel(LABEL_EXTRA4,25+40+40+40,290,"G",clrBlack,25,"WINGDINGS 3");
Quando o botão de volume de negociação for clicado, queremos instanciar a criação de uma lista suspensa, a partir da qual podemos escolher diferentes opções. Precisamos ter 3 opções, além de um ícone que talvez permita arrastar a lista para outro local, longe do ponto de criação inicial. A mesma lógica é utilizada.
#define BTN_DROP_DN "BTN_DROP_DN" #define LABEL_OPT1 "LABEL_OPT1" #define LABEL_OPT2 "LABEL_OPT2" #define LABEL_OPT3 "LABEL_OPT3" #define ICON_DRAG "ICON_DRAG" ... void createDropDown(){ createRecLabel(BTN_DROP_DN,25,95+25,130,70,clrWhite,2,clrBlack); createLabel(LABEL_OPT1,25+10,95+25,"LotSize",clrBlack,12,"stencil"); createLabel(LABEL_OPT2,25+10,95+25+20,"Risk Percent %",clrBlack,12,"calibri Italic"); createLabel(LABEL_OPT3,25+10,95+25+20+20,"Money Balance",clrBlack,12,"Arial bold"); createLabel(ICON_DRAG,25+10+95,95+25,"d",clrRoyalBlue,15,"webdings"); }
Aqui, criamos os botões e rótulos em uma função personalizada, para que possamos chamá-la quando o botão de volume de negociação for clicado. No entanto, para exibir as posições das utilidades, chamamos a função, mas posteriormente comentaremos a chamada.
createDropDown();
O marco final é o seguinte:
Por fim, precisamos destruir e excluir os objetos criados quando o Expert Advisor for removido do gráfico. Para isso, uma nova função é criada para excluir os objetos criados.
void destroyPanel(){ ObjectDelete(0,MAIN_REC); ObjectDelete(0,MAIN_SUB_REC); ObjectDelete(0,MAIN_LINE_UP); //... other objects ChartRedraw(0); }
Uma função personalizada do tipo void é usada, significando que ela não retorna nada. A função nativa ObjectDelete é utilizada para excluir os respectivos objetos passados. Ela aceita dois argumentos: o ID do gráfico (0, para o gráfico atual) e o nome do objeto a ser excluído. Isso é chamado durante a função de desinicialização do Expert Advisor.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- destroyPanel(); }
Segue o código fonte completo responsável pela criação do painel GUI, conforme ilustrado em MQL5 para o MetaTrader 5 (MT5).
//+------------------------------------------------------------------+ //| DASHBOARD PART 1.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- DEFINE MACRO PROPERTIES #define MAIN_REC "MAIN_REC" #define MAIN_SUB_REC "MAIN_SUB_REC" #define MAIN_LINE_UP "MAIN_LINE_UP" #define MAIN_LINE_DN "MAIN_LINE_DN" #define LABEL_NAME "LABEL_NAME" #define ICON_HEART "ICON_HEART" #define ICON_TOOL "ICON_TOOL" #define ICON_CAR "ICON_CAR" #define LINE1 "LINE1" #define BTN_CLOSE "BTN_CLOSE" #define BTN_MARKET "BTN_MARKET" #define BTN_PROFIT "BTN_PROFIT" #define BTN_LOSS "BTN_LOSS" #define BTN_PENDING "BTN_PENDING" #define LINE2 "LINE2" #define BTN_LOTS "BTN_LOTS" #define LABEL_LOTS "LABEL_LOTS" #define ICON_DROP_DN1 "ICON_DROP_DN1" #define EDIT_LOTS "EDIT_LOTS" #define BTN_P1 "BTN_P1" #define BTN_M1 "BTN_M1" #define BTN_SL "BTN_SL" #define LABEL_SL "LABEL_SL" #define ICON_DROP_DN2 "ICON_DROP_DN2" #define EDIT_SL "EDIT_SL" #define BTN_P2 "BTN_P2" #define BTN_M2 "BTN_M2" #define BTN_TP "BTN_TP" #define LABEL_TP "LABEL_TP" #define ICON_DROP_DN3 "ICON_DROP_DN3" #define EDIT_TP "EDIT_TP" #define BTN_P3 "BTN_P3" #define BTN_M3 "BTN_M3" #define BTN_BUY "BTN_BUY" #define LABEL_BUY "LABEL_BUY" #define LABEL_BUY_PRICE "LABEL_BUY_PRICE" #define BTN_OVERLAY "BTN_OVERLAY" #define BTN_SPREAD "BTN_SPREAD" #define BTN_SELL "BTN_SELL" #define LABEL_SELL "LABEL_SELL" #define LABEL_SELL_PRICE "LABEL_SELL_PRICE" #define BTN_CONTACT "BTN_CONTACT" #define BTN_SHARP "BTN_SHARP" #define LABEL_SHARP "LABEL_SHARP" #define BTN_HOVER "BTN_HOVER" #define LABEL_HOVER "LABEL_HOVER" #define LABEL_EXTRA1 "LABEL_EXTRA1" #define LABEL_EXTRA2 "LABEL_EXTRA2" #define LABEL_EXTRA3 "LABEL_EXTRA3" #define LABEL_EXTRA4 "LABEL_EXTRA4" #define BTN_DROP_DN "BTN_DROP_DN" #define LABEL_OPT1 "LABEL_OPT1" #define LABEL_OPT2 "LABEL_OPT2" #define LABEL_OPT3 "LABEL_OPT3" #define ICON_DRAG "ICON_DRAG" //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ createRecLabel(MAIN_REC,10,30,250,400,clrWhite,1,clrBlack); createRecLabel(MAIN_SUB_REC,15,35,240,390,C'245,245,245',1,clrNONE); createRecLabel(MAIN_LINE_UP,15,35,240,1,C'245,245,245',1,clrNONE,BORDER_RAISED); createRecLabel(MAIN_LINE_DN,15,35-1,1,390+1,C'245,245,245',1,clrNONE,BORDER_RAISED); createLabel(LABEL_NAME,25,35,"DashBoard v1.0",clrBlue,14,"Cooper Black"); createLabel(ICON_HEART,190,35,"Y",clrRed,15,"Webdings"); createLabel(ICON_TOOL,210,35,"@",clrBlue,15,"Webdings"); createLabel(ICON_CAR,230,35,"h",clrBlack,15,"Webdings"); createRecLabel(LINE1,15+10,60,240-10,1,C'245,245,245',1,clrNONE,BORDER_RAISED); createLabel(BTN_CLOSE,25,65,"Close",clrBlack,13,"Impact"); createLabel(BTN_MARKET,70,65,"Market",clrDarkRed,13,"Impact"); createLabel(BTN_PROFIT,125,65,"Profit",clrGreen,13,"Impact"); createLabel(BTN_LOSS,170,65,"Loss",clrRed,13,"Impact"); createLabel(BTN_PENDING,205,65,"Pend'n",clrDarkGray,13,"Impact"); createRecLabel(LINE2,15+10,87,240-10,1,C'245,245,245',1,clrNONE,BORDER_RAISED); createButton(BTN_LOTS,25,95,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150'); createLabel(LABEL_LOTS,25+10,95+5,"LotSize",clrBlack,9); //createLabel(ICON_DROP_DN1,150,75,CharToString(100),clrBlack,12,"Wingdings"); createLabel(ICON_DROP_DN1,130,95+5,CharToString(240),C'070,070,070',20,"Wingdings 3"); createEdit(EDIT_LOTS,165,95,60,25,"0.01",clrBlack,14,clrWhite,C'100,100,100',"Callibri"); createButton(BTN_P1,225,95,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createButton(BTN_M1,225,95+12,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createButton(BTN_SL,25,95+30,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150'); createLabel(LABEL_SL,35,95+30,"SL Pips",clrBlack,14); createLabel(ICON_DROP_DN2,130,100+30,CharToString(240),C'070,070,070',20,"Wingdings 3"); createEdit(EDIT_SL,165,95+30,60,25,"100.0",clrBlack,13,clrWhite,C'100,100,100',"Callibri"); createButton(BTN_P2,225,95+30,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createButton(BTN_M2,225,107+30,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createButton(BTN_TP,25,95+30+30,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150'); createLabel(LABEL_TP,35,95+30+30,"TP Pips",clrBlack,14); createLabel(ICON_DROP_DN3,130,100+30+30,CharToString(240),C'070,070,070',20,"Wingdings 3"); createEdit(EDIT_TP,165,95+30+30,60,25,"100.0",clrBlack,13,clrWhite,C'100,100,100',"Callibri"); createButton(BTN_P3,225,95+30+30,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createButton(BTN_M3,225,107+30+30,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings"); createRecLabel(BTN_SELL,25,335,105,60,clrRed,1,clrNONE); createLabel(LABEL_SELL,35,335,"Sell",clrWhite,15,"ARIAL black"); createLabel(LABEL_SELL_PRICE,35,335+30,DoubleToString(Bid(),_Digits),clrWhite,13,"ARIAL black"); createRecLabel(BTN_BUY,140,335,105,60,clrGreen,1,clrNONE); createLabel(LABEL_BUY,150+35,335,"Buy",clrWhite,15,"ARIAL black"); createLabel(LABEL_BUY_PRICE,150,335+30,DoubleToString(Ask(),_Digits),clrWhite,13,"ARIAL black"); createRecLabel(BTN_OVERLAY,90,335,90,25,C'245,245,245',0,clrNONE); createButton(BTN_SPREAD,95,335,80,20,(string)Spread(),clrBlack,13,clrWhite,clrBlack); createButton(BTN_CONTACT,25,335+62,230-10,25,"https://t.me/Forex_Algo_Trader",clrBlack,10,clrNONE,clrBlack); createRecLabel(BTN_SHARP,25,190,220,35,C'220,220,220',2,C'100,100,100'); createLabel(LABEL_SHARP,25+20,190+5,"Sharp Edged Button",clrBlack,12,"ARIAL black"); //createRecLabel(BTN_HOVER,25,230,220,35,C'220,220,220',3,C'050,050,255'); createRecLabel(BTN_HOVER,25,230,220,35,C'220,220,220',3,C'100,100,100'); createLabel(LABEL_HOVER,25+50,230+5,"Hover Effect",clrBlack,12,"ARIAL black"); createLabel(LABEL_EXTRA1,25,290,"_",clrBlack,25,"WEBDINGS"); createLabel(LABEL_EXTRA2,25+40,290,"J",clrBlack,25,"WINGDINGS"); createLabel(LABEL_EXTRA3,25+40+40,290,"{",clrBlack,25,"WINGDINGS 2"); createLabel(LABEL_EXTRA4,25+40+40+40,290,"G",clrBlack,25,"WINGDINGS 3"); // createDropDown(); return(INIT_SUCCEEDED); } double Ask(){return(NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits));} double Bid(){return(NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits));} int Spread(){return((int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD));} //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- destroyPanel(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Function to create rectangle label | //+------------------------------------------------------------------+ bool createRecLabel(string objName, int xD, int yD, int xS, int yS, color clrBg, int widthBorder, color clrBorder = clrNONE, ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) { ResetLastError(); // Reset any previous error codes // Create a rectangle label object if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) { Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError); return (false); // Return false if object creation fails } // Set properties for the rectangle label ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat) ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat) ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat) ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected ChartRedraw(0); // Redraw the chart return (true); // Return true if object creation and property settings are successful } //+------------------------------------------------------------------+ //| Function to create button | //+------------------------------------------------------------------+ bool createButton(string objName, int xD, int yD, int xS, int yS, string txt = "", color clrTxt = clrBlack, int fontSize = 12, color clrBg = clrNONE, color clrBorder = clrNONE, string font = "Arial Rounded MT Bold") { // Reset any previous errors ResetLastError(); // Attempt to create the button object if (!ObjectCreate(0, objName, OBJ_BUTTON, 0, 0, 0)) { // Print an error message if creation fails Print(__FUNCTION__, ": failed to create the button! Error code = ", _LastError); return (false); } // Set properties for the button ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the button ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the button ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the button ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Button state (not pressed) ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected // Redraw the chart to display the button ChartRedraw(0); return (true); // Button creation successful } //+------------------------------------------------------------------+ //| Function to create edit field | //+------------------------------------------------------------------+ bool createEdit(string objName, int xD, int yD, int xS, int yS, string txt = "", color clrTxt = clrBlack, int fontSize = 12, color clrBg = clrNONE, color clrBorder = clrNONE, string font = "Arial Rounded MT Bold") { // Reset any previous errors ResetLastError(); // Attempt to create the edit object if (!ObjectCreate(0, objName, OBJ_EDIT, 0, 0, 0)) { // Print an error message if creation fails Print(__FUNCTION__, ": failed to create the edit! Error code = ", _LastError); return (false); } // Set properties for the edit field ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the edit field ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the edit field ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Default text in the edit field ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color ObjectSetInteger(0, objName, OBJPROP_ALIGN, ALIGN_LEFT); // Text alignment (left-aligned) ObjectSetInteger(0, objName, OBJPROP_READONLY, false); // Edit field is not read-only ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Edit field state (not active) ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected // Redraw the chart to display the edit field ChartRedraw(0); return (true); // Edit field creation successful } //+------------------------------------------------------------------+ //| Function to create text label | //+------------------------------------------------------------------+ bool createLabel(string objName, int xD, int yD, string txt, color clrTxt = clrBlack, int fontSize = 12, string font = "Arial Rounded MT Bold") { // Reset any previous errors ResetLastError(); // Attempt to create the label object if (!ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0)) { // Print an error message if creation fails Print(__FUNCTION__, ": failed to create the label! Error code = ", _LastError); return (false); } // Set properties for the label ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the label ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Label state (not active) ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected // Redraw the chart to display the label ChartRedraw(0); return (true); // Label creation successful } //+------------------------------------------------------------------+ //| Function to create the drop down utilities | //+------------------------------------------------------------------+ void createDropDown(){ createRecLabel(BTN_DROP_DN,25,95+25,130,70,clrWhite,2,clrBlack); createLabel(LABEL_OPT1,25+10,95+25,"LotSize",clrBlack,12,"stencil"); createLabel(LABEL_OPT2,25+10,95+25+20,"Risk Percent %",clrBlack,12,"calibri Italic"); createLabel(LABEL_OPT3,25+10,95+25+20+20,"Money Balance",clrBlack,12,"Arial bold"); createLabel(ICON_DRAG,25+10+95,95+25,"d",clrRoyalBlue,15,"webdings"); } //+------------------------------------------------------------------+ //| Function to destroy the entire GUI Panel | //+------------------------------------------------------------------+ void destroyPanel(){ ObjectDelete(0,MAIN_REC); ObjectDelete(0,MAIN_SUB_REC); ObjectDelete(0,MAIN_LINE_UP); ObjectDelete(0,MAIN_LINE_DN); ObjectDelete(0,BTN_LOTS); ObjectDelete(0,LABEL_NAME); ObjectDelete(0,LABEL_LOTS); ObjectDelete(0,ICON_HEART); ObjectDelete(0,ICON_TOOL); ObjectDelete(0,ICON_CAR); ObjectDelete(0,ICON_DROP_DN1); ObjectDelete(0,LINE1); ObjectDelete(0,BTN_CLOSE); ObjectDelete(0,BTN_MARKET); ObjectDelete(0,BTN_PROFIT); ObjectDelete(0,BTN_LOSS); ObjectDelete(0,BTN_PENDING); ObjectDelete(0,LINE2); ObjectDelete(0,EDIT_LOTS); ObjectDelete(0,BTN_P1); ObjectDelete(0,BTN_M1); ObjectDelete(0,BTN_SL); ObjectDelete(0,LABEL_SL); ObjectDelete(0,ICON_DROP_DN2); ObjectDelete(0,EDIT_SL); ObjectDelete(0,BTN_P2); ObjectDelete(0,BTN_M2); ObjectDelete(0,BTN_TP); ObjectDelete(0,LABEL_TP); ObjectDelete(0,ICON_DROP_DN3); ObjectDelete(0,EDIT_TP); ObjectDelete(0,BTN_P3); ObjectDelete(0,BTN_M3); ObjectDelete(0,BTN_BUY); ObjectDelete(0,LABEL_BUY); ObjectDelete(0,LABEL_BUY_PRICE); ObjectDelete(0,BTN_OVERLAY); ObjectDelete(0,BTN_SPREAD); ObjectDelete(0,BTN_SELL); ObjectDelete(0,LABEL_SELL); ObjectDelete(0,LABEL_SELL_PRICE); ObjectDelete(0,BTN_CONTACT); ObjectDelete(0,BTN_SHARP); ObjectDelete(0,LABEL_SHARP); ObjectDelete(0,BTN_HOVER); ObjectDelete(0,LABEL_HOVER); ObjectDelete(0,LABEL_EXTRA1); ObjectDelete(0,LABEL_EXTRA2); ObjectDelete(0,LABEL_EXTRA3); ObjectDelete(0,LABEL_EXTRA4); ObjectDelete(0,BTN_DROP_DN); ObjectDelete(0,LABEL_OPT1); ObjectDelete(0,LABEL_OPT2); ObjectDelete(0,LABEL_OPT3); ObjectDelete(0,ICON_DRAG); ChartRedraw(0); }
Conclusão
Em conclusão, você pode ver que a criação de painéis GUI não é tão complexa quanto parece. O processo envolve uma série de etapas, desde a definição das dimensões do painel (decidindo a posição, tamanho e aparência, utilizando coordenadas absolutas ou relativas ao gráfico), passando pela criação de vários objetos gráficos, como botões, rótulos, campos de edição e rótulos de retângulo, especificando suas propriedades (cor, texto, fonte, etc.), até a implementação em manipuladores de eventos para criar os painéis e interações com o usuário.
Essa primeira parte apresentou a criação bem-sucedida do painel. A segunda parte dará vida ao painel, tornando-o responsivo. Por exemplo, faremos os botões serem responsivos aos cliques, atualizaremos as cotações de preços a cada tick, tornaremos a lista suspensa arrastável, adicionaremos efeitos de hover aos botões e muito mais. Esperamos que você tenha achado este artigo útil para a criação de painéis GUI e que o conhecimento ilustrado aqui possa ser utilizado para criar painéis GUI mais complexos e sofisticados.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15205
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.





- 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
Não é possível alterar o prefixo dos objetos traid. Mas a ideia está correta: todos os nomes desses objetos começam da mesma forma. Portanto, você pode usar o início do nome do objeto como um prefixo.
Claro
Com certeza
Alguns bytes. Na capa há uma bela interface colorida, e aqui está uma janela do Windows XP)
Olá, irmão... Aceite minha solicitação de amizade... quero sua ajuda