English Русский 中文 Español 日本語 Português
preview
Verbessern Sie Ihre Handelscharts mit interaktiven GUIs in MQL5 (Teil I): Bewegliche GUsI (I)

Verbessern Sie Ihre Handelscharts mit interaktiven GUIs in MQL5 (Teil I): Bewegliche GUsI (I)

MetaTrader 5Handel | 1 August 2023, 13:13
221 0
Kailash Bai Mina
Kailash Bai Mina

Einführung

Willkommen in der aufregenden Welt der beweglichen GUI in MQL5! Dieser Leitfaden soll Ihnen das Wissen vermitteln, wie Sie eine dynamische, interaktive Nutzeroberfläche erstellen können, die Ihre Handelsstrategien aufwertet. Wir beginnen mit der Entschlüsselung des grundlegenden Konzepts der Chartereignisse, dem Motor der Interaktivität unserer GUI (von englisch graphical user interface oder grafischer Nutzeroberfläche). Auf dieser Grundlage führen wir Sie dann durch die Erstellung Ihrer ersten beweglichen (movebale) Nutzeroberfläche.

Im nächsten Teil werden wir uns mit der effizienten Erstellung mehrerer grafischer Nutzeroberflächen für ein einzelnes Chart befassen (nicht nur durch Kopieren und Einfügen von Elementen) und unsere grafische Nutzeroberfläche durch Hinzufügen und Anpassen verschiedener Elemente verbessern, um sie an Ihre individuellen Bedürfnisse anzupassen. Für diejenigen, die sofort loslegen wollen, haben wir einen kurzen Leitfaden erstellt, der schnelle Schritte für eine bewegliche Nutzeroberfläche bietet.

Am Ende dieses Kurses werden Sie wertvolle Kenntnisse über die Erstellung und Manipulation von beweglichen Nutzeroberflächen in MQL5 erlangt haben, einem leistungsstarken Werkzeug für jeden Händler. Auch wenn Sie es eilig haben, bieten wir Ihnen eine Kurzanleitung für diejenigen, die ihre GUI sofort beweglich machen wollen. Also, auf geht's auf diese spannende Reise!

Wir werden wie folgt weiter vorgehen:


Entschlüsselung von Chart-Ereignissen: Die Bausteine einer beweglichen GUI

Ab jetzt sieht der EA-Code so aus, d.h. ein absoluter Basis-EA:

Sie fragen sich vielleicht: Warum eine EA, warum nicht ein Indikator? Nun, der Grund dafür ist, dass ein EA einfacher für die meisten Menschen zu verstehen ist, während ein Indikator einige verwirren könnte. Aber seien Sie versichert, die gleiche Schritte könnten in Indikator auch gemacht werden.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
   {
//---
    
//---
    return(INIT_SUCCEEDED);
   }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
   {
//---

   }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
   {
//---

   }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
   {
//---
   }
//+------------------------------------------------------------------+

Um OnChartEvent besser zu verstehen, vergleichen wir es mit anderen vordefinierten Funktionen, die Sie bereits aus dem obigen grundlegenden EA mit OnChartEvent() kennen.

Vordefinierte Funktionen Ihre Verhalten
OnInit()
Wird zur Initialisierung gestartet. D.h. der EA wird auf dem Chart initialisiert (gestartet), OnInit() läuft nur einmal.
OnTick()
Wird jedesmal gestartet, wenn das Symbol auf dem Chart einen Tick vom Broker erhält. Ein neuer Tick bedeutet eine Preisaktualisierung.
OnDeinit() Wird zur Deinitialisierung gestartet, also wenn der EA aus dem Chart entfernt wird. OnDeinit() läuft auch nur einmal.

Auf die gleiche Weise ist OnChartEvent() eine Funktion, die ausgeführt wird, wenn bestimmte Ereignisse eintreten. Von welchen Ereignissen ist hier die Rede?

Es gibt 9 vordefinierte Ereignisse (mit Ausnahme von 2 nutzerdefinierten Ereignissen):

  1. CHARTEVENT_KEYDOWN
  2. CHARTEVENT_MOUSE_MOVE 
  3. CHARTEVENT_OBJECT_CREATE 
  4. CHARTEVENT_OBJECT_CHANGE
  5. CHARTEVENT_OBJECT_DELETE 
  6. CHARTEVENT_CLICK 
  7. CHARTEVENT_OBJECT_CLICK 
  8. CHARTEVENT_OBJECT_DRAG 
  9. CHARTEVENT_OBJECT_ENDEDIT

Kurzer Überblick über das Beispiel, das wir später im Artikel verwenden werden:

  1. CHARTEVENT_KEYDOWN

    Wenn das Chartfenster im Fokus ist (klicken Sie einfach irgendwo auf das Chartfenster, um es in den Fokus zu bekommen), wird die Funktion OnChartEvent() jedes Mal ausgeführt, wenn eine beliebige Taste auf der Tastatur geklickt wird, d.h. wenn eine Taste gedrückt wird.

    Wenn Sie die Taste gedrückt halten, ist es, als ob Sie immer wieder mit einer Geschwindigkeit von 30 Klicks pro Sekunde auf die Taste drücken.

    Was können wir nach einem Tastendruck machen, NICHT VIEL. Es ist nutzlos, solange wir nicht wissen, welche Taste gedrückt wurde. Wie können wir dann wissen, welche Taste gedrückt wurde? Nun, das ist, wo die Parameter von OnChartEvent() ins Spiel kommt.

    Von welchen Parametern ist die Rede? Es gibt 4 Parameter, die wir erhalten, wenn OnChartEvent() ausgeführt wird

    1. id -> integer
    2. lparam -> long
    3. dparam -> double
    4. sparam -> string

    Dies sind, einfach ausgedrückt, einige Daten über die Ereignisse, für die OnChartEvent() aufgerufen wird, und wir können diese Daten innerhalb der OnChartEvent() Funktion verwenden.

    Zum Beispiel im Falle des Ereignisses CHARTEVENT_KEYDOWN,

    • id enthält CHARTEVENT_KEYDOWN selbst, sodass wir erkennen können, für welches Ereignis OnChartEvent() aufgerufen wird, und die anderen Parameter entsprechend behandeln können.
    • lparam enthält den Keycode der gedrückten Taste.
    • dparam enthält die Anzahl der Tastendrücke, die erzeugt wurden, während die Taste gedrückt gehalten wurde. Wenn wir die Taste jedoch gedrückt halten, wird die Taste nicht in den gedrückten Zustand versetzt und macht stattdessen 30 Klicks pro Sekunde. Dieser Wert ist also immer 1.
    • sparam enthält eine Bitmaske, die einfach ausgedrückt den Zustand der gedrückten oder angeklickten Taste beschreibt, indem sie 2 verschiedene Werte für eine bestimmte Taste anzeigt (siehe das Beispiel unten, um es besser zu verstehen).


    Sagen wir, wir haben die Taste „A“ auf der Tastatur geklickt/gedrückt, dann wird OnChartEvent() ausgeführt mit

    • id = CHARTEVENT_KEYDOWN
    • lparam = 65
    • dparam = 1
    • sparam = 30 für den ersten Klick und 16414 für die darauf folgenden Klicks, wenn A mit einer Rate von 30 Klicks pro Sekunde gehalten wird.


    Nun, da wir die Informationen haben, können wir einige if-Anweisungen verwenden und etwas tun, wenn der Nutzer die Taste A drückt oder hält.



  2. CHARTEVENT_MOUSE_MOVE

    Zunächst muss eine Booleon-Charteigenschaft namens CHART_EVENT_MOUSE_MOVE auf True gesetzt werden. Dies kann einfach mit einer einfachen Codezeile geschehen:

    //Set Chart property CHART_EVENT_MOUSE_DOWN to true 
    ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);

    Es wird normalerweise empfohlen, dies in OnInit() zu tun. Sobald dies geschehen ist, können wir CHARTEVENT_MOUSE_MOVE verwenden.

    Immer wenn die Maus über das Chart bewegt wird, wird OnChartEvent() mit den folgenden Informationen in den Parametern ausgeführt:

    • id = CHARTEVENT_MOUSE_MOVE
    • lparam = Koordinate der x-Achse
    • dparam = Koordinate der y-Achse
    • sparam = Bitmaske, die den Zustand der Maustasten beschreibt

     bitmask enthält folgende Werte -> 

    • Maus links --> 1
    • Maus rechts --> 2
    • Maus Mitte --> 16
    • Maus Erste X-Taste --> 32
    • Maus Zweite X-Taste --> 64
    • Umschalttaste --> 4
    • Steuerungstaste --> 8

    Das Chartfenster befindet sich im 4. Quadranten, d.h. die Koordinaten der x-Achse (lparam) befinden sich auf der linken Seite des Chartfensters und die Koordinaten der y-Achse (dparam) auf der oberen Seite des Chartfensters. Mit all diesen Informationen sind wir nun bereit, CHARTEVENT_MOUSE_MOVE zu verwenden. Wir werden es im Folgenden verwenden, um die GUI zu bewegen.


  3. CHARTEVENT_KLICK

    Es erfordert keine spezielle Eigenschaft, wir können es direkt verwenden, d.h. wenn die Maus auf das Chart geklickt wird, wird OnChartEvent() mit den folgenden Parametern ausgeführt

    • id = CHARTEVENT_CLICK
    • lparam = Koordinate der x-Achse
    • dparam = Koordinate der y-Achse
    • sparam = „“ d.h. leere Zeichenfolge, die keine nützlichen Informationen liefert


    Nun, da wir die oben genannten Informationen haben, können wir einige if-Anweisungen verwenden und etwas tun, wenn der Nutzer irgendwo auf das Chart klickt.


Oben haben wir 3 Ereignisse besprochen, die Funktion OnChartEvent() aufruft, CHARTEVENT_KEYDOWN, CHART_EVENT_MOUSE_MOVE, CHARTEVENT_CLICK

Ich weiß, wenn Sie OnChartEvent() noch nie verwendet haben, dann kann all dies etwas verwirrend und erdrückend erscheinen, Nun kennen wir die ersten Schritte und können durch mehr Lernen und Üben uns verbessern. Wir werden das oben besprochene Wissen unten üben, um die GUI beweglich zu machen. Bleiben Sie bei mir und Sie werden sich sehr bald besser fühlen.

Lesen Sie die Dokumentation oder kommentieren Sie weiter unten, wenn Sie Details zu den anderen Ereignissen benötigen, die OnChartEvent() ausführen.


Erstellen der ersten beweglichen GUI: Ein schrittweiser Leitfaden

Nun, da der ganze langweilige Kram erledigt ist, können wir uns auf das echte Lernen konzentrieren, d.h. die Anwendung der Theorie, die wir gelernt haben, um echte Dinge zu tun und nicht nur zu reden.

In diesem Abschnitt ist unser Ziel, eine sehr einfach aussehende GUI zu erstellen, oder wir können sagen, ein leeres weißes Rechteck. Lassen Sie sich jetzt nicht demotivieren, nur weil wir keine komplexe, gut aussehende GUI erstellen, die Dinge beginnen immer mit den Grundlagen, aber sie steigern ihr Niveau exponentiell.

Glauben Sie, dass Sie da mithalten können? Probieren Sie es aus. Bleiben Sie bis zum Ende dieses Artikels dabei und sehen Sie, ob Sie sagen können, dass dies alles einfach war. Nennen wir diese grafische Nutzeroberfläche „Dashboard“, da wir sie bald zu einem Dashboard (Instrumententafel) machen werden. Also, fangen wir ohne weiteres damit an

Zunächst erstellen wir ein einfaches Rechteck von 200x200 (XSize x YSize) mit 100 Pixeln von links (XDistance) und 100 Pixeln von oben (YDistance) 

int OnInit()
   {
    //---
    //Set the name of the rectangle as "TestRectangle"
    string name = "TestRectangle";
    //Create a Rectangle Label Object at (time1, price1)=(0,0)
    ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);
    //Set XDistance to 100px i.e. Distance of Rectangle Label 100px from Left of the Chart Window
    ObjectSetInteger(0, name,OBJPROP_XDISTANCE, 100);
    //Set YDistance to 100px i.e. Distance of Rectangle Label 100px from Top of the Chart Window
    ObjectSetInteger(0, name,OBJPROP_YDISTANCE, 100);
    //Set XSize to 200px i.e. Width of Rectangle Label
    ObjectSetInteger(0, name,OBJPROP_XSIZE, 200);
    //Set YSize to 200px i.e. Height of Rectangle Label
    ObjectSetInteger(0, name,OBJPROP_YSIZE, 200);
    //---
    return(INIT_SUCCEEDED);
   }


Wenn wir nun den EA mit dem Chart verbinden, sollten wir unser erstelltes Rechteck wie folgt sehen:


Abbildung 1: Bild eines einfachen Rechtecks

Abbildung 1: Bild eines einfachen Rechtecks



Nun, wenn wir können dieses Rechteck mit der Maus ziehen, dann können wir eine Menge Dinge tun, wie eine sehr komplexe mehrere Dashboard frei auf dem Chart-Fenster, die sehr gute interaktive EA's/Indicator's machen kann. Eine der besten Beispiele dafür ist wohl der Trade Assistant EA.

Wie können wir also vorgehen, um sie beweglich zu machen? Lassen Sie uns zunächst einen Plan erstellen:

  • Bedingungen vor dem Verschieben:
    • Die Maus muss sich über dem Dashboard befinden.

    • Die linke Taste der Maus muss unten sein.

  • Wenn wir dann die Maus bewegen, während wir die linke Maustaste gedrückt halten, sollte sich das Dashboard bewegen

  • Es sollte sich genau so weit bewegen, wie sich die Maus von dem Punkt aus bewegt hat, an dem die Maus ihre beiden Bedingungen erfüllt hat.

    So, das ist ein grundlegender Überblick über unseren Plan, um es beweglich zu machen, Schreiben wir jetzt den Code, Schritt für Schritt:

    Für die erste Bedingung, die Maus muss über dem Dashboard befinden, müssen wir zunächst die x- und y-Koordinaten der Mausposition ermitteln


    Es ist Zeit, die Theorie für x und y Achsen Koordinate der Maus anzuwenden, Wir müssen OnChartEvent() verwenden, und dann, was tun wir als nächstes? Versuchen Sie, sich zu erinnern.

    1. Wir setzen die Charteigenschaft CHART_EVENT_MOUSE_MOVE auf True

      Wir fügen den folgenden Code in OnInit() ein, damit er wahr wird, wenn EA initialisiert wird:

      //Set Chart property CHART_EVENT_MOUSE_DOWN to true
      ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);

    2. Jetzt können wir die Mauskoordinate in OnChartEvent() abrufen
      void OnChartEvent(const int id, const long& lparam, const double& dparam, const 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)
             {
              //Comment the X and Y Axes Coordinates
              Comment("X: ", lparam, "\nY: ", dparam);
             }
         }

      In OnChartEvent() überprüfen wir zunächst, ob das Ereignis, das OnChartEvent ausgelöst hat, CHARTEVENT_MOUSE_MOVE war, indem wir eine einfache if-Anweisung verwenden, die prüft, ob die ID gleich CHARTEVENT_MOUSE_MOVE ist, denn wir wollen unseren Kommentarcode nur ausführen, wenn dies der Fall ist.

      Dann kommentieren wir die X- und Y-Achsenkoordinaten (sie werden in der linken oberen Ecke des Chartfensters in weißer Farbe mit etwas kleinerer Schrift angezeigt) wie folgt: 

      Abbildung 2. X,Y-Koordinaten-Kommentar

      Abbildung 2. X,Y-Koordinate Kommentar

    Für unsere Logik, um herauszufinden, ob sich die Maus über dem Dashboard befindet, siehe das folgende Bild: 

    Abbildung 3. Formel-Visualisierung

    Abb. 3. Formel-Visualisierung





    Um herauszufinden, ob sich die Maus über dem Dashboard befindet:

    • X >= XDistance             --> X>=100
    • X <= XDIstance + XSize --> X<=300
    • Y >= YDistance             --> Y>=100
    • Y <= YDistance + YSize --> Y>=300

    Umwandlung in Code:

    void OnChartEvent(const int id, const long& lparam, const double& dparam, const 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;
    
          string name = "TestRectangle";
          int XDistance = ObjectGetInteger(0, name, OBJPROP_XDISTANCE); //Should be 100 initially as we set it in OnInit()
          int YDistance = ObjectGetInteger(0, name, OBJPROP_YDISTANCE); //Should be 100 initially as we set it in OnInit()
          int XSize = ObjectGetInteger(0, name, OBJPROP_XSIZE); //Should be 200 initially as we set it in OnInit()
          int YSize = ObjectGetInteger(0, name, OBJPROP_YSIZE); //Should be 200 initially as we set it in OnInit()
          
          //Check Mouse on Dashboard condition
          if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize)
            {
             //Comment the X and Y Axes Coordinates and Mouse is on the dashboard
             Comment("X: ", lparam, "\nY: ", dparam, "\nMouse is on the Dashboard");
            }
          else
            {
             //Comment the X and Y Axes Coordinates and Mouse is not on the dashboard
             Comment("X: ", lparam, "\nY: ", dparam, "\nMouse is NOT on the Dashboard");
            }
    
         }
      }

    Deklaration der Variablen X, Y, name, XDistance, YDistance, XSize, YSize. Wir erhalten X von lparam, Y von dparam, name ist nur der Textname, den wir oben festgelegt haben, XDistance, YDistance, XSize, YSize liefert die Funktion ObjectGetInteger().

    Denken Sie daran, dass es unser Ziel ist, dass das Dashboard reibungslos funktioniert, und wir uns dann um andere Dinge kümmern.

    Ergebnis:

    Abbildung 4. Maus befindet sich über dem Dashboard GIF

    Abb. 4. Die Maus befindet sich über dem Dashboard.


    Wie Sie sehen können, ändert sich der Kommentar immer dann, wenn sich die Maus über dem Dashboard befindet. Unsere Logik funktioniert also, und wir wissen jetzt, ob sich die Maus über dem Dashboard befindet oder nicht.

    Jetzt brauchen wir den Zustand der Maustasten, erinnern Sie sich an die Theorie, wenn die linke Maustaste geklickt wurde, dann war sparam 1, lassen Sie uns das verwenden:

    void OnChartEvent(const int id, const long& lparam, const double& dparam, const 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 = "TestRectangle";
          int XDistance = ObjectGetInteger(0, name, OBJPROP_XDISTANCE); //Should be 100 initially as we set it in OnInit()
          int YDistance = ObjectGetInteger(0, name, OBJPROP_YDISTANCE); //Should be 100 initially as we set it in OnInit()
          int XSize = ObjectGetInteger(0, name, OBJPROP_XSIZE); //Should be 200 initially as we set it in OnInit()
          int YSize = ObjectGetInteger(0, name, OBJPROP_YSIZE); //Should be 200 initially as we set it in OnInit()
    
          //Check Dashboard move conditions
          if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize && MouseState == 1)
            {
             //Comment that the dashboard is ready to move
             Comment("Dashboard is ready to move.");
            }
          else
            {
             //Comment that the dashboard is not ready to move
             Comment("Dashboard is NOT ready to move.");
            }
          
         }
      }

    Ich habe bei den Variablen hinzugefügt:

    int MouseState = (int)sparam; //To get the mouse state: 1 -> Mouse Left Button Down (You can check the other above)
    

    und in der if-Anweisung:

    if(MouseState == 1) // This insures that Mouse Left button in pressed

    und es wurden die Kommentare ein wenig geändert.

    Immer wenn die linke Maustaste über dem Dashboard gedrückt wird, erhalten wir den Kommentar „Dashboard is ready to move.“ (Dashboard ist bereit zum Verschieben) oder „Dashboard is NOT ready to move.“ (Dashboard ist NICHT bereit zum Verschieben).

    Schauen wir uns das in Aktion an:

    Abbildung 5. Das Dashboard ist bereit zum Verschieben

    Abbildung 5. Das Dashboard ist bereit zum Verschieben


    Sehen Sie, wie sich der Kommentar ändert, wenn die linke Maustaste gedrückt wird.


    Nun, da das erledigt ist, sind wir bereit, unser Dashboard zu verschieben. Wie gehen wir nun vor? Versuchen wir, das herauszufinden.

    Wir wissen, dass sich das Dashboard mit der Maus bewegt und wie können wir die Position des Dashboards ändern? Natürlich mit den Eigenschaften XDistance und YDistance. So ändern wir XDistance und YDistance aber um wie viel? Weil sich das Dashboard mit Maus bewegt, sollte das Dashboard gleich wie Maus bewegen, korrekt?

    Um wie viel hat sich unsere Maus dann bewegt? Das werden wir herausfinden müssen, aber wie? Das waren jetzt eine Menge Fragen, machen wir einen Plan aus diesen Fragen.

    Plan: 

    • Wir finden heraus, um wie viel sich unsere Maus bewegt hat, nachdem wir MLB (Mouse Left Button, Linke Maustaste) gedrückt haben.
    • Wir bewegen das Dashboard um genau dieselben Distanz wie die Maus.
    • Dies machen wir so lange, solange MLB nach unten gedrückt wird, danach hören wir auf, das Dashboard zu bewegen.

    Aber machen wir einen Schritt nach dem anderen.

    Wir können immer die aktuelle Mausposition abfragen, richtig, aber was, wenn wir die Mausposition speichern, wenn MLB das erste Mal geklickt wurde?

    Und wir können wissen, wenn die MLB gedrückt wird, von MouseState Variable, die wir erstellt, dass sparam speichert.

    Nachfolgend finden Sie den Code, der den MLB-Klick beim ersten Mal erkennt: 

    int previousMouseState = 0;
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id, const long& lparam, const double& dparam, const 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)
         {
          int MouseState = (int)sparam;
          
          bool mblDownFirstTime = false;
          if(previousMouseState == 0 && MouseState == 1) {
             mblDownFirstTime = true;
          }
          
          previousMouseState = MouseState;
         }
      }
    //+------------------------------------------------------------------+

    Ich habe andere Dinge entfernt, um die Übersichtlichkeit und das Verständnis zu verbessern. Diese Methode wird häufig bei der Erstellung von Trailing-Funktionen für EA oder bei der Erkennung eines neuen Balkens usw. verwendet.

    Schauen wir uns das mal an:

    1. int previousMouseState = 0;

      Wir deklarieren eine int-Variable mit dem Namen previousMouseState im globalen Bereich und setzen sie auf 0. Diese Variable speichert den MouseState-Wert des letzten CHARTEVENT_MOUSE_MOVE-Ereignisses, Nun, wie? Haben Sie etwas Geduld, Sie werden es bald wissen.


    2. int previousMouseState = 0;

      Wir deklarieren eine int-Variable mit dem Namen previousMouseState im globalen Bereich und setzen sie auf 0. Diese Variable speichert den MouseState-Wert des letzten CHARTEVENT_MOUSE_MOVE-Ereignisses, Nun, wie? Etwas Geduld, wir werden es bald wissen.

    3. int MouseState = (int)sparam;   
      bool mblDownFirstTime = false;
      if(previousMouseState == 0 && MouseState == 1) {
         mblDownFirstTime = true;
      }


      Zuerst deklarieren wir einen MouseState und setzen ihn gleich sparam, der den Mausstatus enthält, dann deklarieren wir eine boolsche Variable namens mblDownFirstTime und setzen ihren Standardwert auf false.

      Dann prüfen wir 2 Bedingungen: einmal sollte previousMouseState 0 sein (MLB Up, No mouse button pressed) und (&&) MouseState sollte 1 sein (MLB Down).

      Diese Bedingung bestätigt oder verneint im Grunde, dass MLB zum ersten Mal gedrückt wurde. Sobald wir wissen, dass es das erste Mal ist, setzen wir mblDownFirstTime gleich true, damit wir diese Variable später verwenden können.


    Damit ist der erste Schritt abgeschlossen und wir können zu Schritt 2 und 3 übergehen.

    Nun, es gibt viele Möglichkeiten, wie wir weiter vorgehen können, aber um eine sehr glatte und subtile Bewegung zu bekommen, sind unten die Schritte, die wir machen werden:

    1. Wir erstellen eine globale Variable mit dem Namen movingState, die wir auf true setzen, sobald der Nutzer auf MLB über dem Dashboard klickt. Wir deklarieren auch MLB Down X, MLB Down Y, MLB Down XDistance, MLB Down YDistance (hier bedeutet MLB Down, dass die MLB als erstes unten war). Diese werden benötigt, um die Position des Dashboards zu ändern.
    2. Wenn movingState true ist, wird die Position des Dashboards entsprechend der Änderung der Mausposition gegenüber der ursprünglichen Position (wenn MLB zum ersten Mal angeklickt wurde) aktualisiert.
    3. Wenn movingState true ist, wird die Position des Dashboards entsprechend der Änderung der Mausposition gegenüber der ursprünglichen Position (wenn MLB zum ersten Mal angeklickt wurde) aktualisiert.


    Neuer Code:

    int previousMouseState = 0;
    int mlbDownX = 0;
    int mlbDownY = 0;
    int mlbDownXDistance = 0;
    int mlbDownYDistance = 0;
    bool movingState = false;
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id, const long& lparam, const double& dparam, const 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)
         {
          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);
             ChartRedraw(0);
            }
    
          if(MouseState == 0)
            {
             movingState = false;
             ChartSetInteger(0, CHART_MOUSE_SCROLL, true);
            }
    
          previousMouseState = MouseState;
         }
      }
    //+------------------------------------------------------------------+

     Lassen Sie uns das Ganze in einfacheren Worten ausdrücken:

    1. int mlbDownX = 0;
      int mlbDownY = 0;
      int mlbDownXDistance = 0;
      int mlbDownYDistance = 0;
      bool movingState = false;

      Wir haben ein paar Variablen im Global Space erstellt, wir haben bereits über den previousMouseState gesprochen, ansonsten:

      • mlbDownX                -> Sichern der X-Koordinate, wenn MLB das erste Mal unten war
      • mlbDownY                -> Sichern der Y-Koordinate, wenn MLB das erste Mal unten war
      • mlbDownXDistance -> Um die XDistance-Eigenschaft des Dashboards zu sichern, wenn die MLB das erste Mal gedrückt wurde
      • mlbDownYDistance -> Um die YDistance-Eigenschaft des Dashboards zu sichern, wenn die MLB das erste Mal gedrückt wurde    
      • movingState             -> Wahr, wenn das Dashboard verschoben wird, sonst falsch

      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;
          }
        }



      Zuerst prüfen wir, ob es der erste MLB-Klick ist, wenn ja, dann aktualisieren wir mlbDownX, mlbDownY, mlbDownXDistance, mlbDownYDistance auf die aktuellen X, Y, XDistance, YDistance, wir werden sie später verwenden.

      Dann prüfen wir, ob MLB über dem Dashboard unten war, und wenn es über dem Dashboard unten war, setzen wir movingState auf true.

    2. if(movingState)
        {
         ChartSetInteger(0, CHART_MOUSE_SCROLL, false);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY);
         ChartRedraw(0);
        }

      Und wenn movingState wahr ist, ändern wir den XDistance und YDistance:

      X - mlbDownX // Change in Mouse X Position form the initial click
      and 
      Y - mlbDownY // Change in Mouse X Position form the initial click

      Diese oben sind die Änderung der Mausposition vom ersten Klick und wir fügen sie zu mlbDownXDistance und mlbDownYDistance hinzu, um die neue Dashboard-Position zu erhalten, was Sinn macht, wenn Sie darüber nachdenken.

      Und wir setzen auch CHART_MOUSE_SCROLL Charteigenschaft auf false, sodass Chart nicht mit unserem Dashboard bewegen, dann wir zeichnen das Chart natürlich neu, um eine sehr glatte, feine Bewegung zu erhalten.

    3. if(MouseState == 0)
        {
         movingState = false;
         ChartSetInteger(0, CHART_MOUSE_SCROLL, true);
        }

      Sobald wir die MLB verlassen, d.h. MouseState wird 0

      Dann setzen wir movingState auf false und erlauben erneut das Verschieben des Charts, indem wir CHART_MOUSE_SCROLL wieder auf true setzen.



    Damit ist unser Code abgeschlossen. Klopfen wir uns auf die Schulter, wenn Sie bis jetzt durchgehalten haben, denn wir sind fast fertig mit Teil I.

    Unser vollständiger Code:

    //+------------------------------------------------------------------+ //| Expert initialization function                                   | //+------------------------------------------------------------------+ int OnInit()   { //---    //Set the name of the rectangle as "TestRectangle"    string name = "TestRectangle";    //Create a Rectangle Label Object at (time1, price1)=(0,0)    ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);    //Set XDistance to 100px i.e. Distance of Rectangle Label 100px from Left of the Chart Window    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 100);    //Set YDistance to 100px i.e. Distance of Rectangle Label 100px from Top of the Chart Window    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 100);    //Set XSize to 200px i.e. Width of Rectangle Label    ObjectSetInteger(0, name, OBJPROP_XSIZE, 200);    //Set YSize to 200px i.e. Height of Rectangle Label    ObjectSetInteger(0, name, OBJPROP_YSIZE, 200); //Set Chart property CHART_EVENT_MOUSE_DOWN to true    ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); //---    return(INIT_SUCCEEDED);   } //+------------------------------------------------------------------+ //| Expert deinitialization function                                 | //+------------------------------------------------------------------+ void OnDeinit(const int reason)   { //---   } //+------------------------------------------------------------------+ //| Expert tick function                                             | //+------------------------------------------------------------------+ void OnTick()   { //---   } //+------------------------------------------------------------------+ //Declare some global variable that will be used in the OnChartEvent() function int previousMouseState = 0; int mlbDownX = 0; int mlbDownY = 0; int mlbDownXDistance = 0; int mlbDownYDistance = 0; bool movingState = false; //+------------------------------------------------------------------+ //|                                                                  | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long& lparam, const double& dparam, const 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 = "TestRectangle";       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      }   } //+------------------------------------------------------------------+

    Dieser einfache Code erfüllt die Aufgabe

    Ergebnis:

    Abbildung 6. Endgültiges Ergebnis

    Abbildung 6. Endgültiges Ergebnis


    Damit schließen wir diesen Abschnitt nun ab.


    Schlussfolgerung

    Es tut mir wirklich leid, dass ich Sie mit einer Art Cliffhanger zurücklasse, denn wir haben noch nichts wirklich Einzigartiges geschaffen. Aber seien Sie versichert, dass in ein paar Tagen ein weiterer Teil folgen wird, in dem:

    • Wir werden dazu übergehen, mehrere GUI auf einem einzigen Chart effizient zu erstellen (nicht nur durch Kopieren und Einfügen von Daten).
    • Wir werden uns mit der Verbesserung unserer Nutzeroberfläche befassen, indem wir verschiedene Elemente hinzufügen und anpassen, um sie auf Ihre individuellen Bedürfnisse zuzuschneiden. Für diejenigen, die sofort loslegen wollen, haben wir einen kurzen Leitfaden erstellt, der schnelle Schritte für eine bewegliche Nutzeroberfläche bietet.

    Am Ende dieses Kurses werden Sie wertvolle Kenntnisse über die Erstellung und Manipulation von beweglichen Nutzeroberflächen in MQL5 erlangt haben, einem leistungsstarken Werkzeug für jeden Händler. Also, auf geht's auf diese spannende Reise!


    Ich hoffe, es hat Ihnen gefallen und in irgendeiner Weise geholfen. Ich hoffe, Sie im nächsten Teil wiederzusehen.

    Fröhliches Kodieren.



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

    Beigefügte Dateien |
    Wie man ein erfolgreicher Signalanbieter auf MQL5.com wird Wie man ein erfolgreicher Signalanbieter auf MQL5.com wird
    Mein Hauptziel in diesem Artikel ist es, Ihnen eine einfache und genaue Beschreibung der Schritte zu geben, die Ihnen helfen werden, ein Top-Signalanbieter auf MQL5.com zu werden. Auf der Grundlage meines Wissens und meiner Erfahrung werde ich erklären, was nötig ist, um ein erfolgreicher Signalanbieter zu werden, und wie man eine gute Strategie findet, testet und optimiert. Darüber hinaus gebe ich Tipps zur Veröffentlichung Ihres Signals, zum Verfassen einer überzeugenden Beschreibung und zur effektiven Werbung und Verwaltung des Signals.
    Kategorientheorie in MQL5 (Teil 10): Monoide Gruppen Kategorientheorie in MQL5 (Teil 10): Monoide Gruppen
    Dieser Artikel setzt die Serie über die Implementierung der Kategorientheorie in MQL5 fort. Hier betrachten wir Monoidgruppen als Mittel zur Normalisierung von Monoidmengen, um sie über eine größere Bandbreite von Monoidmengen und Datentypen hinweg vergleichbar zu machen.
    Prognose mit ARIMA-Modellen in MQL5 Prognose mit ARIMA-Modellen in MQL5
    In diesem Artikel setzen wir die Entwicklung der CArima-Klasse zur Erstellung von ARIMA-Modellen fort, indem wir intuitive Methoden hinzufügen, die Vorhersagen ermöglichen.
    Kategorientheorie (Teil 9): Monoid-Aktionen Kategorientheorie (Teil 9): Monoid-Aktionen
    Dieser Artikel setzt die Serie über die Implementierung der Kategorientheorie in MQL5 fort. Hier setzen wir Monoid-Aktionen als Mittel zur Transformation von Monoiden fort, die im vorigen Artikel behandelt wurden und zu mehr Anwendungen führen.