Types définis par l'utilisateur

Le mot-clé typedef en C++ permet de céer des types de données définis par l'utilisateur. Pour cela, spécifiez simplement un nouveau nom du type de données pour un type de données existant. Le nouveau type de données n'est pas créé. Un nouveau pour le type existant est défini à la place. Les types définis par l'utilisateur rendent les applications plus flexibles : il est parfois suffisant de changer les instructions du typedef avec des macros de substitution (#define). Les types définis par l'utilisateur améliorent également la lisibilité du code puisqu'il est possible d'appliquer des noms personnalisés à des types de données standard avec typedef. Le format général de création d'un type défini par l'utilisateur :

   typedef type nouveau_nom;

Ici, type signifie tout type de données autorisé, tandis que nouveau_nom est un nouveau nom pour le type. Un nouveau nom ne remplace pas le nom d'un type existant, il est seulement ajouté. MQL5 permet de créer des pointeurs de fonctions en utilisant typedef.

Pointeur vers la fonction

Un pointeur de fonction est généralement définit avec le format suivant

   typedef type_de_resultat_de_la_fonction (*Function_name_type)(list_of_input_parameters_types);

où après typedef est écrite la signature de la fonction (nombre et types des paramètres d'entrée, ainsi que le type du résultat retourné par la fonction). Un exemple simple de création et d'utilisation d'un pointeur de fonction se trouve en-dessous :

//--- déclare un pointeur vers une fonction acceptant deux paramètres de type int
   typedef int (*TFunc)(int,int);
//--- TFunc est un type, et il est possible de déclarer la variable pointeur de fonction
   TFunc func_ptr; // pointeur vers la fonction
//--- déclare les fonctions correspondant à la description TFunc
   int sub(int x,int y) { return(x-y); }  // soustrait un nombre d'un autre
   int add(int x,int y) { return(x+y); }  // additionne deux nombre
   int neg(int x)       { return(~x);  }  // inverse les bits de la variable
//--- la variable func_ptr peut stocker l'adresse de la fonction pour la déclarer ensuite
   func_ptr=sub;
   Print(func_ptr(10,5));
   func_ptr=add;
   Print(func_ptr(10,5));
   func_ptr=neg;           // erreur : neg n'a pas le type int (int,int)
   Print(func_ptr(10));    // erreur : deux paramètres requis

Dans cet exemple, la variable func_ptr peut recevoir les fonctions sub et add puisqu'elles ont deux entrées de type int chacune, tel que défini dans le pointeur de fonction TFunc. Au contraire, la fonction neg ne peut pas être assignée au pointeur func_ptr puisque sa signature est différente.

Arrangement des modèles d'évènements dans l'interface graphique

Les pointeurs de fonctions vous permettent de créer facilement des traitements d'évènements lors de la création d'une interface graphique. Utilisons un exemple de la section CButton pour illustrer la façon de créer des boutons et ajouter les fonctions de traitement de l'appui sur les boutons. Premièrement, définissons un pointeur vers la fonction TAction devant être appelée lors de l'appui sur le bouton et créons trois fonctions selon la description de TAction.

//--- créons un type de fonction personnalisé
typedef int(*TAction)(string,int);
//+------------------------------------------------------------------+
//|  Ouvre le fichier                                                |
//+------------------------------------------------------------------+
int Open(string name,int id)
  {
   PrintFormat("Fonction %s appelée (nom=%s id=%d)",__FUNCTION__,name,id);
   return(1);
  }
//+------------------------------------------------------------------+
//|  Sauvegarde le fichier                                           |
//+------------------------------------------------------------------+
int Save(string name,int id)
  {
   PrintFormat("Fonction %s appelée (nom=%s id=%d)",__FUNCTION__,name,id);
   return(2);
  }
//+------------------------------------------------------------------+
//|  Ferme le fichier                                                |
//+------------------------------------------------------------------+
int Close(string name,int id)
  {
   PrintFormat("Fonction %s appelée (nom=%s id=%d)",__FUNCTION__,name,id);
   return(3);
  }
 

Crée ensuite l'instance de classe MyButton de CButton, où nous devons ajouter le pointeur de fonction TAction.

//+------------------------------------------------------------------+
//| Crée la classe du bouton avec traitement des évènements          |
//+------------------------------------------------------------------+
class MyButton: public CButton
  {
private:
   TAction           m_action;                    // handler des évènements du graphique
public:
                     MyButton(void){}
                    ~MyButton(void){}
   //--- constructeur spécifiant le texte du bouton et le pointeur vers la fonction de gestion des évènements
                     MyButton(string text, TAction act)
     {
      Text(text);
      m_action=act;
     }
   //--- définit la fonction personnalisée appelée depuis le gestionnaire d'évènements OnEvent()
   void              SetAction(TAction act){m_action=act;}
   //--- gestionnaire standard d'évènements du graphique
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) override
     {      
      if(m_action!=NULL && lparam==Id())
        { 
         //--- appelle le gestionnaire personnalisée m_action()
         m_action(sparam,(int)lparam);a
         return(true);
        }
      else
      //--- retourne le résultat de l'appel au gestionnaire depuis la classe parente CButton
         return(CButton::OnEvent(id,lparam,dparam,sparam));
     }
  };

Créée la classe CControlsDialog dérivée de CAppDialog, ajoute le tableau m_buttons pour stocker les boutons de type MyButton, ainsi que les méthodes AddButton(MyButton &button) et CreateButtons().

//+------------------------------------------------------------------+
//| Classe CControlsDialog                                           |
//| Objectif : panneau graphique de gestion de l'application         |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
  {
private:
   CArrayObj         m_buttons;                     // tableau de boutons
public:
                     CControlsDialog(void){};
                    ~CControlsDialog(void){};
   //--- création
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) override;
   //--- ajoute le bouton
   bool              AddButton(MyButton &button){return(m_buttons.Add(GetPointer(button)));m_buttons.Sort();};
protected:
   //--- crée les boutons
   bool              CreateButtons(void);
  };
//+------------------------------------------------------------------+
//| Crée l'objet CControlsDialog sur le graphique                    |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
   return(CreateButtons());
//---
  }
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
//--- décalages et espaces
#define INDENT_LEFT                         (11)      // décalage depuis la gauche (en respectant la largeur de la bordure)
#define INDENT_TOP                          (11)      // décalage depuis le haut (en respectant la largeur de la bordure)
#define CONTROLS_GAP_X                      (5)       // coordonnée X de l'espace
#define CONTROLS_GAP_Y                      (5)       // coordonnée Y de l'espace
//--- pour les boutons
#define BUTTON_WIDTH                        (100)     // largeur du bouton
#define BUTTON_HEIGHT                       (20)      // hauteur du bouton
//--- pour la zone de texte
#define EDIT_HEIGHT                         (20)      // hauteur
//+------------------------------------------------------------------+
//| Crée et ajoute les boutons au panneau CControlsDialog            |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButtons(void)
  {
//--- calcule les coordonnées des boutons
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2;
   int y2=y1+BUTTON_HEIGHT;
//--- ajoute les objets boutons avec les pointeurs de fonctions
   AddButton(new MyButton("Open",Open));
   AddButton(new MyButton("Save",Save));
   AddButton(new MyButton("Close",Close));
//--- crée le bouton graphiquement
   for(int i=0;i<m_buttons.Total();i++)
     {
      MyButton *b=(MyButton*)m_buttons.At(i);
      x1=INDENT_LEFT+i*(BUTTON_WIDTH+CONTROLS_GAP_X);
      x2=x1+BUTTON_WIDTH;
      if(!b.Create(m_chart_id,m_name+"bt"+b.Text(),m_subwin,x1,y1,x2,y2))
        {
         PrintFormat("Echec de création du bouton %s %d",b.Text(),i);
         return(false);
        }
      //--- ajoute chaque bouton au conteneur CControlsDialog
      if(!Add(b))
         return(false);
     }
//--- succès
   return(true);
  }

Nous pouvons maintenant développer le programme avec le panneau de contrôle CControlsDialog ayant 3 boutons : Open, Save et Close. En cliquant sur un bouton, la fonction correspondante sous la forme du pointeur TAction est appelée.

//--- déclare l'objet au niveau global pour le créer automatiquement lors du lancement du programme
CControlsDialog MyDialog;
//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'expert                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- crée maintenant l'objet sur le graphique
   if(!MyDialog.Create(0,"Controls",0,40,40,380,344))
      return(INIT_FAILED);
//--- lance l'application
   MyDialog.Run();
//--- application initialisée avec succès
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Fonction de dé-initialisation de l'expert                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- détruit le dialogue
   MyDialog.Destroy(reason);
  }
//+------------------------------------------------------------------+
//| Fonction d'évènement du graphique de l'expert                    |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // identifiant de l'évènement
                  const long& lparam,   // paramètre de l'évènement de type long
                  const double& dparam, // paramètre de l'évènement de type double
                  const string& sparam) // paramètre de l'évènement de type string
  {
//--- appelle le handler depuis la classe parent (ici CAppDialog) pour les évènements du graphique
   MyDialog.ChartEvent(id,lparam,dparam,sparam);
  }

L'apparence de l'application lancée et du résultat de l'appui sur le bouton sont fournis dans la copie d'écran.

panel_buttons

 

Le code source complet du programme

//+------------------------------------------------------------------+
//|                                                Panel_Buttons.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
 
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property description "Panneau avec plusieurs boutons CButton"
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
//--- décalages et espaces
#define INDENT_LEFT                         (11)      // décalage depuis la gauche (en respectant la largeur de la bordure)
#define INDENT_TOP                          (11)      // décalage depuis le haut (en respectant la largeur de la bordure)
#define CONTROLS_GAP_X                      (5)       // coordonnée X de l'espace
#define CONTROLS_GAP_Y                      (5)       // coordonnée Y de l'espace
//--- pour les boutons
#define BUTTON_WIDTH                        (100)     // largeur du bouton
#define BUTTON_HEIGHT                       (20)      // hauteur du bouton
//--- pour la zone de texte
#define EDIT_HEIGHT                         (20)      // hauteur
 
//--- crée le type personnalisé de fonction
typedef int(*TAction)(string,int);
//+------------------------------------------------------------------+
//|  Ouvre le fichier                                                |
//+------------------------------------------------------------------+
int Open(string name,int id)
  {
   PrintFormat("Fonction %s appelée (nom=%s id=%d)",__FUNCTION__,name,id);
   return(1);
  }
//+------------------------------------------------------------------+
//|  Sauvegarde le fichier                                           |
//+------------------------------------------------------------------+
int Save(string name,int id)
  {
   PrintFormat("Fonction %s appelée (nom=%s id=%d)",__FUNCTION__,name,id);
   return(2);
  }
//+------------------------------------------------------------------+
//|  Ferme le fichier                                                |
//+------------------------------------------------------------------+
int Close(string name,int id)
  {
   PrintFormat("Fonction %s appelée (nom=%s id=%d)",__FUNCTION__,name,id);
   return(3);
  }
//+------------------------------------------------------------------+
//| Crée la classe du bouton avec traitement des évènements          |
//+------------------------------------------------------------------+
class MyButton: public CButton
  {
private:
   TAction           m_action;                    // handler des évènements du graphique
public:
                     MyButton(void){}
                    ~MyButton(void){}
   //--- constructeur spécifiant le texte du bouton et le pointeur vers la fonction de gestion des évènements
                     MyButton(string text,TAction act)
     {
      Text(text);
      m_action=act;
     }
   //--- définit la fonction personnalisée appelée depuis le gestionnaire d'évènements OnEvent()
   void              SetAction(TAction act){m_action=act;}
   //--- gestionnaire standard d'évènements du graphique
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) override
     {
      if(m_action!=NULL && lparam==Id())
        {
         //--- appelle le gestionnaire personnalisé
         m_action(sparam,(int)lparam);a
         return(true);
        }
      else
      //--- retourne le résultat de l'appel au gestionnaire depuis la classe parente CButton
         return(CButton::OnEvent(id,lparam,dparam,sparam));
     }
  };
//+------------------------------------------------------------------+
//| Classe CControlsDialog                                           |
//| Objectif : panneau graphique de gestion de l'application         |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
  {
private:
   CArrayObj         m_buttons;                     // tableau de boutons
public:
                     CControlsDialog(void){};
                    ~CControlsDialog(void){};
   //--- création
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) override;
   //--- ajoute le bouton
   bool              AddButton(MyButton &button){return(m_buttons.Add(GetPointer(button)));m_buttons.Sort();};
protected:
   //--- crée les boutons
   bool              CreateButtons(void);
  };
//+------------------------------------------------------------------+
//| Crée l'objet CControlsDialog sur le graphique                    |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
   return(CreateButtons());
//---
  }
//+------------------------------------------------------------------+
//| Crée et ajoute les boutons au panneau CControlsDialog            |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButtons(void)
  {
//--- calcule les coordonnées des boutons
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2;
   int y2=y1+BUTTON_HEIGHT;
//--- ajoute les objets boutons avec les pointeurs de fonctions
   AddButton(new MyButton("Open",Open));
   AddButton(new MyButton("Save",Save));
   AddButton(new MyButton("Close",Close));
//--- crée le bouton graphiquement
   for(int i=0;i<m_buttons.Total();i++)
     {
      MyButton *b=(MyButton*)m_buttons.At(i);
      x1=INDENT_LEFT+i*(BUTTON_WIDTH+CONTROLS_GAP_X);
      x2=x1+BUTTON_WIDTH;
      if(!b.Create(m_chart_id,m_name+"bt"+b.Text(),m_subwin,x1,y1,x2,y2))
        {
         PrintFormat("Echec de création du bouton %s %d",b.Text(),i);
         return(false);
        }
      //--- ajoute chaque bouton au conteneur CControlsDialog
      if(!Add(b))
         return(false);
     }
//--- succès
   return(true);
  }
//--- déclare l'objet au niveau global pour le créer automatiquement lors du lancement du programme
CControlsDialog MyDialog;
//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'expert                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- crée maintenant l'objet sur le graphique
   if(!MyDialog.Create(0,"Controls",0,40,40,380,344))
      return(INIT_FAILED);
//--- lance l'application
   MyDialog.Run();
//--- application initialisée avec succès
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Fonction de dé-initialisation de l'expert                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- détruit le dialogue
   MyDialog.Destroy(reason);
  }
//+------------------------------------------------------------------+
//| Fonction d'évènement du graphique de l'expert                    |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // identifiant de l'évènement
                  const long& lparam,   // paramètre de l'évènement de type long
                  const double& dparam, // paramètre de l'évènement de type double
                  const string& sparam) // paramètre de l'évènement de type string
  {
//--- appelle le handler depuis la classe parent (ici CAppDialog) pour les évènements du graphique
   MyDialog.ChartEvent(id,lparam,dparam,sparam);
  }

 

Voir aussi

Variables, Fonctions