English Русский 中文 Español 日本語 Português
preview
Verbessern Sie Ihre Handelscharts mit interaktiven GUI's in MQL5 (Teil III): Ein einfaches, bewegliches Handels-GUI

Verbessern Sie Ihre Handelscharts mit interaktiven GUI's in MQL5 (Teil III): Ein einfaches, bewegliches Handels-GUI

MetaTrader 5Handel | 29 September 2023, 10:31
341 0
Kailash Bai Mina
Kailash Bai Mina

Einführung

Hallo und herzlich willkommen zu Teil 3 unserer Serie „Verbessern Sie Ihre Handelscharts mit interaktiven GUI's in MQL5“.

Bevor wir uns auf neues Terrain begeben, lassen Sie uns kurz rekapitulieren, was wir in Teil I und II behandelt haben:

1. In Teil I haben wir mit dem Konzept der Chartereignisse begonnen und darauf aufbauend zwei einfache bewegliche Dashboards auf demselben Chart erstellt.

2. Für Teil II sind wir noch einen Schritt weiter gegangen. Wir haben Klassen in einer .mqh-Datei verwendet, um unseren Code effizienter und vielseitiger zu gestalten, damit er in umfassende EAs/Indikatoren integriert werden kann.

Und nun sind wir bereit für Teil III! In diesem Teil werden wir uns darauf konzentrieren, unsere Dashboards zu verbessern, indem wir GUIs in sie integrieren. Denn ohne grafische Nutzeroberflächen erfüllen Dashboards nicht den ihnen zugedachten Zweck.

Hier ein kurzer Überblick über die Themen, die wir in diesem Artikel behandeln werden:

  1. Was werden wir machen?
  2. Erstellung eines einfachen statischen Dashboards für den Handel
  3. Besprechung des Ansatzes, unser statisches Dashboard mit allen darin enthaltenen Elementen zu bewegen
  4. Verwendung des diskutierten Ansatzes, um unser statisches Dashboard beweglich zu machen
  5. Schlussfolgerung


Was werden wir machen?

Unser Ziel ist es, ein bewegliches Dashboard mit einer grafischen Nutzeroberfläche zu erstellen, und dafür müssen wir entscheiden, was wir erstellen wollen. Ich habe einen einfachen EA, nämlich den Simple Trading EA, als Grundlage gewählt.

Zunächst müssen wir dieses statische Dashboard, d. h. den Simple Trading EA, erstellen. Es ist wichtig, dies effizient zu tun, da wir einen vollwertigen EA erstellen. Mit Effizienz meine ich, dass wir nicht einfach eine Datei öffnen und den gesamten Code darin schreiben können. Stattdessen brauchen wir einen gut durchdachten Plan, der es uns erlaubt, das absolute Minimum an Code über mehrere gut organisierte .mqh-Dateien zu schreiben. Vor allem müssen wir vermeiden, denselben Code wiederholt zu duplizieren, um die erforderlichen statischen GUIs für unser bewegliches Dashboard zu erstellen.

Hier ist das grundlegende statische Dashboard, das wir für unseren Zweck erstellen werden:

Abb. 1. Einfaches statisches Dashboard

Abb. 1. Einfaches statisches Dashboard


Es umfasst:

Element Beschreibung
Label 1 Titeltext (Simple Trading EA V1.0)
Label 2 Losgröße
Edit 1 Das weiß gefärbte Eingabefeld, das Sie in der obigen Abbildung sehen, mit der Aufschrift 0,01.
Button 1 Die grün gefärbte Schaltfläche Kaufen.
Button 2 Die rot gefärbte Schaltfläche Verkaufen.
Rectangle Label 1 Titelleiste, die dunkelblaue Leiste, auf der „Simple Trading EA V1.0“ steht.
Rectangle Label 2  Hauptbereich des Dashboards, das hellblau gefärbte Dashboard.

Unser Dashboard besteht also aus einer Kombination dieser sieben Komponenten. Wenn Sie mich fragen, würde ich sagen, dass wir durch die Kombination dieser sieben Elemente ein ziemlich ansehnliches Dashboard geschaffen haben.

Beginnen wir nun mit der Codierung dieses Dashboards.


Erstellen eines einfachen statischen Dashboards für den Handel

Welche Kurse werden wir schreiben? Denken wir kurz nach ...

Wir benötigen 2 Labels, 2 Schaltflächen, 1 Bearbeitungsfeld und 2 rechteckige Labels. Wir erstellen also 4 .mqh-Dateien, eine für jede von ihnen. Hier ist die Ordnerstruktur unseres Projekts:

  • Einfacher Handels-EA:
    • SimpleTradingEA.mq5
    • Button.mqh
    • Label.mqh
    • Edit.mqh
    • RechteckEtikett.mqh

Dies sind die Dateien, in denen wir unseren Code schreiben werden. Erstellen wir nun unsere erste Datei, „SimpleTradingEA.mq5“, die unsere Haupt-EA-Datei ist.

Ich habe die Funktion OnTick() entfernt, da wir sie für dieses Projekt nicht benötigen. So sieht die Datei im Moment aus:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
   {
    return(INIT_SUCCEEDED);
   }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
   {
   }
//+------------------------------------------------------------------+

Erstellen wir jetzt einen Plan. Wir werden unser statisches Dashboard in der folgenden Reihenfolge aufbauen:

  1. Titelleiste
  2. Hauptteil des Dashboards
  3. Titel Text
  4. „Lot Size“: Text
  5. Edit Box
  6. Schaltfläche für Kaufen und Verkaufen
  7. Fügen wir die erforderlichen letzten Handgriffe hinzu.

Dies scheint eine vernünftige Reihenfolge zu sein. Fangen wir an,

  1. Titelleiste

    Um die Titelleiste zu erstellen, müssen wir das Objekt Rectangle Label verwenden. Lassen Sie uns also eine Klasse erstellen, die alles, was mit dem Rectangle Label Object zusammenhängt, behandelt. Wir werden eine .mqh-Datei erstellen; nennen wir sie der Einfachheit halber „RectangleLabel.mqh“, und nennen wir die Klasse „RectangleLabel“.
    Hier ist die leere Klasse, die wir erstellt haben:

    //+------------------------------------------------------------------+
    //| Class Definition: RectangleLabel                                 |
    //+------------------------------------------------------------------+
    class RectangleLabel
       {
    public:
                         RectangleLabel(void);
                        ~RectangleLabel(void);
       };
    
    //+------------------------------------------------------------------+
    //| Constructor: RectangleLabel                                      |
    //+------------------------------------------------------------------+
    RectangleLabel::RectangleLabel(void)
       {
       }
    
    //+------------------------------------------------------------------+
    //| Destructor: RectangleLabel                                       |
    //+------------------------------------------------------------------+
    RectangleLabel::~RectangleLabel(void)
       {
       }
    //+------------------------------------------------------------------+

    Wir werden einige Funktionen benötigen, z.B.

    1. Create             -> So erstellen wir die rechteckige Beschriftung
    2. Destroy            -> So zerstören wir das Dashboard
    3. SetBorderType  -> So legen wie den Rahmentyp fest
    4. SetBGColor       -> So legen wie die Hintergrundfarbe fest

    Deklarieren wir die oben genannten Funktionen in der Liste der Mitgliedsfunktionen. Unsere Klasse sieht nun folgendermaßen aus:

    //+------------------------------------------------------------------+
    //| Class Definition: RectangleLabel                                 |
    //+------------------------------------------------------------------+
    class RectangleLabel
       {
    public:
                         RectangleLabel(void); // Constructor
                        ~RectangleLabel(void); // Destructor
        void             Create(string name, int xDis, int yDis, int xSize, int ySize); //Creates a Rectangle Label with the given parameters
        void             Destroy(); // Destroys the Rectangle Label
        void             SetBorderType(ENUM_BORDER_TYPE borderType); // Sets the border type of the Rectangle Label
        void             SetBGColor(color col); // Sets the background color of the Rectangle Label
       };
    //+------------------------------------------------------------------+

    Schreiben wir die einfache Erstellungsfunktion auf:

    //+------------------------------------------------------------------+
    //| RectangleLabel Class - Create Method                             |
    //+------------------------------------------------------------------+
    void RectangleLabel::Create(string name, int xDis, int yDis, int xSize, int ySize)
       {
        ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0); // Create the Rectangle Label object
        ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xDis); // Set the X-axis distance
        ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yDis); // Set the Y-axis distance
        ObjectSetInteger(0, name, OBJPROP_XSIZE, xSize); // Set the X size
        ObjectSetInteger(0, name, OBJPROP_YSIZE, ySize); // Set the Y size
       }
    //+------------------------------------------------------------------+

    Wir erstellen Destroy, SetBorderType und SetBGColor jeweils in nur einer Zeile, da sie eben nur eine Zeile benötigen. Hier ist unsere aktualisierte Klasse:

    //+------------------------------------------------------------------+
    //| Class Definition for the Rectangle Label                         |
    //+------------------------------------------------------------------+
    class RectangleLabel
       {
    private:
        string           _name; // Name of the rectangle label
    public:
                         RectangleLabel(void); // Constructor
                        ~RectangleLabel(void); // Destructor
    
        void             Create(string name, int xDis, int yDis, int xSize, int ySize); // Method to create a rectangle label with given dimensions
    
        void             Destroy() {ObjectDelete(0, _name);} // Method to delete the object using the object's name
    
        void             SetBorderType(ENUM_BORDER_TYPE borderType) {ObjectSetInteger(0, _name, OBJPROP_BORDER_TYPE, borderType);} // Method to set the border type for the rectangle label
    
        void             SetBGColor(color col) {ObjectSetInteger(0, _name, OBJPROP_BGCOLOR, col);} // Method to set the background color for the rectangle label
       };
    //+------------------------------------------------------------------+

    Außerdem haben wir eine private Variable mit dem Namen „_name“ hinzugefügt, da ObjectDelete einen Namen benötigt, und wir haben „_name“ in der Funktion Create gesetzt:

    //+------------------------------------------------------------------+
    //| Rectangle Label Creation Method                                  |
    //+------------------------------------------------------------------+
    void RectangleLabel::Create(string name, int xDis, int yDis, int xSize, int ySize)
       {
        ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0); // Create rectangle label object
        ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xDis); // Set X distance
        ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yDis); // Set Y distance
        ObjectSetInteger(0, name, OBJPROP_XSIZE, xSize); // Set X size
        ObjectSetInteger(0, name, OBJPROP_YSIZE, ySize); // Set Y size
        _name = name; // Assign the name to the member variable
       }
    //+------------------------------------------------------------------+

    Wir haben einfach „_name = name;“ in die letzte Zeile eingefügt, um die Variable _name auf den Namen der des Labels des Rechtecks zu setzen, als dieses erstellt wurde.

    Wenn Sie sich fragen, wo der Code ist, der es beweglich macht, ignorieren wir diesen Aspekt im Moment, um die Dinge einfach zu halten, bis wir ein einfaches statisches Dashboard erstellen.

    Verwenden wir nun diese Klasse in der Hauptdatei, d.h. SimpleTradingEA.mq5, um das Ergebnis zu sehen:


    Wir haben zuerst die Datei RectangleLabel.mqh mit „#include“ eingebunden und eine Instanz der Klasse namens TitleBar erstellt, da wir die Titelleiste des Dashboards mit dieser Instanz der Klasse RectangleLabel erstellen werden. Wir werden sie wieder für den Hauptteil des Dashboards verwenden.

    Dann haben wir diese Instanz verwendet, um eine rechteckige Beschriftung auf dem Chart an der Koordinate (100,100) mit den Abmessungen 200x20 zu erstellen. Dann setzen wir die Umrandung auf eben (BORDER_FLAT), da dies meiner Meinung nach besser aussieht; Sie können sie nach Ihren Wünschen ändern. Dann verwenden wir die Funktion ChartRedraw(0), um das Chart neu zu zeichnen; auf diese Weise wird das Dashboard sofort im Chart erstellt. Andernfalls kann er auf die nächste Preisaktualisierung, d. h. den nächsten Tick, warten.

    Das war alles in OnInit(), d.h. es wird nur einmal ausgeführt, um das Dashboard zu erstellen und im Chart anzuzeigen.

    Schließlich zerstören wir das Dashboard mit der von uns erstellten Funktion Destroy() in OnDeinit(), d. h. wenn der EA aus dem Chart entfernt wird.

    Ergebnis:

    Abb. 2. Titelleiste

    Abb. 2. Titelleiste


  2. Hauptteil des Dashboards

    Verwenden wir wieder die Klasse RectangleLabel, um den Hauptteil zu erstellen. Es ist einfach; wir müssen nur eine weitere Instanz erstellen; nennen wir sie „MainDashboardBody“ und fügen den folgenden einfachen Code in OnInit() ein, nachdem wir die Titelleiste erstellt haben, und fügen dann schließlich MainDashboardBody.Destroy() in OnDeinit() hinzu:

    // Creating a rectangle label called "MainDashboardBody" with specific dimensions
    MainDashboardBody.Create("MainDashboardBody", 100, 119, 200, 100);
    // Setting the border type of the "MainDashboardBody" rectangle label to be flat
    MainDashboardBody.SetBorderType(BORDER_FLAT);
    Danach sieht unser Code wie folgt aus:
    #include "RectangleLabel.mqh" // Including the RectangleLabel class definition
    RectangleLabel TitleBar; // Declaration of a TitleBar object
    RectangleLabel MainDashboardBody; // Declaration of a MainDashboardBody object
    
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
       {
        TitleBar.Create("TitleBar", 100, 100, 200, 20); // Creating the TitleBar with specified dimensions
        TitleBar.SetBorderType(BORDER_FLAT); // Setting the border type of TitleBar to be flat
    
        MainDashboardBody.Create("MainDashboardBody", 100, 119, 200, 100); // Creating the MainDashboardBody with specified dimensions
        MainDashboardBody.SetBorderType(BORDER_FLAT); // Setting the border type of MainDashboardBody to be flat
    
        ChartRedraw(0); // Redrawing the chart to reflect changes
        return(INIT_SUCCEEDED); // Indicating successful initialization
       }
    
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
       {
        MainDashboardBody.Destroy(); // Destroying the MainDashboardBody object
        TitleBar.Destroy(); // Destroying the TitleBar object
       }
    //+------------------------------------------------------------------+

    Damit sieht unser Ergebnis recht gut aus:

    Abb. 3. Hauptteil des Dashboards ergänzt

    Abb. 3. Hauptteil des Dashboards ergänzt



  3. Titel Text

    Um einen Titeltext hinzuzufügen, müssen wir eine Klasse erstellen, die der Klasse RectangleLabel ähnelt, aber speziell für Beschriftungen gedacht ist und es uns ermöglicht, Text hinzuzufügen. Hier ist der Code für eine neue Klasse mit dem Namen Label :

    //+------------------------------------------------------------------+
    //| Label class definition                                           |
    //+------------------------------------------------------------------+
    class Label
       {
    private:
        string           _name; // Name of the label
    public:
                         Label(void); // Constructor
                        ~Label(void); // Destructor
                        
        void             Create(string name, int xDis, int yDis); // Method to create a label    
        void             Destroy() {ObjectDelete(0, _name);} // Method to destroy a label    
        void             SetTextColor(color col) {ObjectSetInteger(0, _name, OBJPROP_COLOR, col);} // Method to set the text color    
        void             SetText(string text) {ObjectSetString(0, _name, OBJPROP_TEXT, text);} // Method to set the text content    
        string           GetText() {return ObjectGetString(0, _name, OBJPROP_TEXT);} // Method to retrieve the text content    
        void             SetFontSize(int fontSize) {ObjectSetInteger(0, _name, OBJPROP_FONTSIZE, fontSize);} // Method to set the font size    
        void             SetFont(string fontName) {ObjectSetString(0, _name, OBJPROP_FONT, fontName);} // Method to set the font name
       };
    
    //+------------------------------------------------------------------+
    //| Constructor                                                      |
    //+------------------------------------------------------------------+
    Label::Label(void)
       {
    
       }
    
    //+------------------------------------------------------------------+
    //| Destructor                                                       |
    //+------------------------------------------------------------------+
    Label::~Label(void)
       {
    
       }
    
    //+------------------------------------------------------------------+
    //| Method to create a label object                                  |
    //+------------------------------------------------------------------+
    void Label::Create(string name, int xDis, int yDis)
       {
        // Code to create label object, set its position, and assign its name
        ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
        ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xDis);
        ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yDis);
        _name = name;
       }
    //+------------------------------------------------------------------+
    • Erstellen einer Klasse mit dem Namen Label in einer neuen .mqh-Datei mit dem Namen Label.mqh.
    • Dekalieren einer privaten Variable namens _name, um den Namen im Modus privat zu speichern.
    • Es wurde eine Funktion mit dem Namen Create mit 3 erforderlichen Parametern erstellt: name, xDis, yDis. Die Größe ist für ein Label-Objekt irrelevant. Um die Textgröße zu ändern, ändern wir die Schriftgröße.
    • Erstellen einer Funktion mit dem Namen Destroy, um das Label zu zerstören.
    • Erstellen einer Funktion SetTextColor zum Setzen der Textfarbe.
    • Eine Funktion zum Setzen des Textes für das Label-Objekt erstellt.
    • Erstellen einer Funktion GetText, um den Text des Label-Objekts zu erhalten, die natürlich eine Zeichenkette zurückgibt.
    • Erstellen einer Funktion SetFontSize, um natürlich die Schriftgröße zu setzen.
    • Es wurde eine Funktion zum Setzen der Schriftart erstellt, die den Namen der Schriftart in einer Zeichenkette benötigt und natürlich sollte die Schriftart im Betriebssystem verfügbar/installiert sein.

    Das war's mit dem Label. Nun wollen wir damit ein Labelobjekt im Chart erstellen, nein eigentlich 2 Labelobjekte im Chart.
    Unser SimpleTradingEA.mq5 sieht jetzt so aus:
    #include "RectangleLabel.mqh" // Including the RectangleLabel class definition
    RectangleLabel TitleBar; // Declaration of a TitleBar object
    RectangleLabel MainDashboardBody; // Declaration of a MainDashboardBody object
    
    #include "Label.mqh" // Including the Label class definition
    Label TitleText; // Declaration of a Label object
    
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
       {
        TitleBar.Create("TitleBar", 100, 100, 200, 20); // Creating the TitleBar with specified dimensions
        TitleBar.SetBorderType(BORDER_FLAT); // Setting the border type of TitleBar to be flat
    
        MainDashboardBody.Create("MainDashboardBody", 100, 119, 200, 100); // Creating the MainDashboardBody with specified dimensions
        MainDashboardBody.SetBorderType(BORDER_FLAT); // Setting the border type of MainDashboardBody to be flat
        
        TitleText.Create("TitleText", 110, 101); // Creating the TitleText at (110,101)
        TitleText.SetText("Simple Trading EA V1.0"); // Setting its text to "Simple Trading EA V1.0"
        TitleText.SetFontSize(10); // Setting its font size to 10
        TitleText.SetTextColor(clrBlack); // Setting its text color to clrBlack
        
        ChartRedraw(0); // Redrawing the chart to reflect changes
        return(INIT_SUCCEEDED); // Indicating successful initialization
       }
    
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
       {
        MainDashboardBody.Destroy(); // Destroying the MainDashboardBody object
        TitleBar.Destroy(); // Destroying the TitleBar object
        TitleText.Destroy(); // Destroying the TitleText object
       }
    //+------------------------------------------------------------------+
    • Die erstellte Label-Instanz mit dem Namen TitleText.
    • Mit der Funktion TitleText.Create wird der TitleText erstellt.
    • TitleText.SetText wird verwendet, um TitleText auf „Simple Trading EA V1.0“ zu setzen.
    • TitleText.SetFontSize wird verwendet, um FontSize auf 10 zu setzen.
    • TitleText.SetTextColor wird verwendet, um die Farbe auf Schwarz zu setzen.
    • TitleText.Destroy verwendet, um das TitleText-Objekt in OnDeinit zu zerstören.

    Ergebnis:


    Abb. 4. Titeltext hinzugefügt
    Abb. 4. Titeltext hinzugefügt

  4. "Lot Size:" Text

    Für den Text „Lot Size:“ (Losgröße) gehen wir ähnlich vor wie bei dem Titeltext. Der endgültige Code lautet wie folgt:

    #include "RectangleLabel.mqh" // Including the RectangleLabel class definition
    RectangleLabel TitleBar; // Declaration of a TitleBar object
    RectangleLabel MainDashboardBody; // Declaration of a MainDashboardBody object
    
    #include "Label.mqh" // Including the Label class definition
    Label TitleText; // Declaration of a Label object
    Label LotSizeText; // Declaration of a LotSizeText object
    
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
       {
        TitleBar.Create("TitleBar", 100, 100, 200, 20); // Creating the TitleBar with specified dimensions
        TitleBar.SetBorderType(BORDER_FLAT); // Setting the border type of TitleBar to be flat
    
        MainDashboardBody.Create("MainDashboardBody", 100, 119, 200, 100); // Creating the MainDashboardBody with specified dimensions
        MainDashboardBody.SetBorderType(BORDER_FLAT); // Setting the border type of MainDashboardBody to be flat
        
        TitleText.Create("TitleText", 110, 101); // Creating the TitleText at (110,101)
        TitleText.SetText("Simple Trading EA V1.0"); // Setting its text to "Simple Trading EA V1.0"
        TitleText.SetFontSize(10); // Setting its font size to 10
        TitleText.SetTextColor(clrBlack); // Setting its text color to clrBlack
        
        LotSizeText.Create("LotSizeText", 110, 140); // Creating the LotSizeText at (110,140)
        LotSizeText.SetText("Lot Size:"); // Setting its text to "Lot Size:"
        LotSizeText.SetFontSize(12); // Setting its font size to 12
        LotSizeText.SetTextColor(clrBlack); // Setting its text color to clrBlack
        
        ChartRedraw(0); // Redrawing the chart to reflect changes
        return(INIT_SUCCEEDED); // Indicating successful initialization
       }
    
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
       {
        MainDashboardBody.Destroy(); // Destroying the MainDashboardBody object
        TitleBar.Destroy(); // Destroying the TitleBar object
        TitleText.Destroy(); // Destroying the TitleText object
        LotSizeText.Destroy(); // Destroying the LotSizeText object
       }
    //+------------------------------------------------------------------+
    • Label-Instanz mit dem Namen LotSizeText erstellt
    • Wir verwenden die Funktion LotSizeText.Create, um den Lot Size Text zu erstellen.
    • LotSizeText.SetText wird verwendet, um den Text „Lot Size:“ zu schreiben setzen.
    • Verwendung von LotSizeText.SetFontSize um FontSize auf 12 zu setzen
    • Verwendung von LotSizeText.SetTextColor, um die Farbe auf Schwarz zu setzen
    • Verwendung von LotSizeText.Destroy, um das Label-Objekt in OnDeinit zu zerstören

    Das war's dann auch schon. Ergebnis:


    Abb. 5. Text zur Losgröße hinzugefügt
    Abb. 5. Hinzugefügt „Lot Size:“ Text





  5. Edit Box

    Für das Bearbeitungsfeld werden wir eine Klasse erstellen, die der Klasse Label sehr ähnlich ist. Hier ist der Code für eine neue Klasse mit dem Namen Edit :

    //+------------------------------------------------------------------+
    //| Edit class definition                                            |
    //+------------------------------------------------------------------+
    class Edit
       {
    private:
        string           _name; // Name of the edit control
    public:
                         Edit(void); // Constructor
                        ~Edit(void); // Destructor
                        
        void             Create(string name, int xDis, int yDis, int xSize, int ySize); // Method to create an edit control    
        void             Destroy() {ObjectDelete(0, _name);} // Method to destroy an edit control    
        void             SetBorderColor(color col) {ObjectSetInteger(0, _name, OBJPROP_BORDER_COLOR, col);} // Method to set the border color    
        void             SetBGColor(color col) {ObjectSetInteger(0, _name, OBJPROP_BGCOLOR, col);} // Method to set the background color    
        void             SetTextColor(color col) {ObjectSetInteger(0, _name, OBJPROP_COLOR, col);} // Method to set the text color    
        void             SetText(string text) {ObjectSetString(0, _name, OBJPROP_TEXT, text);} // Method to set the text content    
        string           GetText() {return ObjectGetString(0, _name, OBJPROP_TEXT);} // Method to retrieve the text content
       };
    
    //+------------------------------------------------------------------+
    //| Constructor                                                      |
    //+------------------------------------------------------------------+
    Edit::Edit(void)
       {
    
       }
    
    //+------------------------------------------------------------------+
    //| Destructor                                                       |
    //+------------------------------------------------------------------+
    Edit::~Edit(void)
       {
    
       }
    
    //+------------------------------------------------------------------+
    //| Method to create an edit control object                          |
    //+------------------------------------------------------------------+
    void Edit::Create(string name, int xDis, int yDis, int xSize, int ySize)
       {
        // Code to create edit control object, set its position, size, and assign its name
        ObjectCreate(0, name, OBJ_EDIT, 0, 0, 0);
        ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xDis);
        ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yDis);
        ObjectSetInteger(0, name, OBJPROP_XSIZE, xSize);
        ObjectSetInteger(0, name, OBJPROP_YSIZE, ySize);
        _name = name;
       }
    //+------------------------------------------------------------------+
    • Erstellen einer Klasse namens Edit in einer neuen .mqh-Datei namens Edit.mqh.
    • Dekalieren einer privaten Variable namens _name, um den Namen im Modus privat zu speichern.
    • Erstellen einer Funktion namens Create mit 5 erforderlichen Parametern: name, xDis, yDis, xSize, ySize.
    • Erstellen einer Funktion namens Destroy, um das Edit-Objekt zu zerstören.
    • Erstellen einer Funktion SetBorderColor zum Einstellen der Randfarbe.
    • Erstellen einer Funktion SetBGColor um die Hintergrundfarbe auf WhiteSmoke zu setzen.
    • Die Funktion SetTextColor wurde erstellt, um die Textfarbe des Textes innerhalb des Eingabefeldes festzulegen.
    • Erstellen einer Funktion SetText zum Setzen des Texts.
    • Erstellen einer Funktion GetText zum Abrufen des Texts.

    Wir können nun die Klasse Edit in SimpleTradingEA verwenden, wie unten gezeigt:

    #include "RectangleLabel.mqh" // Including the RectangleLabel class definition
    RectangleLabel TitleBar; // Declaration of a TitleBar object
    RectangleLabel MainDashboardBody; // Declaration of a MainDashboardBody object
    
    #include "Label.mqh" // Including the Label class definition
    Label TitleText; // Declaration of a Label object
    Label LotSizeText; // Declaration of a LotSizeText object
    
    #include "Edit.mqh" // Including the Edit class definition
    Edit LotSize; // Declaration of a LotSize object
    
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
       {
        TitleBar.Create("TitleBar", 100, 100, 200, 20); // Creating the TitleBar with specified dimensions
        TitleBar.SetBorderType(BORDER_FLAT); // Setting the border type of TitleBar to be flat
    
        MainDashboardBody.Create("MainDashboardBody", 100, 119, 200, 100); // Creating the MainDashboardBody with specified dimensions
        MainDashboardBody.SetBorderType(BORDER_FLAT); // Setting the border type of MainDashboardBody to be flat
        
        TitleText.Create("TitleText", 110, 101); // Creating the TitleText at (110,101)
        TitleText.SetText("Simple Trading EA V1.0"); // Setting its text to "Simple Trading EA V1.0"
        TitleText.SetFontSize(10); // Setting its font size to 10
        TitleText.SetTextColor(clrBlack); // Setting its text color to clrBlack
        
        LotSizeText.Create("LotSizeText", 110, 140); // Creating the LotSizeText at (110,140)
        LotSizeText.SetText("Lot Size:"); // Setting its text to "Lot Size:"
        LotSizeText.SetFontSize(12); // Setting its font size to 12
        LotSizeText.SetTextColor(clrBlack); // Setting its text color to clrBlack
        
        LotSize.Create("LotSize", 220, 140, 50, 20); // Creating the LotSize with specified dimensions
        LotSize.SetBorderColor(clrBlack); // Setting its Border Color to clrBlack
        LotSize.SetBGColor(clrWhiteSmoke); // Setting its BG Color to clrWhiteSmoke
        LotSize.SetText("0.01"); // Setting its text to 0.01
        LotSize.SetTextColor(clrBlack); // Setting its text color to clrBlack
        
        ChartRedraw(0); // Redrawing the chart to reflect changes
        return(INIT_SUCCEEDED); // Indicating successful initialization
       }
    
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
       {
        MainDashboardBody.Destroy(); // Destroying the MainDashboardBody object
        TitleBar.Destroy(); // Destroying the TitleBar object
        TitleText.Destroy(); // Destroying the TitleText object
        LotSizeText.Destroy(); // Destroying the LotSizeText object
        LotSize.Destroy(); // Destroying the LotSize object
       }
    //+------------------------------------------------------------------+
    • Erstellen von Edit-Instanz namens LotSize.
    • Verwenden der Funktion LotSize.Create, um das Bearbeitungsobjekt zu erstellen.
    • Verwenden von LotSize.SetBorderColor, um die Rahmenfarbe auf Schwarz zu setzen.
    • Verwenden von LotSize.SetBGColor, um die Hintergrundfarbe auf WhiteSmoke zu setzen.
    • Verwenden von LotSize.SetText, um den Text auf 0,01 zu setzen, der die Losgröße darstellt.
    • Verwenden von LotSize.SetTextColor, um die Textfarbe innerhalb des Bearbeitungsfeldes auf Schwarz zu setzen.
    • Verwenden von LotSize.Destroy, um das Edit-Objekt in OnDeinit zu zerstören.

  6. die Schaltflächen für Kaufen und Verkaufen

    Schließlich kommen wir zu den Tasten. Lassen Sie uns eine Klasse für Schaltflächen in ähnlicher Weise wie für die anderen erstellen:

    //+------------------------------------------------------------------+
    //| Button class definition                                          |
    //+------------------------------------------------------------------+
    class Button
       {
    private:
        string           _name; // Name of the button control
    
    public:
                         Button(void); // Constructor
                        ~Button(void); // Destructor
                        
        void             Create(string name, int xDis, int yDis, int xSize, int ySize); // Method to create a button control    
        void             SetBorderColor(color col) {ObjectSetInteger(0, _name, OBJPROP_BORDER_COLOR, col);} // Method to set the border color    
        void             SetBGColor(color col) {ObjectSetInteger(0, _name, OBJPROP_BGCOLOR, col);} // Method to set the background color    
        void             SetText(string text) {ObjectSetString(0, _name, OBJPROP_TEXT, text);} // Method to set the text content    
        void             Destroy() {ObjectDelete(0, _name);} // Method to destroy a button control
       };
    
    //+------------------------------------------------------------------+
    //| Constructor                                                      |
    //+------------------------------------------------------------------+
    Button::Button(void)
       {
    
       }
    
    //+------------------------------------------------------------------+
    //| Destructor                                                       |
    //+------------------------------------------------------------------+
    Button::~Button(void)
       {
    
       }
    
    //+------------------------------------------------------------------+
    //| Method to create a button control object                         |
    //+------------------------------------------------------------------+
    void Button::Create(string name, int xDis = 0, int yDis = 0, int xSize = 0, int ySize = 0)
       {
        // Code to create button control object, set its position, size, and assign its name
        ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0);
        ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xDis);
        ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yDis);
        ObjectSetInteger(0, name, OBJPROP_XSIZE, xSize);
        ObjectSetInteger(0, name, OBJPROP_YSIZE, ySize);
        _name = name;
       }
    //+------------------------------------------------------------------+
    

    In einer neuen .mqh-Datei namens Button.mqh haben wir eine Klasse namens Button erstellt. Wir haben eine private Variable namens _name deklariert, um den Namen privat zu speichern. Wir haben auch die folgenden Funktionen erstellt:

      • Eine Funktion namens Create mit 5 erforderlichen Parametern: name, xDis, yDis, xSize, ySize.
      • Eine Funktion namens Destroy, um das Button-Objekt zu zerstören.
      • Eine Funktion namens SetBorderColor, um die Farbe des Rahmens festzulegen.
      • Eine Funktion namens SetBGColor, um die Hintergrundfarbe auf WhiteSmoke zu setzen.
      • Eine Funktion namens SetText zum Setzen von Text.

      Sehen wir uns nun die Hauptdatei SimpleTradingEA.mq5 an, nachdem wir die Schaltflächen hinzugefügt haben. Sie werden feststellen, dass es jetzt Instanzen für RectangleLabel , Label , Edit , Button für BuyButton und SellButton enthält.

      #include "RectangleLabel.mqh" // Including the RectangleLabel class definition
      RectangleLabel TitleBar; // Declaration of a TitleBar object
      RectangleLabel MainDashboardBody; // Declaration of a MainDashboardBody object
      
      #include "Label.mqh" // Including the Label class definition
      Label TitleText; // Declaration of a Label object
      Label LotSizeText; // Declaration of a LotSizeText object
      
      #include "Edit.mqh" // Including the Edit class definition
      Edit LotSize; // Declaration of a LotSize object
      
      #include "Button.mqh" // Including the Button class definition
      Button BuyButton; // Declaration of a BuyButton object
      Button SellButton; // Declaration of a SellButton object
      
      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
         {
          TitleBar.Create("TitleBar", 100, 100, 200, 20); // Creating the TitleBar with specified dimensions
          TitleBar.SetBorderType(BORDER_FLAT); // Setting the border type of TitleBar to be flat
      
          MainDashboardBody.Create("MainDashboardBody", 100, 119, 200, 100); // Creating the MainDashboardBody with specified dimensions
          MainDashboardBody.SetBorderType(BORDER_FLAT); // Setting the border type of MainDashboardBody to be flat
          
          TitleText.Create("TitleText", 110, 101); // Creating the TitleText at (110,101)
          TitleText.SetText("Simple Trading EA V1.0"); // Setting its text to "Simple Trading EA V1.0"
          TitleText.SetFontSize(10); // Setting its font size to 10
          TitleText.SetTextColor(clrBlack); // Setting its text color to clrBlack
          
          LotSizeText.Create("LotSizeText", 110, 140); // Creating the LotSizeText at (110,140)
          LotSizeText.SetText("Lot Size:"); // Setting its text to "Lot Size:"
          LotSizeText.SetFontSize(12); // Setting its font size to 12
          LotSizeText.SetTextColor(clrBlack); // Setting its text color to clrBlack
          
          LotSize.Create("LotSize", 220, 140, 50, 20); // Creating the LotSize with specified dimensions
          LotSize.SetBorderColor(clrBlack); // Setting its Border Color to clrBlack
          LotSize.SetBGColor(clrWhiteSmoke); // Setting its BG Color to clrWhiteSmoke
          LotSize.SetText("0.01"); // Setting its text to 0.01
          LotSize.SetTextColor(clrBlack); // Setting its text color to clrBlack
          
          BuyButton.Create("BuyButton", 110, 180, 80, 25); // Creating the BuyButton with specified dimensions
          BuyButton.SetBorderColor(clrBlack); // Setting its Border Color to clrBlack
          BuyButton.SetText("Buy"); // Setting its text to "Buy"
          BuyButton.SetBGColor(clrLime); // Setting its BG Color to clrLime
          
          SellButton.Create("SellButton", 210, 180, 80, 25); // Creating the SellButton with specified dimensions
          SellButton.SetBorderColor(clrBlack); // Setting its Border Color to clrBlack
          SellButton.SetText("Sell"); // Setting its text to "Sell"
          SellButton.SetBGColor(clrRed); // Setting its BG Color to clrRed
          
          ChartRedraw(0); // Redrawing the chart to reflect changes
          return(INIT_SUCCEEDED); // Indicating successful initialization
         }
      
      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
         {
          MainDashboardBody.Destroy(); // Destroying the MainDashboardBody object
          TitleBar.Destroy(); // Destroying the TitleBar object
          TitleText.Destroy(); // Destroying the TitleText object
          LotSizeText.Destroy(); // Destroying the LotSizeText object
          LotSize.Destroy(); // Destroying the LotSize object
          BuyButton.Destroy(); // Destroying the BuyButton object
          SellButton.Destroy(); // Destroying the SellButton object
         }
      //+------------------------------------------------------------------+
      • Erstellten einer Instanz für die Schaltfläche mit dem Namen BuyButton.
      • Verwenden der Funktion BuyButton.Create, um das Edit-Objekt zu erstellen.
      • Verwenden von BuyButton.SetBorderColor, um die Rahmenfarbe auf Schwarz zu setzen.
      • Verwenden von BuyButton.SetBGColor, um die Hintergrundfarbe auf Lime zu setzen.
      • Verwenden von BuyButton.SetText, um den Text Buy zu setzen.
      • Verwenden von BuyButton.Destroy, um das Button-Objekt in OnDeinit zu zerstören.

      Nun zur Schaltfläche Verkaufen:

      • Erstellten einer Instanz für die Schaltfläche mit dem Namen SellButton.
      • Verwenden der Funktion SellButton.Create, um das Button-Objekt zu erstellen.
      • Verwenden von SellButton.SetBorderColor, um die Rahmenfarbe auf Schwarz zu setzen.
      • Verwenden von SellButton.SetBGColor, um die Hintergrundfarbe auf Rot zu setzen.
      • Verwenden von SellButton.SetText, um den Text Sell zu setzen.
      • Verwenden von SellButton.Destroy, um das Button-Objekt in OnDeinit zu zerstören.

      Ergebnis:


      Abb. 6. hinzugefügten Schaltflächen für Kaufen und Verkaufen
      Abb. 6. Die hinzugefügten Schaltflächen für Kaufen und Verkaufen

    • Der letzte Schliff

    • Jetzt kommt noch der letzte Schliff: Wir wollen es bunt machen. Wir werden die folgenden Änderungen vornehmen:

      Gehen wir wie folgt vor:

      • Farbe der Titelleiste in Dunkelblau ändern.
      • Farbe des Haupt-Dashboards in Hellblau ändern.
      • Ändern der Farbe des Titeltextes von Schwarz auf Weiß.
      • Ändern der Losgröße Textfarbe von Schwarz auf Weiß.
      • Die Funktionsweise von Kaufen/Verkaufen hinzufügen.

      Der endgültige Code SimpleTradingEA.mq5 enthält Farbänderungen und die Handelsbibliothek. Außerdem wird eine OnChartEvent-Funktion erstellt, sodass beim Anklicken der Schaltfläche Kaufen oder Verkaufen der entsprechende Auftrag sofort erteilt wird.

      #include "RectangleLabel.mqh" // Including the RectangleLabel class definition
      RectangleLabel TitleBar; // Declaration of a TitleBar object
      RectangleLabel MainDashboardBody; // Declaration of a MainDashboardBody object
      
      #include "Label.mqh" // Including the Label class definition
      Label TitleText; // Declaration of a Label object
      Label LotSizeText; // Declaration of a LotSizeText object
      
      #include "Edit.mqh" // Including the Edit class definition
      Edit LotSize; // Declaration of a LotSize object
      
      #include "Button.mqh" // Including the Button class definition
      Button BuyButton; // Declaration of a BuyButton object
      Button SellButton; // Declaration of a SellButton object
      
      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
         {
          TitleBar.Create("TitleBar", 100, 100, 200, 20); // Creating the TitleBar with specified dimensions
          TitleBar.SetBorderType(BORDER_FLAT); // Setting the border type of TitleBar to be flat
          TitleBar.SetBGColor(C'27, 59, 146'); // Setting the color to RGB code: C'27, 59, 146'
      
          MainDashboardBody.Create("MainDashboardBody", 100, 119, 200, 100); // Creating the MainDashboardBody with specified dimensions
          MainDashboardBody.SetBorderType(BORDER_FLAT); // Setting the border type of MainDashboardBody to be flat
          MainDashboardBody.SetBGColor(C'102, 152, 250'); // Setting the color to RGB code: C'102, 152, 250'
          
          TitleText.Create("TitleText", 110, 101); // Creating the TitleBar at (110,101)
          TitleText.SetText("Simple Trading EA V1.0"); // Setting its text to "Simple Trading EA V1.0"
          TitleText.SetFontSize(10); // Setting its font size to 10
          TitleText.SetTextColor(clrWhite); // Setting its text color to clrWhite
          
          LotSizeText.Create("LotSizeText", 110, 140); // Creating the LotSizeText at (110,140)
          LotSizeText.SetText("Lot Size:"); // Setting its text to "Lot Size:"
          LotSizeText.SetFontSize(12); // Setting its font size to 12
          LotSizeText.SetTextColor(clrWhite); // Setting its text color to clrWhite
          
          LotSize.Create("LotSize", 220, 140, 50, 20); // Creating the LotSize with specified dimensions
          LotSize.SetBorderColor(clrBlack); // Setting its Border Color to clrBlack
          LotSize.SetBGColor(clrWhiteSmoke); // Setting its BG Color to clrWhiteSmoke
          LotSize.SetText("0.01"); // Setting its text to 0.01
          LotSize.SetTextColor(clrBlack); // Setting its text color to clrBlack
          
          BuyButton.Create("BuyButton", 110, 180, 80, 25); // Creating the BuyButton with specified dimensions
          BuyButton.SetBorderColor(clrBlack); // Setting its Border Color to clrBlack
          BuyButton.SetText("Buy"); // Setting its text to "Buy"
          BuyButton.SetBGColor(clrLime); // Setting its BG Color to clrLime
          
          SellButton.Create("SellButton", 210, 180, 80, 25); // Creating the SellButton with specified dimensions
          SellButton.SetBorderColor(clrBlack); // Setting its Border Color to clrBlack
          SellButton.SetText("Sell"); // Setting its text to "Sell"
          SellButton.SetBGColor(clrRed); // Setting its BG Color to clrRed
          
          ChartRedraw(0); // Redrawing the chart to reflect changes
          return(INIT_SUCCEEDED); // Indicating successful initialization
         }
      
      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
         {
          MainDashboardBody.Destroy(); // Destroying the MainDashboardBody object
          TitleBar.Destroy(); // Destroying the TitleBar object
          TitleText.Destroy(); // Destroying the TitleText object
          LotSizeText.Destroy(); // Destroying the LotSizeText object
          LotSize.Destroy(); // Destroying the LotSize object
          BuyButton.Destroy(); // Destroying the BuyButton object
          SellButton.Destroy(); // Destroying the SellButton object
         }
      
      //+------------------------------------------------------------------+
      //| Chart event handling function                                    |
      //+------------------------------------------------------------------+
      void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
         {
          // Handles click events for Buy and Sell buttons and opens corresponding positions
          if(id == CHARTEVENT_OBJECT_CLICK) {
              double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
              double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
              if(sparam == "BuyButton") {
                  trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, (double)LotSize.GetText(), ask, 0, 0);
              }
              if(sparam == "SellButton") {
                  trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, (double)LotSize.GetText(), bid, 0, 0);
              }
          }
         }
      //+------------------------------------------------------------------+

      Änderungen:

      1. Farbliche Modifikationen:

        • Die Hintergrundfarbe der Titelleiste wurde mit TitleBar.SetBGColor(C'27, 59, 146') auf Dunkelblau geändert.
        • Die Farbe des Hauptkörpers des Dashboards wurde mit MainDashboardBody.SetBGColor(C'102, 152, 250') auf hellblau aktualisiert.
        • Die Farbe des Titeltextes wurde mit TitleText.SetTextColor(clrWhite) auf weiß geändert.
        • Die Farbe des Losgrößentextes wurde mit LotSizeText.SetTextColor(clrWhite) auf weiß eingestellt.
      2. Einbindung der Handelsbibliothek:

        • Wir integrieren die Handelsbibliothek und erstellen eine Instanz mit dem Namen trade mit folgendem Code:
          #include <Trade/Trade.mqh>
          CTrade trade;

      3. Erstellen der OnChartEvent-Funktion:

        Es wurde eine OnChartEvent-Funktion implementiert, die sofort einen entsprechenden Auftrag ausführt, wenn entweder die Schaltfläche Kaufen oder Verkaufen angeklickt wird. Der Code lautet wie folgt:

        //+------------------------------------------------------------------+
        //| Chart event handling function                                    |
        //+------------------------------------------------------------------+
        void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
           {
            if(id == CHARTEVENT_OBJECT_CLICK) {
                double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
                double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
                if(sparam == "BuyButton") {
                    trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, (double)LotSize.GetText(), ask, 0, 0);
                }
                if(sparam == "SellButton") {
                    trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, (double)LotSize.GetText(), bid, 0, 0);
                }
            }
           }
        //+------------------------------------------------------------------+
        Wenn die Ereignis-ID CHARTEVENT_OBJECT_CLICK ist, erkennt die Funktion einen Objektklick, ermittelt den Namen des angeklickten Objekts über sparam, prüft, ob der Objektname „BuyButton“ oder „SellButton“ ist, und platziert dann den entsprechenden Handel unter Verwendung der Trade-Bibliothek.

      Endgültiges Ergebnis: 


      Abb. 7. Fertiggestellter Simple Trading EA (statisch)
      Abb. 7. Fertiggestellter Simple Trading EA (statisch)


    Dieser Abschnitt endet hier.


    Überlegungen zum Ansatz, unser statisches Dashboard mit allen darin enthaltenen Elementen zu bewegen

    Jetzt beginnt die eigentliche Arbeit. Wie können wir alles beweglich machen? Lassen Sie uns darüber nachdenken.

    Im Moment können wir jedes einzelne Element verschieben. Was wir aber brauchen, ist, dass sich alle Elemente bewegen. Dann lassen wir ein Element sich bewegen und alle anderen folgen ihm. Wir können andere Elemente buchstäblich dem Hauptelement folgen lassen, indem wir CustomChartEvent verwenden, aber leider ist diese Methode langsam und daher ineffizient. Der effizienteste Ansatz besteht also darin, unser Hauptelement (um das sich alle anderen Elemente bewegen) zu verschieben und gleichzeitig andere Elemente zu verschieben. Das ist die Theorie, aber wie wenden wir sie praktisch an?

    Nennen wir unser Hauptelement „Central Element“ (zentrales Element), und machen wir unsere Titelleiste zum zentralen Element. Nun werden wir alle anderen Elemente um da herum verschieben.

    Bisher haben wir ein einzelnes Element mit Hilfe einer in seiner Klasse definierten Funktion namens OnEvent verschoben. Nun werden wir diese Funktion so abändern, dass sie ein einzelnes Element verschiebt und dann alle anderen Elemente um genau denselben Betrag verschiebt.

    Hier ist unsere aktuelle Funktion OnEvent:

    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    void RectangleLabel::OnEvent(int id, long lparam, double dparam, string sparam)
      {
       //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case
       if(id == CHARTEVENT_MOUSE_MOVE)
         {
          //define X, Y, XDistance, YDistance, XSize, YSize
          int X = (int)lparam;
          int Y = (int)dparam;
          int MouseState = (int)sparam;
    
          string name = Name;
          int XDistance = (int)ObjectGetInteger(0, name, OBJPROP_XDISTANCE); //Should be 100 initially as we set it in OnInit()
          int YDistance = (int)ObjectGetInteger(0, name, OBJPROP_YDISTANCE); //Should be 100 initially as we set it in OnInit()
          int XSize = (int)ObjectGetInteger(0, name, OBJPROP_XSIZE); //Should be 200 initially as we set it in OnInit()
          int YSize = (int)ObjectGetInteger(0, name, OBJPROP_YSIZE); //Should be 200 initially as we set it in OnInit()
    
          if(previousMouseState == 0 && MouseState == 1) //Check if this was the MLB first click
            {
             mlbDownX = X; //Set mlbDownX (Variable that stores the initial MLB X location) equal to the current X
             mlbDownY = Y; //Set mlbDownY (Variable that stores the initial MLB Y location) equal to the current Y
             mlbDownXDistance = XDistance; //Set mlbDownXDistance (Variable that stores the initial XDistance i.e. Width of the dashboard) equal to the current XDistance
             mlbDownYDistance = YDistance; //Set mlbDownYDistance (Variable that stores the initial YDistance i.e. Height of the dashboard) equal to the current YDistance
    
             if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize) //Check if the click was on the dashboard
               {
                movingState = true; //If yes the set movingState to True
               }
    
            }
    
          if(movingState)//if movingState is true, Update the Dashboard position
            {
             ChartSetInteger(0, CHART_MOUSE_SCROLL, false);//Restrict Chart to be moved by Mouse
             ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX);//Update XDistance to: mlbDownXDistance + (X - mlbDownX)
             ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY);//Update YDistance to: mlbDownYDistance + (Y - mlbDownY)
             ChartRedraw(0); //Redraw Chart
            }
    
          if(MouseState == 0)//Check if MLB is not pressed
            {
             movingState = false;//set movingState again to false
             ChartSetInteger(0, CHART_MOUSE_SCROLL, true);//allow the cahrt to be moved again
            }
    
          previousMouseState = MouseState;//update the previousMouseState at the end so that we can use it next time and copare it with new value
         }
      }
    //+------------------------------------------------------------------+

    Ich weiß, dass wir diese Funktion noch nicht zur Klasse RectangleLabel hinzugefügt haben; wir werden das nach der Diskussion des Ansatzes tun.

    Was brauchen wir nun, um ein Objekt zu bewegen? Sein Name, richtig?

    Was wir tun werden, ist ganz einfach: Wir gehen diese Namen in einer Schleife durch und verschieben die Objekte um denselben Betrag, um den wir das zentrale Element verschoben haben. Aber es gibt hier einen großen Fehler, der schwerer zu erkennen ist.

    Immer wenn sich die Maus bewegt, setzen wir die XDis und YDis des zentralen Elements wie folgt:

    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX);//Update XDistance to: mlbDownXDistance + (X - mlbDownX)
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY);//Update YDistance to: mlbDownYDistance + (Y - mlbDownY)

    Hier kennen wir die XDis und YDis des zentralen Elements, als die Maus MLB gedrückt wurde. Wir müssen diese Informationen also auch für andere Elemente kennen. Dies würde die Funktion jedoch sehr kompliziert oder ineffizient machen, sodass wir einen besseren Ansatz benötigen.

    Bei näherer Betrachtung liegt ein besserer Ansatz direkt vor uns. Wir müssen lediglich den „X-Abstand und Y-Abstand zwischen zentralen Elementen und anderen Elementen“ beibehalten. Ja, so einfach ist das.

    Wir speichern also den „X-Abstand und Y-Abstand zwischen zentralen Elementen und anderen Elementen“ und halten diesen Abstand ein. Wie können wir diese Entfernungen erfassen? Nun, irgendwann werden wir unsere anderen Elemente zum zentralen Element hinzufügen, und an diesem Punkt werden wir den „X-Abstand und Y-Abstand zwischen zentralen Elementen und anderen Elementen“ sichern.

    Um es noch einmal zu wiederholen: Irgendwann werden wir die Namen der anderen Elemente verwenden, um sie dem zentralen Element hinzuzufügen, und zu diesem Zeitpunkt werden wir den „X-Abstand und Y-Abstand zwischen zentralen Elementen und anderen Elementen“ speichern. Dann werden wir diesen Abstand zwischen den anderen Elementen und dem zentralen Element beibehalten. Wir aktualisieren diesen Abstand, nachdem wir die Position des zentralen Elements aktualisiert haben.

    Das ist unser Ansatz für diese Aufgabe. Setzen wir es nun in die Tat um.


    Verwendung des diskutierten Ansatzes, um unser statisches Dashboard beweglich zu machen

    Lassen Sie uns also besprechen, wo wir den Namen, den X-Abstand und den Y-Abstand zwischen zentralen Elementen und anderen Elementen speichern werden. Dies sind die einzigen beiden Kategorien von Informationen, die wir speichern müssen.

    Wir erstellen eine Funktion namens Add in der Klasse RectangleLabel. Mit dieser Funktion werden wir die folgenden zwei Dinge speichern:

    1. den Name im Array addedNames
    2. X-Abstand und Y-Abstand zwischen zentralen Elementen und anderen Elementen in addedXDisDifference bzw. addedYDisDifference

    Was die Namenskonventionen anbelangt, so bedeutet „added“, dass die Variable mit einem anderen Element zusammenhängt, das dem zentralen Element hinzugefügt wurde, während „XDis“ und „YDis“ recht einfach zu verstehen sind. „Difference“ suggeriert, dass die Variable etwas mit einem Unterschied zu tun hat, und ist daher ein angemessener Name. Der Grund für die Erörterung des Namens ist, dass Missverständnisse vermieden werden sollen, da der korrekte Variablenname Missverständnisse verhindern kann.

    Lassen Sie uns diese Variablen deklarieren:

    string           addedNamed[];
    int              addedXDisDiffrence[], addedYDisDiffrence[];

    Bitte beachten Sie, dass wir sie als privat deklarieren, da wir sie nicht public sein müssen. Außerdem sind es alles Arrays.

    Lassen Sie uns nun die Funktion Add erstellen:

    //+------------------------------------------------------------------+
    //| Method to add an object by name to the rectangle label           |
    //+------------------------------------------------------------------+
    void RectangleLabel::Add(string name)
       {
        ArrayResize(addedNames, ArraySize(addedNames) + 1);
        ArrayResize(addedXDisDiffrence, ArraySize(addedXDisDiffrence) + 1);
        ArrayResize(addedYDisDiffrence, ArraySize(addedYDisDiffrence) + 1);
        
        addedNames[ArraySize(addedNames) - 1] = name;
        addedXDisDiffrence[ArraySize(addedXDisDiffrence) - 1] = ObjectGetInteger(0, _name, OBJPROP_XDISTANCE) - ObjectGetInteger(0, name, OBJPROP_XDISTANCE);
        addedYDisDiffrence[ArraySize(addedYDisDiffrence) - 1] = ObjectGetInteger(0, _name, OBJPROP_YDISTANCE) - ObjectGetInteger(0, name, OBJPROP_YDISTANCE);
       }
    //+------------------------------------------------------------------+

    Diese Funktion wird in der Klasse RectangleLabel deklariert, da die Titelleiste unser zentrales Element ist und es sich im Wesentlichen um ein RECTANGLE_LABEL-Objekt handelt. Wir deklarieren die Variablen natürlich in derselben Klasse, da wir sie in dieser Funktion verwenden.

    Diese Funktion akzeptiert den Namen als Parameter und vergrößert die drei Arrays um eins. Beim letzten Index speichern wir die entsprechenden Daten. Für den Namen speichern wir einfach den Namen. Für die Abstandsdifferenzen (X und Y) wird die Differenz zwischen dem zentralen Element (in diesem Fall TitleBar) und dem Element, dessen Name als Parameter angegeben wird, gespeichert. Dies ist unsere Funktion Add.

    Als Nächstes müssen wir die OnEvent-Funktion ändern. Wir erstellen eine Schleife, um das Array addedNames zu durchlaufen und den Abstand zwischen der Titelleiste und dem benannten Element beizubehalten, indem wir ihn gleich dem neuen X/Y-Abstand der Titelleiste abzüglich des in den jeweiligen Arrays angegebenen Differenzwertes setzen.

    for(int i = 0; i < ArraySize(addedNames); i++)
       {
        ObjectSetInteger(0, addedNames[i], OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX - addedXDisDiffrence[i]);
        ObjectSetInteger(0, addedNames[i], OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY - addedYDisDiffrence[i]);
       }

    Bitte beachten Sie, dass der unterstrichene Teil der neue X/Y-Abstand der Titelleiste (zentrales Element) ist, und wir subtrahieren den Differenzwert, der in den jeweiligen Arrays angegeben ist (bezogen auf die Differenz zwischen X-Abstand und Y-Abstand zwischen zentralen Elementen und anderen Elementen).

    Wo sollen wir diese Schleife platzieren? Wir setzen sie kurz nach der Aktualisierung des zentralen Elements ein.

    Hier ist unsere neue OnEvent-Funktion:

    //+------------------------------------------------------------------+
    //| Event handling for mouse movements                               |
    //+------------------------------------------------------------------+
    void RectangleLabel::OnEvent(int id, long lparam, double dparam, string sparam)
       {
        // Handle mouse movement events for dragging the rectangle label
        if(id == CHARTEVENT_MOUSE_MOVE)
           {
            int X = (int)lparam;
            int Y = (int)dparam;
            int MouseState = (int)sparam;
    
            string name = _name;
            int XDistance = (int)ObjectGetInteger(0, name, OBJPROP_XDISTANCE);
            int YDistance = (int)ObjectGetInteger(0, name, OBJPROP_YDISTANCE);
            int XSize = (int)ObjectGetInteger(0, name, OBJPROP_XSIZE);
            int YSize = (int)ObjectGetInteger(0, name, OBJPROP_YSIZE);
    
            if(previousMouseState == 0 && MouseState == 1)
               {
                mlbDownX = X;
                mlbDownY = Y;
                mlbDownXDistance = XDistance;
                mlbDownYDistance = YDistance;
    
                if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize)
                   {
                    movingState = true;
                   }
    
               }
    
            if(movingState)
               {
                ChartSetInteger(0, CHART_MOUSE_SCROLL, false);
                ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX);
                ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY);
                for(int i = 0; i < ArraySize(addedNames); i++)
                   {
                    ObjectSetInteger(0, addedNames[i], OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX - addedXDisDiffrence[i]);
                    ObjectSetInteger(0, addedNames[i], OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY - addedYDisDiffrence[i]);
                   }
                ChartRedraw(0);
               }
    
            if(MouseState == 0)
               {
                movingState = false;
                ChartSetInteger(0, CHART_MOUSE_SCROLL, true);
               }
    
            previousMouseState = MouseState;
           }
       }

    Der hervorgehobene Teil ist unsere neue Schleife.

    Jetzt müssen wir nur noch die Funktion Add verwenden, um Elemente an das zentrale Element anzuhängen, da wir die Titelleiste gewählt haben. Wir verwenden die Funktion Add der TitleBar-Instanz, die wir „TitleBar“ genannt haben.

    Verwenden wir die Funktion Add in der TitleBar-Instanz, um alle anderen Elemente zur TitleBar hinzuzufügen:

    // Add the other elements to the Central Element i.e. TitleBar object in this case
    TitleBar.Add("MainDashboardBody");
    TitleBar.Add("TitleText");
    TitleBar.Add("LotSizeText");
    TitleBar.Add("LotSize");
    TitleBar.Add("BuyButton");
    TitleBar.Add("SellButton");


    Damit werden die Namen all dieser Elemente dem Array addedNames hinzugefügt, sodass sie sich bewegen können. Außerdem wird ihr Abstand zur Titelleiste gesichert, sodass dieser Abstand beibehalten wird.

    Lassen Sie uns nun die OnEvent-Funktion verwenden. Ohne sie wäre all dies umsonst.

    // Passes events to the TitleBar object
    TitleBar.OnEvent(id, lparam, dparam, sparam);
    Wir fügen dies dem OnChartEvent() hinzu, und sind endlich fertig. Ich weiß, dass dies langwierig war, aber das Endergebnis sollte die Mühe wert sein.

    Abb. 8. Endgültiges Ergebnis

    Abb. 8. Endgültiges Ergebnis



    Schlussfolgerung

    Damit sind wir am Ende dieses Artikels angelangt. Während unserer Reise in diesem Teil haben wir viel erreicht, was in der Fertigstellung unseres Teils 3 „Verbessern Sie Ihre Handelschart mit interaktiven GUIs in MQL5“ gipfelte.

    Wir haben die Ziele, die wir uns in der „Bewegliche GUI“-Serie (Teil 1 und Teil 2) gesetzt haben, erfolgreich erreicht und eine dynamische und nutzerfreundliche Oberfläche für den Handel mit Charts zum Leben erweckt. Vielen Dank, dass Sie sich die Zeit genommen haben, meine Artikel zu lesen. Ich hoffe, Sie finden sie sowohl informativ als auch hilfreich für Ihre Bemühungen.

    Wenn Sie Ideen oder Vorschläge für meinen nächsten Beitrag haben, zögern Sie bitte nicht, sie mir mitzuteilen.

    Viel Spaß beim Coding! Viel Spaß beim Handeln!

    Übersetzt aus dem Englischen von MetaQuotes Ltd.
    Originalartikel: https://www.mql5.com/en/articles/12923

    Beigefügte Dateien |
    RectangleLabel.mqh (5.75 KB)
    Label.mqh (2.35 KB)
    Edit.mqh (2.53 KB)
    Button.mqh (2.31 KB)
    Kategorientheorie in MQL5 (Teil 16): Funktoren mit mehrschichtigen Perceptrons Kategorientheorie in MQL5 (Teil 16): Funktoren mit mehrschichtigen Perceptrons
    In diesem Artikel, dem 16. in unserer Reihe, geht es weiter mit einem Blick auf Funktoren und wie sie mit künstlichen neuronalen Netzen implementiert werden können. Wir weichen von unserem bisherigen Ansatz der Volatilitätsprognose ab und versuchen, eine nutzerdefinierte Signalklasse zum Setzen von Ein- und Ausstiegssignalen zu implementieren.
    Kategorientheorie in MQL5 (Teil 15) : Funktoren mit Graphen Kategorientheorie in MQL5 (Teil 15) : Funktoren mit Graphen
    Dieser Artikel über die Implementierung der Kategorientheorie in MQL5 setzt die Serie mit der Betrachtung der Funktoren fort, diesmal jedoch als Brücke zwischen Graphen und einer Menge. Wir greifen die Kalenderdaten wieder auf und plädieren trotz der Einschränkungen bei der Verwendung von Strategy Tester für die Verwendung von Funktoren zur Vorhersage der Volatilität mit Hilfe der Korrelation.
    Entwicklung eines Replay-Systems — Marktsimulation (Teil 07): Erste Verbesserungen (II) Entwicklung eines Replay-Systems — Marktsimulation (Teil 07): Erste Verbesserungen (II)
    Im letzten Artikel haben wir einige Korrekturen vorgenommen und Tests zu unserem Replay System hinzugefügt, um die bestmögliche Stabilität zu gewährleisten. Wir haben auch mit der Erstellung und Verwendung einer Konfigurationsdatei für dieses System begonnen.
    Wie man einen einfachen Multi-Currency Expert Advisor mit MQL5 erstellt (Teil 1): Indikatorsignale basierend auf ADX in Kombination mit Parabolic SAR Wie man einen einfachen Multi-Currency Expert Advisor mit MQL5 erstellt (Teil 1): Indikatorsignale basierend auf ADX in Kombination mit Parabolic SAR
    Der Multi-Currency Expert Advisor in diesem Artikel ist ein Expert Advisor oder Handelsroboter, der mit mehr als einem Symbolpaar aus einem Symbolchart handeln kann (Positionen öffnen, schließen und verwalten).