MetaTrader 5 herunterladen

Grafische Interfaces X: Updates für die Easy And Fast Bibliothek (Build 2)

15 September 2016, 17:26
Anatoli Kazharski
0
392

Inhalt

Einleitung

Der erste Artikel Grafisches Interface I: Vorbereiten der Bibliotheksstruktur (Kapitel 1) Beschreibt im Detail wofür diese Bibliothek gedacht ist. Am Ende von jedem Kapitel, finden Sie eine vollständige Liste mit Links zu diesem Artikel. Zudem finden Sie dort eine Möglichkeit das Projekt, entsprechend dem aktuellen Entwicklungszustand, herunterzuladen. Die Dateien müssen in den gleichen Verzeichnissen untergebracht werden, so, wie Sie auch in dem Archiv abgelegt sind.

Seit der Veröffentlichung des vorangegangenen Artikels dieser Serie, hat die Easy And Fast Bibliothek einige neue Features bekommen. Die Bibliotheksstruktur und der Programmcode wurden teilweise optimiert, was die CPU-Auslastung leicht reduziert hat. Einige wiederkehrende Methoden in vielen Control-Klassen wurden in die CElement Basisklasse bewegt. Zudem wurden einige kleinere visuelle Verbesserungen und Fehlerbehebungen durchgeführt. Lassen Sie uns diese im Detail anschauen.

 

Updates

1. Veränderung des standardmäßigen Farbschemas. Dieses Farbschema besteht nun meistens aus hellen Farbtönen das dem Charthintergrund entspricht. Die Verwendung des standardmäßigen Farbschemas erlaubt es nun, dass nur eine minimale Menge von Eigenschaften angegeben werden muss, wenn man Methoden für die Erzeugung der Controls in einer benutzerdefinierten Klasse entwickelt. 

Die folgenden Screenshots zeigen Beispiele einer MQL Anwendung mit dem grafischen Interface auf einem hellen und einem dunklen Hintergrund.

 Abbildung  1. Einige grafische Interfaces mit dem Standard-Farbschema auf hellem Hintergrund

Abbildung 1. Einige grafische Interfaces mit dem Standard-Farbschema auf hellem Hintergrund


 Abbildung  2. Einige grafische Interfaces mit dem Standard-Farbschema auf dunklem Hintergrund

Abbildung 2. Einige grafische Interfaces mit dem Standard-Farbschema auf dunklem Hintergrund


 

2. Implementierung der ersten Version der CMouse Klasse für das Abspeichern der Maus- und der Mauszeiger-Parameter. Lassen Sie uns dieses genauer ansehen.

Die CMouse Klasse finden Sie in der Mouse.mqh Datei die sich in dem Ordner für alle Bibliotheksdateien befindet: “<terminal directlory>\MQLX\Include\EasyAndFastGUI\Controls ”. Hier benötigen wir die CChart Klassen-Instanz der Standard-Bibliothek. Aus dieser Klasse wird die CChart::SubwindowY() Methode dazu verwendet, die Y Koordinate relativ zu dem Unterfenster, in welchem sich der Mauszeiger zurzeit befindet, zu berechnen. Die Verbindung zu den Chart Wird in den Konstruktor der Klasse durchgeführt, während Das abkoppeln in dem Destruktor stattfindet.

Die CChart Klasse ist von hier aus für alle grundlegenden Bibliotheks-Klassen erreichbar. Hierfür wurden die notwendigen Änderungen implementiert. 

//+----------------------------------------------------------------
//|                                                        Mouse.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#include <Charts\Chart.mqh>
//+----------------------------------------------------------------
//| Klasse für die Abfrage der Maus-Parameter                         |
//+----------------------------------------------------------------
class CMouse
  {
private:
   //--- Klassen-Instanz für die Verwaltung des Charts
   CChart            m_chart;
   //---
public:
                     CMouse(void);
                    ~CMouse(void);
  };
//+----------------------------------------------------------------
//| Konstruktor                                                      |
//+----------------------------------------------------------------
CMouse::CMouse(void)
  {
//--- Abfrage der aktuellen Chart ID
   m_chart.Attach();
  }
//+----------------------------------------------------------------
//| Destruktor                                                       |
//+----------------------------------------------------------------
CMouse::~CMouse(void)
  {
//--- Abkoppeln vom Chart
   m_chart.Detach();
  }

Die Liste der Maus- und Mauszeiger-Parameter, die in fast allen Klassen verwendet werden kann, wird nachfolgend gezeigt.

  • Die aktuellen Koordinaten des Mauszeigers
  • Die Nummer des Unterfensters, die zur Zeit dem Mauszeiger zugeordnet ist
  • Die Zeit entsprechend der X Koordinate auf dem Chart.
  • Den Wert entsprechend der Y Koordinate auf dem Chart.
  • Status der linken Maustaste (gedrückt/nicht gedrückt)

Die relevanten Variablen auch Methoden für das Abspeichern und Abfragen der Parameter sind in der CMouse Klasse implementiert: 

class CMouse
  {
private:
   //--- Koordinaten
   int               m_x;
   int               m_y;
   //--- Nummer des Fensters, in welchem sich der Mauszeiger befindet
   int               m_subwin;
   //--- Die Zeit entsprechend der x-Koordinate
   datetime          m_time;
   //--- Der Wert entsprechend der y-Koordinate
   double            m_level;
   //--- Status der linken Maustaste (gedrückt/nicht gedrückt)
   bool              m_left_button_state;
   //---
public:
   //--- Rückgabe der Koordinaten
   int               X(void)               const { return(m_x);                 }
   int               Y(void)               const { return(m_y);                 }
   //--- Gibt die (1) Nummer des Fensters mit dem Mauszeiger zurück, (2) die Zeit entsprechend der x-Koordinate zurück, 
   //    (3) Den Wert entsprechend der y-Koordinate zurück
   int               SubWindowNumber(void) const { return(m_subwin);            }
   datetime          Time(void)            const { return(m_time);              }
   double            Level(void)           const { return(m_level);             }
   //--- Status der linken Maustaste (gedrückt/nicht gedrückt)
   bool              LeftButtonState(void) const { return(m_left_button_state); }
  };

Natürlich benötigen wir den Eventhandler für das Nachverfolgen des Auftretens des CHARTEVENT_MOUSE_MOVE Events. Die CMouse Klassenvariablen, werden in dem Abschnitt der Event-Bearbeitung gefüllt. Wir haben diesen Programmcode in allen Control Event-Handlern bereits gesehen. Nun ist dieser Code nur in der CMouse Klasse vorhanden, was den Programmcode der Control Klassen intuitiver gestalten lässt. Außerdem werden jetzt die Maus- und Mauszeiger-Parameter nur noch einmal innerhalb der ganzen Elemente abgefragt, was natürlich die CPU Auslastung verringert.  

class CMouse
  {
   //--- Eventhandler
   void              OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
  };
//+----------------------------------------------------------------
//| Eventhandler für die Bewegung des Mauszeigers                                  |
//+----------------------------------------------------------------
void CMouse::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Eventhandler für die Bewegung des Mauszeigers
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Linke Maustaste, Koordinaten und Status
      m_x                 =(int)lparam;
      m_y                 =(int)dparam;
      m_left_button_state =(bool)int(sparam);
      //--- Abfrage der Position des Mauszeigers
      if(!::ChartXYToTimePrice(0,m_x,m_y,m_subwin,m_time,m_level))
         return;
      //--- Abfrage der relativen y-Koordinate
      if(m_subwin>0)
         m_y=m_y-m_chart.SubwindowY(m_subwin);
     }
  }

Die CMouse Klassen-Instanz wird in der Basisklasse der Bibliotheks-Engine deklariert (CWndContainer):

//+----------------------------------------------------------------
//| Klasse für das Abspeichern der Interface-Objekte                          |
//+----------------------------------------------------------------
class CWndContainer
  {
protected:
   //--- Klassen-Instanz für die Abfrage der Maus-Parameter
   CMouse            m_mouse;
  };

Die CMouse Klassen-Instanz wird auch in der CElement Basis-Control-Klasse für das Abspeichern des Pointers zu dem Objekt von diesen Typ deklariert, was wiederum in der CWndContainer Klasse deklariert wird. Außerdem befinden sich hier die Methoden für das Abspeichern und Abfragen der Pointer. 

//+----------------------------------------------------------------
//| Base control class                                               |
//+----------------------------------------------------------------
class CElement#
  {
protected:
   //--- Klassen-Instanz für die Abfrage der Maus-Parameter
   CMouse           *m_mouse;
   //---
public:
   //--- (1) abspeichern und (2) Rückgabe des Maus-Pointers
   void              MousePointer(CMouse &object)                   { m_mouse=::GetPointer(object);       }
   CMouse           *MousePointer(void)                       const { return(::GetPointer(m_mouse));      }
  };

Der Pointer zu dem CMouse Objekt Wird automatisch allen Controls übergeben, wenn das grafische Interface erzeugt wird. Dafür muss das CMouse Objekt der CWndContainer::AddToObjectsArray() Methode übergeben werden, wo alle Pointer von allen grafischen Objekten der Controls zu dem gemeinsamen Array gesendet werden. Dieses wird in dem nachfolgenden Listing gezeigt. 

//+----------------------------------------------------------------
//| Hinzufügen des Pointers zu den Control-Objekten in das gemeinsame Array    |
//+----------------------------------------------------------------
template<typename T>
void CWndContainer::AddToObjectsArray(const int window_index,T &object)
  {
   int total=object.ObjectsElementTotal();
   for(int i=0; i<total; i++)
      AddToArray(window_index,object.Object(i));
//--- Abspeichern des Mauszeigers in der Basis-Control-Klasse
   object.MousePointer(m_mouse);
  }

Nun hat jede Control-Klasse Zugriff auf die Maus- und Mauszeiger-Parameter, die in einem einzigen Objekt innerhalb der gesamten Bibliothek abgespeichert sind. Damit neue Werte in dem ChartEvent() Eventhandler der CWndEvents Klasse empfangen werden können, muss der CMouse Objekthandler aufgerufen werden und ihm alle aktuellen Parameter des Events übergeben werden. Da der Aufruf vor der Verarbeitung der Events innerhalb aller Controls durchgeführt wird, sind die relevanten Werte der Maus und des Mauszeigers in allen Controls verfügbar ohne die Typen wiederholt konvertieren, Werte zuweisen und die relative Y-Koordinate berechnen zu müssen.

//+----------------------------------------------------------------
//| Verarbeiten der Programm-Events                                      |
//+----------------------------------------------------------------
void CWndEvents::ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verlassen falls das Array leer ist
//--- Initialisierung der Felder der Eventparameter

//--- Abfrage der Maus-Parameter
   m_mouse.OnEvent(id,lparam,dparam,sparam);

//--- Benutzerdefinierte Events
//--- Überprüfung der Interface Control Events
//--- Event für die Bewegung des Mauszeigers
//--- Event bei Chartveränderungen
  }

Lassen Sie uns einen Auszug des CSimpleButton Control Code Handler als ein Beispiel verwenden. Das nachfolgende Listing zeigt eine Kurzfassung der CSimpleButton::OnEvent() Methode. Die in Gelb hervorgehobenen Zeilen enthalten den Aufruf der CMouse Objektmethoden für das Abfragen der (1) Nummer des Unterfensters, in welchem sich der Mauszeiger befindet, (2) die Koordinaten des Mauszeigers (3) und der Status der linken Maustaste.  

//+----------------------------------------------------------------
//| Event handler                                                    |
//+----------------------------------------------------------------
void CSimpleButton::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten des Events für die Bewegung des Mauszeigers
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Verlassen, falls das Control versteckt ist
      if(!CElement::IsVisible())
         return;
      //--- Verlassen, falls das Formular gesperrt ist
      if(m_wnd.IsLocked())
         return;
      //--- Essen, falls die Nummer des Unterfensters nicht stimmt
      if(CElement::m_subwin!=CElement::m_mouse.SubWindowNumber())
         return;
      //--- Verlassen, falls der Button gesperrt ist
      if(!m_button_state)
         return;
      //--- Den Fokus definieren
      CElement::MouseFocus(CElement::m_mouse.X()>X() && CElement::m_mouse.X()<X2() && 
                           CElement::m_mouse.Y()>Y() && CElement::m_mouse.Y()<Y2());
      //--- Verlassen, falls der Maus-Button nicht gedrückt ist
      if(!CElement::m_mouse.LeftButtonState())
         return;
      //--- 
      ...
      return;
     }
//...
  }

Die entsprechenden Veränderungen wurden in allen Klassen der Bibliothek implementiert.  


3. Früher wurden die Methoden für das Abfragen der Control ID und des Index der graphischen Objekte der Controls wiederholt in vielen Klassen der Bibliothek durchgeführt. Nun wurden diese Methoden in der CElement Basisklasse untergebracht, um Wiederholungen zu vermeiden.  

//+----------------------------------------------------------------
//| Basis Control-Klasse                                               |
//+----------------------------------------------------------------
class CElement#
  {
protected:
   //--- Abfrage der ID aus dem Namen des Buttons
   int               IdFromObjectName(const string object_name);
   //--- Abfrage des Index aus dem Namen des Menüs
   int               IndexFromObjectName(const string object_name);
  };

 

4. Hinzufügen von Methoden in der CWindow Klasse um den Button für das Maximieren und Minimieren des Fensters und der Positionierung des Text-Labels in der Kopfzeile zu aktivieren.  

//+----------------------------------------------------------------
//| Klasse für die Erzeugung eines Formulars mit Controls                         |
//+----------------------------------------------------------------
class CWindow : public CElement
  {
private:
   //--- Einrückungen des Text tables der Kopfzeile
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Darstellung des Buttons für das minimieren und maximieren des Fensters
   bool              m_roll_button;
   //---
public:
   //--- Einrückungen des Text Labels
   void              LabelXGap(const int x_gap)                              { m_label_x_gap=x_gap;                }
   void              LabelYGap(const int y_gap)                              { m_label_y_gap=y_gap;                }
   //--- Verwendung des Tooltip-Buttons
   void              UseRollButton(void)                                     { m_roll_button=true;                 }
  };

 

5. Es wurde der CElement Klasse die Methode CheckWindowPointer() hinzugefügt, um die Anwesenheit eines Fenster pointers überprüfen zu können(CWindow). Senden Sie den Typ des Pointers dieser Methode unter Verwendung der CheckPointer() System-Methode zu, um die Korrektheit festzustellen. Zuvor wurde der selbe Code innerhalb der Erzeugung des Haupt-Controls in allen Control Klassen wiederholt. Die CElement::CheckWindowPointer() Methode vereinfacht nun diesen Prozess, reduziert die Menge an Programmcode und macht das System vielseitiger. 

//+----------------------------------------------------------------
//| Base control class                                               |
//+----------------------------------------------------------------
class CElement#
  {
protected:
   //--- Überprüfung ob der Pointer zu einem Formular existiert
   bool              CheckWindowPointer(ENUM_POINTER_TYPE pointer_type);
  };
//+----------------------------------------------------------------
//| Überprüfung, ob der Pointer zu dem Formular existiert                      |
//+----------------------------------------------------------------
bool CElement::CheckWindowPointer(ENUM_POINTER_TYPE pointer_type)
  {
//--- Falls es keinen Pointer zu diesem Formular gibt
   if(pointer_type==POINTER_INVALID)
     {
      //--- Erzeuge eine Nachricht
      string message=__FUNCTION__+" > Before creating the control, the pointer to the form: "+ClassName()+"::WindowPointer(CWindow &object)" should be sent;
      //--- Sende diese Nachricht zu dem Terminal-Journal
      ::Print(message);
      //--- Unterbreche die Erzeugung des grafischen Interfaces
      return(false);
     }
//--- Sende die Attribute für die Existenz des Pointers
   return(true);
  }

Nun können Sie ganz einfach die CElement::CheckWindowPointer() Methode für die Überprüfung der Existenz eines Pointers zu dem Formular, zu welchem das Control hinzugefügt werden soll durchführen, so wie es das nachfolgende Listing zeigt(Erzeugung eines einfachen Buttons in der CSimpleButton Klasse). Die entsprechenden Veränderungen wurden in allen Klassen der Bibliothek implementiert. 

//+----------------------------------------------------------------
//| Erzeugung eines "einfacher Button" Controls                                 |
//+----------------------------------------------------------------
bool CSimpleButton::CreateSimpleButton(const long chart_id,const int subwin,const string button_text,const int x,const int y)
  {
//--- Abbrechen, falls der Pointer zu dem Formular nicht existiert
   if(!CElement::CheckWindowPointer(::CheckPointer(m_wnd)))
      return(false);
//--- Initialisiere die Variablen
   m_id          =m_wnd.LastId()+1;
   m_chart_id    =chart_id;
   m_subwin      =subwin;
   m_x           =x;
   m_y           =y;
   m_button_text =button_text;
//--- Abstände vom Eckpunkt
   CElement::XGap(m_x-m_wnd.X());
   CElement::YGap(m_y-m_wnd.Y());
//--- Erzeugung des Buttons
   if(!CreateButton())
      return(false);
//--- Verstecke das Control, falls es sich bei dem Fenster um ein Dialogfenster handelt oder falls es minimiert ist
   if(m_wnd.WindowType()==W_DIALOG || m_wnd.IsMinimized())
      Hide();
//---
   return(true);
  }

 

6. Es wurde ein Modus für die automatische Veränderung der Breite eines Controls bei der Veränderung der Breite des Formulars, zu welchem das Control hinzugefügt wurde, der CElement Klasse hinzugefügt. Die CElement::AutoXResizeMode() Methode wird für die Festlegung des Modus verwendet. Bei der Verwendung des Modus, ist die rechte Ecke des Controls an die rechte Ecke des Formulars gebunden. Zudem wurde die CElement::AutoXResizeRightOffset() Methode für das Setzen und Abfragen der Einrückungen (in Pixeln) von der rechten Ecke des Formulars hinzugefügt. 

//+----------------------------------------------------------------
//| Base control class                                               |
//+----------------------------------------------------------------
class CElement#
  {
protected:
   //--- Modus für die automatisch Veränderung der Breite eines Controls
   bool              m_auto_xresize_mode;
   //--- Einrückungen von der rechten Seite des Formulars bei dem automatischen Modus für die Veränderung der Breite eines Controls
   int               m_auto_xresize_right_offset;
   //---
public:
   //--- (1) Modus für die automatische Veränderungen Controls, (2) Setzen/Abfragen der Einrückungen von der rechten Seite des Formulars
   bool              AutoXResizeMode(void)                    const { return(m_auto_xresize_mode);         }
   void              AutoXResizeMode(const bool flag)               { m_auto_xresize_mode=flag;            }
   int               AutoXResizeRightOffset(void)             const { return(m_auto_xresize_right_offset); }
   void              AutoXResizeRightOffset(const int offset)       { m_auto_xresize_right_offset=offset;  }
  };

Standardmäßig ist diese Funktion deaktiviert (false) und der Wert für die Einrückungen entspricht 0. Die Initialisierung wird in dem CElement Klassenkonstruktor durchgeführt (Sehen Sie sich dazu das nachfolgende Codebeispiel an): 

//+----------------------------------------------------------------
//| Konstruktor                                                      |
//+----------------------------------------------------------------
CElement::CElement(void) : m_auto_xresize_mode(false),
                           m_auto_xresize_right_offset(0)
  {
  }

Zuvor wurde die CWindow::ChangeWindowWidth() Methode bereits in der CWindow Klasse für die Änderung der Breite des Formulars erzeugt. Jetzt, wenn der Modus aktiviert ist, wird die Breite des Formulars nur dann verändert, falls sich das grafische Interface in einem Indikator-Unterfenster befindet. Mit anderen Worten, wenn sich die Breite des Chartfensters verändert und es einen CHARTEVENT_CHART_CHANGE Event gibt, dann wird die Breite des Formulars verändert. 

//--- Event bei der Veränderung des Charts
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- Wenn der die Taste losgelassen wird / nicht gedrückt ist
      if(m_clamping_area_mouse==NOT_PRESSED)
        {
         //--- Abfrage der Größe des Chart-Fensters
         SetWindowProperties();
         //--- Korrektur der Koordinaten
         UpdateWindowXY(m_x,m_y);
        }
      //--- Verändere die Größe, falls der Modus aktiviert ist
      if(CElement::AutoXResizeMode())
         ChangeWindowWidth(m_chart.WidthInPixels()-2);
      //---
      return;
     }

Die folgende neue ID wurde der Bibliotheks-Event-ID-Liste hinzugefügt: ON_WINDOW_CHANGE_SIZE. Diese ID wird dazu verwendet, um das Event für die Veränderung der Größe des Formulars zu generieren 

//+----------------------------------------------------------------
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
...
//--- Event IDs
#define ON_WINDOW_CHANGE_SIZE     (3)  // Change the window size
...

Die Erzeugung einer solchen Nachricht wurde der CWindow::ChangeWindowWidth() Methode hinzugefügt. Die Kurzfassung des Verfahrens ist unten dargestellt: 

//+----------------------------------------------------------------
//| Ändere die Breite des Fensters                                          |
//+----------------------------------------------------------------
void CWindow::ChangeWindowWidth(const int width)
  {
//--- Abbrechen, falls sich die Breite nicht verändert hat
//--- Aktualisiere die Breite der Kopfzeile und des Hintergrundes
//--- Aktualisiere die Koordinaten und die Einrückungen für alle Buttons:
//    Close button
//--- Maximieren button
//--- Minimieren button
//--- Der Tooltip Button (falls aktiviert)

//--- Nachricht über die Veränderung der Größe des Fensters
   ::EventChartCustom(m_chart_id,ON_WINDOW_CHANGE_SIZE,(long)CElement::Id(),0,””);
  }

Diese Nachricht wird in der Bibliotheks-Engine (in der CWndEvents Klasse) verarbeitet. Es wurde die virtuelle ChangeWidthByRightWindowSide() Methode der CElement Basis Control Klasse hinzugefügt. Zudem wurden einige Implementationen von Methoden in vielen Ableitungen (wo die Breite des Controls verändert wird) geändert.  

//+----------------------------------------------------------------
//| Basis Control-Klasse                                               |
//+----------------------------------------------------------------
class CElement#
  {
public:
   //--- Verändere die Breite über die rechte Kante des Fensters
   virtual void      ChangeWidthByRightWindowSide(void) {}
  };

Nachdem das ON_WINDOW_CHANGE_SIZE Event empfangen worden ist, Kann die Breite der controls, die den entsprechenden Modus aktiviert haben in der CWndEvents Klasse geändert werden. Die CWndEvents::OnWindowChangeSize() Methode wurde hierfür implementiert. 

//+----------------------------------------------------------------
//| Klasse für das Verarbeiten von Events                                             |
//+----------------------------------------------------------------
class CWndEvents : public CWndContainer
  {
private:
   //--- Verarbeitet das Event der Veränderung der Fenstergröße
   bool              OnWindowChangeSize(void);
  };
//+----------------------------------------------------------------
//| ON_WINDOW_CHANGE_SIZE event                                      |
//+----------------------------------------------------------------
bool CWndEvents::OnWindowChangeSize(void)
  {
//--- Im Falle eines "Change control size" Signals
   if(m_id!=CHARTEVENT_CUSTOM+ON_WINDOW_CHANGE_SIZE)
      return(false);
//--- Index des aktiven Fensters
   int awi=m_active_window_index;
//--- Falls die IDs übereinstimmen
   if(m_lparam!=m_windows[awi].Id())
      return(true);
//--- Verändere die Breite aller Controls, mit Ausnahme des Formulars
   int elements_total=CWndContainer::ElementsTotal(awi);
   for(int e=0; e<elements_total; e++)
     {
      if(m_wnd[awi].m_elements[e].ClassName()=="CWindow")
         continue;
      //---
      if(m_wnd[awi].m_elements[e].AutoXResizeMode())
         m_wnd[awi].m_elements[e].ChangeWidthByRightWindowSide();
     }
//---
   return(true);
  }

Die Methode wird in der Hauptmethode der CWndEvents::ChartEventCustom() Bibliotheks-Events aufgerufen: 

//+----------------------------------------------------------------
//| CHARTEVENT_CUSTOM event                                          |
//+----------------------------------------------------------------
void CWndEvents::ChartEventCustom(void)
  {
//--- Signal zum minimieren des Formulars
//--- Signal zum Maximieren des Formulars

//--- Signal zur Veränderung der Größe
   if(OnWindowChangeSize())
      return;

//--- Signal für das Verstecken der Kontextmenüs vom Aufruferitem
//--- Signal für das Verstecken aller Kontextmenüs
//--- Signal zum Öffnen des Dialogfensters
//--- Signal zum Schließen des Dialogfensters
//--- Signal zum Zurücksetzen der Control-Farbe auf dem angegebenen Formular
//--- Signal zum Zurücksetzen der Prioritäten der linken Maustaste
//--- Signal zum Wiederherstellen der Prioritäten der linken Maustaste
  }

Aktuell ist die eindeutige ChangeWidthByRightWindowSide() Methode für die Veränderung der Breite eines Controls relativ zu der Breite des Formulars, zu welchem sie hinzugefügt worden sind, in den folgenden Klassen enthalten:

  • CTabs – Einfache Tabs.
  • CIconTabs – Tabs mit Bildern.
  • CStatusBar – Statusbar.
  • CMenuBar – Hauptmenü.
  • CLabelsTable – Text-Label-Tabelle.
  • CTable – Editbox-Tabelle
  • CCanvasTable – Gerenderte Tabelle.
  • CProgressBar – Fortschrittsanzeige.
  • CTreeView – Baumansicht.
  • CFileNavigator – Datai-Navigator.
  • CLineGraph – Linienchart.

Der Programmcode für die Methode der CLabelsTable wird nachfolgend als Beispiel gezeigt. 

//+----------------------------------------------------------------
//| Verändern der Breite über die rechte Ecke                 |
//+----------------------------------------------------------------
void CLabelsTable::ChangeWidthByRightWindowSide(void)
  {
//--- Koordinaten
   int x=0;
//--- Größe
   int x_size=0;
//--- Berechnung und Setzen der neuen Größe des Hintergrundes der Tabelle
   x_size=m_wnd.X2()-m_area.X()-m_auto_xresize_right_offset;
   CElement::XSize(x_size);
   m_area.XSize(x_size);
   m_area.X_Size(x_size);
//--- Berechnen und Setzen der neuen Koordinate für die vertikale Scrollbar
   x=m_area.X2()-m_scrollv.ScrollWidth();
   m_scrollv.XDistance(x);
//--- Berechnen und Verändern der Breite der horizontalen Scrollbar
   x_size=CElement::XSize()-m_scrollh.ScrollWidth()+1;
   m_scrollh.ChangeXSize(x_size);
//--- Aktualisierung der Positionen der Objekte
   Moving(m_wnd.X(),m_wnd.Y());
  }


7. Es wurde die Möglichkeit hinzugefügt, die Tabs nach ihrer Erzeugung programmtechnisch auszuwählen Die SelectTab() Methode wurde hierfür in den CTabs und CIconTabs Klassen implementiert. Das nachfolgende Listing zeigt die Methode der CTabs Klasse als ein Beispiel:

//+----------------------------------------------------------------
//| Klasse für die Erzeugung von Tabs                                          |
//+----------------------------------------------------------------
class CTabs : public CElement
  {
public:
   //--- Hervorheben des angegebenen Tabs
   void              SelectTab(const int index);
  };
//+----------------------------------------------------------------
//| Hervorheben des angegebenen Tabs                                                |
//+----------------------------------------------------------------
void CTabs::SelectTab(const int index)
  {
   for(int i=0; i<m_tabs_total; i++)
     {
      //--- Falls das Tab selektiert ist
      if(index==i)
        {
         //--- Koordinaten
         int x=0;
         int y=0;
         //--- Größe
         int x_size=0;
         int y_size=0;
         //--- Abspeichern des hervorgehobenen Tab-Index
         SelectedTab(index);
         //--- Setzen der Farben
         m_tabs[i].Color(m_tab_text_color_selected);
         m_tabs[i].BackColor(m_tab_color_selected);
         //--- Berechnung relativ zu der Positionierung des Tab
         CalculatingPatch(x,y,x_size,y_size);
         //--- Aktualisierung des Wertes
         m_patch.X_Size(x_size);
         m_patch.Y_Size(y_size);
         m_patch.XGap(x-m_wnd.X());
         m_patch.YGap(y-m_wnd.Y());
         //--- Aktualisierung der Position der Objekte
         Moving(m_wnd.X(),m_wnd.Y());
        }
      else
        {
         //--- Die Farben für nicht-aktive Tabs setzen
         m_tabs[i].Color(m_tab_text_color);
         m_tabs[i].BackColor(m_tab_color);
        }
     }
//--- Zeige nur die Controls des hervorgehobenen Tabs
   ShowTabElements();
  }

 

8. Es wurde die Möglichkeit hinzugefügt, die Auswahl einer Zeile in einer Entry-Box Tabelle wieder aufzuheben (CTable), indem man noch einmal auf sie Klickt.

9. Der String vom Format "column_row_text" wird in dem generierten Event als String Parameter (sparam) bei einem Klick auf eine Zelle der Tabelle (CTable), bei der der Edit-Modus deaktiviert ist, gesendet.

10. Es wurden Fehler bei der Enumeration und den Methoden für die Definition des Bereichs, in welchen mit der Maus geklickt wurde, behoben. Jetzt wird in allen Controls die ENUM_MOUSE_STATE Enumeration für das Nachverfolgen des Bereiches, in welchem mit der linken Maustaste geklickt wurde, verwendet.

11. Es wurden einige Dateinamen von Bildern, die innerhalb der Ressourcen in der Bibliothek verwendet wurden, geändert, da es Beschränkungen bei der Länge der Dateinamen bei Anwendungen vom Typ-"Indikator" gab.

12. Es wurden noch ein paar kleinere visuelle Verbesserungen und Fehlerbehebungen durchgeführt. Einige Fehler konnte nur in demMetaTrader 4 Terminal reproduziert werden. 


Anwendung für den Test der Updates

Lassen Sie uns eine Anwendung entwickeln, um alle oben angegebenen Updates testen zu können. Wir erzeugen zwei Versionen dieser Anwendung — "Expert" und "Indicator". Die Indikator-Version wird in einem Unterfenster getestet, damit die automatische Anpassung der Fensterbreite getestet werden kann, sowie die automatische Anpassung der Elemente, die diesen Fenster hinzugefügt worden sind. 

Alle verfügbaren Typen von Controls sollten hier implementiert werden, damit wir einen vollständigen Test durchführen können. Die Controls sollten sich auf unterschiedlichen Tabs befinden (CTabs) um das Interface so platzsparend wie möglich gestalten zu können. Da die Liste der Controls bereits sehr groß ist, macht es Sinn, die Implementation der Methoden für die Erzeugung dieser Controls in einer separaten Datei unterzubringen. Lassen Sie uns diese Datei MainWindow.mqh nennen. Sie wird in den gleichen Ordner abgelegt, in welchem sich auch die anderen Projektdateien befinden. Sie sollte direkt nach dem Körper der benutzerdefinierten Klasse verbunden werden, so wie es das nachfolgende Listing zeigt:

//+----------------------------------------------------------------
//|                                                      Program.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#include <EasyAndFastGUI\Controls\WndEvents.mqh>
//+----------------------------------------------------------------
//| Klasse für die Erzeugung der Anwendung                               |
//+----------------------------------------------------------------
class CProgram : public CWndEvents
  {

//...

  };
//+----------------------------------------------------------------
//| Erzeugung der Controls                                                  |
//+----------------------------------------------------------------
#include "MainWindow.mqh"

Program.mqh should be connected to MainWindow.mqh

//+----------------------------------------------------------------
//|                                                   MainWindow.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#include "Program.mqh"

Es macht Sinn, in der Program.mqh Datei, nur die Hauptprogramm-Datei für die Erzeugung des grafischen Interface bestehen zu lassen, in welcher alle Methoden für die Erzeugung der Controls aufgerufen werden. 

Unsere Testanwendung für das grafische Interface wird 8 Tabs beinhalten. Der nachfolgende Screenshot zeigt die Positionierung der Controls Das erste Tab beinhaltet alle Typen von Buttons (auch die Button Gruppen) und die Liste mit der vertikalen Scrollbar. "Simple Button 3" besitzt zwei Modi. Falls aktiviert, dann wird die Fortschrittsanzeige, die eine Ausführung eines Prozesses simuliert, sichtbar.  

 Abbildung 3. Die Gruppe von Controls für das Erste Tab des grafischen Interfaces

Abbildung 3. Die Gruppe von Controls für das Erste Tab des grafischen Interfaces


Wenn der "Simple Button 3" Aktiviert ist, dann wird die Fortschrittsanzeige in dem Bereich der Statusbar dargestellt. (Sehen Sie dazu den nachfolgenden Screenshot):

 Abbildung 4. Fortschrittsanzeige

Abbildung 4. Fortschrittsanzeige


Das zweite, dritte und vierte Tab beinhaltet Tabellen vom unterschiedlichen Typ

 Abbildung 5. Gruppe von Controls für das zweite Tab des grafischen Interfaces

Abbildung 5. Gruppe von Controls für das zweite Tab des grafischen Interfaces

 

 Abbildung 6. Die Gruppe von Controls für das Dritte Tab des grafischen Interfaces

Abbildung 6. Die Gruppe von Controls für das Dritte Tab des grafischen Interfaces

 

Abbildung 7. Die Gruppe von Controls für das Vierte Tab des grafischen Interfaces 

Abbildung 7. Die Gruppe von Controls für das Vierte Tab des grafischen Interfaces


Das fünfte Tab beinhaltet das Linienchart-Control Die Methoden um hiermit zu arbeiten, werden in der CProgram Klasse deklariert und implementiert. Der CProgram::OnTimerEvent() Timer generiert alle 300 Millisekunden zufällige Serien:

 Fig. 8. Die Gruppe von Controls für das Fünfte Tab des grafischen Interfaces

Fig. 8. Die Gruppe von Controls für das Fünfte Tab des grafischen Interfaces


Das sechste und siebente Tab beinhaltet die Baumansicht und den Datei Navigator, sowie verschiedene Typen der Combobox, Eingabefelder und Checkboxen:

 Abbildung 9 Die Gruppe von Controls für das sechste Tab des grafischen Interfaces

Abbildung 9 Die Gruppe von Controls für das sechste Tab des grafischen Interfaces

 

Abbildung 10. Die Gruppe von Controls für das siebte Tab des grafischen Interfaces 

Abbildung 10. Die Gruppe von Controls für das siebte Tab des grafischen Interfaces


Das siebte Tab beinhaltet die folgenden Controls Kalender, Dropdown-Kalender, Schieberegler, doppelter Schieberegler, Trennlinie und Farbpalette-Button:

 Abbildung 11. Die Gruppe von Controls für das achte Tab des grafischen Interfaces

Abbildung 11. Die Gruppe von Controls für das achte Tab des grafischen Interfaces


Wenn Sie die Farbpalette in dem Hauptfenster erzeugen wollen, dann setzen Sie den Index für das Formular und der Controls zurück damit sie hier hinzugefügt werden. Hier wird nur ein Control (Die Farbpalette) dem Formular hinzugefügt. Der nachfolgende Screenshot zeigt das endgültige Ergebnis:

 Fig. 12. Die Farbpalette in dem Haupt-Chartfenster

Fig. 12. Die Farbpalette in dem Haupt-Chartfenster


Wie bereits erwähnt, wurde auch eine andere Anwendung (Expert) mit den gleichen grafischen Interface-Elementen für einen Test erzeugt:

 Fig. 13. Test der Expert Advisor Anwendung

Fig. 13. Test der Expert Advisor Anwendung


Beide Typen von Anwendungen (Expert und Indikator) wurden für die beiden Plattformen – MetaTrader 4 und MetaTrader 5 implementiert. Alle dafür notwendigen Dateien sind nachfolgend angefügt.

 

 


Schlussfolgerung

Die Bibliothek für das Erzeugen von grafischen Interfaces sieht zu dem aktuellen Stand der Entwicklung wie folgt aus: (Schematisch).

 Abbildung 14. Die Struktur der Bibliothek zum aktuellen Stand der Entwicklung

Abbildung 14. Die Struktur der Bibliothek zum aktuellen Stand der Entwicklung


Es wurden viele Fehlerbehebungen und Aktualisierungen auf Wunsch von den Anwendern implementiert. Wenn Ihnen etwas fehlt oder wenn Sie einen Fehler im Zusammenhang mit der Bibliothek erkannt haben oder wenn Sie eine Anwendung entwickeln, dann hinterlassen Sie einen Kommentar zu diesem Artikel oder senden Sie mir eine persönliche Nachricht. Ich werde Ihnen gerne dabei behilflich sein. Ich arbeite bereits an der nächsten Version dieser Bibliothek (Build 3) Sie wird einige zusätzliche Eigenschaften besitzen, die diese Bibliothek auf einen nächsten Level heben werden. 

Zu den hier vorgestellten Testanwendungen, beinhalten die unten angefügten Archive auch die aktualisierten Versionen von allen vorangegangenen Artikeln dieser Serie.

Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/2634

Beigefügte Dateien |
Grafische Interfaces IX: Die Fortschrittsanzeige und das Linienchart-Control (Kapitel 2) Grafische Interfaces IX: Die Fortschrittsanzeige und das Linienchart-Control (Kapitel 2)

Das zweite Kapitel des neuen Teils dieser Serie widmet sich der Fortschrittsanzeige und dem Linienchart-Control Wie immer, gibt es auch hier detaillierte Beispiele, um deutlich zu machen, wie die Controls in den benutzerdefinierten MQL Anwendungen verwendet werden können.

Grafische Interfaces IX: Das Farbauswahl Control (Kapitel 1) Grafische Interfaces IX: Das Farbauswahl Control (Kapitel 1)

Mit diesem Artikel starten wir das Kapitel 9 der Serie der Artikel über die entwicklung von grafischen Interfaces in den Metatrader Trading-Terminals. Diese Serie besteht aus zwei Kapiteln, in welcher neue Elemente und Interfaces vorgestellt werden, wie zum Beispiel das Farbauswahl-Control, farbige Buttons, die Fortschrittsanzeige und Linien Charts.

Rezepte MQL5 - Handelssignale der gleitenden Kanäle Rezepte MQL5 - Handelssignale der gleitenden Kanäle

Der Artikel beschreibt den Prozess der Entwicklung und Implementierung einer Klasse, die Signale auf der Basis gleitender Kanäle entwickelt. Auf der Basis dieser Signale, werden wir eine Handelsstrategie erstellen. Es werden die Klassen der Standardbibliothek zur Erstellung der abgeleiteten Unterklassen verwendet.

Cross-Plattform Expert Advisor: Orders Cross-Plattform Expert Advisor: Orders

MetaTrader 4 und MetaTrader 5 verwenden unterschiedliche Konventionen, um den Handel durchzuführen. Dieser Artikel diskutiert die Möglichkeit, mit einem Klassenobjekt die Aufgaben des Handels mit den Server durchzuführen, unabhängig davon, auf welcher Handelsplattform oder in welchem Modus ein Cross-Plattform Expert Advisor arbeitet.