
Manuale MQL5: Controlli della finestra secondaria dell'indicatore - Pulsanti
Introduzione
In questo articolo considereremo un esempio di sviluppo di un'interfaccia utente con controlli a pulsante. Per trasmettere l'idea di interattività all'utente, i pulsanti cambiano colore quando il cursore passa sopra di essi. Con il cursore posizionato su un pulsante, il colore del pulsante sarà leggermente più scuro, diventando notevolmente più scuro quando si fa clic su di esso. Inoltre, aggiungeremo suggerimenti a ciascun pulsante, creando così un'interfaccia intuitiva.
L'articolo tratterà anche alcuni eventi: l'evento di spostamento del mouse, lo stato del pulsante sinistro del mouse, il clic sinistro su un oggetto e l'evento di modifica delle proprietà del grafico. Creeremo un pannello dei pulsanti che occuperà l'intero spazio della sottofinestra dell'indicatore. A scopo illustrativo, i pulsanti saranno disposti su tre file, con quattro pulsanti in ciascuna riga.
Sviluppo
In MQL5, i pulsanti possono essere creati utilizzando vari oggetti grafici, come OBJ_BUTTON (Button), OBJ_BITMAP (Bitmap), OBJ_BITMAP_LABEL (Bitmap Label) o OBJ_EDIT (Edit).
In questo articolo, creeremo pulsanti utilizzando OBJ_EDIT. Gli oggetti di questo tipo possono essere resi di sola lettura. Sono anche utili in quanto possono visualizzare il testo specificato. Inoltre, puoi rendere nitidi gli angoli dell'oggetto, mantenendone il bordo.
Quindi, creiamo un indicatore utilizzando la procedura guidata MQL5. Leggermente rielaborato, il codice sorgente dell'indicatore sarà il seguente:
//+------------------------------------------------------------------+ //| 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) { //--- } //+------------------------------------------------------------------+
Quello che abbiamo adesso è una finestra vuota con zero serie di grafici. La necessità di un timer sarà discussa un po' più avanti.
Aggiungiamo ora costanti, variabili e array che verranno utilizzati nella creazione di funzioni. Tutti gli array sono bidimensionali. La prima dimensione indica il numero di pulsanti lungo l'altezza della finestra e la seconda dimensione indica il numero di pulsanti lungo la larghezza della finestra:
//--- #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];
Durante il caricamento dell'indicatore nel grafico, gli array devono essere inizializzati alle proprietà dell'oggetto nelle OnInit(), dopo aver calcolato le coordinate e le dimensioni. Dovremmo anche abilitare il tracciamento del cursore. E infine, dobbiamo aggiungere pulsanti alla sottofinestra dell'indicatore. Per comodità, queste azioni verranno eseguite in funzioni separate che esamineremo una per una più avanti. Di conseguenza, le OnInit() avrà il seguente aspetto:
//+------------------------------------------------------------------+ //| 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); }
Nella funzione AddPrefix(), al nome di ogni oggetto grafico viene aggiunto il prefisso, ovvero il nome breve dell'indicatore. Ciò è necessario per escludere la sostituzione/cancellazione/spostamento di oggetti in caso di nomi di oggetti corrispondenti in cui è in esecuzione più di un programma sul grafico.
//+------------------------------------------------------------------+ //| 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]; }
Le proprietà del grafico necessarie per i calcoli verranno inizializzate nella funzione 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); }
Dopo aver ottenuto le proprietà del grafico, possiamo eseguire calcoli per determinare i colori dei pulsanti, i valori delle coordinate e le dimensioni. Tutte queste azioni vengono eseguite in tre funzioni separate fornite di seguito:
//+------------------------------------------------------------------+ //| 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; } } }
E infine, la funzione AddButtonsPanel() aggiunge pulsanti alla sottofinestra dell'indicatore:
//+------------------------------------------------------------------+ //| 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]); } } }
Il codice sorgente della funzione ausiliaria CreateButton() è il seguente:
//+------------------------------------------------------------------+ //| 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" } }
Notare l'ultimo parametro della funzione CreateButton(): è responsabile del suggerimento quando il cursore del mouse passa su un oggetto grafico. Ad esempio, nella funzione AddButtonsPanel() questo parametro è rappresentato dai valori passati dall'array button_texts (testo visualizzato sui pulsanti). Se lo desideri, puoi creare un array separato con descrizioni più dettagliate.
Ora, se colleghi l'indicatore al grafico, il risultato sarà il seguente:
Fig. 1. Pulsanti aggiunti alla sottofinestra dell'indicatore
Al momento, questi sono semplici oggetti disposti nella sottofinestra dell'indicatore. L'interazione con l'utente non è ancora stata implementata. Ora "respiriamo vita" in questi oggetti.
Innanzitutto implementeremo la possibilità di regolare le dimensioni dei pulsanti in base alle dimensioni della sottofinestra quando quest'ultima viene ridimensionata. A questo scopo, scriveremo altre due funzioni: UpdateButtonCoordinates() e ResizeButtons(). Imposteranno le coordinate e le dimensioni dei pulsanti:
//+------------------------------------------------------------------+ //| 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]); } } }
Per gestire l'evento di modifica delle proprietà del grafico e ridimensionamento del grafico, è necessario utilizzare CHARTEVENT_CHART_CHANGE. Di seguito puoi vedere il codice che devi aggiungere alle 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; } }
Se aggiungiamo ora l'indicatore al grafico (o ricompiliamo il codice se l'indicatore è già sul grafico), i pulsanti verranno automaticamente ridimensionati e riposizionati non appena verrà ridimensionata la finestra del grafico o la sottofinestra dell'indicatore.
Implementiamo ulteriormente la modifica del colore del pulsante quando il cursore passa sopra un pulsante. Ma prima di scrivere il codice della funzione, esaminiamo prima il processo di consegna dell'evento con i CHARTEVENT_MOUSE_MOVE.
Nelle OnInit(), abbiamo già una stringa che dice al programma di tenere traccia del movimento del cursore del mouse, nonché dello stato del pulsante sinistro del mouse:
//--- Enable tracking of mouse events ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
Senza questa stringa (o se l'ultimo valore del parametro passato è falso), gli eventi con l'identificatore CHARTEVENT_MOUSE_MOVE non verranno tracciati nelle OnChartEvent(). Questo può sembrare molto utile in quanto potrebbe non essere necessario tenere traccia di tali eventi in ogni programma.
Per capire come funziona il tracciamento degli eventi del mouse, possiamo aggiungere temporaneamente al codice della funzione OnChartEvent() la possibilità di visualizzare il commento corrispondente nel grafico:
//--- 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 );
Se ora inizi a spostare il cursore del mouse nel grafico, sarai in grado di vedere le coordinate correnti del cursore nell'angolo in alto a sinistra. Quando si fa clic con il tasto sinistro, le modifiche verranno visualizzate nella riga di commento sparam (stato dei pulsanti del mouse), dove uno (1) significa che il pulsante del mouse è stato cliccato e zero (0) significa che è stato rilasciato.
Se è necessario conoscere la sottofinestra in cui si trova attualmente il cursore del mouse, è possibile utilizzare le ChartXYToTimePrice(). Ottiene le coordinate e restituisce il numero della finestra/sottofinestra, l'ora e il prezzo (alle variabili passate per riferimento). Puoi vederlo in azione testando il seguente codice:
//--- 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; }
I calcoli nella sottofinestra dell'indicatore saranno più facili se vengono utilizzate le coordinate relative. In questo caso, riguarda la coordinata Y (scala dei prezzi). Per ottenere il valore relativo, devi solo sottrarre la distanza dalla parte superiore del grafico alla sottofinestra dell'indicatore dal valore corrente. Questo può essere fatto come segue:
//--- 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) ); }
Ora, il valore nella variabile y sarà negativo se il cursore del mouse si trova sopra la sottofinestra dell'indicatore e positivo quando il cursore passa sopra l'area della sottofinestra.
Per impostazione predefinita, è possibile scorrere il grafico lungo la scala temporale, indipendentemente dalla posizione del cursore sul grafico. Lo scorrimento del grafico può comunque essere disabilitato, se e quando necessario. Sarà principalmente necessario quando il cursore si trova sopra il pannello o i controlli personalizzati. Il codice per disabilitare lo scorrimento del grafico quando il cursore si trova nella sottofinestra dell'indicatore e abilitarlo quando il cursore si sposta fuori dalla sottofinestra può essere, ad esempio, il seguente:
//--- 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);
Inoltre, scriviamo una funzione che cambierà il colore del pulsante quando il cursore passa sopra il pulsante corrispondente - 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); } } }
Di conseguenza, abbiamo il seguente codice sorgente nei 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; }
Ora, se sposti il cursore sui pulsanti, sarai in grado di vedere il colore del pulsante cambiare / tornare alla normalità.
Attualmente, solo il pulsante 01 ha il colore del pulsante cliccato. Se provi a fare clic su altri pulsanti, non ci sarà risposta e quindi nessun cambiamento di colore. Per implementare il cambio di colore in questo caso, è necessario utilizzare un evento con l'identificatore CHARTEVENT_OBJECT_CLICK.
Scriviamo due funzioni: InitializeButtonStates() e ChangeButtonColorOnClick(). La funzione InitializeButtonStates() verificherà se un dato pulsante è stato cliccato, prendendo in considerazione il prefisso nel suo nome. Se viene identificato l'evento click, l'array di stati del pulsante (button_states) viene quindi inizializzato in un ciclo e la funzione restituisce 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); }
Successivamente, la funzione ChangeButtonColorOnClick() imposta i colori dei pulsanti in base ai valori dell'array 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); } } }
Per far funzionare tutto, assicurati di aggiungere la gestione dei clic sui pulsanti alla funzione di tracciamento degli 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; }
Ora, una volta cliccato, il pulsante cambierà colore.
Abbiamo ancora alcuni punti di cui dobbiamo occuparci. Nelle OnDeinit(), dovremmo abilitare lo scorrimento del grafico nell'area della sottofinestra e disabilitare il tracciamento degli eventi del mouse, quando si elimina l'indicatore dal grafico. Questo può essere importante se nel grafico sono in esecuzione contemporaneamente più programmi che utilizzano il rilevamento degli eventi.
//+------------------------------------------------------------------+ //| 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(); } }
Funzioni per la cancellazione degli oggetti grafici del programma:
//+------------------------------------------------------------------+ //| 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!"); } }
E infine, ecco il motivo per cui abbiamo bisogno di un timer in questo programma. Ad esempio, se nel grafico è in esecuzione più di un programma e ciascuno dei programmi deve tenere traccia degli eventi del mouse, quando uno di essi viene eliminato dal grafico, il monitoraggio verrà disabilitato nelle OnDeinit() funzione per tutti i programmi. Pertanto, in alternativa, puoi eseguire un controllo ogni secondo per vedere se il monitoraggio degli eventi del mouse è abilitato:
//+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Check whether tracking of mouse events is enabled CheckChartEventMouseMove(); }
Il codice della funzione CheckChartEventMouseMove() è fornito di seguito:
A volte, può essere sufficiente eseguire questo controllo per un evento con i CHARTEVENT_CHART_CHANGE.
Di seguito puoi vedere il video che mostra ciò che abbiamo ottenuto come risultato:
Conclusione
Bene, siamo arrivati alla fine. L'indicatore TestButtons.mq5 è allegato all'articolo ed è disponibile per il download. Con un ulteriore sviluppo, questo esempio potrebbe diventare un menu principale interessante. Ad esempio, l'utente potrebbe passare all'informazione pertinente facendo clic su un determinato pulsante. Il numero di pulsanti potrebbe essere aumentato, se necessario.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/750





- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso