Melhore seus gráficos de negociação com uma GUI interativa baseada em MQL5 (Parte I): GUI móvel (I)
Introdução
Bem-vindo ao emocionante mundo das interfaces gráficas móveis em MQL5! Este guia está aqui para capacitá-lo com o conhecimento para criar interfaces gráficas dinâmicas e interativas que elevarão suas estratégias de negociação. Começaremos com o conceito básico de eventos gráficos – o mecanismo que controla a interatividade de nossa GUI. Com essa base, nós o guiaremos na criação de sua primeira GUI móvel.
Na próxima parte, avançaremos para a criação eficiente de várias GUI em um único gráfico (não apenas copiando e colando coisas), aprofundaremos na melhoria da nossa GUI adicionando e personalizando vários elementos, adaptando-a às suas necessidades exclusivas. Para aqueles que querem se aprofundar e criar uma interface móvel, criamos um guia simplificado que oferece etapas rápidas.
Ao final desta jornada, você terá adquirido uma habilidade valiosa na criação e manipulação de GUI móveis em MQL5, uma ferramenta poderosa para qualquer trader. Mesmo se você estiver com pressa, temos um guia rápido para aqueles que desejam pular diretamente na criação de sua GUI móvel.
Continuaremos da seguinte forma:
- Decodificação de eventos gráficos: Blocos de construção de uma GUI móvel
- Desenvolvimento de uma interface gráfica móvel: Guia passo-a-passo
- Considerações finais
Decodificação de eventos gráficos: Blocos de construção de uma GUI móvel
No momento, o código do Expert Advisor se parece com isto (ou seja, ele é absolutamente básico):
Você pode estar se perguntando por que um EA e não um Indicador? Bem, a razão para isso é que o EA é mais fácil de entender para a maioria das pessoas, enquanto o Indicador pode confundir alguns, mas fique tranquilo, os mesmos passos podem ser seguidos no Indicador também.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { //--- } //+------------------------------------------------------------------+
Agora, para entender melhor o OnChartEvent, vamos compará-lo com outra função predefinida que você já conhece a partir do EA básico acima com OnChartEvent().
Funções predefinidas | Propósito |
---|---|
OnInit() | É executada na inicialização, ou seja, o EA é inicializado (anexado) no gráfico. Executada apenas uma vez |
OnTick() | Iniciada com a entrada de um tick, ou seja, quando o símbolo no gráfico recebe um tick da corretora. Tick significa atualização de preço |
OnDeinit() | É executada na desinicialização, ou seja, quando o EA é desinicializado (removido) do gráfico. Executada apenas uma vez |
Da mesma forma, OnChartEvent() é uma função que é executada quando certos eventos ocorrem. Bem, sobre quais eventos estamos falando aqui?
Existem 9 eventos predefinidos (excluindo 2 personalizados):
- CHARTEVENT_KEYDOWN
- CHARTEVENT_MOUSE_MOVE
- CHARTEVENT_OBJECT_CREATE
- CHARTEVENT_OBJECT_CHANGE
- CHARTEVENT_OBJECT_DELETE
- CHARTEVENT_CLICK
- CHARTEVENT_OBJECT_CLICK
- CHARTEVENT_OBJECT_DRAG
- CHARTEVENT_OBJECT_ENDEDIT
Visão geral breve para aqueles que usaremos mais tarde no artigo:
- CHARTEVENT_KEYDOWN
Quando a janela do gráfico está em foco (basta clicar em qualquer lugar na janela do gráfico para colocá-la em foco), a função OnChartEvent() é executada cada vez que qualquer tecla do teclado é pressionada.
Mantê-la pressionada significará clicar na tecla novamente e novamente a uma taxa de 30 cliques por segundo.
Quando uma tecla é pressionada, o que podemos fazer a respeito? Não muito por enquanto. É inútil até que saibamos qual tecla foi pressionada. Como conseguir isso? Bem, é aí que entram os parâmetros do OnChartEvent().
De que parâmetros estamos falando? Existem 4 parâmetros que obtemos quando o OnChartEvent() é executado.
- id -> integer
- lparam -> long
- dparam -> double
- sparam -> string
São simplesmente informações sobre os eventos para os quais o OnChartEvent() é chamado, e podemos usar esses dados dentro da função OnChartEvent().
Por exemplo, no caso do evento CHARTEVENT_KEYDOWN,
- id contém o próprio CHARTEVENT_KEYDOWN para que possamos determinar qual evento OnChartEvent() está sendo chamado e tratar outros parâmetros de acordo.
- lparam contém o código da tecla pressionada.
- dparam contém o número de pressionamentos de tecla gerados enquanto a tecla foi pressionada. Quando mantemos pressionada a tecla, o dparam faz 30 cliques por segundo. Este valor é sempre 1.
- sparam contém uma máscara de bits. Em termos simples, o parâmetro descreve o estado da tecla, pressionada ou mantida pressionada, mostrando dois valores diferentes para uma tecla específica (veja o exemplo abaixo).
Por exemplo, pressionamos/mantemos pressionada a tecla A no teclado, então OnChartEvent() será executado com- id = CHARTEVENT_KEYDOWN
- lparam = 65
- dparam = 1
- sparam = 30 para o primeiro clique e 16414 para cliques subsequentes contínuos enquanto mantém a tecla A a 30 cliques por segundo
Agora que temos as informações, podemos usar algumas instruções "if" e fazer algo quando o usuário pressionar ou segurar a tecla A.
-
CHARTEVENT_MOUSE_MOVE
Primeiro, é necessário definir a propriedade booleana do gráfico CHART_EVENT_MOUSE_MOVE como True. Isso pode ser feito simplesmente usando uma única linha de código://Set Chart property CHART_EVENT_MOUSE_DOWN to true ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
Normalmente, é recomendável fazer isso no OnInit(). Depois disso, podemos usar o CHARTEVENT_MOUSE_MOVE.
Sempre que o mouse for movido sobre o gráfico, o OnChartEvent() será executado com as seguintes informações nos parâmetros:
- id = CHARTEVENT_MOUSE_MOVE
- lparam = coordenada X
- dparam = coordenada Y
- sparam = valor da máscara de bits que descreve o status dos botões do mouse
A máscara de bits contém os seguintes valores ->
- Botão esquerdo do mouse -> 1
- Botão direito do mouse -> 2
- Botão do meio do mouse -> 16
- Primeira tecla X do mouse -> 32
- Segunda tecla X do mouse -> 64
- Tecla Shift -> 4
- Tecla de controle --> 8
A janela do gráfico está no quarto quadrante, ou seja, a coordenada x (lparam) está à esquerda da janela do gráfico e a coordenada y (dparam) está no topo da janela do gráfico. Agora, com todas essas informações, estamos prontos para usar o CHARTEVENT_MOUSE_MOVE. Iremos usá-lo abaixo para tornar a GUI móvel.
-
CHARTEVENT_CLICK
Não requer nenhuma propriedade especial, podemos usá-lo diretamente. Ou seja, sempre que o mouse é clicado no gráfico, o OnChartEvent() é executado com os seguintes parâmetros:- id = CHARTEVENT_CLICK
- lparam = coordenada X
- dparam = coordenada Y
- sparam = "" ou seja, uma string vazia, o que significa que não contém nenhuma informação útil
Agora que temos as informações acima, podemos usar algumas instruções "if" e fazer algo quando o usuário clicar em qualquer lugar no gráfico.
Acima, discutimos 3 eventos que iniciam a função OnChartEvent: CHARTEVENT_KEYDOWN, CHART_EVENT_MOUSE_MOVE e CHARTEVENT_CLICK.
Eu sei que, se você nunca usou a função OnChartEvent() antes, tudo isso pode parecer um pouco confuso. Bem, já estivemos lá, mas todos nós saímos dessa fase aprendendo mais e praticando mais. Vamos recorrer ao conhecimento acima para tornar a GUI móvel. Muito em breve você se sentirá mais confiante.
Leia a documentação ou comente abaixo se você precisar de detalhes sobre os outros eventos que iniciam o OnChartEvent().
Desenvolvimento de uma interface gráfica móvel: Guia passo-a-passo
Agora que todas as coisas chatas foram feitas, podemos nos concentrar no aprendizado real, ou seja, na aplicação da teoria a coisas reais, não apenas falar sobre elas.
Nesta seção, nosso objetivo é criar uma GUI muito simples, ou podemos dizer uma forma retangular vazia. Não fique desmotivado só porque não estamos criando uma GUI complexa e atraente; as coisas sempre começam a partir do básico e depois se vão tornando mais complexas.
Acha que consegue acompanhar? Experimente para descobrir, continue comigo até o final deste artigo e veja se pode dizer que tudo isso foi fácil. Vamos chamar esta GUI de painel (dashboard), pois em breve a transformaremos em um painel.
Primeiro, vamos criar uma forma retangular básica de 200x200 (XSize x YSize) com uma distância de 100 pixels da esquerda (XDistance) e 100 pixels do topo (YDistance)
int OnInit() { //--- //Set the name of the rectangle as "TestRectangle" string name = "TestRectangle"; //Create a Rectangle Label Object at (time1, price1)=(0,0) ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0); //Set XDistance to 100px i.e. Distance of Rectangle Label 100px from Left of the Chart Window ObjectSetInteger(0, name,OBJPROP_XDISTANCE, 100); //Set YDistance to 100px i.e. Distance of Rectangle Label 100px from Top of the Chart Window ObjectSetInteger(0, name,OBJPROP_YDISTANCE, 100); //Set XSize to 200px i.e. Width of Rectangle Label ObjectSetInteger(0, name,OBJPROP_XSIZE, 200); //Set YSize to 200px i.e. Height of Rectangle Label ObjectSetInteger(0, name,OBJPROP_YSIZE, 200); //--- return(INIT_SUCCEEDED); }
Agora, quando executarmos o EA no gráfico, devemos ver nossa forma retangular criada:
Fig. 1. Forma retangular simples
Agora, se pudermos torná-la móvel com o arrasto do mouse, poderemos fazer muitas coisas, como mover uma barra de ferramentas avançada livremente na janela do gráfico, que pode criar EAs/Indicadores interativos muito bons. Uma das melhores aplicações para isso pode ser vista no Trade Assistant EA.
Então, como procedemos para torná-la móvel? Vamos criar um plano primeiro:
- Condições antes do deslocamento:
-
O mouse deve estar no painel.
-
O botão esquerdo do mouse deve estar pressionado.
-
- Se movermos o mouse com o botão esquerdo pressionado, o painel deverá se mover.
- Mas a que distância? O painel deverá mover-se suavemente desde que ambas as condições sejam satisfeitas.
Agora vamos codificá-lo passo a passo:
Para a primeira condição, o mouse deve estar no painel, primeiro precisamos encontrar as coordenadas x e y da posição do mouse.
É hora de aplicar a teoria. Para as coordenadas dos eixos x e y do mouse, precisamos usar o OnChartEvent().
- Definimos a propriedade do gráfico CHART_EVENT_MOUSE_MOVE como True
Vamos colocar o código abaixo no OnInit() para torná-lo verdadeiro ao inicializar o EA:
//Set Chart property CHART_EVENT_MOUSE_DOWN to true ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
- Agora podemos obter as coordenadas do mouse no OnChartEvent().
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case if(id == CHARTEVENT_MOUSE_MOVE) { //Comment the X and Y Axes Coordinates Comment("X: ", lparam, "\nY: ", dparam); } }
No OnChartEvent(), primeiro verificamos se o evento que acionou o OnChartEvent foi CHARTEVENT_MOUSE_MOVE usando um simples operador “if” que verifica se o id é igual a CHARTEVENT_MOUSE_MOVE, porque só queremos executar nosso código de comentário quando esse for o caso.
Em seguida, anotamos as coordenadas dos eixos X e Y (eles aparecerão no canto superior esquerdo da janela do gráfico em branco com fonte pequena), assim:
Fig. 2. Coordenadas X e Y
Agora, para nossa lógica de descobrir se o mouse está no painel, veja a imagem abaixo:
Fig. 3. Visualização da fórmula
Para saber se o mouse está sobre o painel,
- X >= XDistance --> X>=100
- X <= XDIstance + XSize --> X<=300
- Y >= YDistance --> Y>=100
- Y <= YDistance + YSize --> Y>=300
Conversão em código:
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case if(id == CHARTEVENT_MOUSE_MOVE) { //define X, Y, XDistance, YDistance, XSize, YSize int X = (int)lparam; int Y = (int)dparam; string name = "TestRectangle"; int XDistance = ObjectGetInteger(0, name, OBJPROP_XDISTANCE); //Should be 100 initially as we set it in OnInit() int YDistance = ObjectGetInteger(0, name, OBJPROP_YDISTANCE); //Should be 100 initially as we set it in OnInit() int XSize = ObjectGetInteger(0, name, OBJPROP_XSIZE); //Should be 200 initially as we set it in OnInit() int YSize = ObjectGetInteger(0, name, OBJPROP_YSIZE); //Should be 200 initially as we set it in OnInit() //Check Mouse on Dashboard condition if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize) { //Comment the X and Y Axes Coordinates and Mouse is on the dashboard Comment("X: ", lparam, "\nY: ", dparam, "\nMouse is on the Dashboard"); } else { //Comment the X and Y Axes Coordinates and Mouse is not on the dashboard Comment("X: ", lparam, "\nY: ", dparam, "\nMouse is NOT on the Dashboard"); } } }
Definimos as variáveis X, Y, nome, XDistance, YDistance, XSize, YSize. Obtivemos X de lparam, Y de dparam, nome é apenas o nome de string que definimos acima, XDistance, YDistance, XSize, YSize usando a função ObjectGetInteger().
Nosso objetivo aqui é fazer com que o painel se mova suavemente.
Resultado:
Fig. 4. Mouse sobre o painel
Como você pode ver, sempre que o mouse está sobre o painel, o comentário muda. Então nossa lógica funciona, e sabemos se o mouse está no painel ou não.
Agora precisaremos do estado dos botões do mouse. Como lembramos, se clicarmos com o botão esquerdo, sparam será igual a 1. Vamos aproveitar isso.
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case if(id == CHARTEVENT_MOUSE_MOVE) { //define X, Y, XDistance, YDistance, XSize, YSize int X = (int)lparam; int Y = (int)dparam; int MouseState = (int)sparam; string name = "TestRectangle"; int XDistance = ObjectGetInteger(0, name, OBJPROP_XDISTANCE); //Should be 100 initially as we set it in OnInit() int YDistance = ObjectGetInteger(0, name, OBJPROP_YDISTANCE); //Should be 100 initially as we set it in OnInit() int XSize = ObjectGetInteger(0, name, OBJPROP_XSIZE); //Should be 200 initially as we set it in OnInit() int YSize = ObjectGetInteger(0, name, OBJPROP_YSIZE); //Should be 200 initially as we set it in OnInit() //Check Dashboard move conditions if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize && MouseState == 1) { //Comment that the dashboard is ready to move Comment("Dashboard is ready to move."); } else { //Comment that the dashboard is not ready to move Comment("Dashboard is NOT ready to move."); } } }
Adicionei
int MouseState = (int)sparam; //To get the mouse state: 1 -> Mouse Left Button Down (You can check the other above)
às variáveis, bem como condição
if(MouseState == 1) // This insures that Mouse Left button in pressed
à instrução “if”. Também mudei um pouco os comentários.
Agora sempre que o botão esquerdo do mouse é pressionado no painel, obtemos o comentário “Dashboard is ready to move” (o painel está pronto para ser movido). Caso contrário, receberemos o comentário "Dashboar is NOT ready to move" (o painel NÃO está pronto para ser movido).
Vamos ver isso em ação:
Fig. 5. O painel está pronto para ser movido
Observe a alteração do comentário quando o botão esquerdo do mouse é mantido pressionado.
Agora, com isso feito, estamos prontos para mover nosso painel. Então, como procedemos?
Sabemos que o painel se moverá com nosso mouse, e como mudamos a posição do painel? Claro, com as propriedades XDistance e YDistance. Mas quanto devemos mudar XDistance e YDistance? Como o painel se move com o mouse, ele deve se mover na mesma medida que o mouse, certo?
Bem, então, até que ponto nosso mouse se moveu? Ainda há muitas perguntas. Bem, vamos fazer um plano com base nessas perguntas.
Plano:
- Descobrimos até que ponto o mouse se moveu depois de pressionar o botão esquerdo
- Movemos o painel exatamente na mesma medida em que o mouse se move.
- Faremos isso enquanto o botão esquerdo do mouse estiver pressionado e, depois disso, pararemos de mover o painel.
Vamos dar um passo de cada vez.
Sempre podemos obter a posição atual do mouse, certo? E se salvássemos a posição do mouse quando o botão esquerdo do mouse foi clicado pela primeira vez?
E podemos saber se o botão esquerdo do mouse está pressionado a partir da variável MouseState que criamos para armazenar sparam.
Abaixo está o código que detecta o primeiro clique esquerdo do mouse:
int previousMouseState = 0; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case if(id == CHARTEVENT_MOUSE_MOVE) { int MouseState = (int)sparam; bool mblDownFirstTime = false; if(previousMouseState == 0 && MouseState == 1) { mblDownFirstTime = true; } previousMouseState = MouseState; } } //+------------------------------------------------------------------+
Removi algumas linhas para facilitar a compreensão. Este método é bastante comumente usado na criação de funções de trailing para EA ou na detecção de uma nova barra, etc.
Vamos analisar isso:
-
int previousMouseState = 0;
Declaramos uma variável int chamada previousMouseState no espaço global e a definimos como 0. Esta variável armazenará o valor MouseState da última vez que o evento CHARTEVENT_MOUSE_MOVE ocorreu. Como exatamente? Você descobrirá em breve.
-
int previousMouseState = 0;
Declaramos uma variável int chamada previousMouseState no espaço global e a definimos como 0. Esta variável armazenará o valor MouseState da última vez que o evento CHARTEVENT_MOUSE_MOVE ocorreu. Como exatamente? Tenha um pouco de paciência, você logo entenderá.
-
int MouseState = (int)sparam; bool mblDownFirstTime = false; if(previousMouseState == 0 && MouseState == 1) { mblDownFirstTime = true; }
Primeiro, declaramos uma variável MouseState e a definimos como igual a sparam, que contém o estado do mouse. Em seguida, declaramos uma variável bool chamada mblDownFirstTime e definimos seu valor padrão como false.Em seguida, verificamos 2 condições: primeiro, previousMouseState deve ser igual a 0 (MLB solto, nenhum botão do mouse pressionado) e (&&) MouseState deve ser igual a 1 (MLB pressionado).
Essa condição basicamente confirma ou nega se o MLB foi pressionado pela primeira vez ou não. Uma vez que sabemos que é a primeira vez, definimos mblDownFirstTime como true para que possamos usar essa variável posteriormente.
Nossa primeira etapa está concluída, vamos seguir para as etapas 2 e 3.
Agora, há muitas maneiras de prosseguir, mas para obter um movimento muito suave e sutil, abaixo estão os passos que seguiremos:
- Criamos uma variável global lógica movingState, que será definida como true assim que o usuário clicar com o botão esquerdo do mouse na barra de ferramentas, e declaramos MLB Down X, MLB Down Y, MLB Down XDistance, MLB Down YDistance (aqui, MLB Down significa que o botão esquerdo do mouse foi liberado primeiro). Isso será necessário para alterar a posição da barra de ferramentas.
- Enquanto movingState for true, atualizaremos a posição da barra de ferramentas de acordo com a alteração da posição do mouse em comparação com a posição original (quando o botão esquerdo do mouse foi pressionado pela primeira vez).
- Enquanto movingState for true, atualizaremos a posição da barra de ferramentas de acordo com a alteração da posição do mouse em comparação com a posição original (quando o botão esquerdo do mouse foi pressionado pela primeira vez).
Novo código:
int previousMouseState = 0; int mlbDownX = 0; int mlbDownY = 0; int mlbDownXDistance = 0; int mlbDownYDistance = 0; bool movingState = false; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case if(id == CHARTEVENT_MOUSE_MOVE) { if(previousMouseState == 0 && MouseState == 1) { mlbDownX = X; mlbDownY = Y; mlbDownXDistance = XDistance; mlbDownYDistance = YDistance; if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize) { movingState = true; } } if(movingState) { ChartSetInteger(0, CHART_MOUSE_SCROLL, false); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY); ChartRedraw(0); } if(MouseState == 0) { movingState = false; ChartSetInteger(0, CHART_MOUSE_SCROLL, true); } previousMouseState = MouseState; } } //+------------------------------------------------------------------+
Vamos simplificar isso:
-
int mlbDownX = 0; int mlbDownY = 0; int mlbDownXDistance = 0; int mlbDownYDistance = 0; bool movingState = false;
Criamos diversas variáveis no escopo global. Já falamos sobre a previousMouseState além disso:
- mlbDownX -> Manter a coordenada X quando o botão esquerdo do mouse for pressionado pela primeira vez
- mlbDownY -> Manter a coordenada Y quando o botão esquerdo do mouse for pressionado pela primeira vez
- mlbDownXDistance -> Manter a propriedade XDistance da barra de ferramentas quando o botão esquerdo do mouse for clicado pela primeira vez
- mlbDownYDistance -> Manter a propriedade YDistance da barra de ferramentas quando o botão esquerdo do mouse for clicado pela primeira vez
- movingState -> Manter como true se movermos o painel; caso contrário, false
if(previousMouseState == 0 && MouseState == 1) { mlbDownX = X; mlbDownY = Y; mlbDownXDistance = XDistance; mlbDownYDistance = YDistance; if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize) { movingState = true; } }
Primeiro, verificamos se é o primeiro clique do mouse; Nesse caso, atualizamos mlbDownX, mlbDownY, mlbDownXDistance, mlbDownYDistance para X, Y, XDistance e YDistance atuais, respectivamente. Nós os usaremos mais tarde.Em seguida, verificamos se o botão esquerdo do mouse estava pressionado no painel e, se estivesse, definimos movingState como true.
-
if(movingState) { ChartSetInteger(0, CHART_MOUSE_SCROLL, false); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY); ChartRedraw(0); }
E se movingState for true, modificamos XDistance e YDistance.
X - mlbDownX // Change in Mouse X Position form the initial click and Y - mlbDownY // Change in Mouse X Position form the initial click
Essas são as alterações na posição do mouse a partir do clique inicial e as adicionamos a mlbDownXDistance e mlbDownYDistance para obter a nova posição do painel. Faz sentido se você pensar sobre isso.
E também definimos a propriedade CHART_MOUSE_SCROLL como false para que o gráfico não se mova com nosso painel e, claro, redesenhamos o gráfico para obter um movimento muito suave.
-
if(MouseState == 0) { movingState = false; ChartSetInteger(0, CHART_MOUSE_SCROLL, true); }
Agora, assim que soltarmos o botão esquerdo do mouse, MouseState se tornará 0.
Em seguida, definimos movingState como false e permitimos que o gráfico se mova novamente, definindo CHART_MOUSE_SCROLL como true novamente.
Agora, com isso feito, nosso código está concluído. Dê um tapinha nas costas se você seguiu até agora.
Nosso código completo fica assim:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //Set the name of the rectangle as "TestRectangle" string name = "TestRectangle"; //Create a Rectangle Label Object at (time1, price1)=(0,0) ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0); //Set XDistance to 100px i.e. Distance of Rectangle Label 100px from Left of the Chart Window ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 100); //Set YDistance to 100px i.e. Distance of Rectangle Label 100px from Top of the Chart Window ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 100); //Set XSize to 200px i.e. Width of Rectangle Label ObjectSetInteger(0, name, OBJPROP_XSIZE, 200); //Set YSize to 200px i.e. Height of Rectangle Label ObjectSetInteger(0, name, OBJPROP_YSIZE, 200); //Set Chart property CHART_EVENT_MOUSE_DOWN to true ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //Declare some global variable that will be used in the OnChartEvent() function int previousMouseState = 0; int mlbDownX = 0; int mlbDownY = 0; int mlbDownXDistance = 0; int mlbDownYDistance = 0; bool movingState = false; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case if(id == CHARTEVENT_MOUSE_MOVE) { //define X, Y, XDistance, YDistance, XSize, YSize int X = (int)lparam; int Y = (int)dparam; int MouseState = (int)sparam; string name = "TestRectangle"; int XDistance = (int)ObjectGetInteger(0, name, OBJPROP_XDISTANCE); //Should be 100 initially as we set it in OnInit() int YDistance = (int)ObjectGetInteger(0, name, OBJPROP_YDISTANCE); //Should be 100 initially as we set it in OnInit() int XSize = (int)ObjectGetInteger(0, name, OBJPROP_XSIZE); //Should be 200 initially as we set it in OnInit() int YSize = (int)ObjectGetInteger(0, name, OBJPROP_YSIZE); //Should be 200 initially as we set it in OnInit() if(previousMouseState == 0 && MouseState == 1) //Check if this was the MLB first click { mlbDownX = X; //Set mlbDownX (Variable that stores the initial MLB X location) equal to the current X mlbDownY = Y; //Set mlbDownY (Variable that stores the initial MLB Y location) equal to the current Y mlbDownXDistance = XDistance; //Set mlbDownXDistance (Variable that stores the initial XDistance i.e. Width of the dashboard) equal to the current XDistance mlbDownYDistance = YDistance; //Set mlbDownYDistance (Variable that stores the initial YDistance i.e. Height of the dashboard) equal to the current YDistance if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize) //Check if the click was on the dashboard { movingState = true; //If yes the set movingState to True } } if(movingState)//if movingState is true, Update the Dashboard position { ChartSetInteger(0, CHART_MOUSE_SCROLL, false);//Restrict Chart to be moved by Mouse ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX);//Update XDistance to: mlbDownXDistance + (X - mlbDownX) ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY);//Update YDistance to: mlbDownYDistance + (Y - mlbDownY) ChartRedraw(0); //Redraw Chart } if(MouseState == 0)//Check if MLB is not pressed { movingState = false;//set movingState again to false ChartSetInteger(0, CHART_MOUSE_SCROLL, true);//allow the cahrt to be moved again } previousMouseState = MouseState;//update the previousMouseState at the end so that we can use it next time and copare it with new value } } //+------------------------------------------------------------------+
Agora, esse código simples faz o trabalho.
Resultado:
Fig. 6. Resultado final
Conclusão
Peço desculpas por deixar você em um suspense, pois ainda não criamos algo verdadeiramente único. Porém, dentro de alguns dias será publicada a próxima parte, na qual:
- Criaremos várias interfaces gráficas em um gráfico (sem copiar e colar básico)
- Melhoraremos nossa interface gráfica adicionando e customizando diversos elementos, adaptando-a às suas necessidades únicas. Para aqueles que querem se aprofundar e criar uma interface móvel, criamos um guia simplificado que oferece etapas rápidas.
Ao final desta jornada, você terá adquirido uma habilidade valiosa na criação e manipulação de GUI móveis em MQL5, uma ferramenta poderosa para qualquer trader.
Espero que tenha gostado e que tenha ajudado de alguma forma.
Divirta-se codificando!
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/12751
- Aplicativos de negociação gratuitos
- VPS Forex grátis por 24 horas
- 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