Galería de interfaces de usuario escritas en MQL - página 69

 

Se ha añadido la posibilidad de cambiar mediante programación el color de los marcos de los elementos y asociarlos a los valores de los parámetros. Se trata de un indicador informativo y útil que ayuda a darse cuenta rápidamente del nivel de riesgo de los valores introducidos. Resultó práctico y claro. Además, en caso de sobrepasar los límites fijados, aparecen ventanas de advertencia.

Algunos ejemplos:


Mañana lo veremos con ejemplos y código.

 
Empecemos en una nueva página.
 

Antes de continuar con el tema de la implementación de la protección escalonada de los límites de los parámetros y las advertencias al usuario, debemos mencionar otro tema que le precede directamente. A saber, el preajuste de parámetros.

Empezaré por lo conocido: la mayoría de los programas MQL tienen variables de la categoría de entrada. Se declaran a nivel global y son visibles en una única ventana de configuración. La ventana aparece al inicio del programa y dentro de ella el usuario puede cambiar los valores iniciales de las variables "externas", si surge tal necesidad. Pero antes, el usuario inicializa las variables externas dentro del programa. La cuestión es que los preajustes del programa no son universales, y por eso hay una categoría de variables que requieren la posibilidad de ajuste en cada inicio. También se sabe que cualquier intento de acceder manualmente a las variables externas durante la ejecución del programa es imposible y requiere un reinicio. Con una interfaz gráfica, se elimina esta necesidad. Los ajustes del programa pueden abrirse en tiempo de ejecución.

Sin embargo, sigue existiendo la misma necesidad de establecer los valores iniciales de los parámetros del programa al inicio.

Si tenemos una interfaz gráfica , no tiene sentido declarar variables del tipo de entrada, porque ya no necesitamos la ventana de ajustes estándar , pero la esencia sigue siendo la misma. En lugar de variables deentrada, debemos establecer valores iniciales a los parámetros de los controles.

En la inicialización del programa debemos llamar a alguna función que establezca valores iniciales a nuestras propias ventanas, no a la ventana estándar. Como opción, esto se puede hacer en el KIB-constructor, en la etapa de construcción de la interfaz, cuando se establecen los valores V_CURRENT, o los estados ON/OFF, etc., pero ahora es posible inicializar los elementos mediante programación. Ahora es posible combinar la inicialización de elementos en el constructor y en el programa.

Por lo tanto, necesitamos una función especial llamada desde OnInit() para hacer este trabajo.

Que hará exactamente esta función:

  • Abrir las ventanas necesarias al inicio del programa.
  • Establecer valores en los controles de destino.

¿Cómo se llamará la función?

Yo la llamaría Initialize(), pero cualquiera puede inventar su propia variante.

Loprincipal es que esta función debe estar en cualquier interfaz Expert Advisor. Se puede comparar con la función OnTick() de un Asesor Experto o OnCalculate() de un indicador. Es importante entender esto.


¿Qué valor devolverá la función?

La función será de tipo void. No hay necesidad de devolver un valor. Cuando es llamada, abrirá las ventanas necesarias, inicializará los parámetros de los elementos, y posiblemente preestablecerá algunas propiedades. Eso es básicamente todo. Teóricamente, se pueden establecer límites de parámetros iniciales en ella, pero creo que el control de valores se implementará en una función separada llamada en eventos de elementos desde el archivo API y desde el temporizador. Probablemente escribiré una impresión de las llamadas de control en la próxima versión.

*Es importantetener en cuenta que en estos momentos el concepto de interfaz Expert Advisors se está formando y nos esperan muchos descubrimientos.


He aquí un ejemplo de la función de inicialización de un Asesor Experto de interfaz en el contexto del actual proyecto de demostración:

1. 1. Llamada a la función:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int _OnInit()
  {
   //------------------------------------------------
   //Initializing program interface:
   //------------------------------------------------
   Initialize();
   //------------------------------------------------


2. Implementación de la función:

void Initialize()   
{
   //------------------------------------------------
   //Opening the windows:
   //------------------------------------------------
   //1. "Main Parameters". 

    w_14_Main_Parameters();
   //------------------------------------------------

   //------------------------------------------------
   //2. "Input parameters".

   w_10_Input_parameters();
   //------------------------------------------------

   //------------------------------------------------
   //3. "Setting example 1"

   w_6_Settings_example_1();
   //------------------------------------------------


  //------------------------------------------------
  //Initializing the elements:
  //------------------------------------------------
  
   w6_d_p5_S_EDIT_Spin_the_value(55);

   w6_i_p3_H_SLIDER_Roll_the_value(55);

   w14_i_p3_V_SLIDER_Vertical_slider(55);

   w14_s_p4_EDIT_Max("100");

   w14_s_p4_EDIT_Min("0");

   w14_s_p4_EDIT_Selected("55");

   w15_i_p2_P_BAR_P1(55);

   w15_s_p4_VALUE_V1("55");
  //------------------------------------------------
}


Hasta ahora, veo la estructura de la función de la siguiente manera. Una función muy simple. Abre ventanas y envía los valores requeridos a los parámetros de los elementos. Es posible cambiar la inicialización de los elementos y la apertura de las ventanas en algunos lugares, porque la apertura de las ventanas mostrará inmediatamente los valores requeridos de los elementos sin redibujado adicional. Sin embargo, estas son cosas menores.


Entonces pasemos al tema principal: la implementación de la protección paso a paso de los parámetros.

 

14.realización de la protección escalonada de los límites de los parámetros:

  • 1. Escritura de la lógica de control de los ajustes en los límites preestablecidos y creación de un sistema de alerta.
  • 2. Elprimer aviso: el usuario recibe una señal en forma de cambio de color de partes de los elementos responsables de los ajustes.( Vinculemos el color del texto, las bases, los marcos y la barradeslizante a los límites de los valores).
  • 3. Segundo aviso: apertura de un cuadro de diálogo con una notificación de riesgo y una sugerencia de volver a los ajustes originales.(Probemos la posibilidad real de volver a la configuración anterior al pulsar el botón "Cancelar").
  • 4. tercera advertencia: apertura de una ventana de advertencia que bloquea el cambio posterior de la configuración y requiere la confirmación manual del usuario.(Comprobemos el bloqueo de ventanas y elementos cuando aparece la ventana de advertencia).

//------------------------------------------------------------------------------------------------------------

Escribiendo la lógica de control de los ajustes dentro de los límites preestablecidos, y creando un sistema de avisos:

  • La primera parte de la implementación es establecer los valores iniciales de los parámetros de los elementos seleccionados y abrir las ventanas requeridas. Para ello, escribiremos la función Initialise() y pondremos su llamada en la función _OnInit().
  • La segunda parte de la implementación - vamos a abrir el archivo API y escribir la conexión de los elementos. En el caso de cada elemento de la cadena común, vamos a escribir las llamadas y pasar el valor a los otros elementos de destino. Por ejemplo: en el evento del campo con botones llamamos al deslizador horizontal y le pasamos el valor. Luego, cuando el evento llega al caso del deslizador, lo pasamos de nuevo al campo con botones, y adicionalmente al deslizador vertical. Este último, a su vez, pasa el valor a los campos de entrada cercanos a él y a la ventana de la barra de progreso .... En total, habrá siete elementos principales en la cadena que pasan el valor en varias direcciones. Aquí están:"Ajustes ejemplo 1" con los elementos"Girar el valor" y"Girar el valor","Parámetros principales" con los elementos"V_SLIDER", campo"Seleccionado" y"Porcentaje", y"Procesando los datos..." con los elementos VALOR y P_BAR .
  • Tercera parte: Probemos la conexión.
  • Cuarta parte: Escribamos una función de control de parámetros con un nombre condicional: void Gestión_riesgo_grupo_1(). Su tarea es avisar al usuario cuando se acerque a los límites de valores peligrosos dentro de este grupo de elementos, y avisar cuando se sobrepasen los límites permitidos. La función aceptará valores de elementos relacionados y los pasará a través de los filtros establecidos dentro de las condiciones. Implementaremos la advertencia a través de niveles de riesgo apropiados de texto y cambios de color del marco y la enviaremos a todos los elementos de la cadena. Paralelamente, llamaremos a ventanas de bloqueo que no permitan al usuario continuar la acción sin confirmación adicional.
  • Quinta parte: probemos el funcionamiento de la función.

//-----------------------------------------------------------------------------

Procedamos:

1. Establezcamos los valores iniciales de los parámetros de los elementos seleccionados y abramos las ventanas necesarias. Para ello, escribamos la funciónInitialise() y llamémosla en la función _OnInit().

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int _OnInit()
  {
   //------------------------------------------------
   //Initializing program interface:
   //------------------------------------------------
   Initialize();
   //------------------------------------------------
void Initialize()   
{
   //------------------------------------------------
   //Opening the windows:
   //------------------------------------------------
   //1. "Main Parameters". 
    w_14_Main_Parameters();

   //2. "Input parameters".
   w_10_Input_parameters();

   //3. "Setting example 1"
   w_6_Settings_example_1();

   //------------------------------------------------
  //Initializing the elements:
  //------------------------------------------------
   w6_d_p5_S_EDIT_Spin_the_value(55);
   w6_i_p3_H_SLIDER_Roll_the_value(55);
   w14_i_p3_V_SLIDER_Vertical_slider(55);
   w14_s_p4_EDIT_Max("100");
   w14_s_p4_EDIT_Min("0");
   w14_s_p4_EDIT_Selected("55");
   w15_i_p2_P_BAR_P1(55);
   w15_s_p4_VALUE_V1("55");
  //------------------------------------------------
}

Resultado: Se abren las ventanas necesarias y se establecen los valores iniciales de los elementos de destino.


2. Abrir el archivo API y escribir la conexión de los elementos. En el caso de cada elemento, escribir las llamadas y pasar el valor a los otros elementos de destino en la cadena:

case Settings_example_1___Spin_the_value:
  
               //------------------------------------------------------------------------------------------------------
               //What to do when the value is set?
               //------------------------------------------------------------------------------------------------------
               //Min value:  NOT SET  |   Max value:  NOT SET  |   V_step:  1.7  |   Default value:  468.99  |  Digits: 3
               //------------------------------------------------------------------------------------------------------
               w6_i_p3_H_SLIDER_Roll_the_value((int)value);

               //------------------------------------------------------------------------------------------------------
               //Your comment:
               //------------------------------------------------------------------------------------------------------
               break;
case Settings_example_1___Roll_the_value:
  
               //------------------------------------------------------------------------------------------------------
               //What to do when the slider's handle is moved?
               //------------------------------------------------------------------------------------------------------
               //Min value:  0  |   Max value:  100  |   V_step:  1  |   Default value:  55  |  Digits: Integer value
               //------------------------------------------------------------------------------------------------------
               //Transferring the value:
               w14_i_p3_V_SLIDER_Vertical_slider((int)value);

               w6_d_p5_S_EDIT_Spin_the_value((double)value);
               //------------------------------------------------------------------------------------------------------
               //Your comment:
               //------------------------------------------------------------------------------------------------------
               break;
case Main_Parameters___Vertical_slider:
  
               //------------------------------------------------------------------------------------------------------
               //What to do when the slider's handle is moved?
               //------------------------------------------------------------------------------------------------------
               //Min value:  0  |   Max value:  100  |   V_step:  1  |   Default value:  50  |  Digits: Integer value
               //------------------------------------------------------------------------------------------------------
               {
                //----------------------------------------------------- 
                //Transferring value to other destinations:
                //----------------------------------------------------- 
                w14_s_p4_EDIT_Percent(value);
                //-----------------------------------------------------
                w14_s_p4_EDIT_Selected(value);
                //-----------------------------------------------------
                w15_i_p2_P_BAR_P1((int)value);
                //-----------------------------------------------------
                w15_s_p4_VALUE_V1(value);
                //-----------------------------------------------------
                w6_i_p3_H_SLIDER_Roll_the_value((int)value);
                //-----------------------------------------------------
                w6_d_p5_S_EDIT_Spin_the_value((double)value);
                //-----------------------------------------------------
                w8_s_p4_CELL_Account_balance__Value(value);
                //------------------------------------------------------------------------------------------------------
                //Your comment:
                //------------------------------------------------------------------------------------------------------
               }
               break;


3. Pruebe la conexión:

Resultado: los valores de los elementos se conectan según lo previsto.



4. Escribir una función para controlar los parámetros de nuestro grupo de elementos: void Risk_management_group_1().

void Risk_management_group_1(string value)
{
 uint Color = 0;
 //--------------------
 static uint This_color;
 static bool User_warned, Last_warning;
 //------------------------------------------------------------
 //Setting limit colors:
 //------------------------------------------------------------
 if((int)value < 25)                      Color = clrLightGreen;
 //------------------------------------------------------------
 if((int)value >= 25 && (int)value < 50)  Color = clrLimeGreen;
 //------------------------------------------------------------
 if((int)value >= 50 && (int)value < 70)  Color = clrGreen;
 //------------------------------------------------------------
 if((int)value >= 70 && (int)value < 85)  Color = clrDarkGreen;
 //------------------------------------------------------------
 if((int)value >= 85 && (int)value < 90)  Color = clrBrown;
 //------------------------------------------------------------
 if((int)value >= 90 && (int)value < 95)  Color = C'170,0,0';
 //------------------------------------------------------------
 if((int)value >= 95 && (int)value <=100) Color = clrRed;
 //------------------------------------------------------------  

 //------------------------------------------------------------ 
 //Changing colors when the limits are passed:
 //------------------------------------------------------------
 if(This_color != Color)
   {
    w14_s_p4_EDIT_Percent((string)Color, p4_COLOR_base); 
    //-----------------------------------------------------
    w14_s_p4_EDIT_Selected((string)Color, p4_COLOR_base); 
    //-----------------------------------------------------
    w15_i_p2_P_BAR_P1(Color, p2_COLOR_bar);
    w15_i_p2_P_BAR_P1(Color, p2_COLOR_frame);
    w15_s_p4_VALUE_V1((string)Color, p4_COLOR_frame);
                   
    w8_s_p4_CELL_Account_balance__Value((string)Color, p4_COLOR_text);
    w8_s_p4_CELL_Account_balance__Value((string)Color, p4_COLOR_frame);
    //-----------------------------------------------------
    w14_i_p3_V_SLIDER_Vertical_slider(Color,p3_COLOR_bar);
    //-----------------------------------------------------
    w15_s_p4_VALUE_V1((string)Color, p4_COLOR_text);
    //-----------------------------------------------------
    w6_i_p3_H_SLIDER_Roll_the_value(Color,p3_COLOR_bar);
    //-----------------------------------------------------
    w6_d_p5_S_EDIT_Spin_the_value((double)Color, p5_COLOR_text);
    //-----------------------------------------------------
    w6_d_p5_S_EDIT_Spin_the_value((double)Color, p5_COLOR_frame);
    //-----------------------------------------------------
    w14_i_p1_BUTTON_BUY_OFF(Color, p1_N_COLOR_frame);
    w14_i_p1_BUTTON_BUY_OFF(Color, p1_A_COLOR_frame);
    //-----------------------------------------------------
    w14_i_p1_BUTTON_SELL_OFF(Color, p1_N_COLOR_frame);
    w14_i_p1_BUTTON_SELL_OFF(Color, p1_A_COLOR_frame);
    //-----------------------------------------------------
    w7_s_p4_EDIT_Comment_1(Color, p4_COLOR_frame);
    //-----------------------------------------------------
    This_color = Color;
    //-----------------------------------------------------
   }   
 //-----------------------------------------------------
 //Opening warning window 1:
 //-----------------------------------------------------
 if((int)value >= 85 && (int)value < 95 && !User_warned)
   { 
    //---------------------------------
    //Opening dialog window:
    //---------------------------------
    w_13_Risky_managment(); 
    //---------------------------------
    //Setting flag of warning 1:
    //---------------------------------
    User_warned = true;
    //---------------------------------
   }
 //-----------------------------------------------------
 if((int)value < 85)User_warned = false;
 //-----------------------------------------------------
 //Opening warning window 2:
 //-----------------------------------------------------
 if((int)value >= 96 && !Last_warning)
   { 
    //---------------------------------
    //Calling blocking window:
    //---------------------------------
    w_17_Last_warning();
    //---------------------------------
    //Setting flag of warning 2:
    //---------------------------------
    Last_warning = true;
    //---------------------------------
   }
 //-----------------------------------------------------
 if((int)value < 95)Last_warning = false;                
 //-----------------------------------------------------                 
}

5. Llame a la función Risk_management_group_1() desde la función _OnInit():

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int _OnInit()
  {
   //------------------------------------------------
   //Initializing program interface:
   //------------------------------------------------
   Initialize();
   //----------------------------------------------------------
   //Checking default value of the parameters in the group:  
   //----------------------------------------------------------
   Risk_management_group_1();
   //----------------------------------------------------------
 

Resultado: funciona según lo previsto, pero al introducir un valor en el campo de entrada, la ventana de advertencia no restablece el valor introducido cuando aparece(requiere mejoras).

(*También - el ajuste del color del marco se añadió en la actualización, pero falta en la versión actual).


 

La siguiente tarea es considerar la posibilidad de cancelar los parámetros introducidos pulsando el botón "Cancelar".

Esta es una tarea muy difícil, pero ya la he implementado parcialmente. Intentaré restaurar la funcionalidad anterior.

 
Además de la indicación de colores, ahora estoy implementando el parpadeo de marcos, textos y bases. Creo que estará listo mañana. A continuación, la cancelación de los valores introducidos con el botón Cancelar.

El problema es que al introducir valores en los elementos, el núcleo los recibe inmediatamente y los pasa al archivo API, lo que lógicamente provoca el procesamiento de código personalizado. Es necesario retrasar la aceptación de valores en ventanas con botones de confirmación antes de que lleguen a los parámetros y vincularlo a pulsar "Ok" o "Confirmar" (o "Aplicar").

Pero también, es necesario devolver a los elementos los valores anteriores a los cambios, si el usuario hace clic en el botón de cancelación (Cancelar).

Este es un problema muy interesante y su solución eleva inmediatamente la utilidad práctica de la interfaz a un nuevo nivel. Afortunadamente, en su mayor parte, el objetivo se alcanzó hace tiempo. Es increíble la cantidad de cosas interesantes que ya se implementaron hace 4 años.

Creo que realizaré la tarea en una semana y más adelante, me pondré en serio con las tablas.
 

En el último desglose mostré cómo aplicar la indicación de riesgo por colores y abrir ventanas de bloqueo al cruzar los límites de los parámetros establecidos. Sin embargo, se descubrieron dos problemas que no esperaba.

1. La función de gestión de riesgos abre la primera ventana de aviso cuando se cruza un nivel peligroso, pero si se mantiene pulsado el cursor sobre el elemento en ese momento, el valor sigue creciendo y alcanza el siguiente nivel condicional. - Crítico.

2. Cuando se cruza el valor crítico, se abre la última ventana de advertencia, pero tampoco impide que el valor cambie si el usuario sigue manteniendo pulsado el botón izquierdo del ratón.

3. Si el usuario suelta el botón del ratón y quiere cerrar las ventanas de aviso, no puede hacerlo. Para ser más precisos, no puede. La razón es que las dos ventanas de bloqueo empiezan a bloquearse mutuamente. Cuando una de las ventanas de bloqueo está abierta, se cierra fácilmente, pero cuando hay dos ventanas abiertas al mismo tiempo, nada más en la interfaz puede funcionar. El programa entra en estado de estupor, aunque sigue funcionando.

La imagen de abajo muestra cómo ocurrió esto:

 

Entonces, arreglé los problemas de bloqueo mutuo de las ventanas de configuración y ahora las ventanas no interfieren entre sí. Realizan la función de bloqueo conjuntamente sin entrar en conflicto unas con otras.


Ahora tengo que hacer que la ventana de advertencia detenga automáticamente los cambios en el valor del parámetro, incluso si se pulsa el botón izquierdo del ratón y el elemento está activo.

 
Hoy voy a publicar una continuación del tema de la indicación por colores de los valores de los parámetros - el parpadeo de los elementos. La tarea resultó ser un poco más complicada de lo que pensaba, así que la retrasé. Al final, la solución justificó el tiempo empleado. En mi opinión, en todo caso.