English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Controlli Grafici Personalizzati. Parte 3. Moduli

Controlli Grafici Personalizzati. Parte 3. Moduli

MetaTrader 5Esempi | 9 dicembre 2021, 14:16
82 0
Dmitry Fedoseev
Dmitry Fedoseev

 

Introduzione

Il primo articolo "Creazione di un Controllo Semplice" ha trattato i principi di creazione del controllo grafico e ha fornito un esempio passo-passo che dimostra la creazione di un controllo semplice. L'articolo di continuazione "Control Library" ha predisposto una serie di controlli già pronti. C'è ancora un altro componente molto importante dell'interfaccia grafica: il modulo.

Il modulo rappresenta una parte rettangolare appositamente designata dello schermo su cui vengono mostrati i controlli. Inoltre, il form è anche un contenitore che permette di gestire contemporaneamente tutti i controlli che contiene: nasconderli, visualizzarli e spostarli tutti insieme.

L'articolo di chiusura enuncia la creazione dei moduli e il loro utilizzo in combinazione con i controlli.

Le classi per l'utilizzo dei moduli sono state aggiunte al file IncGUI.mqh utilizzato negli articoli precedenti (il nuovo nome file è IncGUI_v3.mqh). Oltre alle classi per lavorare con i moduli, sono state aggiunte altre classi al file, le classi CHMenu (Horizontal Menu) e CVMenu (Vertical Menu) sono state aggiornate e sono stati corretti alcuni errori.

Classi aggiunte:

  • Classe CFrame - Frame. La classe è identica al frame creato dal metodo Frame della classe CWorkPiece.
  • Classe CButton - Pulsante. Un pulsante normale (OBJ_BUTTON).
  • Classe CLabel - Etichetta. Oltre a visualizzare l'etichetta come viene fatto dall'oggetto grafico "Label" (OBJ_LABEL), questa classe consente la visualizzazione di un testo in poche righe in cui le linee sono separate dal simbolo "\n".

Come risultato dell'aggiunta di nuove classi, la classe CColorSchemes è stata modificata, come segue: sono stati aggiunti i colori per i nuovi controlli.

Modifiche nelle classi CHMenu e CVMenu: le modifiche applicate consentono di creare menu a due livelli con tab a cascata. Questo sarà considerato in modo più dettagliato nella sezione "Creazione del Menu Principale" di seguito.

Errori: una correzione nel metodo Frame() della classe CWorkPiece - non è stato possibile impostare un numero di sottofinestra per un'etichetta rettangolare. Classe CListMS - Metodi Selected() e SetSelected() - la dimensione dell'array è ora selezionata, altrimenti era impossibile utilizzare un elenco vuoto.

 

1. Moduli

Il modulo si basa sugli oggetti grafici "Rectangle Label" OBJ_RECTANGLE_LABEL con l'uso di diversi pulsanti OBJ_BUTTON. Visivamente, il modulo rappresenta un rettangolo (Fig. 1) con una barra nella parte superiore del modulo in cui vengono visualizzati il nome del modulo e i pulsanti di controllo.

Un pulsante che sposta il modulo (con un'immagine a mano) si trova a sinistra, il pulsante di minimizzazione (con un'immagine rettangolare) e il pulsante di chiusura (con un'immagine incrociata) si trovano a destra.

Fig. 1. Modulo

Fig. 1. Modulo

Per spostare il modulo, premere il pulsante di spostamento (il pulsante entrerà nella posizione premuta) e fare click in un punto qualsiasi del grafico in cui il modulo deve essere spostato. Di conseguenza, il pulsante di spostamento verrà rilasciato e il modulo si sposterà nella posizione indicata (il suo angolo in alto a sinistra sarà situato sul punto cliccato).

Se la posizione indicata si trova sul bordo del grafico e il modulo deve essere posizionato al di fuori del bordo del grafico, la posizione del modulo verrà regolata in modo che sia completamente visibile sul grafico.

È possibile creare diversi tipi di moduli:

  • Tipo 0 (Fig. 1);
  • Tipo 1 - con pulsanti aggiuntivi "Annulla" e "Applica" (Fig. 2);
  • Tipo 2 - con pulsante "Close" aggiuntivo (Fig. 3);

Fig. 2. Modulo di tipo 1 (con i pulsanti "Annulla" e "Applica")

Fig. 2. Modulo di tipo 1 (con i pulsanti "Annulla" e "Applica")

Fig. 3. Forma di tipo 2 (con il pulsante "Chiudi")

Fig. 3. Forma di tipo 2 (con il pulsante "Chiudi")

I mezzi programmatici per lavorare con i moduli sono rappresentati da due classi: CFormBase e CFormTemplate.

La classe CFormBase è una classe base mentre CFormTemplate è una sottoclasse della classe CFormBase. In effetti e in linea di principio (incluso il principio dell'applicazione), la classe CFormBase è esattamente lo stesso controllo degli altri controlli descritti in precedenza.

La classe CFormBase dispone del metodo Init() per la preparazione del controllo, dei metodi SetPos() e Show() per la visualizzazione di un form (creazione di oggetti grafici che rappresentano un form), del metodo Hide() per nascondere, del metodo Refresh() per l'aggiornamento della visualizzazione, del metodo Event() per la gestione degli eventi e di altri metodi come in tutti gli altri controlli.

L'applicazione di un modulo e l'uso dei controlli inizia con la chiamata del metodo Init(), seguita dall'impostazione di una posizione con l'uso del metodo SetPos() e dall'abilitazione della visualizzazione con il metodo Show(), altrimenti la visualizzazione può essere abilitata utilizzando solo il metodo Show() con parametri e un modulo può essere nascosto utilizzando il metodo Hide().

Una chiamata al metodo Event() viene aggiunta alla funzione OnChartEvent() per garantire la capacità di controllo del modulo (spostamento, minimizzazione, chiusura e così via). Laddove sia necessario garantire il funzionamento del modulo in una sottofinestra, viene utilizzato il metodo SetSubWindow() che viene chiamato subito dopo aver chiamato il metodo Init() e nella funzione OnChartEvent() al momento dell'evento CHARTEVENT_CHART_CHANGE. Tutto è uguale agli altri controlli.

Mentre i controlli standard sono indipendenti (non devono essere associati ad altri controlli), il modulo implica l'esistenza di un'associazione obbligatoria con altri controlli al fine di garantire la visualizzazione/occultamento simultanei dei controlli situati nel modulo insieme all'occultamento/visualizzazione del modulo. Pertanto, dovrebbe essere garantita un'operazione sincronizzata dei metodi Init(), Show() e Hide() del form e dei relativi controlli.

Certamente, si può semplicemente chiamare (ad esempio quando si chiama il metodo Show() del form) i metodi Show() di tutti i controlli relativi al form, ma quando nel programma vengono utilizzati diversi form tale approccio si tradurrà in un codice non strutturato e scomodo per la comprensione, il debug e l'aggiornamento.

È possibile creare una copia della classe del modulo per ogni modulo e aggiungere codice funzionante con controlli al suo livello; tuttavia ciò comporterà nuovamente il codice non strutturato (in cui il codice del modulo non sarà separato dal codice relativo all'operazione di controllo), un'eccessiva duplicazione del codice in cui verrà duplicata solo la parte di codice responsabile della progettazione e della funzionalità del modulo; tutto ciò complicherà l'applicazione delle modifiche a qualsiasi funzione del modulo in quanto richiederà le modifiche da apportare in ogni copia della classe.

La divisione in classe base e sottoclasse aiuta a risolvere il problema della creazione di più moduli, la sincronizzazione della visualizzazione del modulo e dei relativi controlli e la chiara separazione del codice relativo a diversi moduli. Oltre a risolvere i problemi di base, l'uso della classe e della sottoclasse consentirà il futuro aggiornamento della classe base senza dover apportare modifiche al lavoro già completato.

Per sincronizzare la chiamata dei metodi Init(), Show() e Hide() dei controlli e del modulo, la classe CFormBase presenta alcune differenze rispetto alla classe di controllo standard: alcuni metodi virtuali in una sezione protetta:

virtual void MainProperties() {}
virtual void OnInitEvent() {}
virtual void OnShowEvent() {}
virtual void OnHideEvent() {}
virtual void EventsHandler(const int id, const long& lparam, const double& dparam, const string& sparam){}
virtual void OnWindowChangeEvent(int aSubWindow) {}
virtual bool OnCancelEvent() {return(true);}
virtual bool OnApplyEvent()  {return(true);} 

Questi metodi sono virtuali, il che significa che il reindirizzamento ai corrispondenti metodi reali della sottoclasse CFormTemplate viene effettuato tramite di essi.

La sottoclasse CFormTemplate non viene utilizzata da sola, è un modello. Per creare un nuovo modulo, creare una copia della classe CFormTemplate con un nome univoco (basta copiare il codice della classe CFormTemplate, rinominarlo e ripetere lo stesso per ogni modulo). La copia delle sottoclassi consente la separazione del codice relativo ai diversi moduli.

I metodi virtuali si trovano nella sezione protetta e saranno quindi inaccessibili per una chiamata che non è nemmeno necessaria poiché i metodi sono già chiamati dalla classe base in base a diversi eventi del modulo - è necessario aggiungere solo un codice per il funzionamento dei controlli corrispondenti a questi eventi.

Il grafico sottostante mostra l'interazione tra le funzioni dell’Expert Advisor e i metodi di classe di controllo standard. (Fig. 4) e come confronto l'interazione con i metodi della classe dei moduli (Fig. 5).

Fig. 4. Interazione tra le funzioni dell’Expert Advisor e i metodi di controllo
Fig. 4. Interazione tra le funzioni dell’Expert Advisor e i metodi di controllo

Fig. 5. Interazione tra le funzioni dell’Expert Advisor e i metodi della classe dei moduli
Fig. 5. Interazione tra le funzioni dell’Expert Advisor e i metodi della classe moduli

Esaminiamo lo scopo di ciascun metodo in dettaglio:

  • I metodi MainProperties() e OnInitEvent() vengono chiamati dal metodo Init() del modulo. Il metodo MainProperties() imposta l'aspetto del modulo (tipo di modulo, presenza dei pulsanti di spostamento, minimizza e chiusura). Il metodo OnInitEvent() chiama i metodi Init() di tutti i controlli e imposta i valori predefiniti sui controlli.

  • Il metodo OnShowEvent() viene chiamato dal metodo Show(); ad esso viene aggiunto il codice di chiamata dei metodi Show() di tutti i controlli.

  • Il metodo OnHideEvent() viene chiamato dal metodo Hide(); ad esso viene aggiunto il codice di chiamata dei metodi Hide() di tutti i controlli.

  • Il metodo EventsHandler() è equivalente alla funzione OnChartEvent() dell’Expert Advisor. Il metodo Event() del modulo viene chiamato dalla funzione OnChartEvent() dell’Expert Advisor e tutti gli eventi del grafico vengono semplicemente reindirizzati a questo metodo. Il codice di chiamata dei metodi Event() di tutti i controlli e la gestione degli eventi corrispondente vengono aggiunti a EventsHandler().

  • Il metodo OnWindowChangeEvent() viene chiamato dal metodo SetSubWindow() quando si modifica una sottofinestra. Ad esso viene aggiunto il codice di chiamata dei metodi SetSubWindow() di tutti i controlli. Il metodo dispone di un parametro che trasmette un nuovo numero di sottofinestra da impostare in tutti i controlli.

  • Il metodo OnCancelEvent() viene eseguito alla chiusura del modulo (quando si clicca sul pulsante con un'immagine incrociata, i pulsanti "Annulla" o "Chiudi"). È possibile aggiungere un codice di controllo alla chiusura del modulo, ad esempio una chiamata di una finestra di conferma per assicurarsi che il modulo debba essere chiuso. Se il metodo restituisce true, il codice che chiude il modulo verrà completato e il modulo verrà chiuso; se il metodo restituisce false, l'esecuzione del codice che chiude il modulo verrà interrotta e il modulo rimarrà aperto.

  • Il metodo OnApplyEvent() viene eseguito quando si clicca sul pulsante "Applica" del modulo. Qui (come nel metodo OnCancelEvent()) si può eseguire qualche controllo e vedere se il metodo restituisce true o false permettendo o non permettendo così al modulo di chiudersi. Questo metodo può anche contenere un codice per il salvataggio dei valori di controllo in modo che i valori di controllo all'avvio successivo dell’Expert Advisor siano gli stessi di prima della chiusura del programma. A tale scopo, i valori salvati devono essere caricati nel metodo OnInitEvent() e impostati sui controlli.

 

2. Procedura Step-By-Step per la Creazione di un Nuovo Modulo

Quindi una procedura step-by-step per la creazione di un nuovo modulo è, la seguente:

1. Includi il file IncGUI_v3.mqh.

#include <IncGUI_v3.mqh>
2. Copiare il codice della classe CFormTemplate dal file IncGUI_v3.mqh a un file di Expert Advisor (la sottoclasse si trova alla fine del file) e rinominarlo (nell'esempio dell'uso della libreria la sottoclasse è denominata CForm). 

 

class CFormTemplate: public CFormBase{
   public:
   protected      void MainProperties()
     {
        m_Name        = "Form";       // Form name. The names of all the controls of this form should start with it.
        m_Width       = 200;           // Form width
        m_Height      = 150;           // Form height
        m_Type        = 1;             // Form type: 0 - without buttons, 1 - with "Apply" and "Cancel" buttons, 2 - with the "Close" button
        m_Caption     = "FormCaption"; // Form caption
        m_Movable     = true;          // Movable form (the button with a hand image is displayed in the top left corner)
        m_Resizable   =  true;         // Form minimizing/maximizing allowed (the button with a rectangle image 
                                           // is displayed in the top right corner)
        m_CloseButton = true;          // Form closing allowed (the button with a cross image is displayed in the top right corner)
     }
      void OnInitEvent() {} 
      void OnShowEvent(int aLeft, int aTop) {}
      void OnHideEvent() {}
      void OnWindowChangeEvent(int aSubWindow) {}
      void EventsHandler(const int id,const long& lparam,const double& dparam,const string& sparam){}
      bool OnApplyEvent()  {return(true);}
      bool OnCancelEvent() {return(true);}
};

È possibile creare un file di include separato per il codice del modulo, includerlo in Expert Advisor, copiare il codice della sottoclasse CFormTemplate in esso ed eseguire la codifica rimanente relativa all'operazione del modulo in questo file.

Disegnando un'analogia con l'uso di un editor visivo, questo passaggio sarebbe abbastanza simile a fare click sul pulsante per creare un nuovo modulo in seguito al quale un nuovo file di modulo con funzioni di vari eventi del modulo apparirebbe nel progetto.

3. Impostare le proprietà principali del modulo. Questo passaggio viene eseguito nel metodo MainProperties() assegnando valori alle variabili dichiarate nella classe base. Commenti dettagliati sugli scopi di tutte le variabili sono forniti nel template. È possibile notare la somiglianza di questo passaggio con l'utilizzo della finestra delle proprietà del modulo in un editor visivo (ad esempio VBA in Excel).

void MainProperties()
{
   m_Name         =  "Form";        // Form name. The names of all the controls of this form should start with this one.
   m_Width        =  200;           // Form width
   m_Height       =  150;           // Form height
   m_Type         =  1;             // Form type: 0 - without buttons, 1 - with "Apply" and "Cancel" buttons, 2 - with the "Close" button
   m_Caption      =  "FormCaption";   // Form caption
   m_Movable      =  true;          // Movable form (the button with a hand image is displayed in the top left corner)
   m_Resizable    =  true;          // Form minimizing/maximizing allowed (the button with a rectangle image 
                                    // is displayed in the top right corner)
   m_CloseButton = true;            // Form closing allowed (the button with a cross image is displayed in the top right corner)
}

Si può notare un'altra differenza del modulo rispetto agli altri controlli: il nome del modulo viene impostato nel metodo MainProperties() anziché essere trasmesso come parametro del metodo Init().

Il lavoro principale sul modulo viene svolto in una sottoclasse; ogni sottoclasse del modulo viene dichiarata una sola volta, quindi non è necessario specificare nomi diversi quando si chiama il metodo Init() di una sottoclasse del modulo.

L'unico parametro che può essere trasmesso al metodo Init() è il parametro State ma anche questo non è obbligatorio. Il valore del parametro State determina lo stato iniziale del modulo quando viene visualizzato: ingrandito o ridotto a icona. Se il valore è 1, il modulo viene massimizzato (Fig. 1, 2, 3), se il valore è 2, il modulo è ridotto a icona (Fig. 6).

Fig. 6. Modulo ridotto a icona

Fig. 6. Modulo ridotto a icona

4. Dichiarare una classe.

CForm frm;

5. Effettuare passaggi standard per l'utilizzo del controllo: chiama il metodo Init() del modulo dalla funzione OnInit() di Expert Advisor, chiama il metodo Deinit() dalla funzione OnDeinit(), chiamare il metodo Event() dalla funzione OnChartEvent() e, se necessario, chiama il metodo SetSubWindow() al momento dell'evento CHARTEVENT_CHART_CHANGE.

Il modulo dovrebbe in seguito essere visibile nel grafico e rispondere al click sui pulsanti sposta, riduci a icona, chiudi, ecc.

Si procede, quindi, all'aggiunta dei controlli al modulo.

 

3. Procedura Step-By-Step per l'Aggiunta dei Controlli ai Moduli

  1. Dichiarazione dei controlli. Se è necessario garantire l'accesso ai metodi di controllo all'esterno del modulo, le classi di controllo devono essere dichiarate nella sezione pubblica; se tutto il lavoro può essere eseguito all'interno della classe di modulo, le classi di controllo devono essere dichiarate nella sezione protetta.

  2. Dichiarazione delle variabili per ripristinare i valori di controllo. Un passaggio facoltativo. Se si utilizza il modulo con i pulsanti "Annulla" e "Applica", è necessario aggiungere una variabile a ogni controllo per memorizzare il valore che il controllo aveva all'apertura del modulo al fine di ripristinare il valore se un utente modifica il valore del controllo ma preme il pulsante "Annulla".

  3. Chiamata dei metodi Int() di tutti i controlli. Viene eseguito nel metodo OnInitEvent().

  4. Caricamento dei dati salvati. Un passaggio facoltativo. Viene eseguito nel metodo OnInitEvent(). Il passaggio viene utilizzato quando è necessario che i controlli mantengano i loro valori dopo il riavvio dell’Expert Advisor, Terminale o computer. Il salvataggio dei dati viene eseguito nel passaggio 12.

  5. Impostazione dei valori predefiniti. In questo passaggio, tutti i controlli vengono impostati su valori che verranno visualizzati nei controlli alla prima apertura del modulo dopo l'avvio dell’Expert Advisor (fino a quando i loro valori non vengono modificati da un utente). Se i dati sono stati caricati nel passaggio 4, vengono utilizzati i dati caricati. In questo passaggio, viene eseguita anche un'ulteriore preparazione dei controlli, ad esempio qui vengono aggiunte anche le voci di elenco e di menu.

  6. La chiamata dei metodi Show() (versione con i parametri) per tutti i controlli viene eseguita nel metodo OnShowEvent(). Il metodo OnShowEvent() dispone di due parametri (int aLeft, int aTop) che trasmettono le coordinate dell'angolo superiore sinistro dell'area di lavoro del modulo. Le posizioni di controllo sono impostate in base ai valori di queste variabili (i valori devono essere aggiunti).

  7. Una chiamata del metodo Hide()per tutti i controlli del modulo viene eseguita nel metodo OnHideEvent().

  8. Chiamata al metodo SetSubWindow(). Un passaggio facoltativo. Se è necessario visualizzare il modulo in una sottofinestra, viene chiamato il metodo SetSubWindow() per tutti i controlli. Viene eseguito nel metodo OnWindowChangeEvent() che dispone di un parametro (int aSubWindow) che trasmette un nuovo numero di sottofinestre.

  9. Chiamata dei metodi Event() di tutti i controlli. Questo viene eseguito nel metodo EventsHandler().

  10. Gestione degli eventi di controllo. Un passaggio facoltativo. Se è necessario garantire l'interazione tra i controlli in base ai loro eventi, è in questo passaggio che gli eventi vengono gestiti e vengono eseguite le azioni appropriate. Questo viene eseguito nel metodo EventsHandler().

  11. Applicazione di nuovi valori. Un passaggio facoltativo che viene eseguito utilizzando il pulsante "Applica". Viene eseguito nel metodo OnApplyEvent(). In questo passaggio, i valori di controllo vengono esaminati per verificarne l'accuratezza; se vengono trovati valori errati, l'utente deve essere avvisato, il metodo deve restituire false e il modulo rimarrà aperto. Se i valori sono corretti, true deve essere restituito per la chiusura del modulo.

  12. Salvataggio dei dati. Un passaggio facoltativo. Viene eseguito nel metodo OnApplyEvent() utilizzando il pulsante "Applica". I dati possono essere salvati (a seconda degli obiettivi e degli scopi) in un file, variabili globali, oggetti invisibili nel grafico, ecc.

  13. Controllare il metodo OnCancelEvent(). Un passaggio facoltativo. Se false viene restituito dal metodo OnCancelEvent(), il modulo rimarrà aperto, ovvero il pulsante di chiusura non risponderà. Affinché il modulo venga chiuso, true deve essere restituito dal metodo.

Un esempio di utilizzo dei moduli è disponibile nel file allegato eIncGUI_v3_Test_Form.mq5. Il modulo principale con diversi controlli si apre all'avvio (Fig. 7).

Si noti che il modulo non dispone di un pulsante di chiusura; questa è la forma principale e non dovrebbe essere fatta sparire dal grafico altrimenti l'Expert Advisor dovrà essere riavviato affinché il modulo ricompaia.

Fig. 7. Modulo principale dall'esempio eIncGUI_v3_Test_Form.mq5 con un tab del menu principale aperto

Fig. 7. Modulo principale dall'esempio eIncGUI_v3_Test_Form.mq5 con un tab del menu principale aperto

Utilizzando i comandi del menu principale, è possibile aprire le altre due varianti del modulo.

Menu principale - Tipi di modulo - Il tipo 1 apre un modulo di tipo 1 (con i pulsanti "Annulla" e "Applica").
Menu principale - Tipi di modulo - Il tipo 2 apre un modulo di tipo 2 (con il pulsante "Chiudi").

Entrambi i moduli richiedono una conferma alla loro chiusura (effettuata utilizzando la funzione MessageBox(). Il modulo di tipo 1 ha una casella di input; un valore di input viene controllato facendo click sul pulsante "Applica". Il modulo di tipo 2 ha un nuovo controllo "Label" (classe CLabel) e alcuni pulsanti (classe CButton) per testarlo.

Ora, come accennato nell'introduzione, esaminiamo le modifiche nelle classi CHMenu e CVMenu come esemplificato creando il menu principale.

 

Prima di tutto, vorrei dire che è possibile creare solo menu a due livelli: una barra orizzontale (basata sulla classe CHMenu) e tab (basati sulla classe CVMenu). In linea di principio, è possibile creare ancora più livelli ma il processo sarà molto complicato e laborioso, motivo per cui non è raccomandato e non sarà considerato ulteriormente.

In effetti, la creazione del menu principale per il modulo non era nemmeno pianificata e le classi CHMenu e CVMenu dovevano essere utilizzate individualmente e indipendentemente l'una dall'altra per abilitare/disabilitare varie funzioni e strumenti. Tuttavia, un leggero miglioramento delle classi CHMenu e CVMenu ha permesso di ottenere il menu principale che è abbastanza adatto per la maggior parte dei casi.

Per creare un menu multilivello a tutti gli effetti, è necessario applicare un approccio un po’ diverso (creazione di una struttura di dati ad albero) che può servire un argomento per un intero articolo separato, quindi ora ci limiteremo ai mezzi esistenti.

Esaminiamo prima tutte le modifiche e le correzioni applicate alle classi CHMenu e CVMenu.

Nella classe CVMenu, è stata fissata una risposta al click sull'oggetto grafico "Label" che viene utilizzato per visualizzare il simbolo del tick. Di conseguenza, ci sono state modifiche nel funzionamento dei metodi LastClickedX(), LastClickedY() e LastClickedQuarter(). Quando si fa click sulle etichette, i valori vengono ora restituiti come nel caso delle caselle di testo. Correzioni simili sono state applicate ai metodi di classe CHMenu e LastClickedX(), LastClickedY(), LastClickedQuarter() e LastClickedW().

Entrambe le classi sono state aggiornate aggiungendo i metodi SolvePosX() e SolvePosY() destinati al calcolo delle coordinate di un oggetto grafico visualizzato nel comando di menu. La larghezza dell'oggetto visualizzato viene trasmessa al metodo SolvePosX() e l'altezza dell'oggetto visualizzato viene trasmessa al metodo SolvePosY() che restituisce rispettivamente le coordinate X o Y dell'oggetto visualizzato. Ora non è più necessario utilizzare i metodi LastClickedX(), LastClickedY(), LastClickedQuarter() e LastClickedW().

Entrambe le classi sono state aggiornate aggiungendo i metodi LastClickedName1() e LastClickedName2(). Questi metodi restituiscono i nomi degli oggetti grafici che formano l'ultima voce di menu cliccata. LastClickedName1() restituisce il nome della casella di testo, LastClickedName2() restituisce il nome dell'etichetta per il tick.

I metodi ToggleNameAdd() e ToggleNamesClear() sono stati aggiunti a CVMenu. Il metodo ToggleNameAdd() viene utilizzato per creare un elenco di nomi "toggle", il metodo ToggleNamesClear() viene utilizzato per cancellare questo elenco. Quando si utilizza il metodo ToggleNameAdd() (aggiungendo un nome all'elenco), il menu si chiude automaticamente in base a qualsiasi evento del grafico, ad eccezione degli eventi degli oggetti grafici che formano il menu e degli oggetti grafici i cui nomi sono stati aggiunti dal metodo ToggleNameAdd(). Il menu ritorna alla modalità operativa normale quando l'elenco viene cancellato dal metodo ToggleNamesClear().

Il funzionamento del menu a due livelli è, come segue: quando l'evento di fare click sulla voce di menu orizzontale è definito dai metodi LastClickedName1() e LastClickedName2(), otteniamo i nomi degli oggetti di questa voce che vengono ulteriormente trasmessi a ToggleNameAdd() del menu verticale.

Successivamente, il menu verticale sarà nascosto su qualsiasi grafico anche ad eccezione degli eventi del menu verticale e di una voce di menu orizzontale (per mezzo della quale è stato aperto il menu verticale).

Se un utente ha selezionato una voce del menu verticale, il menu verticale deve essere chiuso e le azioni corrispondenti a questa voce devono essere eseguite. Se un utente ha fatto ripetutamente click sulla stessa voce di menu orizzontale (mediante la quale è stato aperto il menu verticale), il menu verticale dovrebbe essere nascosto.

Esaminiamo un esempio di creazione di menu t/phe.

Il menu principale ha tre voci, quindi abbiamo bisogno di tre menu verticali. Dichiarare una classe di menu orizzontale e tre classi di menu verticali nella sezione pubblica della sottoclasse form (l'esempio seguente la mostra esattamente nello stesso modo dell'esempio eIncGUI_v3_Test_Form.mq5):

class CForm: public CFormBase{
public:
   CHMenu m_hm;
   CVMenu m_vm1;
   CVMenu m_vm2;
   CVMenu m_vm3; 

Inizializzare le classi di menu nel metodo OnInitEvent() e aggiungere le voci del menu:

// Horizontal menu
m_hm.Init(m_Name+"_HM",m_Width,2);
// Adding horizontal menu items
m_hm.AddItem("Form types");
m_hm.AddItem("Item-2");
m_hm.AddItem("Item-3");
// Vertical menu 1
m_vm1.Init(m_Name+"_VM1",70,10); 
// Adding items to vertical menu 1
m_vm1.AddItem("Type-1");
m_vm1.AddItem("Type-2");
// Vertical menu 2
m_vm2.Init(m_Name+"_VM2",70,3);
// Adding items to vertical menu 2
m_vm2.AddItem("Item-2-1");
m_vm2.AddItem("Item-2-2");
m_vm2.AddItem("Item-2-3"); 
m_vm2.AddItem("Item-2-4");
m_vm2.AddItem("Item-2-5"); 
// Vertical menu 3
m_vm3.Init(m_Name+"_VM3",70,3);
// Adding items to vertical menu 3
m_vm3.AddItem("Item-3-1");
m_vm3.AddItem("Item-3-2");
m_vm3.AddItem("Item-3-3"); 
m_vm3.AddItem("Item-3-4");
m_vm3.AddItem("Item-3-5"); 

Nascondere il menu nel metodo OnHideEvent():

void OnHideEvent()
{
   m_hm.Hide(); 
   m_vm1.Hide(); 
   m_vm2.Hide(); 
   m_vm3.Hide(); 
}

Visualizzare il menu orizzontale nel metodo OnShowEvent():

void OnShowEvent(int aLeft,int aTop)
{
    m_hm.Show(aLeft,aTop); 
}

Infine, il lavoro principale nel metodo EventsHandler().

Chiama i metodi Event() di tutti i menu:

void EventsHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
{
    int m_event0=m_hm.Event(id,lparam,dparam,sparam);
    int m_event1=m_vm1.Event(id,lparam,dparam,sparam);
    int m_event2=m_vm2.Event(id,lparam,dparam,sparam);
    int m_event3=m_vm3.Event(id,lparam,dparam,sparam); 

A seconda del valore m_event0 (indice delle voci di menu orizzontali), utilizzare il menu verticale appropriato (ad esempio con il punto 0 e il menu verticale 1):

if(m_event0==0)
{ // Clicking item 0
   if(m_vm1.Visible())
   { 
      m_vm1.Hide(); // If the vertical menu is open, close it
   }
   else{ // If the vertical menu is closed
      m_vm1.ToggleNamesClear(); // Clear the list of "toggle" names
      // Add to the list the names of the graphical objects forming the item 
      // of the horizontal menu which led to the last event 
      // of the horizontal menu 
      m_vm1.ToggleNameAdd(m_hm.LastClickedName1()); 
      m_vm1.ToggleNameAdd(m_hm.LastClickedName2());
      // Display the vertical menu
      m_vm1.Show(m_hm.SolvePosLeft(m_vm1.Width()),m_hm.SolvePosTop(m_vm1.Height())); 
   }
}

Tali azioni devono essere eseguite per tutte le voci di menu orizzontali che aprono il menu verticale. Se si è verificato l'evento del menu verticale, chiudere il menu.

A seconda dell'indice dell'elemento cliccato, fare come segue:

if(m_event1>=0)
{ // Vertical menu event 1
   m_vm1.Hide(); // Hide the menu
      if(m_event1==0)
      { // Clicking item 0
        //...
      }
      if(m_event1==1)
      { // Clicking item 1
        //...
      }
}

Tali azioni dovrebbero essere eseguite per tutti i menu verticali e tutti i loro elementi.

La creazione del menu principale è stata completata.

 

Conclusione

Questo articolo finalizza la serie di articoli dedicati alla creazione di un'interfaccia grafica.

Come risultato del nostro lavoro, abbiamo un notevole arsenale di mezzi per una rapida creazione di un'interfaccia grafica multifunzionale e facile da usare. Questo è abbastanza coerente con i requisiti esistenti per un'interfaccia grafica:

  • Utilizzare il framework sotto forma di didascalia e un modulo che può essere minimizzato/massimizzato, spostato;
  • Aree di codice chiaramente designate relative a un modulo o all'altro;
  • La visualizzazione/occultamento dei controlli viene sincronizzata con la visualizzazione/occultamento del modulo.

Tutti i controlli e il modulo hanno un design e una combinazione di colori comuni che possono essere modificati rapidamente.

Ripetiamo la procedura per la creazione di un modulo.

Una breve procedura per la creazione di un modulo:

  1. Includi il file IncGUI_v3.mqh.

  2. Creare una copia della classe CFormTemplate con un nome univoco e dichiarare questa classe.

  3. Impostare le proprietà del modulo nel metodo MainProperties() della copia della sottoclasse.

  4. Chiamare i metodi Init(), Hide() ed Event() del modulo rispettivamente dalle funzioni OnInit(), OnDeinit() e OnChartEvent() dell’Expert Advisor. Chiamare il metodo Show() dalla funzione OnInit() dell’Expert Advisor o, se necessario,

  5. lavorare con i controlli. Dichiarare le classi di controllo nella copia della sottoclasse. Chiamare i metodi Init(), Show(), Hide() e Event() dei controlli dai metodi OnInitEvent(), OnShowEvent(), OnHideEvent() e EventHandler() della copia della sottoclasse.

 

Appendice

Elenco dei File Allegati:

  • IncGUI_v3.mqh - un file di include contenente tutte le classi per creare un'interfaccia grafica. Il file deve essere inserito nella directory MQL5/Include della Directory dei Dati del Terminale.
  • eIncGUI_v3_Test_Form.mq5 - un esempio di lavoro con i moduli. Il file deve essere inserito nella directory MQL5/Experts della Terminal Data Directory.
  • IncGUIv3mqh.chm - documentazione al file IncGUI_v3.mqh.

Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/322

Velocizza i Calcoli con il Cloud Network MQL5 Velocizza i Calcoli con il Cloud Network MQL5
Quanti core hai sul tuo computer di casa? Quanti computer puoi utilizzare per ottimizzare una strategia di trading? Qui mostriamo come utilizzare il Cloud Network MQL5 per accelerare i calcoli ricevendo la potenza di calcolo in tutto il mondo con un click del mouse. La frase "Il tempo è denaro" diventa ancora più attuale con il passare degli anni e non possiamo permetterci di aspettare calcoli importanti per decine di ore o addirittura giorni.
Controlli Grafici Personalizzati. Parte 2. Libreria di Controllo Controlli Grafici Personalizzati. Parte 2. Libreria di Controllo
Il secondo articolo della serie "Custom Graphical Controls" introduce una libreria di controlli per la gestione dei principali problemi che sorgono nell'interazione tra un programma (Expert Advisor, script, indicatore) e un utente. La libreria contiene un gran numero di classi (CInputBox, CSpinInputBox, CCheckBox, CRadioGroup, CVSсrollBar, CHSсrollBar, CList, CListMS, CComBox, CHMenu, CVMenu, CHProgress, CDialer, CDialerInputBox, CTable) ed esempi del loro utilizzo.
Le Basi della Programmazione Orientata agli Oggetti Le Basi della Programmazione Orientata agli Oggetti
Non hai bisogno di sapere cosa sono il polimorfismo, l'incapsulamento, ecc. per usare la programmazione orientata agli oggetti (OOP) ... puoi semplicemente usare queste funzionalità. Questo articolo descrive le basi dell'OOP attraverso degli esempi pratici.
Controlli Grafici Personalizzati. Parte 1: Creazione di un Controllo Semplice Controlli Grafici Personalizzati. Parte 1: Creazione di un Controllo Semplice
Questo articolo tratta i principi generali di sviluppo dei controlli grafici. Prepariamo strumenti per un lavoro rapido e conveniente con oggetti grafici, analizzeremo un esempio di creazione di un semplice controllo per l'inserimento di testo o dati numerici e le sue modalità di utilizzo.