Verbessern Sie Ihre Handelscharts mit interaktiven GUI's in MQL5 (Teil III): Ein einfaches, bewegliches Handels-GUI
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:
- Was werden wir machen?
- Erstellung eines einfachen statischen Dashboards für den Handel
- Besprechung des Ansatzes, unser statisches Dashboard mit allen darin enthaltenen Elementen zu bewegen
- Verwendung des diskutierten Ansatzes, um unser statisches Dashboard beweglich zu machen
- 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
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:
- Titelleiste
- Hauptteil des Dashboards
- Titel Text
- „Lot Size“: Text
- Edit Box
- Schaltfläche für Kaufen und Verkaufen
- Fügen wir die erforderlichen letzten Handgriffe hinzu.
Dies scheint eine vernünftige Reihenfolge zu sein. Fangen wir an,
- 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.
- Create -> So erstellen wir die rechteckige Beschriftung
- Destroy -> So zerstören wir das Dashboard
- SetBorderType -> So legen wie den Rahmentyp fest
- 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
- 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
- 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
- "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
- 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.
- 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. Die hinzugefügten Schaltflächen für Kaufen und Verkaufen - Der letzte Schliff
- 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.
-
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.
-
Einbindung der Handelsbibliothek:
- Wir integrieren die Handelsbibliothek und erstellen eine Instanz mit dem Namen trade mit folgendem Code:
#include <Trade/Trade.mqh> CTrade trade;
- Wir integrieren die Handelsbibliothek und erstellen eine Instanz mit dem Namen trade mit folgendem Code:
-
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.
Das war's dann auch schon. Ergebnis:
Abb. 5. Hinzugefügt „Lot Size:“ Text
Jetzt kommt noch der letzte Schliff: Wir wollen es bunt machen. Wir werden die folgenden Änderungen vornehmen:
Gehen wir wie folgt vor: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:
Endgültiges Ergebnis:
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:
- den Name im Array addedNames
- 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
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
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.