
Concevoir et implémenter de nouveaux widgets GUI axés sur la classe CChartObject
Introduction
Après avoir écrit unarticle sur Expert Advisor automatique avec interface GUI , il s'est avéré qu'il serait souhaitable d'améliorer l'interface avec de nouvelles fonctionnalités pour les indicateurs et les Expert Advisors plus complexes. Après m'être familiarisé avec les classes de la bibliothèque standard MQL5, j'ai implémenté de nouveaux widgets.
Dans cet article je vais décrire un processus d’utilisation des classes deMQL5 Standard Library pour les objets GUI et comment implémenter de nouvelles classes dérivées depuis la classeCChartObjectEdit: CChartObjectProgressBar, CChartObjectSpinner et CChartEditTable. La classe CChartEditTable utilise un tableau d'objets dynamique bi-dimensionnel, il s'agit d'un exemple pratique sur la façon d'implémenter un tableau d'objets 2D dynamique dans MQL5.
1. CChartObject et ses descendants
Si nous n'utilisons pas la classe de bibliothèque MQL5 standard, nous devons utiliser les Fonctions d’objet pour créer et gérer tout objet sur le graphique.
Les objets sont créés avec la fonction ObjectCreate() et le type d’objet est transmis vers la fonctionObjectCreate() en tant que valeur ENUM_OBJECT. Tous les objets sur le graphique disposent de leurs propres caractéristiques qui peuvent être de typeInteger, Double, ou String Toutes les propriétés sont définies et récupérées via des fonctions dédiées : ObjectGetInteger(), ObjectSetInteger(), ObjectGetDouble(), ObjectSetDouble(), ObjectGetString(), ObjectSetString(). Il y a également des fonctions poursupprimer, déplacer et compter les objets sur tout graphique donné.
En raison du paradigme de la POO dans MQL5, la gestion de divers objets graphiques peut être effectuée à l'aide de la classeCChartObject et de ses descendants.
La classeCChartObject est une classe de base pour tous les objets graphiques pouvant être placés sur un graphique. Veuillez observer le diagramme d'héritage de base pour CChartObject ci-dessous :
Figure 1. Diagramme d'héritage pour la classe CChartObject
Comme nous pouvons le constater, quelques classes sont marquées d'un petit triangle dans le coin inférieur droit.
Ce sont des classes qui sont parentes d'autres classes. Fondamentalement, les classes descendantes améliorent les possibilités d'une classe de base en ajoutant de nouvelles variables et méthodes qui agissent sur l'objet. EIles peuvent également différer dans les méthodes Create() et Type() pour créer un objet dérivé et renvoyer son type.
Permettez-moi de montrer ceci par exemple: CChartObjectTrend est une classe parente à CChartObjectTrendByAngle, CChartObjectChannel, CChartObjectStdDevChannel, CChartObjectRegression et CChartObjectPitchfork classes.
La CChartObjectTrendest une classe de base pour les objets qui disposent de propriétés OBJPROP_RAY_RIGHT et OBJPROP_RAY_LEFTet définie comme suit:
class CChartObjectTrend : public CChartObject { public: //--- methods of access to properties of the object bool RayLeft() const; bool RayLeft(bool new_sel); bool RayRight() const; bool RayRight(bool new_sel); //--- method of creating the object bool Create(long chart_id,string name,int window, datetime time1,double price1,datetime time2,double price2); //--- method of identifying the object virtual int Type() const { return(OBJ_TREND); } //--- methods for working with files virtual bool Save(int file_handle); virtual bool Load(int file_handle); };
Il y a des commentaires dans la définition qui permettent de distinguer différents types de méthodes.
Les méthodes d'accès aux propriétés de l'objet sont RayLeft() et RayRight(). Leur implémentation est d’appeler les méthodesObjectGetInteger() et ObjectSetInteger() qui agissent sur l’objet CChartObjectTrend.
bool CChartObjectTrend::RayLeft(bool new_ray) { //--- checking if(m_chart_id==-1) return(false); //--- return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT,new_ray)); }
La méthode Create () est chargée de créer et d’attacher l’objet sur le graphique
Il appelle la méthode ObjectCreate()avec OBJ_TREND comme un des paramètres:
bool CChartObjectTrend::Create(long chart_id,string name,int window, datetime time1,double price1,datetime time2,double price2) { bool result=ObjectCreate(chart_id,name,OBJ_TREND,window,time1,price1,time2,price2); if(result) result&=Attach(chart_id,name,window,2); //--- return(result); }
Les méthodes Save() et Load() stockent et téléchargent les données de l’objet sur un disque dur à l’aide des fonctions FileWriteInteger() et FileLoadInteger():
bool CChartObjectTrend::Save(int file_handle) { bool result; //--- checking if(file_handle<=0) return(false); if(m_chart_id==-1) return(false); //--- writing result=CChartObject::Save(file_handle); if(result) { //--- writing value of the "Ray left" property if(FileWriteInteger(file_handle,(int) ObjectGetInteger(m_chart_id,m_name, OBJPROP_RAY_LEFT),CHAR_VALUE)!=sizeof(char)) return(false); //--- writing value of the "Ray right" property if(FileWriteInteger(file_handle,(int) ObjectGetInteger(m_chart_id,m_name, OBJPROP_RAY_RIGHT),CHAR_VALUE)!=sizeof(char)) return(false); } //--- return(result); } bool CChartObjectTrend::Load(int file_handle) { bool result; //--- checking if(file_handle<=0) return(false); if(m_chart_id==-1) return(false); //--- reading result=CChartObject::Load(file_handle); if(result) { //--- reading value of the "Ray left" property if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT, FileReadInteger(file_handle,CHAR_VALUE)))return(false); //--- reading value of the "Ray right" property if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT, FileReadInteger(file_handle,CHAR_VALUE))) return(false); } //--- return(result); }
Examinons rapidement les définitions des classes descendantes deCChartObjectTrend
La classe CChartObjectTrendByAngle ajoute Angle() modificateur de propriété et renvoie le type d’objet OBJ_TRENDBYANGLE:
class CChartObjectTrendByAngle : public CChartObjectTrend { public: //--- methods of access to properties of the object double Angle() const; bool Angle(double angle); //--- method of creating the object bool Create(long chart_id,string name,int window,datetime time1,double price1, datetime time2,double price2); //--- method of identifying the object virtual int Type() { return(OBJ_TRENDBYANGLE); } };
La classe CChartObjectChannelrenvoie OBJ_CHANNEL le type d’objet et puisque elle gère les canaux, trois paires de paramètres de prix/date sont transmises vers la méthode to Create():
class CChartObjectChannel : public CChartObjectTrend { public: //--- method of creating the object bool Create(long chart_id,string name,int window,datetime time1,double price1, datetime time2,double price2,datetime time3,double price3); //--- method of identifying the object virtual int Type() const { return(OBJ_CHANNEL); } };
La classeCChartObjectStdDevChannel ajoute un modificateur de propriété Deviations() et un paramètre de déviation supplémentaire dans la méthode Create() :
class CChartObjectStdDevChannel : public CChartObjectTrend { public: //--- methods of access to properties of the object double Deviations() const; bool Deviations(double deviation); //--- method of creating the object bool Create(long chart_id,string name,int window, datetime time1,datetime time2,double deviation); //--- method of identifying the object virtual int Type() const { return(OBJ_STDDEVCHANNEL); } //--- methods for working with files virtual bool Save(int file_handle); virtual bool Load(int file_handle); };
La classeCChartObjectRegression crée une ligne de tendance de régression, seules les méthodes Create() et Type() sont remplacées par celles de la classeCChartObjectTrend
class CChartObjectRegression : public CChartObjectTrend { public: //--- method of creating the object bool Create(long chart_id,string name,int window,datetime time1,datetime time2); //--- method of identifying the object virtual int Type() const { return(OBJ_REGRESSION); } };
La classeCChartObjectPitchfork gère le type de fourche, seules les méthodes Create () et Type () sont également modifiées :
class CChartObjectPitchfork : public CChartObjectTrend { public: //--- method of creating the object bool Create(long chart_id,string name,int window,datetime time1,double price1, datetime time2,double price2,datetime time3,double price3); //--- method of identifying the object virtual int Type() const { return(OBJ_CHANNEL); } };
Cette analyse rapide a indiqué les règles de base appliquées lors de l'écriture d'une nouvelle classe d'objets graphiques axée sur une autre classe :
- changer la méthode Create () pour la création d'objets
- changer la méthode Type() pour renvoyer le type d'objet
- ajout de modificateurs d'accès aux propriétés
Pas toutes les règles doivent être appliquées, on peut seulement ajouter de nouveaux modificateurs d'accès ou ajouter de nouvelles variables et/ou objets dans la classe.
Avant d'aller plus loin, permettez-moi de vous expliquer comment utiliser les méthodes CChartObject sur des objets graphiques.
Au lieu d'utiliser la famille de méthodes ObjectSet et ObjectGet et d'utiliser des propriétés d'objet, il suffit de déclarer CChartObject ou un objet descendant et faire appel à des méthodes qui modifient les propriétés souhaitées. Afin de faciliter les choses, j’offre un exemple d'étiquette ordinaire.
Au lieu d'écrire :
void OnStart() { //--- string label_name="my_OBJ_LABEL_object"; if(ObjectFind(0,label_name)<0) { Print("Object ",label_name," not found. Error code = ",GetLastError()); ObjectCreate(0,label_name,OBJ_LABEL,0,0,0); ObjectSetInteger(0,label_name,OBJPROP_XDISTANCE,200); ObjectSetInteger(0,label_name,OBJPROP_YDISTANCE,300); ObjectSetInteger(0,label_name,OBJPROP_COLOR,White); ObjectSetString(0,label_name,OBJPROP_TEXT,UP); ObjectSetString(0,label_name,OBJPROP_FONT,"Wingdings"); ObjectSetInteger(0,label_name,OBJPROP_FONTSIZE,10); ObjectSetDouble(0,label_name,OBJPROP_ANGLE,-45); ObjectSetInteger(0,label_name,OBJPROP_SELECTABLE,false); ChartRedraw(0); } }
Nous pouvons l'implémenter en utilisant le paradigme OOP :
1. Déclarez l'objetCChartObjectLabel:
CChartObjectLabel label;
2. Agir sur l'objet :
int OnInit() { //--- label.Create(0, label_name, 0, 0); label.X_Distance(200); label.Y_Distance(300); label.Color(White); label.Description(UP); label.Font("Wingdings"); label.FontSize(10); label.Angle(-45); label.Selectable(false); //--- return(0); }
Comme vous pouvez le constater, la principale différence est que nous n’agissons plus sur une chaîne label_name :
string label_name="my_OBJ_LABEL_object";
et faites appel à ObjectSetInteger(), ObjectGetInteger(), ObjectSetDouble(), ObjectGetDouble() fonctions avec des noms de labels comme paramètres mais nous déclarons CChartObjectLabel objet et utilisons ses méthodes C'est non seulement plus simple à retenir et logique à implémenter mais aussi plus rapide à écrire.
L'éditeur de code MQL5 nous offre une fonctionnalité de complétion de code lorsque vous placez un point (.) après l'instance d'objet. Il n’est pas nécessaire de parcourir MQL5 documentation dans tous les sens pour voir quelle propriété OBJPROP à mettre ou obtenir une propriété donnée.
Analogiquement pour la classeCChartObjectTrend qui a été décrite précédemment, pour obtenir ou définir un rayon à gauche ou à droite, il suffit de déclarer l'objet CChartObjectTrend et d'appeler la méthode RayRight() ou RayLeft() :
CChartObjectTrend trendline; trendline.RayRight(true);
2. ProgressBar
Le premier widget que nous allons implémenter est ProgressBar. Les barres de progression indiquent la progression de certaines opérations, de 0 à x pour cent.
Pour le rendre plus robuste, ne contraignons pas la valeur maximale à 100, mais à n'importe quelle valeur entière positive. Nous avons besoin d'une bande de couleur qui changera de taille en fonction de la valeur de progression. La première chose qui me vient à l'esprit est d'utiliser deux rectangles, mais j'ai pris une autre voie : utiliser deux objetsCChartObjectEdit, l'un dans l'autre, avec des couleurs de fond différentes.
Il simplifie le codage et ajoute du texte qui peut être placé dans la barre de progression pour montrer sa valeur. Ce serait idéal si notre barre de progression pouvait être horizontale ou verticale selon les besoins de chacun.
2.1. Implémentation de ProgressBar
La classe CChartObjectProgress est dérivée de la classeCChartObjectEdit .
J'ai ajouté des variables internes privées pour contenir la valeur et les contraintes sur la valeur : m_value, m_min, m_max.
La direction de la barre de progression est définie comme une valeur entière et maintenue par la variable m_direction. La couleur est détenue par la variable m_color. La méthode Type() renvoie la valeurOBJ_EDIT , car de toute façon, aucune valeur n'est reconnue pour notre besoin. On peut remarquer la variable m_bar deCChartObjectEdità l'intérieur de la définition de classe - c'est la barre intérieure qui change de taille en fonction de la m_value. Les variables supplémentaires m_name et m_chart comportent en interne des valeurs pour la variable m_bar.
class CChartObjectProgressBar : public CChartObjectEdit { private: int m_value; int m_min; int m_max; int m_direction; color m_color; CChartObjectEdit m_bar; string m_name; long m_chart_id; public: int GetValue(); int GetMin(); int GetMax(); void SetValue(int val); void SetMin(int val); void SetMax(int val); void SetColor(color bgcol,color fgcol); bool Create(long chart_id,string name,int window,int X,int Y, int sizeX,int sizeY,int direction); //--- method of identifying the object virtual int Type() const { return(OBJ_EDIT); } };
La méthode Create() crée l'objet ProgressBar et l'attache au graphique.
Vous remarquerez peut-être que la variable Y est soustraite de la variable sizeY au cas où la barre verticale est dessinée, car normalementCChartObjectEdit est dessiné de haut en bas, et je voulais dessiner le rectangle intérieur de bas en haut :
bool CChartObjectProgressBar::Create(long chart_id,string name,int window,int X,int Y, int sizeX,int sizeY,int direction=0) { bool result=ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0); m_name=name; m_chart_id=chart_id; m_direction=direction; if(direction!=0) { Y=Y-sizeY; } ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,White); ObjectSetInteger(chart_id,name,OBJPROP_COLOR,White); ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(chart_id,name,OBJPROP_READONLY,true); result&=m_bar.Create(chart_id,name+"m_bar",window,X,Y,sizeX,sizeY); m_bar.Color(White); m_bar.ReadOnly(true); m_bar.Selectable(false); //--- if(result) result&=Attach(chart_id,name,window,1); result&=X_Distance(X); result&=Y_Distance(Y); result&=X_Size(sizeX); result&=Y_Size(sizeY); //--- return(result); }
La méthode SetColor() définit les couleurs d'arrière-plan et de premier plan sur les deux rectangles :
void CChartObjectProgressBar::SetColor(color bgCol,color fgCol=White) { m_color=bgCol; m_bar.BackColor(m_color); m_bar.Color(fgCol); }
La méthode SetValue() est responsable à la fois de la définition de la valeur m_val et du recalcul de la taille de l'objet du rectangle intérieur.
La taille est calculée différemment pour les barres horizontales et verticales :
void CChartObjectProgressBar::SetValue(int val) { if(m_direction==0) // horizontal ProgressBar { double sizex=(double)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE,0); double stepSize=sizex/(m_max-m_min); m_value=val; m_bar.Create(m_bar.ChartId(),m_bar.Name(),m_bar.Window(), m_bar.X_Distance(),m_bar.Y_Distance(),(int)MathFloor(stepSize*m_value),m_bar.Y_Size()); } else { double sizey=(double)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE,0); double stepSize=sizey/(m_max-m_min); m_value=val; m_bar.Create(m_bar.ChartId(),m_bar.Name(),m_bar.Window(), m_bar.X_Distance(),(int)(this.Y_Distance()+sizey-MathFloor(stepSize*m_value)), m_bar.X_Size(),(int)MathFloor(stepSize*m_value)); } m_bar.Description(IntegerToString(m_value)); }
2.2. Démo ProgressBar
Puisque nous avons déjà implémenté la classe CChartObjectProgressBar, il est temps de la voir à l’œuvre
Pour placer une nouvelle barre de progression sur le graphique, il suffit de déclarer l'objet CChartObjectProgressBar et d'utiliser Create() et les méthodes de propriété appropriées :
progressBar.Create(0, "progressBar1", 0, 10, 10, 200, 40); progressBar.SetColor(YellowGreen); progressBar.SetMin(0); progressBar.SetMax(100); progressBar.SetValue(0);
J'ai écrit une démo Expert Advisor qui place six barres de progression différentes sur le graphique et modifie leur valeur après avoir cliqué sur un objet à l'écran.
Le code source complet de cette démo et d'autres se trouvent dans les pièces jointes, veuillez suivre la présentation ci-dessous :
3. Spinner
Le widget Spinner est un widget qui comporte un champ et deux boutons. Il permet d'incrémenter ou de décrémenter une valeur dans le champ d'édition en cliquant sur l'un des boutons.
Lors de la conception de l'objet, je ne voulais pas agir uniquement sur des valeurs entières, donc Spinner a été conçu pour fonctionner sur un type double. Spinner offre également la possibilité de définir le pas de traceur, c'est-à-dire la valeur pour incrémenter ou décrémenter la valeur actuelle. Il doit également avoir une valeur minimale et maximale qui ne peut pas être franchie.
3.1. Implémentation du spinner
Dans MQL5 nous avons les classes CChartObjectEdit et CChartObjectButton qui peuvent être combinées en une seule classe CChartObjectSpinner. CChartObjectSpinner hérite deCChartObjectEdit et comporte deux objets CChartObjectButton membres privés.
Il existe des contraintes pour la m_value minimale et maximale stockées dans les variables membres m_min et m_max et la variable m_precision stocke la précision du calcul jusqu'à la valeur du n-ième chiffre. Les méthodes nécessaires donnent accès à la valeur, le pas de traceur d'incrémentation et de décrémentation et la valeur de réglage.
class CChartObjectSpinner: public CChartObjectEdit { private: double m_value; double m_stepSize; double m_min; double m_max; int m_precision; string m_name; long m_chart_id; CChartObjectButton m_up,m_down; public: double GetValue(); double GetMin(); double GetMax(); void SetValue(double val); void SetMin(double val); void SetMax(double val); double Inc(); double Dec(); bool Create(long chart_id,string name,int window,int X,int Y, int sizeX,int sizeY,double val,double stepSize,int precision); //--- method of identifying the object virtual int Type() const { return(OBJ_EDIT); } };
La méthode Create () crée un nouveau CChartObjectSpinner et l'attache au graphique.
Il y a deux CChartObjectButtons créés sur le côté droit deCChartObjectEdit, chacun ayant une hauteur de la moitié de la hauteur de CChartObjectEdit.
Le bouton d'incrémentation a le signe '+' et le bouton de décrémentation '-'.
bool CChartObjectSpinner::Create(long chart_id,string name,int window,int X,int Y, int sizeX,int sizeY,double val=0.0,double stepSize=1.0,int precision=8) { bool result=ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0); m_name=name; m_chart_id=chart_id; m_value=val; m_stepSize=stepSize; m_precision=precision; ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,White); ObjectSetInteger(chart_id,name,OBJPROP_COLOR,Black); ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(chart_id,name,OBJPROP_READONLY,true); result&=m_up.Create(chart_id, name+"_up", window, X+sizeX, Y, 15, sizeY/2); result&=m_down.Create(chart_id, name+"_down", window, X+sizeX, Y+sizeY/2, 15, sizeY/2); m_up.Description("+"); m_down.Description("-"); ObjectSetString(chart_id,name,OBJPROP_TEXT,0,(DoubleToString(m_value,precision))); //--- if(result) result&=Attach(chart_id,name,window,1); result&=X_Distance(X); result&=Y_Distance(Y); result&=X_Size(sizeX); result&=Y_Size(sizeY); //--- return(result); }
La méthode SetValue() définit la variable privée m_value sur une valeur double à condition qu'elle se trouve dans la plage <m_min, m_max>.
void CChartObjectSpinner::SetValue(double val) { if(val>=m_min && val<=m_max) m_value=val; this.Description(DoubleToString(m_value)); }
La méthode Inc() incrémente la valeur d'un pas de traceur donnée, mais pas plus de la valeur m_max.
Veuillez noter que j'ai dû utiliser la fonctionNormalizeDouble()pour comparer des valeurs doubles à une précision donnée.
double CChartObjectSpinner::Inc(void) { if(NormalizeDouble(m_max-m_value-m_stepSize,m_precision)>0.0) m_value+=m_stepSize; else m_value=m_max; this.Description(DoubleToString(m_value, m_precision)); m_up.State(false); return m_value; }
La méthode Dec() décrémente la valeur d'un pas de traceur donnée, mais pas moins que la valeur m_min.
double CChartObjectSpinner::Dec(void) { if(NormalizeDouble(m_value-m_stepSize-m_min,m_precision)>0.0) m_value-=m_stepSize; else m_value=m_min; this.Description(DoubleToString(m_value,m_precision)); m_down.State(false); return m_value; }
3.2. Démo de Spinner
Il est temps de tester les objets Spinner. Pour les utiliser, il suffit de déclarer l'objet CChartObjectSpinner et d'utiliser les méthodes Create(), SetMin() et SetMax().
spinner.Create(0, "spinner1", 0, 10, 10, 200, 40, 0.0, 0.4); spinner.SetMin(0); spinner.SetMax(100);
J'ai préparé une démo qui utilise trois widgets Spinner et ajoute toutes les valeurs après avoir cliqué sur n’importe quel bouton Spinner.
Cela se fait dans la fonction OnChartEvent() ;
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Check the event by pressing a mouse button if(id==CHARTEVENT_OBJECT_CLICK) { if (sparam=="spinner1_up") spinner.Inc(); if (sparam=="spinner1_down") spinner.Dec(); if (sparam=="spinner2_up") spinner2.Inc(); if (sparam=="spinner2_down") spinner2.Dec(); if (sparam=="spinner3_up") spinner3.Inc(); if (sparam=="spinner3_down") spinner3.Dec(); label.Description(DoubleToString(NormalizeDouble(spinner.GetValue()+spinner2.GetValue()+spinner3.GetValue(),10),10)); ChartRedraw(); } }
Veuillez voir la démo ci-jointe :
4. CChartObjectEditTable
Dans de nombreux Expert Advisors multi-temps (MTF), des valeurs d'indicateur sont affichées pour chaque intervalle de temps séparément.
Parfois, chaque intervalle de temps a des paramètres d'indicateur différents affichés sous la forme d'un tableau 2D de rectangles ou de carrés de différentes couleurs. J'ai conçu une table 2D universelle de tels objets en créant la classe CChartObjectEditTable. Cette classe peut contenir un nombre arbitraire de lignes et de colonnes, car j'utilise un tableau dynamique d'objets 2D.
Lors de la conception, j'ai décidé de définir une couleur pour chaque cellule séparément et d'ajouter également la possibilité de mettre différentes chaînes de texte sur n'importe quelle cellule. Les cellules sont de taille identique, mais je voulais définir leur hauteur et leur largeur et l'espace entre les cellules.
La classe CChartObjectEditTable comporte le pointeur CArrayObj vers un tableau d'objets bi-dimensionnel, et les variables membres m_rows et m_columns comportent le nombre de lignes et de colonnes de la table.
Il existe une variable membre m_baseName qui comporte le préfixe de tous les objetsCChartObjectEdit de cellule dans la table. Les méthodes GetColor(), SetColor(), GetText(), SetText() permettent de définir et d'obtenir des valeurs de couleur et de texte dans n'importe quelle cellule souhaitée. La méthode Delete() supprime tous les objets créés par la méthode Create().
class CChartObjectEditTable { private: CArrayObj *array2D; int m_rows; int m_cols; string m_baseName; public: bool Create(long chart_id,string name,int window,int rows,int cols,int startX,int startY, int sizeX,int sizeY,color Bg,int deltaX,int deltaY); bool Delete(); bool SetColor(int row,int col,color newColor); color GetColor(int row,int col); bool SetText(int row,int col,string newText); string GetText(int row,int col); };
La méthode Create() crée une table dynamique bidimensionnelle d'objetsCChartObjectEdit
Veuillez observer comment créer un tableau d'objets 2D dans MQL5 : nous déclarons d'abord un pointeur vers un tableau 2D, puis nous remplissons le tableau avec un certain nombre d'objetsCArrayObj(), c'est-à-dire que nous créons des tableaux dans le tableau. Tous les tableaux peuvent être considérés comme des supports pour les colonnes du tableau.
Chaque colonne contient des lignes comportant des objets CChartObjectEdit, chaque objet étant une seule cellule à afficher.
bool CChartObjectEditTable::Create(long chart_id,string name,int window,int rows=1,int cols=1, int startX=0,int startY=0,int sizeX=15,int sizeY=15, color Bg=White,int deltaX=5,int deltaY=5) { m_rows=rows; m_cols=cols; m_baseName=name; int i=0,j=0; array2D=new CArrayObj(); if (array2D==NULL) return false; for(j=0; j<m_cols; j++) { CArrayObj *new_array=new CArrayObj(); if (array2D==NULL) return false; array2D.Add(new_array); for(i=0; i<m_rows; i++) { CChartObjectEdit *new_edit=new CChartObjectEdit(); new_edit.Create(chart_id, name+IntegerToString(i)+":"+IntegerToString(j), window, startX+j*(sizeX+deltaX), startY+i*(sizeY+deltaY), sizeX, sizeY); new_edit.BackColor(Bg); new_edit.Color(White); new_edit.Selectable(false); new_edit.ReadOnly(true); new_edit.Description(""); new_array.Add(new_edit); } } return true; }
La méthode SetColor() définit la couleur de n'importe quelle cellule unique. Au début, elle trouve le tableau de colonnes, puis le nième élément dans le tableau de colonnes.
Ensuite, la valeur de couleur de l'élément est modifiée en faisant appel à la méthode BackColor().
bool CChartObjectEditTable::SetColor(int row,int col,color newColor) { CArrayObj *sub_array; CChartObjectEdit *element; if((row>=0 && row<m_rows) && (col>=0 && col<m_cols)) { if(array2D!=NULL) { sub_array=array2D.At(col); element=(CChartObjectEdit*)sub_array.At(row); element.BackColor(newColor); return true; } } return false; }
La méthode GetColor () dispose du même algorithme pour trouver la cellule que la méthode SetColor () mais elle renvoie la valeur de couleur de n'importe quelle cellule donnée.
color CChartObjectEditTable::GetColor(int row,int col) { CArrayObj *sub_array; CChartObjectEdit *element; if((row>=0 && row<m_rows) && (col>=0 && col<m_cols)) { if(array2D!=NULL) { sub_array=array2D.At(col); element=(CChartObjectEdit*)sub_array.At(row); return element.BackColor(); } } return NULL; }
La méthode SetText() trouve l'élément et définit sa valeur de texte en faisant appel à la méthode Description().
bool CChartObjectEditTable::SetText(int row,int col,string newText) { CArrayObj *sub_array; CChartObjectEdit *element; if((row>=0 && row<m_rows) && (col>=0 && col<m_cols)) { if(array2D!=NULL) { sub_array=array2D.At(col); element=(CChartObjectEdit*)sub_array.At(row); element.Description(newText); return true; } } return false; }
La méthode Delete() supprime tous les objets créés par la méthode Create().
Au début, elle efface tous les tableaux de colonnes, puis supprime l'objet array2D de la mémoire.
bool CChartObjectEditTable::Delete(void) { for(int j=0; j<m_cols; j++) { CArrayObj *column_array=array2D.At(j); column_array.Clear(); delete column_array; } delete array2D; return true; }
4.2. Démo CChartObjectEditTable
Pour utiliser le widget CChartObjectEditTable, il est nécessaire de déclarer l'objet CChartEditTable et d'utiliser la méthode Create() avec des paramètres indiquant le nombre de lignes et de colonnes que la table doit comporter
Ensuite, en utilisant des modificateurs de propriétés, on peut simplement changer la couleur et le texte sur n'importe quelle cellule.
table.Create(0,"t",0,1,10,10,10,15,15,Yellow); table.SetColor(2,2,Red); table.SetText(2,2,"2");
Veuillez consulter le script que j'ai préparé qui indique les possibilités d'utilisation de l'objet CChartObjectEditTable.
Le code source du script est en pièce jointe.
Conclusion
J'ai décrit et introduit dans l'article un processus de création de nouveaux widgets graphiques dérivés de la classeCChartObject
Le processus d'utilisation des widgets implémentés est très simple et n’occupe que quelques lignes de code.
Pour utiliser les widgets, veuillez inclure le fichier ChartObjectsExtControls.mqh dans Expert Advisor ou le code indicateur.
Traduit de l’anglais par MetaQuotes Ltd.
Article original : https://www.mql5.com/en/articles/196





- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation