Discussion de l'article "Le MQL5 Cookbook : Commandes de la sous-fenêtre d'indicateur - Boutons" - page 7

 
TheXpert:
Êtes-vous sûr que votre article est parfait ?

Je suis très heureux que vous l'ayez lu.

Je me ferai un plaisir de répondre à toutes les questions dans le fil de discussion approprié.

===

Pour qu'il n'y ait pas de malentendus inutiles, je n'ai rien contre Anatoly ! Bravo à lui pour son article ! Mais il est nécessaire de répondre aux questions...

 
DC2008:

Excusez-moi, est-ce que par hasard je vous distrais de l'écriture d'un autre tutoriel ou d'une autre recette ?

Si ce n'est pas le cas, continuons à discuter de votre article sur le contrôle dans la sous-fenêtre de l'indicateur. Vous proposez donc une solution de masse (ou une idée) pour créer un menu pratique dans un indicateur. Bien, l'objectif de l'article est tout à fait louable ! Mais comment un programmeur "débutant" peut-il utiliser tout cet arsenal ? Où placer les fonctions personnalisées ? Démontrez-le par l'exemple. Et en même temps, expliquez ce qu'il faut corriger dans le code pour utiliser, par exemple, 5 boutons ? Considérez qu'il s'agit d'une question de débutant.

Non, ce n'est pas le cas. Je n'écris encore rien. Je dois me reposer au moins un jour par an. Se reposer n'est pas intéressant, surtout pas pendant une longue période. )

Ce n'est pas une décision de masse et je n'ai rien écrit à ce sujet. N'attribuons pas quelque chose qui n'est pas arrivé. Il a déjà été dit au début de la discussion qu'il ne s'agit pas d'une solution universelle, mais d'un cas particulier. À mon avis, il s'agit d'un bon exemple à mettre en pratique pour un débutant. Et non pas pour obtenir gratuitement une solution toute faite et courir, la bouche ouverte dans un large sourire, à la rencontre du soleil. ) Vous comprenez ? J'aimerais avoir un exemple aussi simple et clair au tout début de l'apprentissage de la programmation. Surtout lorsqu'il s'agit du premier langage de programmation de votre vie et qu'auparavant, l'activité de toute votre vie s'est déroulée dans un domaine complètement différent, sans aucun rapport avec la programmation.

Pour créer 5 boutons, dans ce cas, nous devons modifier la taille des tableaux et exclure les éléments inutiles lors de la déclaration des tableaux pour les noms des objets-boutons, le texte affiché dans les boutons et les états des boutons.

Il existe un tableau d'états de boutons, de sorte que le même principe peut être utilisé pour vérifier quel bouton est enfoncé et, au lieu de simplement changer la couleur du bouton, effectuer une autre action (requise par l'utilisateur). Il peut s'agir, par exemple, de fonctions de négociation (et pas seulement) : suppression de tous les ordres en attente, fermeture de toutes les positions, etc. Les idées sont infinies. Et s'il n'y a pas d'idées, c'est que vous avez choisi le mauvais type d'activité. )

Pour mettre cela en œuvre, vous devez créer un autre tableau, qui sera initialisé avec les identifiants d'une énumération personnalisée (qui doit également être créée), par exemple, avec le nom ENUM_SCRIPT. Les identifiants seront ensuite appelés, par exemple : SCRIPT_01 =0, SCRIPT_02 =2, etc. Toujours dans la boucle, lorsque vous vérifiez si le bouton du panneau est enfoncé, vous devez déterminer l'identificateur lié au bouton enfoncé et l'état actuel du bouton, puis transmettre la fonction correspondante au programme pour qu'il l'exécute.

C'est volontairement que je ne montrerai pas d'exemple de code. Il s'agit d'un devoir pour les débutants. )

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

J'ai fait les modifications comme vous l'avez dit :

//--- Texte affiché dans les boutons
string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"Button 01","Button 02","Button 03","Button 04"},
     {"Button 05"}
  };
//--- Noms des objets
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}
  };

Et voici ce que j'ai obtenu à l'écran :

Comment puis-je résoudre ce problème ? (je suis débutant)

 
DC2008:

J'ai fait les modifications comme vous l'avez dit :

Et voici ce que j'ai obtenu à l'écran :

Comment puis-je résoudre ce problème ? (je suis débutant)

Comme ceci :

#define  BUTTON_COLUMNS 5 // Nombre de boutons par largeur
#define  BUTTON_ROWS    1 // Nombre de boutons par hauteur
...
//--- Texte affiché dans les boutons
string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"Button 01","Button 02","Button 03","Button 04","Button 05"}
  };
//--- Noms des objets
string button_object_names[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"button_01","button_02","button_03","button_04","button_05"}
  };
...
//--- États des boutons
bool button_states[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {true,false,false,false,false}
  };
 

Oh, c'est génial ! Cela fonctionne.

Mais je ne comprends pas comment connecter mes fonctions aux boutons. Montrez-moi un exemple.

 
DC2008:

Oh, c'est génial ! Cela fonctionne.

Mais je ne comprends pas comment connecter mes fonctions aux boutons. Montrez-moi un exemple.

Eh bien, continuons le jeu du "débutant" que vous avez commencé. )

À quel point êtes-vous bloqué ? Montrez une tentative de compréhension au point où vous en êtes. Créez une énumération avec cinq identificateurs et un tableau dont les éléments doivent recevoir ces identificateurs.

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

Que faire ensuite ?

 
DC2008:

Que faire ensuite ?

C'est le type de tableau dont vous avez besoin :

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

Vous devez donc écrire une fonction comme celle-ci :

//+------------------------------------------------------------------+
//|| Exécution de scripts
//+------------------------------------------------------------------+
void ScriptOn()
  {
   for(int i=0; i<NUMBER_BUTTONS_WIDTH; i++)
     {
      for(int j=0; j<NUMBER_BUTTONS_HEIGHT; j++)
        {
         //--- Si ce bouton est pressé, nous exécuterons le script correspondant
         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;
              }
           }
        }
     }
  }

...et placer cette fonction dans cette partie du code :

//--- Suivi des clics du bouton gauche de la souris sur un objet graphique
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Si vous cliquez sur le bouton
      if(InitializeButtonStates(sparam))
        {
         //--- Définir les couleurs des boutons
         ChangeButtonColorOnClick();
         //--- Exécuter le script
         ScriptOn();
        }
      //--- Mise à jour du graphique
      ChartRedraw();
      return;
     }

Ensuite, vous pouvez réfléchir à la manière d'optimiser le code, si nécessaire. :)

 
tol64:

C'est ainsi que je procède.

Le programme dont le suivi est activé au démarrage le désactive au moment du déchargement. Et le programme qui reste sur le graphique et qui a besoin du suivi, vérifie s'il est activé, et s'il est désactivé, il l'active.

Il est souhaitable de donner votre variante sur les exemples de code d'Expert Advisor et d'indicateur de mon post sur la page précédente afin d' exclure toute ambiguïté dans les déclarations.

Il n'est pas nécessaire de vérifier constamment si quelqu'un a désactivé le suivi des événements de la souris. Pour être plus précis, si vous voulez vous protéger de n'importe quelle situation, vous pouvez le vérifier, mais je pense que c'est trop.

Peut-être devrions-nous suggérer aux développeurs de générer CHARTEVENT_CHART_CHANGE lorsque CHART_EVENT_MOUSE_MOVE change ? Il serait alors possible de restaurer élégamment le paramètre nécessaire lorsque l'Expert Advisor est en cours d'exécution.

Pour l'instant, j'ai cette 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 - fonctionne avec le suivi de la souris, false - sans lui

bool PrevState = false;

//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'indicateur personnalisé
//+------------------------------------------------------------------+
int OnInit()
{
        if ( EnableMouseDetect )
        {
                //--- Obtenir l'état actuel
                PrevState = (bool)ChartGetInteger(0,CHART_EVENT_MOUSE_MOVE);
                //--- Activer le suivi des événements de la souris
                if ( PrevState == false ) ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
        }

        return(0);
}

//+------------------------------------------------------------------+
//| Fonction de désinitialisation de l'expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        if ( EnableMouseDetect )
        {
                //--- Désactiver le suivi des événements de la souris
                if ( PrevState == false )
                {
                        ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,false);
                        ChartRedraw(); // Sans cette ligne, le suivi n'est désactivé qu'à l'arrivée d'un tic. Est-ce ainsi que le système a été conçu ?
                }
        }
}

//+------------------------------------------------------------------+
//| 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);
       }
//+------------------------------------------------------------------+
//| Fonction ChartEvent|
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Suivi des mouvements de la souris et des pressions sur le bouton gauche de la souris
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      static int count=1;
      Print("CHARTEVENT_MOUSE_MOVE; EXPERT; ",count);
      count++;
     }
  }
//+------------------------------------------------------------------+

J'ai créé un indicateur, mais avec un paramètre : run with EnableMouseDetect = true - contrôle le suivi, false - imprime simplement le nombre d'événements si le suivi est activé.


------------------
Maintenant, j'y ai réfléchi un peu plus, et je dois admettre que cette option ne fonctionnera pas. Si vous lancez d'abord un programme qui suit la souris (il activera le suivi), puis le second (il verra ce qui est déjà activé), et que vous supprimez ensuite le premier, il désactivera le suivi, et le second se retrouvera sans rien. En d'autres termes, nous devons trouver une sorte de sémaphore pour signaler que le suivi est nécessaire.

Et à la lumière des recherches menées ici (sur la charge du processeur), de telles béquilles ne sont pas nécessaires.

Je propose donc de voter ma proposition aux développeurs, et le sujet peut être clos.

 
ChartRedraw(); // Sans cette ligne, le suivi n'est désactivé qu'à l'arrivée d'un tic. Est-ce ainsi que le système a été conçu ?
MT5 dispose d'une mise à jour asynchrone des propriétés du graphique. En d'autres termes, le fait que nous ayons défini une propriété ne signifie pas que le terminal l'ait immédiatement prise en compte. La fonction ChartRedraw() est utilisée pour que toutes les propriétés soient relues par le terminal. Vous pouvez également utiliser la fonction ChartGet... ObjectGet, dans ce cas les propriétés seront également relues.
Документация по MQL5: Операции с графиками / ChartRedraw
Документация по MQL5: Операции с графиками / ChartRedraw
  • www.mql5.com
Операции с графиками / ChartRedraw - Документация по MQL5