Erstellen Ihrer eigenen grafischen Panels in MQL5

MetaQuotes | 26 Januar, 2016

Einleitung

In der Standardbibliothek steht Ihnen eine Reihe neuer Klassen zur Verfügung. Diese Klassen dienen der unabhängigen Entwicklung von Kontrolldialogen und Anzeigefeldern in MQL5-Programmen.

Mit den neuen Klassen kann jeder benutzerdefinierte Oberflächenkomponenten mithilfe des zugrundeliegenden ereignisbasierten Modells erstellen. Alles basiert auf den eingebetteten Diagrammobjekten und Ereignissen des Terminals.

Die entwickelten Klassen können auf die folgenden Arten genutzt werden:
  1. Anzeigefeld in einem separaten Unterfenster eines Diagramms;
  2. Bedienfeld für einen Expert Advisor;
  3. Bedienfeld für einen benutzerdefinierten Indikator.

Dieser Beitrag führt vor, wie einfach es ist, mithilfe der Klassen aus der Standardbibliothek Ihre eigenen Anzeigefelder in einem separaten Unterfenster eines Diagramms zu erstellen.


Was hat die Standardbibliothek zu bieten?

Die Standardbibliothek stellt Entwicklern die folgenden benutzerfreundlichen Bedienelemente zur Verfügung:

1. Einfache Bedienelemente:

Bedienelement Anwendung Umsetzung auf Basis des eingebetteten Objekts Datei in der Standardbibliothek

Button mit Text

Sicherstellen der Interaktion zwischen Maus und MQL-Programm

"Button"  <Controls\Button.mqh>

Button mit Bild

Sicherstellen der Interaktion zwischen Maus und MQL-Programm

"Grafisches Label"  <Controls\BmpButton.mqh>

Bearbeitungsfeld

Eingabe oder Anzeige von Textinformationen (im "Nur lesen"-Modus)

"Bearbeitungsfeld"  <Controls\Edit.mqh>

Beschriftung

Anzeige von Hilfstexten

"Textbeschriftung"  <Controls\Label.mqh>

Panel

Zusätzliches Bedienelement (optische Gruppierung von Bedienelementen)

"Rechteckige Beschriftung"  <Controls\Panel.mqh>

Bild

Dekoratives Bedienelement

 "Grafisches Label"  <Controls\Picture.mqh>



2. Komplexe Bedienelemente:


Bedienelement Anwendung Umsetzung auf Basis der Bedienelemente Datei in der Standardbibliothek

Liste

Ansicht einer Liste

"Rechteck", "Button mit Bild" und "Bearbeitungsfeld"  <Controls\List.mqh>

Feld mit Drop-Down-Liste

Auswahl aus einer Drop-Down-Liste

"Bearbeitungsfeld", "Button mit Bild" und "Liste"  <Controls\ComboBox.mqh>

Zunahme-/Abnahmefeld

Aufzählung von Werten

"Bearbeitungsfeld" und "Button mit Bild"  <Controls\SpinEdit.mqh>

Optionsschaltfläche

Umschalter "Button mit Bild" und "Beschriftung"  <Controls\RadioButton.mqh>
 Gruppe von Optionsschaltflächen  Bearbeiten von Feldern des Typen enum  "Rechteck" und "Optionsschaltfläche"  <Controls\RadioGroup.mqh>

Kontrollkästchen

Auswahloption

"Button mit Bild" und "Beschriftung"  <Controls\CheckBox.mqh>

Gruppe von Kontrollkästchen

Bearbeitung eines Satzes von Flags

 "Rechteck" und "Kontrollkästchen"  <Controls\CheckGroup.mqh>
 Dialog  Dialogform  "Rechteck", "Button mit Bild" und "Bearbeitungsfeld"  <Controls\Dialog.mqh>



Erstellen eines Anzeigefelds

Legen wir zuerst die Terminologie fest. Anzeigefeld ist ein Begriff, den wir verwenden werden, um einen benutzerdefinierten Indikator in einem separaten Fenster zu beschreiben, der über keinen Zeichenpuffer verfügt. Ein solches Feld zeigt einfach die erforderlichen Informationen mithilfe der im Terminal eingebetteten Diagrammobjekte an. Die Informationen können

Wir sehen uns jeden erforderlichen Schritt im Detail an und erstellen ein grafisches Panel, das wie folgt aussieht:



Um ein Anzeigefeld zu erstellen, benötigen wir zwei Dateien:

  1. Die Include-Datei, die die Beschreibung der Klasse des Anzeigefelds enthält.
  2. Die Datei mit dem Quellcode des Indikators.

Templates dieser Dateien können mithilfe des MQL5 Wizard abgerufen werden. Erstellen Sie im Verzeichnis der Indikatoren (MQL5\Indicators) einen separaten Ordner mit dem Namen MyIndicators und einen Unterordner mit dem Namen MyPanel. Der Prozess zum Erstellen von Ordnern wird hier nicht behandelt, da er in der Hilfe ausführlich beschrieben wird.


Klassenbeschreibung

Den Arbeitsordner haben wir also schon erstellt. Suchen wir ihn im "Navigator"-Fenster und rechtsklicken auf ihn. Wählen Sie im aufgerufenen Menü "New File" (Neue Datei). Wählen Sie in den Optionen des MQL5 Wizard "New Class" (Neue Klasse) und klicken Sie auf "Weiter >". Füllen Sie den Dialog für die Klassenbeschreibung aus, wie unten abgebildet:

Erstellen einer neuen Klasse im MQL Wizard

Klicken Sie auf "Fertigstellen". Als Ergebnis erhalten wir den folgenden Code:

//+------------------------------------------------------------------+
//|                                                  PanelDialog.mqh |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CPanelDialog : public CAppDialog
  {
private:

public:
                     CPanelDialog();
                    ~CPanelDialog();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPanelDialog::CPanelDialog()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPanelDialog::~CPanelDialog()
  {
  }
//+------------------------------------------------------------------+


Fügen Sie die Include-Datei <Controls\Dialog.mqh> aus der Standardbibliothek mit der Beschreibung der Basisklasse CAppDialog und Kommentaren hinzu.

//+------------------------------------------------------------------+
//|                                                  PanelDialog.mqh |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Controls\Dialog.mqh>
//+------------------------------------------------------------------+
//| CPanelDialog class                                               |
//| Function: main application dialog                                |
//+------------------------------------------------------------------+
class CPanelDialog : public CAppDialog
  {
private:

public:
                     CPanelDialog(void);
                    ~CPanelDialog(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CPanelDialog::CPanelDialog(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CPanelDialog::~CPanelDialog(void)
  {
  }
//+------------------------------------------------------------------+

Nun haben wir die Beschreibung der Klasse, die es uns ermöglichen wird, ein Dialogfenster in ihrem Indikator zu verwenden. Unser Dialog ist derzeit noch leer, aber wir werden ihm etwas später Bedienelemente hinzufügen. Fahren wir aber vorerst mit dem Indikator fort.


Der Quellcode des Indikators

Der Indikator wird ebenfalls mithilfe des MQL5 Wizard erstellt. Die dafür erforderlichen Aktionen sind denen beim Schreiben der Klassenbeschreibung ähnlich. Es gibt nur einen Unterschied: In den Optionen des MQL5 Wizard wählen wir "Custom Indicator" (Benutzerdefinierter Indikator). Um einen Indikator zu erstellen, müssen drei Dialoge ausgefüllt werden.

Im ersten muss der Name des Indikators angegeben werden:

Erstellen eines neuen Indikators im MQL Wizard


Im zweiten Dialog setzen Sie das Häkchen bei "OnChartEvent" (erforderlich) und "OnTimer":

Festlegen von Ereignis-Handlern für den benutzerdefinierten Indikator im MQL Wizard



Setzen Sie im dritten Dialog das Häkchen bei "Indicator in separate window" (Indikator in separatem Fenster) (erforderlich):

Festlegen der Zeicheneigenschaften des Indikators im MQL Wizard


Und klicken Sie auf "Fertigstellen". Der Code sieht so aus:

//+------------------------------------------------------------------+
//|                                               PanelIndicator.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| 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)
  {
//---
   
  }
//+------------------------------------------------------------------+


Wir fügen unserem Template Folgendes hinzu:

Nun haben wir einen gebrauchsfertigen Indikator:

//+------------------------------------------------------------------+
//|                                               PanelIndicator.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_plots               0
#property indicator_buffers             0
#property indicator_minimum             0.0
#property indicator_maximum             0.0
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "PanelDialog.mqh"
//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
CPanelDialog ExtDialog;
//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- creating the application dialog
   if(!ExtDialog.Create(0,"Panel Indicator",0,0,0,0,130))
     return(-1);
//--- starting the application
   if(!ExtDialog.Run())
     return(-2);
//--- creating the timer
   EventSetTimer(1);
//--- success
   return(0);
  }
//+------------------------------------------------------------------+
//| Deinitialization                                                 |
//+------------------------------------------------------------------+
int OnDeinit()
  {
//--- destroying the dialog
   ExtDialog.Destroy();
//--- killing the timer
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Iteration                                                        |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
              const int prev_calculated,
              const int begin,
              const double &price[])
  {  
//--- returning the prev_calculated value for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer event handler                                              |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
  }
//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                const long &lparam,
                const double &dparam,
                const string &sparam)
  {
//--- handling the event
   ExtDialog.ChartEvent(id,lparam,dparam,sparam);
  }
//+------------------------------------------------------------------+


In dieser Form zeigt der Indikator noch nichts an. Wenn er kompiliert und aus dem Navigator in das Diagramm übertragen wird, wird er als leerer Dialog in einem separaten Fenster angezeigt.

Obwohl der Dialog leer ist, hat unser Indikator bereits bestimmte Merkmale erhalten:


Ermöglichen der Anzeige

Damit unser Panel anfangen kann, Informationen anzuzeigen, müssen wir drei Fragen beantworten:

  1. Welche Art von Informationen wollen wir anzeigen lassen?
  2. Welche zusätzlichen Anzeige- und/oder Bedienelemente müssen in unserem Dialog platziert werden?
  3. Wie interagieren diese zusätzlichen Anzeige-/Bedienelemente miteinander?

Ein weiterer wichtiger Faktor ist, dass unser Dialog optisch ansprechend und benutzerfreundlich sein soll. Dies betrifft nicht die Funktionalität des Dialogs, doch es zeigt, dass wir uns um die Anwender unseres zukünftigen MQL5-Programms kümmern.

   Schritt 1. Welche Art von Informationen wollen wir anzeigen lassen?

Da dieser Beitrag Lernzwecken dient, halten wir uns nicht mit der Benutzerfreundlichkeit des Indikators auf. Die Farbe wird als Funktion von drei Parametern angezeigt. Wir wollen die Parameter nicht zu kompliziert machen, deshalb werden es "rote", "grüne" und "blaue" Anteile sein.

Die Parameterwerte werden wie folgt festgelegt:

  • Der Wert des "roten" Anteils liegt im Bereich zwischen 0 und 255 und ändert sich zufällig bei jedem Calculate-Ereignis;
  • Der Wert des "grünen" Anteils liegt im Bereich zwischen 0 und 255 und ändert sich zufällig bei jedem Timer-Ereignis;
  • Der Wert des "blauen" Anteils liegt im Bereich zwischen 0 und 255 und wird durch ein spezielles Bedienelement manuell geändert.

Übrigens werden die Werte dieser Anteile auch in unserem Indikator angezeigt.


   Schritt 2. Welche zusätzlichen Bedienelemente werden benötigt?

  1. Die Farbe wird mithilfe des Bedienelements "Panel" angezeigt.
  2. Der "rote" und "grüne" Anteil wird mithilfe des Bedienelements "Eingabefeld" im "Nur lesen"-Modus angezeigt.
  3. Der "blaue" Anteil wird mithilfe des Bedienelements "Spin-Button" verwaltet. Dasselbe Bedienelement hilft auch bei der Anzeige des Anteilswerts.
  4. Die Bedienelemente "Bearbeitungsfeld" und "Spin-Button" werden beide durch das Bedienelement "Beschriftung" um erläuternde Beschriftungen erweitert.

Fügen Sie die Include-Dateien aus der Standardbibliothek sowie die erforderlichen Bedienelemente und Variablen zur Speicherung der Parameterwerte zur Klassenbeschreibung hinzu, nachdem Sie sie mit Kommentaren versehen haben.

Wir erhalten:

//+------------------------------------------------------------------+
//|                                                  PanelDialog.mqh |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Controls\Dialog.mqh>
#include <Controls\Panel.mqh>
#include <Controls\Edit.mqh>
#include <Controls\Label.mqh>
#include <Controls\SpinEdit.mqh>
//+------------------------------------------------------------------+
//| CPanelDialog class                                               |
//| Function: main application dialog                                |
//+------------------------------------------------------------------+
class CPanelDialog : public CAppDialog
  {
private:
   //--- additional controls
   CPanel            m_color;                         // object for displaying color
   CLabel            m_label_red;                     // "red" level caption object
   CEdit             m_field_red;                     // "red" value display object
   CLabel            m_label_green;                   // "green" level caption object
   CEdit             m_field_green;                   // "green" value display object
   CLabel            m_label_blue;                    // "blue" level caption object
   CSpinEdit         m_edit_blue;                     // "blue" value control object
   //--- parameter values
   int               m_red;                           // "red" value
   int               m_green;                         // "green" value
   int               m_blue;                          // "blue" value

public:
                     CPanelDialog(void);
                    ~CPanelDialog(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CPanelDialog::CPanelDialog(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CPanelDialog::~CPanelDialog(void)
  {
  }
//+------------------------------------------------------------------+


   Schritt 3. Wie interagieren diese zusätzlichen Dialog-Bedienelemente miteinander?
Das Prinzip der Interaktion zwischen den Dialog-Bedienelementen ist sehr einfach: "Der Dialog muss Änderungen in jedem Parameter ("roten", "grünen" und "blauen" Anteil) anzeigen". Auf die Umsetzung der Interaktionsalgorithmen gehen wir später ein, da es jetzt an der Zeit ist, mit der Erstellung des Dialogs zu beginnen.


Ein paar Wörter zum ansprechenden Äußeren

Bevor wir mit der Erstellung des Dialogs fortfahren, gehen wir kurz auf das ansprechende Äußere ein. Oder, besser gesagt, eine benutzerfreundliche Anordnung und (mögliche) zukünftige Neuanordnung der Dialog-Bedienelemente. Benannte Konstanten (#define) dienen diesem Zweck am besten.

Die vordefinierten benannten Konstanten haben einige Vorteile:


Die Verwendung der folgenden Konstanten wird empfohlen:

//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
//--- indents and spacing
#define INDENT_LEFT                         (11)      // left indent (including the border width)
#define INDENT_TOP                          (11)      // top indent (including the border width)
#define INDENT_RIGHT                        (11)      // right indent (including the border width)
#define INDENT_BOTTOM                       (11)      // bottom indent (including the border width)
#define CONTROLS_GAP_X                      (10)      // spacing along the X-axis
#define CONTROLS_GAP_Y                      (10)      // spacing along the Y-axis
//--- for labels
#define LABEL_WIDTH                         (50)      // size along the X-axis
//--- for edits
#define EDIT_WIDTH                          (50)      // size along the Y-axis
#define EDIT_HEIGHT                         (20)      // size along the Y-axis
//--- for base colors (RGB)
#define BASE_COLOR_MIN                      (0)       // minimum value of the color component
#define BASE_COLOR_MAX                      (255)     // maximum value of the color component


Ausfüllen des Anzeigefelds

Vorher haben wir die Klasse des Anzeigefelds erstellt. Um nun die nötige Funktionalität zu erhalten, müssen wir Folgendes tun:

1. Die Create(...)-Methode der übergeordneten Klasse neu definieren. Zunächst sieht unsere Methode so aus:

//+------------------------------------------------------------------+
//| Creation                                                         |
//+------------------------------------------------------------------+
bool CPanelDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
//--- calling the method of the parent class
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))  return(false);
//--- additional controls shall be created here

//--- success
   return(true);
  }


2. Erstellen zusätzlicher Bedienelemente.

Hier machen wir eine kleine "lyrische" Abweichung. Die Codes für die Erstellung aller zusätzlichen Bedienelemente können natürlich direkt in den Hauptteil der Create(...)-Methode eingefügt werden, doch damit riskieren wir, dass wir eine große, unlesbare "Masse" erhalten.

Deshalb teilen wir den Erstellungsprozess in eigenständige Teile auf, die durch Methoden repräsentiert werden:

Diese Methoden werden durch die Create(...)-Methode sequentiell aufgerufen:

//+------------------------------------------------------------------+
//| Creation                                                         |
//+------------------------------------------------------------------+
bool CPanelDialog::Create(const long chart,const string name,const int subwin,
                             const int x1,const int y1,const int x2,const int y2)
  {
//--- calling the parent class method
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2)) return(false);

//--- creating additional elements
   if(!CreateColor()) return(false);
   if(!CreateRed())   return(false);
   if(!CreateGreen()) return(false);
   if(!CreateBlue())  return(false);
//--- success
   return(true);
  }


Erstellen von Bedienelementen

Wir gehen nicht auf die Erstellung jedes einzelnen zusätzlichen Bedienelements ein, sehen uns aber die Methode bool CreateBlue(void) im Detail an.

Sie sieht wie folgt aus:

//+------------------------------------------------------------------+
//| Creating the "Blue" control with explanatory caption             |
//+------------------------------------------------------------------+
bool CPanelDialog::CreateBlue(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+2*(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2=x1+EDIT_WIDTH;
   int y2=y1+EDIT_HEIGHT;
//--- creating the caption
   if(!m_label_blue.Create(m_chart_id,m_name+"LabelBlue",m_subwin,x1,y1+1,x2,y2)) return(false);
   if(!m_label_blue.Text("Blue")) return(false);
   if(!Add(m_label_blue)) return(false);
//--- adjusting coordinates
   x1+=LABEL_WIDTH+CONTROLS_GAP_X;
   x2=x1+EDIT_WIDTH;
//--- creating the control
   if(!m_edit_blue.Create(m_chart_id,m_name+"Blue",m_subwin,x1,y1,x2,y2)) return(false);
   if(!Add(m_edit_blue)) return(false);
   m_edit_blue.MinValue(BASE_COLOR_MIN);
   m_edit_blue.MaxValue(BASE_COLOR_MAX);
   m_edit_blue.Value(m_blue);
//--- success
   return(true);
  }

Es gibt zwei Feinheiten zu beachten:

  1. Das Bedienelement wird mit relativen Koordinaten erstellt. Das heißt, die Verschiebung bezieht sich auf die linke obere Ecke des Containers (des komplexen Elements), dem das Bedienelement nach seiner Erstellung hinzugefügt wird.
  2. Nach der Erstellung muss das Bedienelement mithilfe der Add(...)-Methode einem Container hinzugefügt werden. In unserem Fall dient der Dialog als Container.


Ändern der Parameter

Fügen Sie die Methode void SetColor(void) hinzu, um die Farbe des Farb-Panels zu ändern;

Um die Parameter (Anteile der Basisfarben) extern ändern zu können, fügen wir drei öffentliche Methoden hinzu:

Der Teilsatz "zeigt die Änderung im Indikator an" bedeutet, dass der neue Wert des Basisfarbenanteils in numerischer Form im entsprechenden Bedienelement angezeigt wird und das Farb-Panel seine Farbe ändert.

Hier sehen Sie den Code einer der Methoden als Beispiel:

//+------------------------------------------------------------------+
//| Setting the "Red" value                                          |
//+------------------------------------------------------------------+
void CPanelDialog::SetRed(const int value)
  {
//--- checking
   if(value<0 || value>255) return;
//--- saving
   m_red=value;
//--- setting
   m_field_red.Text(IntegerToString(value));
//--- setting the panel color
   SetColor();
  }

Wie oben beschrieben:

Fügen wir den entsprechenden Code im ursprünglichen Indikator ein:

//+------------------------------------------------------------------+
//|                                               PanelIndicator.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_plots               0
#property indicator_buffers             0
#property indicator_minimum             0.0
#property indicator_maximum             0.0
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "PanelDialog.mqh"
//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
CPanelDialog ExtDialog;
//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- creating the application dialog
   if(!ExtDialog.Create(0,"Panel Indicator",0,0,0,0,130))
      return(-1);
//--- starting the application
   if(!ExtDialog.Run())
      return(-2);
//--- creating the timer
   EventSetTimer(1);
//--- success
   return(0);
  }
//+------------------------------------------------------------------+
//| Deinitialization                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroying the dialog
   ExtDialog.Destroy();
//--- killing the timer
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Iteration                                                        |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//--- changing the dialog property
   ExtDialog.SetRed(MathRand()%256);
//--- returning the prev_calculated value for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer event handler                                              |
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- changing the dialog property
   ExtDialog.SetGreen(MathRand()%256);
  }
//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- handling the event
   ExtDialog.ChartEvent(id,lparam,dparam,sparam);
  }
//+------------------------------------------------------------------+


Verarbeiten der Ereignisse

Die gesamte Interaktion zwischen dem Dialog und dem Terminal sowie die Interaktion zwischen den Dialog-Bedienelementen basieren auf dem Ereignis-Mechanismus. Wir sehen uns seine Funktionen nicht an, sondern nutzen ihn einfach.

Ereignisse können für gewöhnlich in zwei Gruppen unterteilt werden:

Wir verarbeiten beide Typen von Ereignissen.

Von den internen Ereignissen müssen nur die Ereignisse der Änderung der Größe des Dialogs verarbeitet werden. Laden Sie zu diesem Zweck die OnResize()-Methode der übergeordneten Klasse erneut. Unsere Methode wird einfach ausfallen, da die Höhe des Dialogs nicht verändert wird. Wenn sich die Breite des Dialogs ändert, müssen wir nur die Breite des Farb-Panels anpassen:

//+------------------------------------------------------------------+
//| Resize handler                                                   |
//+------------------------------------------------------------------+
bool CPanelDialog::OnResize(void)
  {
//--- calling the parent class method
   if(!CAppDialog::OnResize()) return(false);
//--- changing the color panel width
   m_color.Width(ClientAreaWidth()-(INDENT_RIGHT+LABEL_WIDTH+CONTROLS_GAP_X+EDIT_WIDTH+CONTROLS_GAP_X+INDENT_LEFT));
//--- success
   return(true);
  }

Die Liste externer Ereignisse beschränkt sich ebenfalls auf einen Eintrag: Das Ereignis der Änderung des "blauen" Anteils. Die Anforderungen an den externen Ereignis-Handler sind minimal: Der Handler muss die parameterlose Methode der Klasse des Typen void sein.

Beschreiben wir den Handler dieses Ereignisses:

//+------------------------------------------------------------------+
//| Handler of the event of changing the "blue" level                |
//+------------------------------------------------------------------+
void CPanelDialog::OnChangeBlue(void)
  {
//--- saving
   m_blue=m_edit_blue.Value();
//--- setting the panel color
   SetColor();
  }

Wie Sie sehen, ist es absolut nicht schwierig.

Damit unser Dialog externe Ereignisse verarbeitet, muss die Methode der übergeordneten Klasse erneut geladen werden:

virtual bool  OnEvent(const int id,const long &lparam,
                       const double &dparam,const string &sparam);

Und jetzt noch etwas "Mysteriöses". Falls Sie die Datei PanelDialog.mqh bereits im Editor geöffnet haben, werden Sie feststellen, dass die OnEvent(...)-Methode keinen Hauptteil hat.

Lassen Sie sich dadurch nicht verwirren. Das liegt daran, dass für die Beschreibung der Verarbeitung externer Ereignisse eine Reihe von Makros erstellt wurde (siehe Datei <Controls\Defines.mqh> in der Standardbibliothek).

Unser Ereignis-Handler sieht wie folgt aus:

//+------------------------------------------------------------------+
//| Handling events                                                  |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CPanelDialog)
   ON_EVENT(ON_CHANGE,m_edit_blue,OnChangeBlue)
EVENT_MAP_END(CAppDialog)

Der Pseudocode, der auf den ersten Blick unklar aussieht, bewirkt Folgendes:


Fazit

Mit diesem Beitrag haben Sie einen Überblick über den Prozess der Erstellung eines Anzeigefelds mithilfe der Klassen der Standardbibliothek erhalten.

Es ist unwahrscheinlich, dass Sie den Indikator in dieser Form nutzen werden, allerdings ist er nicht mit unnötigen Informationen überladen und wir sind auf fast alle Besonderheiten des Prozesses zu seiner Erstellung eingegangen.

Komplexere Beispiele für die Standardbereitstellung finden Sie in den folgenden Verzeichnissen Ihres Terminals: