English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Controlli Grafici Personalizzati. Parte 1: Creazione di un Controllo Semplice

Controlli Grafici Personalizzati. Parte 1: Creazione di un Controllo Semplice

MetaTrader 5Esempi | 9 dicembre 2021, 14:13
162 0
Dmitry Fedoseev
Dmitry Fedoseev

Introduzione

Il linguaggio MQL5 fornisce agli sviluppatori un'ampia gamma di oggetti grafici controllati programmaticamente: un pulsante, un'etichetta di testo, un campo di modifica, un'etichetta bitmap (fig. 1), diversi strumenti grafici per l'analisi (fig. 2).


Fig. 1. Oggetti grafici: un pulsante, un'etichetta di testo, un campo di modifica, un'etichetta bitmap


Fig. 2. Qualche oggetto grafico per l'analisi: un'ellisse, il Ventaglio di Fibonacci, l'Espansione di Fibonacci

In totale, ci sono oltre quaranta oggetti grafici nel client terminal MetaTrader 5. Tutti questi oggetti possono essere utilizzati separatamente, ma più spesso vengono utilizzati in una catena di oggetti interconnessi. Ad esempio, quando viene utilizzato un campo di modifica (OBJ_EDIT), molto spesso viene utilizzata insieme ad esso un'etichetta bitmap (OBJ_LABEL) per indicare la funzione del campo di modifica.

Quando si utilizza un campo di modifica, spesso è necessario verificare la correttezza dei dati inseriti da un utente, nonché prevedere la possibilità di utilizzare sia un punto che una virgola come separatore decimale.

Quando si utilizza un output di dati programmatico, dovresti formattare i dati. Ad esempio, dovresti eliminare gli zeri non necessari. Pertanto, sarebbe più semplice avere un singolo oggetto che includa il campo di modifica, l'etichetta bitmap e alcune altre caratteristiche funzionali.

Attualmente, esiste un certo insieme di controlli grafici nel mondo della programmazione che viene utilizzato in quasi tutte le applicazioni: un form (la base dell'interfaccia di un'applicazione, dove si trovano tutti gli elementi di controllo), un frame (consente di raggruppare e separare insiemi di elementi che hanno uno scopo funzionale), un pulsante, un campo di modifica, un'etichetta, una check box, pulsanti di opzione, barre di scorrimento verticali e orizzontali, un elenco, un elenco a discesa, una riga di menu, un tab menu (fig. 3). 

 
Fig. 3. Il modulo con i controlli standard più comuni

Il modo in cui gli elementi sopra menzionati sono rappresentati in MQL5 è simile ad altri linguaggi di programmazione (un pulsante ed un campo di modifica). Sarebbe conveniente avere altri controlli diffusi nel proprio arsenale.

Diversi ambienti di sviluppo forniscono ai programmatori strumenti speciali per la creazione di controlli personalizzati. MQL5 non fornisce tale funzionalità. Tuttavia, poiché MQL5 è un linguaggio orientato agli oggetti, non è necessario averlo. Tutto può essere fatto sotto forma di oggetti programmati separati.

I principi e la metodologia di creazione dei controlli personalizzati saranno discussi in seguito in questo articolo. Sulla base di essi, chiunque sia esperto nella programmazione può creare un set di controlli necessario che può essere utilizzato ripetutamente nelle applicazioni.


1. Come dovrebbe essere un controllo grafico?

1.1. Requisiti e Principi Generali

Per essere utili, i controlli grafici dovrebbero facilitare lo sviluppo delle applicazioni. Per essere così, dovrebbero soddisfare i seguenti requisiti:

  1. Dovrebbe essere possibile creare rapidamente un controllo durante lo sviluppo. Questo problema viene risolto utilizzando l'approccio alla programmazione orientato agli oggetti. Un controllo grafico è rappresentato come un oggetto programmato.
     
  2. Un controllo dovrebbe essere flessibile. In altre parole, dovrebbe essere possibile modificarne le proprietà: dimensione, posizione, colore, ecc.
     
  3. Un controllo dovrebbe essere facile da usare: dovrebbe avere solo le proprietà ei metodi richiesti, il cui scopo è comprensibile dallo scopo dell'elemento e dai nomi dei metodi. Ora dividiamo le proprietà dei controlli in categorie:
     
    1. Proprietà incontrollate. Tali proprietà includono lo schema dei colori. Tutti i controlli utilizzati in un'applicazione dovrebbero avere uno stile generale. Ecco perché l'impostazione dei colori per ciascun controllo individualmente sarebbe estenuante.
      Inoltre, la ricerca di un colore per alcuni controlli è un compito piuttosto difficile per cui non vorrei perdere tempo. Ad esempio, una barra di scorrimento. Alcuni sviluppatori web potrebbero aver affrontato questo compito interessante.
       
    2. Proprietà impostate nella fase di creazione di un controllo o proprietà modificate raramente. Ad esempio, la dimensione di un controllo. La posizione equilibrata e conveniente di tutti i controlli utilizzati in un'applicazione è un compito speciale e difficile che viene risolto nella fase di creazione dell'interfaccia.
      In relazione a ciò, la dimensione dei controlli di solito non cambia durante il funzionamento del programma. Tuttavia, a volte potrebbe essere necessario modificare tali proprietà. Ecco perché dovresti fornire la possibilità di modificare queste proprietà durante il funzionamento del programma.
       
    3. Principali proprietà operative. Proprietà che cambiano frequentemente dal programma. Le proprietà che costituiscono lo scopo di un controllo. Queste proprietà possono essere suddivise in due categorie:
       
      1. Proprietà con aggiornamento automatico della visualizzazione di un controllo. Ad esempio, una modifica. Una volta impostato un valore dal programma, le modifiche dovrebbero essere visualizzate sullo schermo. Nella programmazione, dovrebbe essere eseguito utilizzando una singola riga di codice.
         
      2. Proprietà che richiedono un aggiornamento obbligatorio della visualizzazione. Ad esempio, un elenco. Gli elenchi implicano l'utilizzo di array di dati, ecco perché un elenco non deve essere aggiornato dopo aver lavorato con un singolo elemento dell'elenco. Qui, è meglio eseguire un aggiornamento obbligatorio alla fine lavorando con tutti gli elementi della lista. Questo approccio aumenta notevolmente le prestazioni dell'applicazione.
         
  4. Una possibilità di nascondere e mostrare il controllo in modo semplice e veloce. Rendere visibile un controllo non dovrebbe richiedere l'impostazione ripetuta delle proprietà di visualizzazione; l'accesso alle proprietà dell'oggetto dovrebbe essere indipendente dalla visibilità degli oggetti grafici di questo controllo. In altre parole, un oggetto programmato dovrebbe contenere tutte le proprietà del controllo al suo interno e non dovrebbe utilizzare le proprietà degli oggetti grafici.
      
  5. Per avere l'output degli eventi che corrispondono al controllo, dovrebbe esserci l'elaborazione degli eventi dei singoli oggetti grafici che sono inclusi nel controllo.

1.2. Il Modo di Usare un Controllo e i Metodi Richiesti 

Considerando i requisiti sopra menzionati, abbiamo il seguente schema di creazione di un'interfaccia grafica nonché l'insieme delle proprietà e dei metodi richiesti di un oggetto programmato:

  1. Inizializzazione di un controllo e impostazione parallela di proprietà raramente modificate. Questo metodo sarà chiamato Init(); ha diversi parametri. Il primo obbligatorio - il nome di un controllo. Questo parametro verrà utilizzato come prefisso per i nomi di tutti gli oggetti grafici inclusi nel controllo. Inoltre, possono essere inclusi i parametri che impostano la dimensione del controllo e altri parametri (a seconda dello scopo del controllo).
     
  2. I controlli possono avere una posizione fissa su un grafico e possono richiedere la possibilità di essere spostati. Quindi, useremo metodi separati per determinare le coordinate: SetPosLeft() - impostazione della coordinata X, SetPosTop() - impostazione della coordinata Y. Ciascuno di questi metodi dovrebbe avere un parametro. Molto spesso è necessario cambiare entrambe le coordinate, quindi è bene avere il metodo SetPos() con due parametri che cambia contemporaneamente sia le coordinate X che Y.
    Per calcolare la posizione di un controllo, potrebbe essere necessario ottenere le informazioni sulla dimensione e la posizione di un altro controllo. A tal fine, utilizzeremo i seguenti metodi: Width() - larghezza, Height() - altezza, Left) - la coordinata X, Top() - la coordinata Y. In questa fase dell'operazione, vengono calcolate le coordinate del controllo e vengono chiamati i metodi per impostarle.
     
  3. Subito dopo la creazione o in un'altra fase di funzionamento dell'applicazione, dobbiamo rendere visibile il controllo. Per farlo, viene utilizzato il metodo Show(). Per nascondere il controllo, viene utilizzato il metodo Hide().
     
  4. Come detto in precedenza, durante il funzionamento del programma potrebbe essere necessario modificare la dimensione del controllo. Ecco perché l'oggetto programmato dovrebbe avere metodi separati per impostare la dimensione: SetWidth() e/o SetHeght(). Poiché si tratta di proprietà raramente modificate, affinché le modifiche abbiano effetto è necessario chiamare il metodo Refresh() che aggiorna la visualizzazione.

  5. Gli eventi dei singoli oggetti grafici verranno elaborati nel metodo Event() che restituirà un valore che corrisponde ad uno specifico evento del controllo. Il metodo Event() dovrebbe essere chiamato dalla funzione OnChartEvent(); avrà lo stesso set di parametri della funzione OnChartEvent().

Quindi, otteniamo l'insieme dei metodi richiesti di un oggetto programmato:

  • void Init(string aName...) - inizializzazione del controllo;
  • void SetPosLeft(int aLeft) - impostazione della coordinata X;
  • void SetPosTop(int aTop) - impostazione della coordinata Y;
  • void SetPos(int aLeft, int aTop) - impostazione simultanea delle coordinate X e Y;
  • void SetWidth(int aWidth) - impostazione della larghezza;
  • void SetHeght(int aHeight) - impostazione dell'altezza;
  • int Width() - ottenere la larghezza;
  • int Height() - ottenere l'altezza;
  • int Left() - ottenere la coordinata X;
  • int Top() - ottenere la coordinata Y;
  • void Refresh() - aggiornamento completo della visualizzazione;
  • void Show() - mostrare;
  • void Hide() - nascondere;
  • int Event(const int id, const long & lparam, const double & dpam, const string & sparam) - elaborazione degli eventi del grafico;

La presenza degli altri metodi (o l'assenza di alcuni dei metodi elencati) dipende dal controllo stesso e dal suo scopo.

Più avanti, in questo articolo cercheremo di implementare i principi sopra descritti: creeremo un controllo per consentire a un utente di inserire un testo o un numero.

Prima di ciò, dobbiamo dotarci degli strumenti per lavorare in modo rapido e conveniente con gli oggetti grafici.


2. Come Lavorare con Oggetti Grafici in Modo Rapido e Conveniente

Per lavorare con oggetti grafici, MQL5 fornisce le seguenti funzioni di base: ObjectCreate(), ObjectDelete(), ObjectSetDouble(), ObjectSetInteger(), ObjectSetString(), ObjectGetDouble(), ObjectGetInteger(), ObjectGetString(). Possiamo usare queste funzioni direttamente, ma il processo di programmazione sarà molto lungo e laborioso. Le funzioni hanno nomi lunghi; molti identificatori con nomi lunghi devono essere passati alle funzioni.

Per rendere più comodo il lavoro con gli oggetti grafici, possiamo utilizzare una classe già pronta inclusa nel pacchetto del client terminal MetaTrader 5 (la classe CChartObject dal file MQL5/Include/ChartObjects/ChartObject.mqh), oppure possiamo scrivere la nostra classe e darle tutti i metodi necessari.

Scherzando, questo approccio alla programmazione consiste nel premere un tasto seguito da un punto. Dopo aver specificato il nome di un oggetto, non resta che mettere un punto e si apre l'elenco delle sue proprietà e dei suoi metodi; basta scegliere un elemento necessario dall'elenco (fig. 4).


Fig. 4. L'elenco delle proprietà e dei metodi dell'oggetto

Esistono due varianti di gestione di un oggetto grafico utilizzando la classe ausiliaria:

  1. Viene creata una singola istanza di classe per ogni oggetto grafico. Metodo abbastanza conveniente ma non economico dal punto di vista della quantità di memoria consumata. Per questa variante, è meglio scrivere classi speciali per ogni tipo di oggetto grafico. Tuttavia, questo approccio non è ottimale poiché è molto laborioso. A differenza della programmazione di un Expert Advisor, non esiste un requisito rigoroso sulle massime prestazioni durante la creazione di un'interfaccia utente.
  2. Usa un'istanza di classe. Se è necessario gestire un oggetto grafico, l'oggetto viene aggiunto alla classe. Useremo la seconda variante.

Creiamo una classe universale più adatta al secondo tipo di gestione degli oggetti grafici.


3. La Classe Universale per la Gestione degli Oggetti Grafici

Durante la programmazione, il lavoro con ogni oggetto grafico si compone di tre fasi: creazione, lettura/impostazione delle proprietà, cancellazione al termine dell'operazione dell'applicazione.

Quindi, prima di tutto, la classe per la gestione degli oggetti grafici dovrebbe contenere i metodi che li creano. Un parametro obbligatorio per la creazione di un oggetto grafico è il suo nome; quindi, i metodi di creazione degli oggetti avranno un parametro obbligatorio per specificare un nome di un oggetto creato.

Di solito, gli oggetti grafici vengono creati sul grafico, dove viene eseguito il programma (Expert Advisor, Indicator o Script). Un caso più raro è una sottofinestra e un caso ancora più raro è un'altra finestra del grafico del terminale. Quindi il secondo parametro opzionale sarà quello che specifica il numero di una sottofinestra; e il terzo è l'identificatore di un grafico.

Di default, entrambi i parametri opzionali saranno uguali a 0 (il grafico dei prezzi è sul grafico "proprio"). Cerca l'elenco dei tipi di oggetti grafici nella documentazione. Aggiungi il metodo Create per ogni tipo.

Prima di questo, dobbiamo creare un file. Per farlo, apri MetaEditor, crea un nuovo file di inclusione e chiamalo IncGUI.mqh. Nel file aperto, crea la classe CGraphicObjectShell con le sezioni protette e pubbliche. Nella sezione protetta, dichiara le variabili per il nome di un oggetto e l'identificatore di un grafico.

Nei metodi di creazione degli oggetti, a tali variabili verranno assegnati i valori passati dai metodi come parametri, in modo da avere la possibilità di gestirli dopo la creazione dell'oggetto senza specificare un nome e un identificatore del grafico. Quindi, possiamo usare la classe anche per la prima variante di gestione degli oggetti grafici.

Per avere la possibilità di utilizzare la classe per la seconda variante (per gestire qualsiasi oggetto grafico), dare un metodo per allegare un oggetto grafico (il metodo Attach()). Questo metodo avrà un parametro obbligatorio, il nome di un oggetto grafico, e un parametro opzionale, un identificatore del grafico. Potrebbe essere necessario conoscere il nome e l'identificatore di un oggetto grafico allegato. Per farlo, aggiungi i seguenti metodi all'oggetto: Name() e ChartID().

Di conseguenza, otteniamo il seguente "pezzo" della classe: 

class CGraphicObjectShell
  {
protected:
   string            m_name;
   long              m_id;
public:
   void Attach(string aName,long aChartID=0)
     {
      m_name=aName;
      m_id=aChartID;
     }
   string Name()
     {
      return(m_name);
     }    
   long ChartID()
     {
      return(m_id);
     }
  };

Aggiungere i suddetti metodi di creazione di oggetti grafici. I nomi di questi metodi inizieranno con "Create".

I lettori possono saltarlo, il file IncGUI.mqh allegato all'articolo contiene la classe già pronta CGraphicObjectShell.

A titolo di esempio, ecco un metodo di creazione dell'oggetto grafico a linee verticali (OBJ_VLINE):

void CreateVLine(string aName,int aSubWindow=0,long aChartID=0)
  {
   ObjectCreate(m_id,m_name,OBJ_VLINE,aSubWindow,0,0);
   Attach(aName,aChartID);
  }

Ora, apri l’elenco delle proprietà degli oggetti grafici nella guida dell'utente; e scrivere metodi per impostare un valore per ogni proprietà utilizzando le funzioni ObjectSetDouble(), ObjectSetInteger() e ObjectSetString(). Il nome dei metodi inizierà con "Set". Quindi, scrivi i metodi per leggere le proprietà utilizzando le funzioni ObjectGetDouble() e ObjectGetInteger(). ObjectGetString().

Ad esempio, ecco i metodi per impostare e ottenere il colore:

void SetColor(color aColor)
  {
   ObjectSetInteger(m_id,m_name,OBJPROP_COLOR,aColor);
  }
color Color()
  {
   return(ObjectGetInteger(m_id,m_name,OBJPROP_COLOR));
  }

Bene, ora sembra che abbiamo gli strumenti minimi richiesti per lavorare con gli oggetti grafici, ma non tutti.

A volte, quando si lavora con un oggetto grafico, potresti aver bisogno di eseguire solo un'azione con un oggetto. In questo caso, non sarà conveniente eseguire il metodo Attach() per l'oggetto, quindi tornare all'oggetto principale ed eseguire nuovamente Attach() per esso.

Aggiungiamo alla classe altre due varianti di tutti i metodi di impostazione/ottenimento delle proprietà.

Il primo - per nome sul "proprio" grafico :

void SetColor(string aName,color aColor)
  {
   ObjectSetInteger(0,aName,OBJPROP_COLOR,aColor);
  }
color Color(string aName)
  {
   return(ObjectGetInteger(0,aName,OBJPROP_COLOR));
  }

Il secondo - per nome e identificatore di un grafico:

void SetColor(long aChartID,string aName,color aColor)
  {
   ObjectSetInteger(aChartID,aName,OBJPROP_COLOR,aColor);
  }
color Color(long aChartID,string aName)
  {
   return(ObjectGetInteger(aChartID,aName,OBJPROP_COLOR));
  }

Oltre alle funzioni ObjectGet... e ObjectSet..., esistono altre funzioni per lavorare con gli oggetti grafici: ObjectDelete(), ObjectMove(), ObjectFind(), ObjectGetTimeByValue(), ObjectGetValueByTime(), ObjectsTotal(). Possono anche essere aggiunti alla classe con tre varianti di chiamata di ciascuno.

Infine, dichiara la classe CGraphicObjectShell con un nome semplice e breve "g" in questo file. 

CGraphicObjectShell g;

Ora, per iniziare a lavorare con gli oggetti grafici, è sufficiente collegare il file IncGUI.mqh; quindi, avremo la classe "g" con cui lavorare. Usandolo, è facile gestire tutti gli oggetti grafici disponibili.


4. Pezzi per i Controlli

Nonostante abbiamo la classe per lavorare velocemente con oggetti grafici, possiamo creare controlli in un modo più semplice. Tutti i controlli possono essere creati sulla base di quattro oggetti grafici:

  1. Etichetta Rettangolare (OBJ_RECTANGLE_LABEL);
  2. Etichetta di testo (OBJ_LABEL);
  3. Campo di Modifica (OBJ_EDIT),
  4. Pulsante (OBJ_BUTTON);

Dopo la creazione di oggetti grafici, dovrebbero essere impostate molte proprietà per loro: coordinate, dimensione, colore, dimensione del carattere, ecc. Per accelerare il processo, creiamo un'altra classe e la chiamiamo CWorkPiece (pezzi), e le forniamo metodi per la creazione di oggetti grafici con proprietà passate nei parametri. 

Affinché i controlli funzionino, puoi gestire gli eventi del grafico. Gli eventi degli altri grafici non sono disponibili, quindi lavoreremo solo con il proprio grafico - non ci sarà alcun identificatore del grafico nei parametri dei metodi della classe CWorkPiece. 0 (proprio grafico) verrà utilizzato ovunque.

Il parametro che specifica un numero di sottofinestra verrà utilizzato per fornire la possibilità di creazione di controlli sia nel grafico dei prezzi che nelle sue sottofinestre. Gli oggetti grafici saranno vincolati solo all'angolo in alto a sinistra; se è necessario riposizionare un controllo rispetto a qualsiasi altro angolo, è molto più semplice ricalcolare le coordinate dell'intero controllo considerando la dimensione del grafico. Per controllare le modifiche di dimensione del grafico, puoi gestire l'evento CHARTEVENT_CHART_CHANGE.

Come base per molti controlli, utilizzeremo l'oggetto "Rectangle label"; aggiungere il metodo di creazione di questo oggetto alla classe CWorkPiece; il metodo si chiama Canvas():

void Canvas(string aName="Canvas",
             int aSubWindow=0,
             int aLeft=100,
             int aTop=100,
             int aWidth=300,
             int aHeight=150,
             color aColorBg=clrIvory,
             int aColorBorder=clrDimGray)
  {
   g.CreateRectangleLabel(aName,aSubWindow); // Creation of rectangle label
   g.SetXDistance(aLeft);                    // Setting of the X coordinate
   g.SetYDistanse(aTop);                        // Setting of the Y coordinate
   g.SetXSize(aWidth);                          // Setting of width
   g.SetYSize(aHeight);                         // Setting of height
   g.SetBgColor(aColorBg);                   // Setting of background color
   g.SetColor(aColorBorder);                 // Setting of border color
   g.SetCorner(CORNER_LEFT_UPPER);             // Setting of a anchor point
   g.SetBorderType(BORDER_FLAT);             // Setting of border type
   g.SetTimeFrames(OBJ_ALL_PERIODS);            // Setting visibility at all timeframes
   g.SetSelected(false);                        // Disabling selection
   g.SetSelectable(false);                   // Disabling of selection possibility
   g.SetWidth(1);                               // Setting of border width
   g.SetStyle(STYLE_SOLID);                  // Setting of border style
  }

Attenzione: il metodo è composto da 14 righe di codice; sarebbe molto frustrante scriverli tutti ogni volta che crei questo oggetto. Ora è sufficiente scrivere una sola riga, tutti i parametri del metodo sono opzionali e sono elencati nell'ordine di frequenza del loro utilizzo: posizione, dimensione, colore, ecc.

Analogamente al metodo Canvas(), scrivi i metodi di creazione di un'etichetta di testo, un pulsante e un campo di modifica: Label(), Button() and Edit(). La classe pronta CWorkPiece è allegata all'articolo nel file IncGUI.mqh. Oltre ai metodi sopra menzionati, la classe contiene molti altri metodi: Frame() e DeleteFrame() - i metodi di creazione e cancellazione di un frame (fig. 5). Un frame è un'etichetta rettangolare con una didascalia nell'angolo in alto a sinistra.

I frame sono pianificati per essere utilizzati quando si raggruppano i controlli in un modulo.


Fig. 5. Frame con didascalia.

L'elenco di tutti i metodi della classe CWorkPiece è allegato all'articolo.

Analogamente alla classe CGraphicObjectShell, dichiarare la classe CWorkPiece con il nome breve "w" per poterla utilizzare subito dopo aver collegato il file IncGUI.mqh.

CWorkPiece w;

Tutti gli strumenti ausiliari sono pronti, quindi possiamo continuare con l'argomento dell'articolo: creazione di un controllo personalizzato.


5. Creazione di un Controllo "Edit"

Innanzitutto, per non confondere la terminologia, definiamo l'oggetto grafico OBJ_EDIT come campo di testo, l'oggetto OBJ_LABEL - come etichetta, ed i controlli creati - come campo di modifica. Il controllo creato è costituito da due oggetti grafici: un campo di modifica (OBJ_EDIT) e un'etichetta di testo (OBJ_LABEL).

Il controllo supporterà due modalità di funzionamento: input di dati di testo e input di dati numerici. Nella modalità di inserimento dei dati numerici, ci sarà una limitazione all'intervallo dei valori di input e sia una virgola che un punto saranno accettabili come separatori decimali. All'uscita programmata di un valore nel campo di modifica, viene formattato secondo un numero specificato di posizioni decimali.

Quindi, quando si inizializza un controllo, dovremmo specificare la sua modalità di funzionamento: testo o numerico; la modalità viene specificata utilizzando il parametro aDigits. Un valore maggiore di zero imposta la modalità numerica con il numero di posizioni decimali specificato, un valore negativo imposta la modalità testo.

Per impostazione predefinita, l'intervallo di valori accettabili va da - DBL_MAX a DBL_MAX (l'intero intervallo di valori di una variabile doppia). Se necessario, puoi impostare un altro intervallo chiamando i metodi SetMin() e SetMax(). Tra i parametri di dimensione, verrà impostata solo la larghezza per il controllo. Affinché il campo di modifica appaia equilibrato, è necessario impostare un'altezza e una larghezza corrispondenti.

Una modifica della dimensione del carattere richiede la corrispondente modifica dell'altezza dell'oggetto grafico. E ciò richiede la modifica della posizione di tutti gli altri controlli; nessuno lo farebbe. Supponiamo l'uso di una dimensione del carattere costante per tutti i controlli e i corrispondenti campi di modifica. Tuttavia, la classe del controllo avrà un metodo che restituisce la sua altezza per comodità di calcolo delle coordinate di altri elementi.

Ci saranno quattro parametri di colore: colore di sfondo, colore del testo, colore della didascalia e colore di avviso (sarà possibile cambiare il colore di sfondo del campo di testo per attirare l'attenzione dell'utente, ad esempio, in caso di inserimento di un valore errato).

Come accennato in precedenza, sono supportati i controlli in una finestra secondaria. Oltre ai parametri principali necessari per il funzionamento di un controllo, utilizzeremo l'altro parametro Tag; è un semplice valore di testo memorizzato in un'istanza della classe. Un tag è un comodo strumento ausiliario.

La classe si chiamerà CInputBox. Quindi, abbiamo il seguente set di variabili della classe (che si trova nella sezione privata):

string m_NameEdit;    // Name of the Edit object
string m_NameLabel;   // Name of the Label object
int m_Left;           // X coordinate
int m_Top;            // Y coordinate
int m_Width;           // Width
int m_Height;          // Height
bool m_Visible;        // Visibility flag of the control
int m_Digits;          // Number of decimal places for the double number; -1 set the text mode
string m_Caption;      // Caption
string m_Value;        // Value
double m_ValueMin;     // Minimum value
double m_ValueMax;     // Maximum value
color m_BgColor;       // Background color
color m_TxtColor;     // Text color
color m_LblColor;      // Caption color
color m_WarningColor; // Warning font color
bool m_Warning;        // Flag of warning
int m_SubWindow;       // Subwindow
string m_Tag;           // Tag

Quando si utilizza un controllo, il primo metodo chiamato è Init().

In questo metodo, prepariamo i valori di tutti i parametri determinati in precedenza:

// The initialization method
void Init(string aName="CInputBox",
           int aWidth=50,
           int aDigits=-1,
           string aCaption="CInputBox")
 { 
   m_NameEdit=aName+"_E";  // Preparing the name of the text field
   m_NameLabel=aName+"_L"; // Preparing the caption name
   m_Left=0;                 // X coordinate
   m_Top=0;                  // Y coordinate
   m_Width=aWidth;          // Width
   m_Height=15;             // Height
   m_Visible=false;         // Visibility
   m_Digits=aDigits;       // The mode of operation and the number of decimal places
   m_Caption=aCaption;     // Caption text
   m_Value="";              // Value in the text mode
   if(aDigits>=0)m_Value=DoubleToString(0,m_Digits); // Value in the numeric mode
   m_ValueMin=-DBL_MAX;                   // Minimal value
   m_ValueMax=DBL_MAX;                  // Maximal value
   m_BgColor=ClrScheme.Color(0);       // Background color of the text field
   m_TxtColor=ClrScheme.Color(1);      // Color of text and frame of the text field
   m_LblColor=ClrScheme.Color(2);      // Caption color
   m_WarningColor=ClrScheme.Color(3); // Warning color
   m_Warning=false;                      // Mode: warning, normal
   m_SubWindow=0; // Number of subwindow
   m_Tag=""; // Tag
 }

Se un controllo funziona in modalità testo, alla variabile m_Value viene assegnato il valore "", se funziona in modalità numerica - uno zero con il numero di posizioni decimali specificato. I parametri del colore sono impostati sui valori predefiniti; ci occuperemo degli schemi dei colori nell'ultima fase.

Le variabili che determinano le coordinate del controllo sono settate su zero, poiché il controllo non è ancora visibile. Dopo aver chiamato il metodo Init() (se è previsto che il controllo avrà una posizione fissa sul grafico) possiamo impostare le coordinate utilizzando il metodo SetPos():

// Setting the X and Y coordinates
void SetPos(int aLeft,int aTop)
{ 
   m_Left=aLeft;
   m_Top=aTop;
}

Dopo di che, possiamo rendere visibile il controllo (il metodo Show()):

// Enable visibility on the previously specified position
void Show()
{ 
   m_Visible=true; // Registration of visibility
   Create();       // Creation of graphical objects
   ChartRedraw();   // Refreshing of the chart
}

La funzione Create() viene chiamata dal metodo Show(); crea oggetti grafici (situati nella sezione privata), quindi il grafico viene aggiornato (ChartRedraw()). Il codice della funzione Create() viene riportato di seguito:

// The function of creation of graphical objects
void Create(){ 
   color m_ctmp=m_BgColor;  // Normal background color
      if(m_Warning){ // The warning method is set
         m_ctmp=m_WarningColor; // The text field will be color in the warning color
      }
    // Creation of the text field
   w.Edit(m_NameEdit,m_SubWindow,m_Left,m_Top,m_Width,m_Height,m_Value,m_ctmp,m_TxtColor,7,"Arial"); 
      if(m_Caption!=""){ // There is a caption
          // Creation of caption
         w.Label(m_NameLabel,m_SubWindow,m_Left+m_Width+1,m_Top+2,m_Caption,m_LblColor,7,"Arial"); 
      } 
}   

Quando si creano oggetti grafici nella funzione Create() in base al valore di m_Warning, al campo di testo viene assegnato il colore di sfondo corrispondente. Se la variabile m_Caption ha un valore, viene creata la didascalia (puoi creare un controllo senza didascalia).

Se hai intenzione di creare un controllo mobile, usa la seconda variante del metodo Show() - specificando le coordinate. In questo metodo, vengono impostate le coordinate e viene chiamata la prima variante del metodo Show():

// Setting the X and Y coordinates
void SetPos(int aLeft,int aTop){ 
   m_Left=aLeft;
   m_Top=aTop;
}

Dopo che il controllo è stato visualizzato, dovrai nasconderlo per un po' di tempo.

A questo scopo viene utilizzato il metodo Hide():

// Hiding (deletion of graphical objects)
void Hide()
{ 
   m_Visible=false; // Registration of the invisible state
   Delete();        // Deletion of graphical objects
   ChartRedraw();    // Refreshing of the chart
}  

Il metodo Hide() chiama la funzione Delete() che elimina gli oggetti grafici, quindi chiama la funzione ChartRedraw() per aggiornare il grafico. La funzione Delete() si trova nella sezione privata:

// The function of deletion of graphical objects
void Delete()
{ 
   ObjectDelete(0,m_NameEdit);  // Deletion of the text field
   ObjectDelete(0,m_NameLabel); // Deletion of caption
}   

Poiché abbiamo già trovato un metodo che imposta solo i valori delle proprietà senza modificare la visualizzazione di un controllo (il metodo SetPos()), è logico creare un metodo per un aggiornamento forzato di un controllo - il metodo Refresh() : 

// Refreshing of displaying (deletion and creation)
void Refresh()
{ 
   if(m_Visible)
   {   // Visibility enabled
      Delete();     // Deletion of graphical object
      Create();     // Creation of graphical objects
      ChartRedraw(); // Redrawing of the chart 
   }            
}   

Il controllo è piuttosto semplice, ecco perché utilizziamo il semplice metodo di aggiornamento: eliminazione e creazione. Se fosse un controllo più complesso come un elenco composto da molti campi di modifica, sceglieremmo un approccio più intelligente.

Quindi, abbiamo finito con il posizionamento del controllo. Ora procediamo con l'impostazione di un valore: il metodo SetValue(). Poiché il controllo può funzionare in due modalità, ci saranno due varianti del metodo SetValue(): con la stringa e il tipo doppio. Nella modalità testo, il valore viene utilizzato così com'è:

// Setting a text value
void SetValue(string aValue)
{ 
   m_Value=aValue; // Assigning a value to variable to store it
      if(m_Visible)
      { // The visibility of the control is enabled
          // Assigning the text field to the object for managing graphical objects
         g.Attach(m_NameEdit); 
         g.SetText(m_Value); // Setting the value for the text field
         ChartRedraw();        // Redrawing the chart
      }
} 

L'argomento ottenuto viene assegnato alla variabile m_Value e, se il controllo è visibile, viene visualizzato nel campo di testo.

Nella modalità numerica, l'argomento ottenuto viene normalizzato in base al valore m_Digits, quindi corretto in base al valore massimo e minimo (m_MaxValue, m_MinValue), trasformato in una stringa, quindi viene chiamato il primo metodo SetValue().

// Setting a number value
void SetValue(double aValue)
{ 
   if(m_Digits>=0)
   {  // In the numeric mode
       // Normalization of the number according to the specified accuracy
      aValue=NormalizeDouble(aValue,m_Digits);
      // "Alignment" of the value according to the minimal acceptable value
      aValue=MathMax(aValue,m_ValueMin); 
       // "Alignment" of the value according to the maximal acceptable value
      aValue=MathMin(aValue,m_ValueMax); 
       // Setting the obtained value as a string
      SetValue(DoubleToString(aValue,m_Digits)); 
   }
   else
   { // In the text mode
      SetValue((string)aValue); // Assigning the value to the variable to store it as is
   }            
}

Scriviamo due metodi per ottenere valori: uno è per ottenere un valore stringa, l'altro è per ottenere un valore doppio:

// Getting a text value
string ValueStrind()
{ 
   return(m_Value);
}

// Getting a numeric value
double ValueDouble()
{ 
   return(StringToDouble(m_Value));
}

Il valore impostato per il controllo viene corretto in base ai valori massimi e minimi accettabili; aggiungiamo metodi per ottenerli e impostarli:

// Setting the maximal acceptable value
void SetMaxValue(double aValue)
{ 
   m_ValueMax=aValue; // Registration of the new maximal accepted value
      if(m_Digits>=0)
     { // The control works in the numeric mode
         if(StringToDouble(m_Value)>m_ValueMax)
         { /* The current value of the control is greater than the new maximal acceptable value*/
            SetValue(m_ValueMax); // Setting the new value that is equal to the maximal accepted value
         }
      }         
}

// Setting the minimal acceptable value
void SetMinValue(double aValue)
{ 
   m_ValueMin=aValue; // Registration of the new minimal acceptable value     
      if(m_Digits>=0)
      { // The control works in the numeric mode
         if(StringToDouble(m_Value)<m_ValueMin)
         { /* The current value of the control is less than the new minimal acceptable value*/
            SetValue(m_ValueMin); // Setting the new value that is equal to the minimum acceptable value
         }
      }
}

// Getting the maximal accepted value
double MaxValue()
{ 
   return(m_ValueMax); 
}

// Getting the minimal accepted value
double MinValue()
{ 
   return(m_ValueMin);
}

Se il controllo funziona in modalità numerica, la verifica e la correzione (se necessaria) del valore corrente vengono eseguite quando si impostano nuovi valori massimi e minimi accettabili.

Ora ci occupiamo dell'input di un valore da parte di un utente, il metodo Event(). La verifica dei dati inseriti da un utente verrà eseguita utilizzando l'evento CHARTEVENT_OBJECT_ENDEDIT. Quando si lavora in modalità testo, se un valore specificato da un utente non è uguale a m_Value, il nuovo valore viene assegnato a m_Value così come il valore 1 viene assegnato alla variabile m_event restituita dal metodo Event().

Quando si lavora in modalità numerica, memorizzare il valore precedente di m_Value nella variabile m_OldValue, sostituire la virgola con un punto, convertire la stringa in numero e passarla alla funzione SetValue(). Quindi se m_Value e m_OldValue non sono uguali, "genera" l'evento (imposta il valore 1 sulla variabile m_event).

// Handling of events
int Event(const int id,
           const long & lparam,
           const double & dparam,
           const string & sparam)
{ 
   bool m_event=0; // Variable for an event of this control
      if(id==CHARTEVENT_OBJECT_ENDEDIT)
      { // There has been an event of end of editing the text field
         if(sparam==m_NameEdit)
         { // The text field with the name m_NameEdit has been modified
            if(m_Digits<0)
            { // In the text mode
               g.Attach(m_NameEdit); // Assigning the text field for controlling it
                  if(g.Text()!=m_Value)
                  { // New value in the text field
                     m_Value=g.Text(); // Assigning the value to the variable to store it
                     m_event=1;         // There has been an event
                  }
            }
            else
            { // In the numeric mode
               string m_OldValue=m_Value; // The variable with the previous value of the control
               g.Attach(m_NameEdit);      // Attaching the text field for controlling it
               string m_stmp=g.Text();     // Getting text specified by a user in the text field
               StringReplace(m_stmp,",",".");       // Replacing comma with a dot
               double m_dtmp=StringToDouble(m_stmp); // Conversion to a number
               SetValue(m_dtmp);                     // Setting the new numeric value
                     // Comparing the new value with the previous one
                  if(StringToDouble(m_Value)!=StringToDouble(m_OldValue))
                  { 
                     m_event=1; // There has been an event 
                  }
            }
         }
      }               
   return(m_event); // Return the event. 0 - there is no event, 1 - there is an event
}

Supporto al funzionamento del controllo nelle sottofinestre. Per fornirlo, aggiungi il metodo SetSubWindow() che dovrebbe essere chiamato dalla funzione OnChartEvent() in caso di evento CHARTEVENT_CHART_CHANGE. Se prevedi di utilizzare il controllo solo su un grafico dei prezzi, non è necessario chiamare questo metodo. 

La variabile m_SubWindow è già dichiarata, è uguale a 0 di default e viene passata ai metodi Edit() e Label() della classe "w" alla creazione degli oggetti grafici di un controllo. Il numero di una sottofinestra verrà passato al metodo SetSubWindowName(); se il numero viene modificato, modificare il valore della variabile m_SubWindow ed eseguire il metodo Refresh().

// Setting a subwindow by number
void SetSubWindow(int aNumber)
{ 
   int m_itmp=(int)MathMax(aNumber,0); /* If the number is negative, 0 will be used - the price chart*/
      if(m_itmp!=m_SubWindow)
      { /* The specified number doesn't correspond the number where the control is located*/
         m_SubWindow=m_itmp; // Registration of the new number of subwindow
         Refresh(); // Recreation of the graphical objects
      }
} 

Probabilmente, sarà più conveniente passare alla funzione il nome di una sottofinestra invece del suo numero. Aggiungi un'altra variante del metodo SetSubWindow():

// Setting a subwindow by name
void SetSubWindow(string aName)
{ 
   SetSubWindow(ChartWindowFind(0,aName)); // Determination of the number of the subwindow by its name and setting the subwindow by number
}

Fornire alla classe del controllo gli altri metodi mancanti, secondo il concetto descritto all'inizio dell'articolo.

Non appena abbiamo il metodo SetPos() che consente di impostare contemporaneamente entrambe le coordinate del controllo, aggiungiamo i metodi per l'impostazione separata delle coordinate:

// Setting the X coordinate
void SetPosLeft(int aLeft)
{ 
   m_Left=aLeft;
}      

// Setting the Y coordinate
void SetPosTop(int aTop)
{ 
   m_Top=aTop;
}  

Metodo di impostazione di una larghezza:

// Setting the width
void SetWidth(int aWidth)
{ 
   m_Width=aWidth;
}

Metodo per ottenere le coordinate e la dimensione:

// Getting the X coordinate
int Left()
{ 
   return(m_Left);
}

// Getting the Y coordinate
int Top()
{ 
   return(m_Top);
}

// Getting the width
int Width()
{ 
   return(m_Width);
}

// Getting the height
int Height()
{
   return(m_Height); 
}

I metodi per lavorare con il tag:

// Setting the tag
void SetTag(string aValue)
{ 
   m_Tag=aValue;
}

// Getting the tag
string Tag()
{ 
   return(m_Tag);
}  

I metodi di avviso:

// Setting the warning mode
void SetWarning(bool aValue)
{ 
      if(m_Visible)
      { // Visibility is enabled
         if(aValue)
         { // We need to turn on the warning mode
            if(!m_Warning)
            { // The warning mode has not been enabled
               g.Attach(m_NameEdit);         // Attaching the text field for controlling
               g.SetBgColor(m_WarningColor); // Setting the warning color of text in the text field
            }
         }
         else
         { // We need to disable the warning mode
            if(m_Warning)
            { // The warning mode is enabled
               g.Attach(m_NameEdit);    // Attach the text field for controlling 
               g.SetBgColor(m_BgColor); // Setting the normal font color                
            }
         }
      }
   m_Warning=aValue; // Registration of the current mode
}

// Getting the warning mode
bool Warning()
{ 
   return(m_Warning);
}

Se il controllo è visibile durante l'impostazione della modalità di avviso, viene verificato il valore del parametro passato al metodo SetWarning; se il suo valore non corrisponde allo stato corrente del controllo, il colore di sfondo del campo di testo viene modificato.

In ogni caso, viene registrata la modalità impostata, non per configurare il colore corrispondente al campo di testo nel caso in cui il controllo sia invisibile.

È rimasta una proprietà: m_Digits. Aggiungiamo metodi per ottenere e impostare il suo valore: 

// Setting the number of decimal places
void SetDigits(int aValue)
{ 
   m_Digits=aValue; // Registration of the new value
      if(m_Digits>=0)
      { // The numeric mode
         SetValue(ValueDouble()); // Resetting of the current value
      }
}  

// Getting the m_Digits value
int Digits()
{ 
   return(m_Digits);
}  

Bene, abbiamo finito con la parte più interessante. Ora è il momento di quella più bella.


6. Schema dei Colori

Gli schemi dei colori verranno memorizzati nelle variabili della classe CСolorSchemes.

La classe verrà dichiarata preventivamente nel file IncGUI.mqh con il nome ClrScheme. Per impostare uno schema dei colori, chiameremo il metodo SetScheme() con il numero di uno schema di colori specificato come parametro. Se il metodo SetScheme() non viene chiamato, verrà utilizzata lo schema di colori con il numero 0.

Per ottenere un colore, utilizzeremo il metodo Color() con un numero specificato di colori dallo schema di colori. Scriviamo la classe CСolor Schemes con le sezioni private e pubbliche. Nella sezione privata, dichiarare la variabile m_ShemeIndex per memorizzare l'indice di uno schema di colori. Nella sezione pubblica, scrivi il metodo SetScheme():

// Setting the color scheme number
void SetScheme(int aShemeIndex)
{ 
   m_ShemeIndex=aShemeIndex;
}

Il metodo Color(). Nel metodo viene dichiarato un array bidimensionale: la prima dimensione è il numero dello schema di colori; il secondo è il numero del colore nello schema. A seconda del numero specificato di uno schema di colori, restituisce il colore per numero specificato nei parametri del metodo.

color Color(int aColorIndex)
{
   color m_Color[3][4];  // The first dimension - the color scheme number, the second one - the number of the color in the color scheme
   // default
   m_Color[0][0]=clrSnow;
   m_Color[0][1]=clrDimGray;
   m_Color[0][2]=clrDimGray;
   m_Color[0][3]=clrPink;
   // yellow-black
   m_Color[1][0]=clrLightYellow;
   m_Color[1][1]=clrBrown;
   m_Color[1][2]=clrBrown;
   m_Color[1][3]=clrPink;
   // blue
   m_Color[2][0]=clrAliceBlue;
   m_Color[2][1]=clrNavy;
   m_Color[2][2]=clrNavy;
   m_Color[2][3]=clrPink;
   return(m_Color[m_ShemeIndex][aColorIndex]); // Returning a value according to the scheme number and the number of color in the scheme
}

Per ora, gli schemi di colori includono quattro colori ciascuno; due di essi hanno gli stessi valori. Inoltre, durante la creazione di altri controlli, potremmo aver bisogno di più colori.

Per trovare facilmente un colore appropriato nello schema o decidere di aggiungere un nuovo colore, la classe include un metodo che consente di visualizzare i colori - il metodo Show() (fig. 6). E c'è anche il metodo inverso Hide() per eliminare esempi di colore dal grafico.


Fig. 6. Visualizzazione di combinazioni di colori utilizzando il metodo Show()

L'articolo ha il ColorSchemesView.mq5 allegato. È un Expert Advisor per la visualizzazione di combinazioni di colori (ColorSchemesView.mq5).

Modifichiamo leggermente il metodo Init() nella classe CInputBox. Sostituisci i suoi colori con i colori della classe ClrScheme:

m_BgColor=ClrScheme.Color(0);       // Background color of the text field
m_TxtColor=ClrScheme.Color(1);      // Font color and frame color of the text field
m_LblColor=ClrScheme.Color(2);     // Caption color
m_WarningColor=ClrScheme.Color(3); // Warning color

Questa è la fine della creazione di un controllo; e ora abbiamo la base per sviluppare altri controlli.


7. Uso del Controllo

Creiamo un Expert Advisor e chiamiamolo GUITest; collegare il file IncGUI.mqh:  

#include <IncGUI.mqh>
Dichiarare la classe CInputBox con il nome ib:
CInputBox ib;

In OnInit() dell'EA, chiama il metodo Init() dell'oggetto ib:

ib.Init("InpytBox",50,4,"input");

Rendi visibile il controllo e imposta una posizione per esso:

ib.Show(10,20);

Nella funzione OnDeinit() dell'EA, elimina il controllo:

ib.Hide(); 

Compila e allega l'Expert Advisor a un grafico. Vedrai il nostro controllo (fig. 7).


Fig. 7. Il controllo InputBox

Aggiungi la possibilità di cambiare lo schema di colori all'Expert Advisor.

In questo momento, abbiamo tre schemi di colori. Facciamo un'enumerazione e una variabile esterna per la scelta di uno schema di colori: 

enum eColorScheme
  {
   DefaultScheme=0,
   YellowBrownScheme=1,
   BlueScheme=2
  };

input eColorScheme ColorScheme=DefaultScheme;

All'inizio della funzione OnInit() dell'Expert Advisor, aggiungi l'impostazione di uno schema di colori:

ClrScheme.SetScheme(ColorScheme);

Adesso nella finestra delle proprietà dell'EA possiamo scegliere uno dei tre schemi di colori (fig. 8).




Fig. 8. Diversi Schemi di Colori

Per gestire l'evento di specificare un nuovo valore, aggiungi il seguente codice alla funzione OnChartEvent() dell'EA:

if(ib.Event(id,lparam,dparam,sparam)==1)
  {
   Alert("Entered value "+ib.ValueStrind());
  }

Ora, quando viene specificato un nuovo valore nel campo di modifica, viene aperta una finestra di messaggio che informa sul valore specificato.

Fornire all'Expert Advisor la possibilità di creare controlli in una sottofinestra.

Innanzitutto, crea un indicatore di test TestSubWindow (allegato nel file TestSubWindow.mq5). Quando si crea l'indicatore in MQL5 Wizard, specifica che dovrebbe funzionare in una sottofinestra separata. Aggiungi il seguente codice alla funzione OnChartEvent() dell'EA:

if(CHARTEVENT_CHART_CHANGE)
  {
   ip.SetSubWindow("TestSubWindow");
  }

Ora, se l'indicatore non è sul grafico, il controllo viene creato sul grafico dei prezzi. Se si associa l'indicatore al grafico, il controllo salterà alla sottofinestra (fig. 9). Se elimini l'indicatore, il controllo tornerà al grafico dei prezzi.

 
Fig. 9. Il controllo nella sottofinestra

Conclusione

Come risultato del lavoro svolto, abbiamo il file include IncGUI.mqh che contiene le seguenti classi: CGraphicObjectShell (creazione e gestione di oggetti grafici), CWorkPiece (creazione rapida di diversi oggetti grafici con impostazione delle loro proprietà tramite parametri), CColorSchemes (impostazione di uno schema di colori e acquisizione del colore dello schema di colori corrente) e una classe di un controllo - CInputBox.

Le classi CGraphicObjectShell, CWorkPiece e CColorSchemes sono già dichiarate nel file con i nomi "g", "w" e "ClrScheme", cioè sono pronte all'uso subito dopo aver associato il file IncGUI.mqh.

Ripetiamo come usare la classe CInputBox:

  1. Collega il file IncGUI.mqh.
  2. Dichiarare una classe di tipo CInputBox.
  3. Chiama il metodo Init().
  4. Imposta le coordinate usando il metodo SetPos(); attiva la visibilità usando Show() se necessario. La seconda variante: attiva la visibilità usando Show() con la specifica delle coordinate.
  5. Se necessario o al termine del lavoro dell'Expert Advisor, nascondere il controllo utilizzando il metodo Hide().
  6. Aggiungi la chiamata del metodo Event() alla funzione OnChartEvent().
  7. Se è necessario creare un controllo in una sottofinestra, fornire alla funzione OnChartEvent() una chiamata del metodo SetSubWindow() quando si verifica un evento CHARTEVENT_CHART_CHANGE.
  8. Per utilizzare gli schemi dei colori, chiama il metodo SetScheme() della classe ClrScheme prima di chiamare il metodo Init(). 


Allegati

  • IncGUI.mqh - file di inclusione principale. Il file deve essere posizionato nella cartella MQL5/Include della cartella dei dati del client terminal.
  • GUITest.mq5 - Expert Advisor con un esempio del controllo CInputBox. Il file deve essere posizionato nella cartella MQL5/Experts della cartella dei dati del client terminal.
  • TestSubWindow.mq5 - l'indicatore per testare la funzione di visualizzazione di un controllo in una sottofinestra. Il file deve essere posizionato nella cartella MQL5/Indicators della cartella dati del client terminal.
  • ColorSchemesView.mq5 - Expert Advisor per la visualizzazione degli schemi dei colori. Uno strumento ausiliario per la creazione di controlli. Il file deve essere posizionato nella cartella MQL5/Experts della cartella dei dati del client terminal.
  • IncGUImqh.chm - documentazione per il file IncGUI.mqh.  

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

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.
MQL5 Wizard: Nuova Versione MQL5 Wizard: Nuova Versione
L'articolo contiene le descrizioni delle nuove funzionalità disponibili in MQL5 Wizard aggiornato. L'architettura modificata dei segnali consente di creare robot di trading basati sulla combinazione di vari modelli di mercato. L'esempio contenuto nell'articolo spiega la procedura di creazione interattiva di un Expert Advisor.
Controlli Grafici Personalizzati. Parte 3. Moduli Controlli Grafici Personalizzati. Parte 3. Moduli
Questo è l'ultimo dei tre articoli dedicati ai controlli grafici. Esso tratta la creazione del componente principale dell'interfaccia grafica - il modulo - e il suo utilizzo in combinazione con altri controlli. Oltre alle classi form, alla libreria di controllo sono state aggiunte le classi CFrame, CButton, CLabel.
I Fondamenti dei Testing in MetaTrader 5 I Fondamenti dei Testing in MetaTrader 5
Quali sono le differenze tra le tre modalità di testing in MetaTrader 5 e cosa dovremmo cercare in particolare? Come si svolge il testing di un EA, facendo trading simultaneamente su più strumenti? Quando e in che modo vengono calcolati i valori degli indicatori durante il testing e in che modo vengono gestiti gli eventi? Come sincronizzare le barre di diversi strumenti durante il testing in modalità "solo prezzi di apertura"? Questo articolo si propone di fornire risposte a queste e a molte altre domande.