Discusión sobre el artículo "Guía práctica de MQL5: Controles de la subventana del indicador: Botones" - página 7

 
TheXpert:
¿Está tan seguro de que su artículo es perfecto?

Me complace mucho que lo haya leído.

Estaré encantado de responder a todas las preguntas en el hilo correspondiente.

===

Para que no haya malentendidos innecesarios, ¡no tengo nada en contra de Anatoly! Le felicito por el artículo. Pero es necesario responder a las preguntas...

 
DC2008:

Perdona, ¿te estoy distrayendo por casualidad de escribir otro tutorial o receta?

Si no es así, vamos a seguir discutiendo su artículo sobre el control en la subventana del indicador. Por lo tanto, usted ofrece una solución masiva (o una idea) cómo hacer un menú conveniente en un indicador. Bien, ¡el propósito del artículo es muy digno! Pero, ¿cómo puede un programador "principiante" utilizar todo este arsenal? ¿Dónde colocar las funciones personalizadas? Demuéstrelo con un ejemplo. Y al mismo tiempo explicar lo que hay que arreglar en el código para utilizar, por ejemplo, 5 botones? Considéralo una pregunta de principiante.

No, no lo es. Todavía no estoy escribiendo nada. Tengo que descansar al menos un día al año. Descansar no es interesante, y menos durante mucho tiempo. )

No es una decisión masiva y no he escrito sobre ello. No atribuyamos algo que no ha sucedido. Ya se dijo al principio de la discusión que no es una solución universal, sino un caso especial. En mi opinión, es un buen ejemplo para que un principiante practique. Y no para obtener una solución prefabricada de forma gratuita y correr, con la boca abierta en una amplia sonrisa, al encuentro del sol. ) ¿Comprende? Me gustaría un ejemplo tan simple y claro en el comienzo del aprendizaje de la programación. Especialmente cuando este es el primer lenguaje de programación en su vida y antes de que la actividad de toda su vida estaba en un campo completamente diferente, de ninguna manera conectado con ella.

Con el fin de hacer 5 botones, en este caso, tenemos que cambiar el tamaño de las matrices y excluir elementos innecesarios al declarar matrices para los nombres de los objetos-botones, el texto que aparece en los botones y los estados de los botones.

Hay una matriz de estados de botón, por lo que el mismo principio se puede utilizar para comprobar qué botón está pulsado y en lugar de simplemente cambiar el color del botón, realizar alguna otra acción (requerida por el usuario). Esto puede ser, por ejemplo, funciones de trading (y no sólo): borrar todas las órdenes pendientes, cerrar todas las posiciones, etc. Las ideas son infinitas. Y si no hay ideas, entonces usted ha elegido el tipo equivocado de actividad. )

Para implementar esto, necesitas crear otro array, que será inicializado con identificadores de una enumeración personalizada (que también necesita ser creada), por ejemplo, con el nombre ENUM_SCRIPT. Y luego se llamará a los identificadores, por ejemplo: SCRIPT_01 =0, SCRIPT_02 =2, etc. También en el bucle, al comprobar si el botón del panel está pulsado, tendrás que determinar qué identificador está ligado al botón pulsado y el estado actual del botón, y luego pasar la función correspondiente al programa para su ejecución.

No voy a mostrar un código de ejemplo a propósito. Que sea una tarea para principiantes. )

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

Hice los cambios como me dijiste:

//--- Texto mostrado en los botones
string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"Button 01","Button 02","Button 03","Button 04"},
     {"Button 05"}
  };
//--- Nombres 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}
  };

Y esto es lo que tengo en la pantalla:

¿Cómo lo arreglo? (soy principiante)

 
DC2008:

Hice los cambios como me dijiste:

Y esto es lo que tengo en la pantalla:

¿Cómo lo arreglo? (soy principiante)

Así

#define  BUTTON_COLUMNS 5 // Número de botones por anchura
#define  BUTTON_ROWS    1 // Número de botones por altura
...
//--- Texto mostrado en los botones
string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"Button 01","Button 02","Button 03","Button 04","Button 05"}
  };
//--- Nombres de objetos
string button_object_names[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"button_01","button_02","button_03","button_04","button_05"}
  };
...
//--- Estados de los botones
bool button_states[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {true,false,false,false,false}
  };
 

¡Genial! Funciona.

Pero no entiendo cómo conectar mis funciones a los botones. Muéstrame un ejemplo.

 
DC2008:

¡Genial! Funciona.

Pero no entiendo cómo conectar mis funciones a los botones. Muéstrame un ejemplo.

Bueno, continuemos el juego de "principiante" iniciado por ti. )

¿En qué punto estás atascado? Muestre un intento de cómo se entiende en el punto actual. Crea una enumeración con cinco identificadores y un array a cuyos elementos haya que asignar esos 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);}

¿Qué hacemos ahora?

 
DC2008:

¿Qué hacemos ahora?

Este es el tipo de array que necesitas:

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

Entonces necesitas escribir una función como esta:

//+------------------------------------------------------------------+
//|| Ejecutando scripts ||
//+------------------------------------------------------------------+
void ScriptOn()
  {
   for(int i=0; i<NUMBER_BUTTONS_WIDTH; i++)
     {
      for(int j=0; j<NUMBER_BUTTONS_HEIGHT; j++)
        {
         //--- Si se pulsa este botón, ejecutaremos el script correspondiente
         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;
              }
           }
        }
     }
  }

...y colocar esta función en esta parte del código:

//--- Seguimiento de los clics del botón izquierdo del ratón en un objeto gráfico
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Si hace clic en el botón
      if(InitializeButtonStates(sparam))
        {
         //--- Establecer los colores para los botones
         ChangeButtonColorOnClick();
         //--- Ejecutar el script
         ScriptOn();
        }
      //--- Actualizar el gráfico
      ChartRedraw();
      return;
     }

Y luego puedes pensar en cómo optimizar el código, si lo necesitas. :)

 
tol64:

Así es como yo lo tengo hecho.

El programa que tiene activado el seguimiento al arrancar lo desactiva al descargar. Y el programa que permanece en el gráfico y necesita seguimiento, comprueba si está activado, y si está desactivado, lo activa.

Es deseable dar su variante en los ejemplos de Asesor Experto y el código del indicador de mi post en la página anterior para excluir la ambigüedad de las declaraciones.

No hay necesidad de comprobar constantemente si alguien ha desactivado el seguimiento de eventos del ratón. Para ser más precisos, si quieres protegerte de cualquier situación, puedes comprobarlo, pero creo que es demasiado.

¿Quizás deberíamos sugerir a los desarrolladores que generen CHARTEVENT_CHART_CHANGE cuando CHART_EVENT_MOUSE_MOVE cambie? Entonces sería posible restaurar elegantemente la configuración necesaria cuando el Asesor Experto se está ejecutando.

Hasta ahora, tengo esta variante:

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

input   bool    EnableMouseDetect = false; // true - funciona con seguimiento del ratón, false - sin él

bool PrevState = false;

//+------------------------------------------------------------------+
//| Función de inicialización del indicador personalizada |
//+------------------------------------------------------------------+
int OnInit()
{
        if ( EnableMouseDetect )
        {
                //--- Obtener el estado actual
                PrevState = (bool)ChartGetInteger(0,CHART_EVENT_MOUSE_MOVE);
                //--- Activar el seguimiento de eventos del ratón
                if ( PrevState == false ) ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
        }

        return(0);
}

//+------------------------------------------------------------------+
//| Función de desinicialización del experto ||
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        if ( EnableMouseDetect )
        {
                //--- Desactivar el seguimiento de eventos del ratón
                if ( PrevState == false )
                {
                        ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,false);
                        ChartRedraw(); // Sin esta línea, el seguimiento se desactiva sólo cuando llega un tick. ¿Es así como está diseñado?
                }
        }
}

//+------------------------------------------------------------------+
//| 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);
       }
//+------------------------------------------------------------------+
//| Función ChartEvent|
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Seguimiento del movimiento del ratón y de la pulsación del botón izquierdo del ratón
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      static int count=1;
      Print("CHARTEVENT_MOUSE_MOVE; EXPERT; ",count);
      count++;
     }
  }
//+------------------------------------------------------------------+

Hice un indicador, pero con un parámetro: ejecutar con EnableMouseDetect = true - controla el seguimiento, false - sólo imprime el número de eventos, si el seguimiento está habilitado.


------------------
Ahora lo he pensado un poco más, y tengo que estar de acuerdo - esta opción no funcionará. Si ejecutas primero un programa que rastrea el ratón (habilitará el rastreo), luego el segundo (verá lo que ya está habilitado), y luego eliminas el primero, deshabilitará el rastreo, y el segundo se quedará sin nada. Es decir, tenemos que idear algún tipo de semáforo para señalar que el rastreo es necesario.

Y a la luz de la investigación realizada aquí (sobre la carga en el procesador) en tales muletas no es necesario.

Así que propongo votar mi propuesta a los desarrolladores, y el tema puede ser cerrado.

 
ChartRedraw(); // Sin esta línea, el seguimiento se desactiva sólo cuando llega un tick. ¿Es así como está diseñado?
MT5 tiene actualización asíncrona de las propiedades del gráfico. Es decir, el hecho de que establezcamos una propiedad no significa que el terminal la recoja inmediatamente. La función ChartRedraw() se utiliza para que todas las propiedades sean releídas por el terminal. También se puede utilizar la función ChartGet... ObjectGet, en este caso las propiedades también serán releídas.
Документация по MQL5: Операции с графиками / ChartRedraw
Документация по MQL5: Операции с графиками / ChartRedraw
  • www.mql5.com
Операции с графиками / ChartRedraw - Документация по MQL5