Discussão do artigo "Guia prático do MQL5: Controles de sub-janela indicadora - botões" - página 7

 
TheXpert:
Tem certeza de que seu artigo é perfeito?

Estou muito satisfeito por você tê-lo lido.

Terei prazer em responder a todas as perguntas no tópico apropriado.

===

Para que não haja equívocos desnecessários, não tenho nada contra Anatoly! Parabéns a ele pelo artigo! Mas é necessário responder às perguntas...

 
DC2008:

Desculpe-me, por acaso estou distraindo-o de escrever outro tutorial ou receita?

Se não, vamos continuar discutindo seu artigo sobre controle na subjanela do indicador. Então, você oferece uma solução em massa (ou uma ideia) de como criar um menu conveniente em um indicador. Ótimo, o objetivo do artigo é muito válido! Mas como um programador "iniciante" pode usar todo esse arsenal? Onde colocar as funções personalizadas? Demonstre-o com um exemplo. E, ao mesmo tempo, explique o que você precisa corrigir no código para usar, por exemplo, 5 botões? Considere essa pergunta como de um iniciante.

Não, não é. Ainda não estou escrevendo nada. Tenho que descansar pelo menos um dia por ano. Apenas descansar não é interessante, especialmente por um longo período. )

Não é uma decisão em massa e eu não escrevi sobre isso. Não vamos atribuir algo que não aconteceu. Já foi dito no início da discussão que essa não é uma solução universal, mas um caso especial. Na minha opinião, é um bom exemplo para um iniciante praticar. E não para obter uma solução pronta de graça e correr, com a boca aberta em um sorriso largo, para encontrar o sol. ) Está entendendo? Eu gostaria de ter um exemplo tão simples e claro logo no início do aprendizado de programação. Especialmente quando essa é a primeira linguagem de programação de sua vida e, antes disso, toda a atividade de sua vida foi em um campo completamente diferente, de forma alguma relacionado a ela.

Para criar 5 botões, nesse caso, precisamos alterar o tamanho das matrizes e excluir elementos desnecessários ao declarar matrizes para os nomes dos objetos-botões, texto exibido nos botões e estados dos botões.

Há uma matriz de estados de botões, portanto, o mesmo princípio pode ser usado para verificar qual botão foi pressionado e, em vez de apenas alterar a cor do botão, executar alguma outra ação (exigida pelo usuário). Isso pode ser, por exemplo, funções de negociação (e não apenas): excluir todas as ordens pendentes, fechar todas as posições etc. As ideias são infinitas. E se não houver ideias, então você escolheu o tipo errado de atividade. )

Para implementar isso, você precisa criar outra matriz, que será inicializada com identificadores de uma enumeração personalizada (que também precisa ser criada), por exemplo, com o nome ENUM_SCRIPT. E os identificadores serão chamados, por exemplo: SCRIPT_01 =0, SCRIPT_02 =2, etc. Também no loop, ao verificar se o botão no painel está pressionado, você precisará determinar qual identificador está vinculado ao botão pressionado e o estado atual do botão e, em seguida, passar a função correspondente ao programa para execução.

Não mostrarei um exemplo de código propositalmente. Que seja um dever de casa para iniciantes. )

Документация по MQL5: Стандартные константы, перечисления и структуры / Торговые константы / Свойства ордеров
Документация по MQL5: Стандартные константы, перечисления и структуры / Торговые константы / Свойства ордеров
  • www.mql5.com
Стандартные константы, перечисления и структуры / Торговые константы / Свойства ордеров - Документация по MQL5
 

Fiz as alterações como você disse:

//--- Texto exibido nos botões
string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"Button 01","Button 02","Button 03","Button 04"},
     {"Button 05"}
  };
//--- Nomes de objetos
string button_object_names[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"button_01","button_02","button_03","button_04"},
     {"button_05"}
  };
....
bool button_states[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {true,false,false,false},
     {false}
  };

E foi isso que obtive na tela:

Como faço para corrigir isso? (Sou iniciante)

 
DC2008:

Fiz as alterações como você disse:

E foi isso que obtive na tela:

Como faço para corrigir isso? (Sou iniciante)

Assim:

#define  BUTTON_COLUMNS 5 // Número de botões por largura
#define  BUTTON_ROWS    1 // Número de botões por altura
...
//--- Texto exibido nos botões
string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"Button 01","Button 02","Button 03","Button 04","Button 05"}
  };
//--- Nomes de objetos
string button_object_names[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"button_01","button_02","button_03","button_04","button_05"}
  };
...
//--- Estados do botão
bool button_states[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {true,false,false,false,false}
  };
 

Que ótimo! Funciona.

Mas não entendo como conectar minhas funções aos botões. Mostre-me um exemplo.

 
DC2008:

Que ótimo! Funciona.

Mas não entendo como conectar minhas funções aos botões. Mostre-me um exemplo.

Bem, vamos continuar o jogo de "iniciante" iniciado por você. )

Em que ponto você está travado? Mostre uma tentativa de como você entendeu o ponto atual. Crie uma enumeração com cinco identificadores e uma matriz cujos elementos precisam ser atribuídos a esses identificadores.

 
bool fun_states[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {true,false,false,false,false}
  };
enum ENUM_SCRIPT
  {
   SCRIPT_01 =0,
   SCRIPT_02 =1,
   SCRIPT_03 =2,
   SCRIPT_04 =3,
   SCRIPT_05 =4,
  };
void F1()
  {Print("F1");}
bool F2()
  {Print("F2");return(false);}
int F3()
  {Print("F3");return(0);}
double F4()
  {Print("F4");return(0.1);}
color F5()
  {Print("F5");return(clrAliceBlue);}

Então, o que faremos a seguir?

 
DC2008:

Então, o que faremos a seguir?

Esse é o tipo de matriz de que você precisa:

//--- Scripts
ENUM_SCRIPT buttons_scripts[NUMBER_BUTTONS_HEIGHT][NUMBER_BUTTONS_WIDTH]=
  {
     {SCRIPT_01,SCRIPT_02,SCRIPT_03,SCRIPT_04,SCRIPT_05}
  };

Então, você precisa escrever uma função como esta:

//+------------------------------------------------------------------+
//|| Execução de scripts
//+------------------------------------------------------------------+
void ScriptOn()
  {
   for(int i=0; i<NUMBER_BUTTONS_WIDTH; i++)
     {
      for(int j=0; j<NUMBER_BUTTONS_HEIGHT; j++)
        {
         //--- Se esse botão for pressionado, executaremos o script correspondente
         if(buttons_state[j][i])
           {
            if(buttons_scripts[j][i]==SCRIPT_01)
              {
               F1();
               return;
              }
            //---
            if(buttons_scripts[j][i]==SCRIPT_02)
              {
               F2();
               return;
              }
            //---
            if(buttons_scripts[j][i]==SCRIPT_03)
              {
               F3();
               return;
              }
            //---
            if(buttons_scripts[j][i]==SCRIPT_04)
              {
               F4();
               return;
              }
            //---
            if(buttons_scripts[j][i]==SCRIPT_05)
              {
               F5();
               return;
              }
           }
        }
     }
  }

...e colocar essa função nessa parte do código:

//--- Rastreamento de cliques do botão esquerdo do mouse em um objeto gráfico
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Se você clicar no botão
      if(InitializeButtonStates(sparam))
        {
         //--- Definir as cores dos botões
         ChangeButtonColorOnClick();
         //--- Executar o script
         ScriptOn();
        }
      //--- Atualizar o gráfico
      ChartRedraw();
      return;
     }

E então você pode pensar em como otimizar o código, se necessário. :)

 
tol64:

É assim que eu faço.

O programa que tem o rastreamento ativado na inicialização o desativa ao descarregar. E o programa que permanece no gráfico e precisa de rastreamento verifica se ele está ativado e, se estiver desativado, ele o ativa.

É desejável dar sua variante nos exemplos de Expert Advisor e código de indicador da minha postagem na página anterior para excluir a ambiguidade das declarações.

Não há necessidade de verificar constantemente se alguém desativou o rastreamento de eventos do mouse. Para ser mais preciso, se quiser se proteger de qualquer situação, você pode verificar, mas acho que isso é demais.

Talvez devêssemos sugerir aos desenvolvedores que gerem CHARTEVENT_CHART_CHANGE quando CHART_EVENT_MOUSE_MOVE for alterado? Assim, seria possível restaurar com elegância a configuração necessária quando o Expert Advisor estiver em execução.

Até o momento, tenho essa variante:

#property copyright "Copyright 2013, komposter"
#property link      "http://www.komposter.me/"
#property version   "1.00"
#property indicator_chart_window

input   bool    EnableMouseDetect = false; // verdadeiro - funciona com o rastreamento do mouse, falso - sem ele

bool PrevState = false;

//+------------------------------------------------------------------+
//| Função de inicialização do indicador personalizado
//+------------------------------------------------------------------+
int OnInit()
{
        if ( EnableMouseDetect )
        {
                //--- Obter o estado atual
                PrevState = (bool)ChartGetInteger(0,CHART_EVENT_MOUSE_MOVE);
                //--- Ativar o rastreamento de eventos do mouse
                if ( PrevState == false ) ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
        }

        return(0);
}

//+------------------------------------------------------------------+
//| Função de desinicialização do especialista
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        if ( EnableMouseDetect )
        {
                //--- Desativar o rastreamento de eventos do mouse
                if ( PrevState == false )
                {
                        ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,false);
                        ChartRedraw(); // Sem essa linha, o rastreamento é desativado somente quando um tique chega. É assim que ele foi projetado?
                }
        }
}

//+------------------------------------------------------------------+
//| OnTick|
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                     const int prev_calculated,
                     const datetime& time[],
                     const double& open[],
                     const double& high[],
                     const double& low[],
                     const double& close[],
                     const long& tick_volume[],
                     const long& volume[],
                     const int& spread[])
       {
        
        return(rates_total);
       }
//+------------------------------------------------------------------+
//| Função ChartEvent|
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Rastreamento do movimento do mouse e pressionamento do botão esquerdo do mouse
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      static int count=1;
      Print("CHARTEVENT_MOUSE_MOVE; EXPERT; ",count);
      count++;
     }
  }
//+------------------------------------------------------------------+

Criei um indicador, mas com um parâmetro: executar com EnableMouseDetect = true - controla o rastreamento, false - apenas imprime o número de eventos, se o rastreamento estiver ativado.


------------------
Agora pensei um pouco mais e tenho que concordar: essa opção não funcionará. Se você executar primeiro um programa que rastreia o mouse (ele ativará o rastreamento), depois o segundo (ele verá o que já está ativado) e, em seguida, excluir o primeiro, ele desativará o rastreamento e o segundo ficará sem nada. Ou seja, precisamos criar algum tipo de semáforo para sinalizar que o rastreamento é necessário.

E, à luz da pesquisa realizada aqui (sobre a carga no processador), essas muletas não são necessárias.

Portanto, proponho que minha proposta seja votada pelos desenvolvedores, e o tópico pode ser encerrado.

 
ChartRedraw(); // Sem essa linha, o rastreamento é desativado somente quando um tique chega. É assim que ele foi projetado?
O MT5 tem atualização assíncrona das propriedades do gráfico. Ou seja, o fato de definirmos uma propriedade não significa que o terminal a tenha captado imediatamente. A função ChartRedraw() é usada para que todas as propriedades sejam lidas novamente pelo terminal. Você também pode usar a função ChartGet... ObjectGet; nesse caso, as propriedades também serão lidas novamente.
Документация по MQL5: Операции с графиками / ChartRedraw
Документация по MQL5: Операции с графиками / ChartRedraw
  • www.mql5.com
Операции с графиками / ChartRedraw - Документация по MQL5