Le MQL5 Cookbook : Commandes de la sous-fenêtre d'indicateur - Boutons
Introduction
Dans cet article, nous examinerons un exemple de développement d'une interface utilisateur avec des commandes de bouton. Pour transmettre l'idée d'interactivité à l'utilisateur, les boutons changeront de couleur lorsque le curseur les survolera. Avec le curseur sur un bouton, la couleur du bouton sera légèrement assombrie, devenant nettement plus sombre lorsque le bouton est cliqué. De plus, nous ajouterons des info-bulles à chaque bouton, créant ainsi une interface intuitive.
L'article couvrira également certains événements : l'événement de déplacement de la souris, l'état du bouton gauche de la souris, le clic gauche sur un objet et l'événement de modification des propriétés du graphique. Nous allons créer un panneau de boutons qui occupera tout l'espace de la sous-fenêtre de l'indicateur. À des fins d'illustration, les boutons seront disposés en trois rangées, avec quatre boutons dans chaque rangée.
Développement
Dans MQL5, les boutons peuvent être créés en utilisant divers objets graphiques, comme OBJ_BUTTON (Bouton), OBJ_BITMAP (Bitmap), OBJ_BITMAP_LABEL (Bitmap Label) ou OBJ_EDIT (Edit).
Dans cet article, nous allons créer des boutons en utilisant OBJ_EDIT. Les objets de ce type peuvent être mis en lecture seule. Ils sont également utiles dans la mesure où ils peuvent afficher le texte que vous spécifiez. De plus, vous pouvez rendre les coins de l'objet nets, tout en gardant sa bordure.
Créons donc un indicateur à l'aide de MQL5 Wizard. Légèrement retravaillé, le code source de l'indicateur sera le suivant :
//+------------------------------------------------------------------+ //| TestButtons.mq5 | //| Copyright 2013, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2013, MetaQuotes Software Corp." #property link "http://www.mql5.com" #property version "1.00" //--- #property indicator_separate_window // Indicator is in the subwindow #property indicator_plots 0 // No plotting series //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- } //+------------------------------------------------------------------+
Ce que nous avons en ce moment, c'est une fenêtre vide avec zéro série de tracés. La nécessité d'une minuterie sera discutée un peu plus tard.
Ajoutons maintenant des constantes, des variables et des tableaux qui seront utilisés dans la création de fonctions. Tous les tableaux sont à deux dimensions. La première dimension indique le nombre de boutons sur toute la hauteur de la fenêtre et la deuxième dimension indique le nombre de boutons sur toute la largeur de la fenêtre :
//--- #define BUTTON_COLUMNS 4 // Number of buttons across the width #define BUTTON_ROWS 3 // Number of buttons across the height //+------------------------------------------------------------------+ //| Global parameters | //+------------------------------------------------------------------+ //--- Font string font_name="Calibri"; //--- Indicator subwindow properties int subwindow_number =WRONG_VALUE; // Subwindow number int subwindow_height =0; // Subwindow height string subwindow_shortname ="TestButtons"; // Short name of the indicator string prefix =subwindow_shortname+"_"; // Prefix for object names int chart_width =0; // Chart width int chart_height =0; // Chart height int chart_y_offset =0; // Distance from the chart top to the subwindow //--- Colors of button elements color background_color =clrSteelBlue; // Button color color font_color =clrWhite; // Font color color hover_background_color =C'38,118,166'; // Button color when the cursor goes over color clicked_background_color =C'2,72,136'; // Clicked button color //--- Text displayed on buttons string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]= { {"Button 01","Button 02","Button 03","Button 04"}, {"Button 05","Button 06","Button 07","Button 08"}, {"Button 09","Button 10","Button 11","Button 12"} }; //--- Object names string button_object_names[BUTTON_ROWS][BUTTON_COLUMNS]= { {"button_01","button_02","button_03","button_04"}, {"button_05","button_06","button_07","button_08"}, {"button_09","button_10","button_11","button_12"} }; //--- Button widths int button_widths[BUTTON_ROWS][BUTTON_COLUMNS]; //--- Button heights int button_heights[BUTTON_ROWS][BUTTON_COLUMNS]; //--- X-coordinates int button_x_distances[BUTTON_ROWS][BUTTON_COLUMNS]; //--- Y-coordinates int button_y_distances[BUTTON_ROWS][BUTTON_COLUMNS]; //--- Button states bool button_states[BUTTON_ROWS][BUTTON_COLUMNS]= { {true,false,false,false}, {false,false,false,false}, {false,false,false,false} }; //--- Button colors color button_colors[BUTTON_ROWS][BUTTON_COLUMNS];
Lors du chargement de l'indicateur dans le graphique, les tableaux doivent être initialisés aux propriétés de l'objet dans les OnInit(), après avoir calculé les coordonnées et les tailles. Nous devrions également activer le suivi du curseur. Et enfin, nous devons ajouter des boutons à la sous-fenêtre de l'indicateur. Pour plus de commodité, ces actions seront effectuées dans des fonctions distinctes que nous allons examiner une par une plus loin. Par conséquent, les OnInit() se présentent comme suit :
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Set the timer at 1-second intervals EventSetTimer(1); //--- Add prefix to object names AddPrefix(); //--- Enable tracking of mouse events ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true); //--- Set the short name IndicatorSetString(INDICATOR_SHORTNAME,subwindow_shortname); //--- Set subwindow properties SetSubwindowProperties(); //--- Set button properties SetButtonColors(); // Colors SetButtonCoordinates(); // Coordinates SetButtonSizes(); // Sizes //--- Add the button panel AddButtonsPanel(); //--- Refresh the chart ChartRedraw(); //--- Everything completed successfully return(INIT_SUCCEEDED); }
Dans la fonction AddPrefix(), le préfixe, c'est-à-dire le nom court de l'indicateur, est ajouté au nom de chaque objet graphique. Ceci est nécessaire pour exclure le remplacement/suppression/shift d'objets en cas de correspondance de noms d'objets où plus d'un programme s'exécute sur le graphique.
//+------------------------------------------------------------------+ //| Adding prefix to all object names | //+------------------------------------------------------------------+ void AddPrefix() { //--- Add prefix to object names for(int i=0; i<BUTTON_COLUMNS; i++) for(int j=0; j<BUTTON_ROWS; j++) button_object_names[j][i]=prefix+button_object_names[j][i]; }
Les propriétés du graphique requises pour les calculs seront initialisées dans la fonction SetSubwindowProperties() :
//+------------------------------------------------------------------+ //| Setting subwindow properties | //+------------------------------------------------------------------+ void SetSubwindowProperties() { //--- Indicator subwindow number subwindow_number=ChartWindowFind(0,subwindow_shortname); //--- Subwindow width and height chart_width=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); subwindow_height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,subwindow_number); }
Après avoir obtenu les propriétés du graphique, nous pouvons effectuer des calculs pour déterminer les couleurs des boutons, les valeurs de coordonnées et les tailles. Toutes ces actions sont effectuées dans trois fonctions distinctes fournies ci-dessous :
//+------------------------------------------------------------------+ //| Setting button color | //+------------------------------------------------------------------+ void SetButtonColors() { for(int i=0; i<BUTTON_COLUMNS; i++) { for(int j=0; j<BUTTON_ROWS; j++) { //--- If the button is clicked if(button_states[j][i]) button_colors[j][i]=clicked_background_color; //--- If the button is unclicked else button_colors[j][i]=background_color; } } } //+------------------------------------------------------------------+ //| Setting X and Y coordinates for buttons | //+------------------------------------------------------------------+ void SetButtonCoordinates() { int button_width=chart_width/BUTTON_COLUMNS; int button_height=subwindow_height/BUTTON_ROWS; //--- for(int i=0; i<BUTTON_COLUMNS; i++) { for(int j=0; j<BUTTON_ROWS; j++) { if(i==0) button_x_distances[j][i]=0; else button_x_distances[j][i]=(button_width*i)-i; //--- if(j==0) button_y_distances[j][i]=0; else button_y_distances[j][i]=(button_height*j)-j; } } } //+------------------------------------------------------------------+ //| Setting button width and height | //+------------------------------------------------------------------+ void SetButtonSizes() { int button_width=chart_width/BUTTON_COLUMNS; int button_height=subwindow_height/BUTTON_ROWS; //--- for(int i=0; i<BUTTON_COLUMNS; i++) { for(int j=0; j<BUTTON_ROWS; j++) { if(i==BUTTON_COLUMNS-1) button_widths[j][i]=chart_width-(button_width*(BUTTON_COLUMNS-1)-i); else button_widths[j][i]=button_width; //--- if(j==BUTTON_ROWS-1) button_heights[j][i]=subwindow_height-(button_height*(BUTTON_ROWS-1)-j)-1; else button_heights[j][i]=button_height; } } }
Et enfin, la fonction AddButtonsPanel() ajoute des boutons à la sous-fenêtre de l'indicateur :
//+------------------------------------------------------------------+ //| Adding buttons to the indicator subwindow | //+------------------------------------------------------------------+ void AddButtonsPanel() { //--- Create buttons for(int i=0; i<BUTTON_COLUMNS; i++) { for(int j=0; j<BUTTON_ROWS; j++) { CreateButton(0,subwindow_number,button_object_names[j][i],button_texts[j][i], CORNER_LEFT_UPPER,font_name,8,font_color,button_colors[j][i],clrNONE, button_widths[j][i],button_heights[j][i], button_x_distances[j][i],button_y_distances[j][i],2,true,button_texts[j][i]); } } }
Le code source de la fonction auxiliaire CreateButton() est le suivant :
//+------------------------------------------------------------------+ //| Creating a button (graphical object of the Edit type) | //+------------------------------------------------------------------+ void CreateButton(long chart_id, // chart id int sub_window, // (sub)window number string object_name, // object name string text, // displayed text long corner, // chart corner string font, // font int font_size, // font size color c_font, // font color color c_background, // background color color c_border, // border color int x_size, // width int y_size, // height int x_dist, // X-coordinate int y_dist, // Y-coordinate long zorder, // Z-order bool read_only, // Read Only flag string tooltip) // tooltip { //--- If the object has been created successfully, set the remaining properties if(ObjectCreate(chart_id,object_name,OBJ_EDIT,subwindow_number,0,0)) { ObjectSetString(chart_id,object_name,OBJPROP_TEXT,text); // name ObjectSetInteger(chart_id,object_name,OBJPROP_CORNER,corner); // chart corner ObjectSetString(chart_id,object_name,OBJPROP_FONT,font); // font ObjectSetInteger(chart_id,object_name,OBJPROP_FONTSIZE,font_size); // font size ObjectSetInteger(chart_id,object_name,OBJPROP_COLOR,c_font); // font color ObjectSetInteger(chart_id,object_name,OBJPROP_BGCOLOR,c_background); // background color ObjectSetInteger(chart_id,object_name,OBJPROP_BORDER_COLOR,c_border); // border color ObjectSetInteger(chart_id,object_name,OBJPROP_XSIZE,x_size); // width ObjectSetInteger(chart_id,object_name,OBJPROP_YSIZE,y_size); // height ObjectSetInteger(chart_id,object_name,OBJPROP_XDISTANCE,x_dist); // X-coordinate ObjectSetInteger(chart_id,object_name,OBJPROP_YDISTANCE,y_dist); // Y-coordinate ObjectSetInteger(chart_id,object_name,OBJPROP_SELECTABLE,false); // object is not available for selection ObjectSetInteger(chart_id,object_name,OBJPROP_ZORDER,zorder); // Z-order ObjectSetInteger(chart_id,object_name,OBJPROP_READONLY,read_only); // Read Only text ObjectSetInteger(chart_id,object_name,OBJPROP_ALIGN,ALIGN_CENTER); // align center ObjectSetString(chart_id,object_name,OBJPROP_TOOLTIP,tooltip); // no tooltip if "\n" } }
Veuillez noter le dernier paramètre de la fonction CreateButton() : il est responsable de l'info-bulle lorsque le curseur de la souris passe sur un objet graphique. Par exemple, dans la fonction AddButtonsPanel() ce paramètre est représenté par les valeurs passées du tableau button_texts (texte affiché sur les boutons). Vous pouvez créer un tableau séparé avec des descriptions plus détaillées, si vous le souhaitez.
Maintenant, si vous attachez l'indicateur au graphique, le résultat sera le suivant :
Fig. 1. Boutons ajoutés à la sous-fenêtre de l'indicateur
Pour le moment, ce ne sont que des objets disposés dans la sous-fenêtre de l'indicateur. L'interaction avec l'utilisateur n'est pas encore implémentée. Insufflons maintenant la vie à ces objets.
Tout d'abord, nous allons implémenter la possibilité d'ajuster la taille des boutons en fonction de la taille de la sous-fenêtre lorsque celle-ci est redimensionnée. À cette fin, nous écrirons deux autres fonctions - UpdateButtonCoordinates() et ResizeButtons(). Ils définiront les coordonnées et les tailles des boutons :
//+------------------------------------------------------------------+ //| Updating button coordinates | //+------------------------------------------------------------------+ void UpdateButtonCoordinates() { //--- Set coordinates for(int i=0; i<BUTTON_COLUMNS; i++) { for(int j=0; j<BUTTON_ROWS; j++) { ObjectSetInteger(0,button_object_names[j][i],OBJPROP_XDISTANCE,button_x_distances[j][i]); ObjectSetInteger(0,button_object_names[j][i],OBJPROP_YDISTANCE,button_y_distances[j][i]); } } } //+------------------------------------------------------------------+ //| Updating button sizes | //+------------------------------------------------------------------+ void ResizeButtons() { //--- Set sizes for(int i=0; i<BUTTON_COLUMNS; i++) { for(int j=0; j<BUTTON_ROWS; j++) { ObjectSetInteger(0,button_object_names[j][i],OBJPROP_XSIZE,button_widths[j][i]); ObjectSetInteger(0,button_object_names[j][i],OBJPROP_YSIZE,button_heights[j][i]); } } }
Pour gérer l'événement de modification des propriétés du graphique et de redimensionnement du graphique, nous devons utiliser l'identifiant CHARTEVENT_CHART_CHANGE. Ci-dessous, vous pouvez voir le code que vous devez ajouter aux OnChartEvent() :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // event identifier const long &lparam, // parameter of the event of type long const double &dparam, // parameter of the event of type double const string &sparam) // parameter of the event of type string { //--- Tracking the event of modifying the chart properties and resizing the chart if(id==CHARTEVENT_CHART_CHANGE) { //--- Set subwindow properties SetSubwindowProperties(); //--- Set button coordinates SetButtonCoordinates(); //--- Set button sizes SetButtonSizes(); //--- Set new button coordinates UpdateButtonCoordinates(); //--- Set new button sizes ResizeButtons(); //--- Refresh the chart ChartRedraw(); return; } }
Si nous ajoutons l'indicateur au graphique maintenant (ou recompilons le code si l'indicateur est déjà sur le graphique), les boutons seront automatiquement redimensionnés et repositionnés dès que la fenêtre du graphique ou la sous-fenêtre de l'indicateur sera redimensionnée.
Nous implémentons en outre le changement de couleur du bouton lorsque le curseur survole un bouton. Mais avant d'écrire le code de la fonction, examinons d'abord le processus de gestion de l'événement avec les CHARTEVENT_MOUSE_MOVE identifiant.
Dans la OnInit(), nous avons déjà une chaîne qui indique au programme de suivre le mouvement du curseur de la souris, ainsi que l'état du bouton gauche de la souris :
//--- Enable tracking of mouse events ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
Sans cette chaîne (ou si la dernière valeur de paramètre passée est fausse), les événements avec CHARTEVENT_MOUSE_MOVE ne seront pas suivis dans la OnChartEvent(). Cela peut sembler très utile car il n'est peut-être pas nécessaire de suivre de tels événements dans chaque programme.
Pour comprendre le fonctionnement du suivi des événements souris, nous pouvons ajouter temporairement au code de la fonction OnChartEvent() la possibilité d'afficher le commentaire correspondant dans le graphique :
//--- Mouse movement and left-click tracking if(id==CHARTEVENT_MOUSE_MOVE) { Comment("id: ",CHARTEVENT_MOUSE_MOVE,"\n", "lparam (x): ",lparam,"\n", "dparam (y): ",dparam,"\n", "sparam (state of the mouse buttons): ",sparam );
Si vous commencez maintenant à déplacer le curseur de la souris dans le graphique, vous pourrez voir les coordonnées actuelles du curseur dans le coin supérieur gauche. Lors d'un clic gauche, les modifications seront affichées dans la ligne de commentaire sparam (état des boutons de la souris), où un (1) signifie que le bouton de la souris est cliqué et zéro (0) signifie qu'il est relâché.
Si vous avez besoin de connaître la sous-fenêtre où se trouve actuellement le curseur de la souris, vous pouvez utiliser les ChartXYToTimePrice(). Il obtient les coordonnées et renvoie le numéro de fenêtre/sous-fenêtre, l'heure et le prix (aux variables qui lui sont transmises par référence). Vous pouvez le voir en action en testant le code suivant :
//--- Mouse movement and left-click tracking if(id==CHARTEVENT_MOUSE_MOVE) { int x =(int)lparam; // X-coordinate int y =(int)dparam; // Y-coordinate int window =WRONG_VALUE; // Number of the window where the cursor is located datetime time =NULL; // Time corresponding to the X-coordinate double price =0.0; // Price corresponding to the Y-coordinate //--- Get the position of the cursor if(ChartXYToTimePrice(0,x,y,window,time,price)) { Comment("id: ",CHARTEVENT_MOUSE_MOVE,"\n", "x: ",x,"\n", "y: ",y,"\n", "sparam (state of the mouse buttons): ",sparam,"\n", "window: ",window,"\n", "time: ",time,"\n", "price: ",DoubleToString(price,_Digits) ); } //--- return; }
Les calculs dans la sous-fenêtre de l'indicateur seront plus faciles si des coordonnées relatives sont utilisées. Dans ce cas, il s'agit de la coordonnée Y (barème de prix). Pour obtenir la valeur relative, il vous suffit de soustraire la distance entre le partie supérieure du graphique et la sous-fenêtre de l'indicateur de la valeur actuelle. Cela peut être fait comme suit :
//--- Get the position of the cursor if(ChartXYToTimePrice(0,x,y,window,time,price)) { //--- Get the distance from the chart top to the indicator subwindow chart_y_offset=(int)ChartGetInteger(0,CHART_WINDOW_YDISTANCE,subwindow_number); //--- Convert the Y-coordinate to the relative value y-=chart_y_offset; Comment("id: ",CHARTEVENT_MOUSE_MOVE,"\n", "x: ",x,"\n", "y: ",y,"\n", "sparam (state of the mouse buttons): ",sparam,"\n", "window: ",window,"\n", "time: ",time,"\n", "price: ",DoubleToString(price,_Digits) ); }
Désormais, la valeur de la variable y sera négative si le curseur de la souris est au-dessus de la sous-fenêtre de l'indicateur et positive lorsque le curseur passe sur la zone de la sous-fenêtre.
Par défaut, il est possible de faire défiler le graphique le long de l'échelle de temps, quelle que soit la position du curseur sur le graphique. Le défilement du graphique peut cependant être désactivé, si et quand cela est nécessaire. Cela sera surtout nécessaire lorsque le curseur est situé au-dessus du panneau ou des commandes personnalisées. Le code pour désactiver le défilement du graphique lorsque le curseur est dans la sous-fenêtre de l'indicateur et l'activer lorsque le curseur sort de la sous-fenêtre peut, par exemple, être le suivant :
//--- If the cursor is in the subwindow area, disable chart scrolling if(window==subwindow_number) ChartSetInteger(0,CHART_MOUSE_SCROLL,false); //--- Enable chart scrolling if the cursor moves out of the indicator subwindow area else ChartSetInteger(0,CHART_MOUSE_SCROLL,true);
De plus, écrivons une fonction qui changera la couleur du bouton lorsque le curseur survole le bouton correspondant - ChangeButtonColorOnHover() :
//+------------------------------------------------------------------+ //| Changing the button color when the cursor hovers over the button | //+------------------------------------------------------------------+ void ChangeButtonColorOnHover(int x,int y) { int x1,y1,x2,y2; //--- Initialize the array of XY coordinates for buttons SetButtonCoordinates(); //--- Determine if the cursor is over any of the buttons for(int i=0; i<BUTTON_COLUMNS; i++) { for(int j=0; j<BUTTON_ROWS; j++) { //--- If this button is clicked, go to the next one if(button_states[j][i]) continue; //--- Get the button boundaries x1=button_x_distances[j][i]; y1=button_y_distances[j][i]; x2=button_x_distances[j][i]+button_widths[j][i]; y2=button_y_distances[j][i]+button_heights[j][i]; //--- If the cursor is within the button area, set the new button color if(x>x1 && x<x2 && y>y1 && y<y2) ObjectSetInteger(0,button_object_names[j][i],OBJPROP_BGCOLOR,hover_background_color); //--- Otherwise set the standard color else ObjectSetInteger(0,button_object_names[j][i],OBJPROP_BGCOLOR,background_color); } } }
En conséquence, nous avons le code source suivant dans les CHARTEVENT_MOUSE_MOVE :
//--- Mouse movement and left-click tracking if(id==CHARTEVENT_MOUSE_MOVE) { int x =(int)lparam; // X-coordinate int y =(int)dparam; // Y-coordinate int window =WRONG_VALUE; // Number of the window where the cursor is located datetime time =NULL; // Time corresponding to the X-coordinate double price =0.0; // Price corresponding to the Y-coordinate //--- Get the position of the cursor if(ChartXYToTimePrice(0,x,y,window,time,price)) { //--- Get the distance from the chart top to the indicator subwindow chart_y_offset=(int)ChartGetInteger(0,CHART_WINDOW_YDISTANCE,subwindow_number); //--- Convert the Y-coordinate to the relative value y-=chart_y_offset; //--- If the cursor is in the subwindow area, disable chart scrolling if(window==subwindow_number) ChartSetInteger(0,CHART_MOUSE_SCROLL,false); //--- Enable chart scrolling if the cursor moves out of the indicator subwindow area else ChartSetInteger(0,CHART_MOUSE_SCROLL,true); //--- Change the button color when the cursor is hovered over ChangeButtonColorOnHover(x,y); } //--- Refresh the chart ChartRedraw(); return; }
Maintenant, si vous déplacez le curseur sur les boutons, vous pourrez voir la couleur des boutons changer/revenir à la normale.
Actuellement, seul le bouton 01 a la couleur du bouton cliqué. Si vous essayez de cliquer sur d'autres boutons, il n'y aura aucune réponse et donc aucun changement de couleur. Pour implémenter le changement de couleur dans ce cas, nous devons utiliser un événement avec les CHARTEVENT_OBJECT_CLICK.
Écrivons deux fonctions : InitializeButtonStates() et ChangeButtonColorOnClick(). La fonction InitializeButtonStates() vérifiera si un bouton donné a été cliqué, en tenant compte du préfixe de son nom. Si l'événement click est identifié, le tableau des états des boutons (button_states) est alors initialisé dans une boucle et la fonction retourne true.
//+------------------------------------------------------------------+ //| Initializing button states in case of click | //+------------------------------------------------------------------+ bool InitializeButtonStates(string clicked_object) { //--- Get the indicator subwindow number subwindow_number=ChartWindowFind(0,subwindow_shortname); //--- If a button in the indicator subwindow has been clicked if(ObjectFind(0,clicked_object)==subwindow_number && StringFind(clicked_object,prefix+"button_",0)>=0) { //--- Determine the clicked button for(int i=0; i<BUTTON_COLUMNS; i++) { for(int j=0; j<BUTTON_ROWS; j++) { //--- Determine the state of all buttons if(clicked_object==button_object_names[j][i]) button_states[j][i]=true; else button_states[j][i]=false; } } //--- return(true); } //--- return(false); }
Ensuite, la fonction ChangeButtonColorOnClick() définit les couleurs des boutons en fonction des valeurs du tableau button_states.
//+------------------------------------------------------------------+ //| Changing the button color in case of click | //+------------------------------------------------------------------+ void ChangeButtonColorOnClick() { for(int i=0; i<BUTTON_COLUMNS; i++) { for(int j=0; j<BUTTON_ROWS; j++) { //--- If the button has been clicked, it is set a distinctive color if(button_states[j][i]) ObjectSetInteger(0,button_object_names[j][i],OBJPROP_BGCOLOR,clicked_background_color); //--- Set the standard color to the unclicked button else ObjectSetInteger(0,button_object_names[j][i],OBJPROP_BGCOLOR,background_color); } } }
Pour que tout fonctionne, assurez-vous d'ajouter la gestion des clics sur les boutons à la OnChartEvent() :
//--- Tracking left mouse button clicks on a graphical object if(id==CHARTEVENT_OBJECT_CLICK) { //--- If the button has been clicked if(InitializeButtonStates(sparam)) { //--- Set button colors ChangeButtonColorOnClick(); } //--- Refresh the chart ChartRedraw(); return; }
Désormais, lorsque vous cliquez dessus, le bouton change de couleur.
Nous avons encore quelques points à régler. Dans la OnDeinit(), nous devons activer le défilement du graphique dans la zone de la sous-fenêtre et désactiver le suivi des événements de la souris lors de la suppression de l'indicateur à partir du graphique. Cela peut être important si plusieurs programmes qui utilisent le suivi des événements s'exécutent dans le graphique en même temps.
//+------------------------------------------------------------------+ //| Deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(reason==REASON_REMOVE || // If the indicator has been deleted from the chart or reason==REASON_RECOMPILE) // the program has been recompiled { //--- Deactivate the timer EventKillTimer(); //--- Delete the objects DeleteButtons(); //--- Enable chart scrolling ChartSetInteger(0,CHART_MOUSE_SCROLL,true); //--- Disable tracking of mouse events ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,false); //--- Refresh the chart ChartRedraw(); } }
Fonctions de suppression des objets graphiques du programme :
//+------------------------------------------------------------------+ //| Deleting all buttons | //+------------------------------------------------------------------+ void DeleteButtons() { for(int i=0; i<BUTTON_COLUMNS; i++) for(int j=0; j<BUTTON_ROWS; j++) DeleteObjectByName(button_object_names[j][i]); } //+------------------------------------------------------------------+ //| Deleting the object by name | //+------------------------------------------------------------------+ void DeleteObjectByName(string object_name) { //--- If such object exists if(ObjectFind(0,object_name)>=0) { //--- If an error occurred when deleting, print the relevant message if(!ObjectDelete(0,object_name)) Print("Error ("+IntegerToString(GetLastError())+") when deleting the object!"); } }
Et enfin, voici la raison pour laquelle nous avons besoin d'une minuterie dans ce programme. Par exemple, si plusieurs programmes sont en cours d'exécution dans le graphique et que chacun des programmes est requis pour suivre les événements de la souris, alors lorsque l'un d'entre eux est supprimé du graphique, le suivi sera désactivé dans les OnDeinit () pour tous les programmes. Par conséquent, vous pouvez, à titre d'alternative, exécuter une vérification toutes les secondes pour voir si le suivi des événements de souris est activé :
//+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Check whether tracking of mouse events is enabled CheckChartEventMouseMove(); }
Le code de la fonction CheckChartEventMouseMove() est fourni ci-dessous :
Parfois, il peut être tout à fait suffisant de faire cette vérification pour un événement avec les CHARTEVENT_CHART_CHANGE.
Ci-dessous, vous pouvez voir la vidéo démontrant ce que nous avons obtenu comme résultat :
Conclusion
Eh bien, cela termine essentiellement. L'indicateur TestButtons.mq5 est joint à l'article et est disponible en téléchargement. Avec le développement ultérieur, cet exemple pourrait devenir un menu principal intéressant. Par exemple, l'utilisateur pourrait accéder à l'information pertinente en cliquant sur un certain bouton. Le nombre de boutons peut être augmenté, si nécessaire.
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/750
- 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