Galerie d'interfaces utilisateur écrites en MQL - page 69

 
Maxim Kuznetsov projet?

Il y a un dépôt de quelque chose (que l'on peut difficilement qualifier de code source ) et de la documentation .

Pourquoi le cherches-tu, le cherches-tu, et tu ne le trouves pas)). Le projet se trouve sur les pages de la branche, avec les instructions d'installation. Je ne vous donnerai pas la page exacte, faites défiler vers l'arrière.

La prochaine version sera publiée dans kodobase. Si vous voulez, vous pouvez attendre un peu.
 

Ajout de la possibilité de modifier par programme la couleur des cadres des éléments et de les associer aux valeurs des paramètres. Il s'agit d'un indicateur informatif et utile qui permet de se rendre compte rapidement du niveau de risque des valeurs saisies. Il s'est avéré pratique et clair. En outre, en cas de dépassement des limites fixées, des fenêtres d'avertissement apparaissent.

Quelques exemples :


Demain, nous irons plus loin avec des exemples et du code.

 
Commençons par une nouvelle page.
 

Avant d'aborder la question de la mise en œuvre de la protection échelonnée des limites des paramètres et des avertissements à l'intention des utilisateurs, il convient d'évoquer un autre sujet qui la précède directement. Il s'agit de la présélection des paramètres.

Je commencerai par ce qui est bien connu : la plupart des programmes MQL ont des variables de la catégorie input. Elles sont déclarées au niveau global et sont visibles dans une seule fenêtre de paramétrage. Cette fenêtre apparaît au début du programme et l'utilisateur peut y modifier les valeurs initiales des variables "externes", si le besoin s'en fait sentir. Mais avant cela, l'utilisateur initialise les variables externes à l'intérieur du programme. Le fait est que les préréglages du programme ne sont pas universels, et c'est pourquoi il existe une catégorie de variables qui nécessitent la possibilité d'être paramétrées à chaque démarrage. On sait également que toute tentative d'accès manuel aux variables externes pendant l'exécution du programme est impossible et nécessite un redémarrage. Avec une interface graphique, cette nécessité est éliminée. Les paramètres du programme peuvent être ouverts au moment de l'exécution.

Cependant, il est toujours nécessaire de définir des valeurs initiales pour les paramètres du programme au début.

Si nous disposons d'une interface graphique , il est inutile de déclarer des variables de type entrée, car nous n'avons plus besoin de la fenêtre de paramétrage standard , mais l'essentiel reste le même : à la place des variables d'entrée, nous devons définir des valeurs initiales pour les paramètres des commandes.

Lors de l'initialisation du programme, nous devons appeler une fonction qui définit les valeurs initiales de nos propres fenêtres, et non de la fenêtre standard. En option, cela peut être fait dans le constructeur de KIB, au stade de la construction de l'interface, lorsque les valeurs V_CURRENT sont définies, ou les états ON/OFF, etc. Il est désormais possible de combiner l'initialisation des éléments dans le constructeur et dans le programme.

Par conséquent, nous avons besoin d'une fonction spéciale appelée OnInit() pour effectuer ce travail.

Ce que cette fonction fera exactement :

  • Ouvrir les fenêtres nécessaires au début du programme.
  • Définir des valeurs dans les contrôles cibles.

Quel sera le nom de cette fonction ?

Je l'appellerais Initialize(), mais chacun peut trouver sa propre variante.

L'essentiel est que cette fonction doit se trouver dans n'importe quelle interface Expert Advisor. Elle peut être comparée à la fonction OnTick() d'un Expert Advisor ou OnCalculate() d'un indicateur. Il est important de comprendre ceci.


Quelle valeur la fonction renverra-t-elle ?

La fonction est de type void. Il n'est pas nécessaire de renvoyer une valeur. Lorsqu'elle est appelée, elle ouvre les fenêtres nécessaires, initialise les paramètres des éléments et prédéfinit éventuellement certaines propriétés. C'est à peu près tout. Théoriquement, on peut y définir les limites initiales des paramètres, mais je pense que le contrôle des valeurs sera implémenté dans une fonction séparée appelée sur les événements d'éléments provenant du fichier API et de la minuterie. Je vais probablement écrire une impression des appels de contrôle dans la prochaine version.

*Il est important deprendre en compte le fait qu'à l'heure actuelle, le concept d'interface Expert Advisors n'en est qu'à ses débuts et que de nombreuses découvertes nous attendent.


Voici un exemple de la fonction d'initialisation d'une interface Expert Advisor dans le contexte du projet de démonstration actuel :

1. Appel de la fonction :

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


2. mise en œuvre de la fonction :

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");
  //------------------------------------------------
}


Jusqu'à présent, je vois la structure de la fonction comme suit. Une fonction très simple. Elle ouvre des fenêtres et envoie les valeurs requises aux paramètres des éléments. Il est possible de modifier l'initialisation des éléments et l'ouverture des fenêtres à certains endroits, car l'ouverture des fenêtres affichera immédiatement les valeurs requises des éléments sans redessin supplémentaire. Il s'agit toutefois de choses mineures.


Passons maintenant au sujet principal : la mise en œuvre de la protection des paramètres étape par étape.

 

14.réalisation de la protection par étapes des limites des paramètres :

  • 1. Écriture de la logique de contrôle des paramètres dans les limites prédéfinies et création d'un système d'alerte.
  • 2. Premier avertissement: l'utilisateur reçoit un signal sous la forme d'un changement de couleur de certaines parties des éléments responsables des réglages.( Lions la couleur du texte, des bases, des cadres et de la barre dedéfilement aux limites des valeurs).
  • 3. Deuxième avertissement: ouverture d'une boîte de dialogue contenant un avis de risque et une suggestion de retour aux paramètres d'origine.(Testons la possibilité réelle de revenir aux paramètres précédents en cliquant sur le bouton "Annuler").
  • 4. troisième avertissement : ouverture d'une fenêtre d'avertissement bloquant toute modification ultérieure des paramètres et exigeant une confirmation manuelle de la part de l'utilisateur.(Vérifions le blocage des fenêtres et des éléments lorsque la fenêtre d'avertissement apparaît).

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

Écriture de la logique de contrôle des paramètres dans les limites prédéfinies et création d'un système d'avertissement :

  • La première partie de la mise en œuvre consiste à définir les valeurs initiales des paramètres des éléments sélectionnés et à ouvrir les fenêtres requises. Pour ce faire, nous écrirons la fonction Initialise() et placerons son appel dans la fonction _OnInit().
  • La deuxième partie de la mise en œuvre - ouvrons le fichier API et écrivons la connexion des éléments. Dans le cas de chaque élément de la chaîne commune, nous écrirons des appels et transmettrons la valeur aux autres éléments cibles. Par exemple : lors de l'événement du champ avec boutons, nous appelons le curseur horizontal et lui transmettons la valeur. Ensuite, lorsque l'événement survient dans le cas du curseur, nous le transmettons à nouveau au champ avec les boutons et, en plus, au curseur vertical. Ce dernier, à son tour, transmet la valeur aux champs de saisie proches de lui et à la fenêtre de la barre de progression.... Au total, la chaîne comporte sept éléments principaux qui transmettent la valeur dans plusieurs directions. Les voici : "Paramètres exemple 1" avec les éléments"Faire tourner la valeur" et"Faire rouler la valeur","Paramètres principaux" avec les éléments"V_SLIDER", champ"Sélectionné" et"Pourcentage", et"Traitement des données..." avec les éléments VALUE et P_BAR .
  • Troisième partie : tester la connexion.
  • Quatrième partie : écrivons une fonction de contrôle des paramètres avec un nom conditionnel : void Risk_management_group_1(). Sa tâche consiste à signaler à l'utilisateur qu'il s'approche des limites des valeurs dangereuses au sein de ce groupe d'éléments, et à l'avertir en cas de dépassement des limites autorisées. La fonction acceptera des valeurs provenant d'éléments connexes et les fera passer par les filtres définis dans les conditions. Nous mettrons en œuvre l'avertissement en modifiant les niveaux de risque appropriés du texte et de la couleur du cadre et nous l'enverrons à tous les éléments de la chaîne. Parallèlement, nous appellerons des fenêtres de blocage qui ne permettront pas à l'utilisateur de poursuivre l'action sans confirmation supplémentaire.
  • Cinquième partie : testons le fonctionnement de la fonction.

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

Procédons de la sorte :

1) Définir les valeurs initiales des paramètres des éléments sélectionnés et ouvrir les fenêtres nécessaires. Pour ce faire, écrivons la fonctionInitialise() et appelons-la dans la fonction _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");
  //------------------------------------------------
}

Résultat : les fenêtres nécessaires sont ouvertes et les valeurs initiales sont définies pour les éléments cibles.


2) Ouvrir le fichier API et écrire la connexion des éléments. Dans le cas de chaque élément, écrire les appels et transmettre la valeur aux autres éléments cibles de la chaîne:

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. Testez la connexion :

Résultat : les valeurs des éléments sont connectées comme prévu.



4. Écrire une fonction pour contrôler les paramètres de notre groupe d'éléments : 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;                
 //-----------------------------------------------------                 
}

Appeler la fonction Risk_management_group_1() à partir de la fonction _OnInit() :

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

Résultat : fonctionne comme prévu, mais lors de la saisie d'une valeur dans le champ de saisie, la fenêtre d'avertissement ne réinitialise pas la valeur saisie lorsqu'elle apparaît(nécessite une amélioration).

(*En outre, le réglage de la couleur du cadre a été ajouté dans la mise à jour, mais n'existe pas dans la version actuelle).


 

La tâche suivante consiste à envisager d'annuler les paramètres saisis en appuyant sur le bouton "Annuler".

Il s'agit d'une tâche très difficile, mais je l'ai déjà partiellement mise en œuvre. J'essaierai de rétablir la fonctionnalité précédente.

 
En plus de l'indication des couleurs, je suis en train de mettre en place le clignotement des cadres, des textes et des bases. Je pense que ce sera prêt demain. Ensuite, l'annulation des valeurs saisies à l'aide du bouton Annuler.

Le problème est que lorsque l'on entre des valeurs dans des éléments, elles sont immédiatement reçues par le noyau et transmises au fichier API, ce qui entraîne logiquement le traitement d'un code personnalisé. Il est nécessaire de retarder l'acceptation des valeurs dans les fenêtres avec des boutons de confirmation avant qu'elles n'arrivent dans les paramètres et de la lier au fait de cliquer sur "Ok" ou "Confirmer" (ou "Appliquer").

Mais il est également nécessaire de renvoyer aux éléments les valeurs précédentes avant les changements, si l'utilisateur clique sur le bouton d'annulation (Cancel).

Il s'agit là d'un problème très intéressant, dont la solution porte immédiatement l'utilité pratique de l'interface à un niveau supérieur. Heureusement, pour l'essentiel, l'objectif a été atteint depuis longtemps. C'est incroyable de voir combien de choses intéressantes ont déjà été implémentées il y a 4 ans.

Je pense que je vais accomplir cette tâche en une semaine et ensuite, je vais m'occuper sérieusement des tableaux.
 

Dans la dernière analyse, j'ai montré comment appliquer l'indication de couleur du risque et ouvrir des fenêtres de blocage lors du franchissement des limites des paramètres fixés. Cependant, deux problèmes auxquels je ne m'attendais pas ont été découverts.

1. La fonction de gestion des risques ouvre la première fenêtre d'avertissement lorsqu'un niveau dangereux est franchi, mais si vous maintenez le curseur enfoncé sur l'élément à ce moment-là, la valeur continue d'augmenter et atteint le niveau conditionnel suivant. - Critique.

2. Lorsque la valeur critique est franchie, la dernière fenêtre d'avertissement s'ouvre, mais elle n'empêche pas non plus la valeur de changer si l'utilisateur continue à maintenir le bouton gauche de la souris enfoncé.

3) Si l'utilisateur relâche le bouton de la souris et veut fermer les fenêtres d'avertissement, il ne peut pas le faire. Pour être plus précis, il ne le peut pas. La raison en est que les deux fenêtres de blocage commencent à se bloquer l'une l'autre. Lorsqu'une des fenêtres de blocage est ouverte, elle se ferme facilement, mais lorsque deux fenêtres sont ouvertes en même temps, rien d'autre dans l'interface ne peut fonctionner. Le programme devient statique, bien qu'il continue à fonctionner.

L'image ci-dessous montre comment cela s'est produit :

 

J'ai ensuite corrigé les problèmes de verrouillage mutuel des fenêtres de paramétrage et maintenant les fenêtres n'interfèrent pas l'une avec l'autre. Elles exécutent ensemble la fonction de verrouillage sans entrer en conflit l'une avec l'autre.


Je dois maintenant faire en sorte que la fenêtre d'avertissement interrompe automatiquement les modifications de la valeur du paramètre, même si le bouton gauche de la souris est enfoncé et que l'élément est actif.