MetaTrader 5 herunterladen

Grafische Interfaces II: Das Hauptmenü Element (Kapitel 4)

1 Juli 2016, 08:19
Anatoli Kazharski
0
229

Inhalt

 


Einleitung

Der erste Artikel Grafische Interfaces I: Vorbereiten der Bibliotheks-Struktur(Kapitel 1) Betrachtet im Detail Buch für diese Bibliothek gedacht ist. Eine vollständige Liste der Links zu den Artikeln finden Sie am Ende von jedem Kapitel. 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.    

Dieses ist das letzte Kapitel des zweiten Teils der Serie über die grafischen Interfaces. Hier betrachten wir die Erzeugung des Hauptmenüs. Hier demonstrieren wir die Entwicklung dieses Controls und das Einrichten der Eventhandler innerhalb der Bibliotheks-Klasse, damit später die Anwendung korrekt auf die Aktionen des Users reagiert. Wir besprechen hier zudem, wie man Kontextmenüs dem Hauptmenü hinzufügt. Zudem werden wir über das Blockieren von in aktiven Elementen sprechen.

 


Entwicklung der Klasse für das Erzeugen des Hauptmenüs

Die Klassen für das Erzeugen aller Elemente eines Hauptmenüs, wurden in den vorherigen drei Kapiteln besprochen. Wir haben die folgenden Klassen:

  • CMenuItem – Menüpunkt (Menu item).
  • CSeparateLine – Trennlinie.
  • CContextMenu – Kontext-Menü.

Erzeugen Sie die MenuBar.mqh Datei in dem Controls Verzeichnis, in welchem sich auch alle Dateien aller anderen Elemente befinden. Beziehen sie in dieser Datei die Datei, welche die Basisklasse, die Formular-Klasse und alle Dateien, die Elemente dieser Klassen beinhalten mit ein:

//+----------------------------------------------------------------
//|                                                      MenuBar.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#include "Element.mqh"
#include "Window.mqh"
#include "MenuItem.mqh"
#include "ContextMenu.mqh"

The basic objects of the main menu are the background and menu items. Context menus will be attached to the items of the main menu via pointers.

Abbildung  1. Grundlegende Bestandteile des Hauptmenüs.

Abbildung 1. Grundlegende Bestandteile des Hauptmenüs.


Im nachfolgenden Programmcode sehen Sie die Ausgangsform der Klasse CMenuBar mit allen notwendigen Klassen Pointern und virtuellen Methoden für jedes Element.

//+----------------------------------------------------------------
//| Klasse für das Erzeugen des Hauptmenüs                     |
//+----------------------------------------------------------------
class CMenuBar : public CElement
  {
private:
   //--- Ein Pointer zu der Form zu welchem das Element hinzugefügt worden ist
   CWindow          *m_wnd;
   //--- Objekte für die Erzeugung eines Menüelements
   CRectLabel        m_area;
   CMenuItem         m_items[];
   //--- Array of context menu pointers
   CContextMenu     *m_contextmenus[];
   //---
public:
                     CMenuBar(void);
                    ~CMenuBar(void);
   //--- Speichert den Pointer
   void              WindowPointer(CWindow &object) { m_wnd=::GetPointer(object); }

   //--- Chart Eventhandler
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Bewegen des Elementes
   virtual void      Moving(const int x,const int y);
   //--- (1) Anzeigen, (2) verstecken, (3) zurücksetzen, (4) löschen
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- (1) Setzen, (2) Zurücksetzen der Prioritäten der linken Maustaste
   virtual void      SetZorders(void);
   virtual void      ResetZorders(void);
   //---
  };

Ähnlich wie bei jedem anderen Interface-Element, muss es eine Möglichkeit geben, das Erscheinungsbild des Hauptmenüs festlegen zu können. Es werden dazu Variablen und Methoden erzeugt, die uns folgendes erlauben:

  • Festlegen der Hintergrundfarbe des Hauptmenüs
  • Grundlegende Eigenschaften der Menüpunkte

Zudem benötigen wir noch Methoden für das setzen und Abfragen des Status des Hauptmenüs. Alles Felder werden in dem Konstruktor mit Standardwerten initialisiert. Die Standardhöhe des Hauptmenüs wird bei 22 pixels liegen. Die Höhe eines Menüpunktes wird automatisch in Relation zu der Höhe des Hintergrundes des Hauptmenüs berechnet. Dieser Wert kann jedoch vor dem Hinzufügen des Elementes zu dem Chart mit der Methode CElement::YSize() der Basisklasse geändert werden. Die Breite des Hintergrundes des Hauptmenüs ist gleich der Breite des Formulars, zu welchem dieses Menü hinzugefügt wird. Dieser Parameter wird daher automatisch berechnet, sobald das Element dem Chart hinzugefügt wird.

class CMenuBar : public CElement
  {
private:
   //--- Die Eigenschaften des Hintergrundes
   int               m_area_zorder;
   color             m_area_color;
   color             m_area_color_hover;
   color             m_area_border_color;
   //--- Die grundlegenden Eigenschaften der Menüpunkte
   int               m_item_y_size;
   color             m_item_color;
   color             m_item_color_hover;
   color             m_item_border_color;
   int               m_label_x_gap;
   int               m_label_y_gap;
   color             m_label_color;
   color             m_label_color_hover;
   //--- Status des Menüpunktes
   bool              m_menubar_state;
   //---
public:
   //--- Farbe des (1) Hintergrundes und (2) Des Rahmens des Hintergrundes des Hauptmenüs
   void              MenuBackColor(const color clr)       { m_area_color=clr;                    }
   void              MenuBorderColor(const color clr)     { m_area_border_color=clr;             }
   //--- (1) Hintergrundfarbe, (2) Hintergrundfarbe, wenn sich der Mauszeiger darüber befindet und (3) Rahmenfarbe der Hauptmenü-Elemente
   void              ItemBackColor(const color clr)       { m_item_color=clr;                    }
   void              ItemBackColorHover(const color clr)  { m_item_color_hover=clr;              }
   void              ItemBorderColor(const color clr)     { m_item_border_color=clr;             }
   //--- Ränder der Text-Labels von dem Eckpunkt eines Menüpunkt-Hintergrundes
   void              LabelXGap(const int x_gap)           { m_label_x_gap=x_gap;                 }
   void              LabelYGap(const int y_gap)           { m_label_y_gap=y_gap;                 }
   //--- (1) Standard und (2) Fokussierte Textfarbe
   void              LabelColor(const color clr)          { m_label_color=clr;                   }
   void              LabelColorHover(const color clr)     { m_label_color_hover=clr;             }
   //--- Status des Menüpunktes
   void              State(const bool state);
   bool              State(void)                    const { return(m_menubar_state);             }
   //---
  };
//+----------------------------------------------------------------
//| Konstruktor                                                      |
//+----------------------------------------------------------------
CMenuBar::CMenuBar(void) : m_menubar_state(false),
                           m_area_zorder(0),
                           m_area_color(C'240,240,240'),
                           m_area_border_color(clrSilver),
                           m_item_color(C'240,240,240'),
                           m_item_color_hover(C'51,153,255'),
                           m_item_border_color(C'240,240,240'),
                           m_label_x_gap(15),
                           m_label_y_gap(3),
                           m_label_color(clrBlack),
                           m_label_color_hover(clrWhite)
  {
//--- Abspeichern des namens der Elementklasse in der Basisklasse
   CElement::ClassName(CLASS_NAME);
//--- Standardhöhe des Hauptmenüs
   m_y_size=22;
  }
//+----------------------------------------------------------------
//| Festlegen des Status des Hauptmenüs                         |
//+----------------------------------------------------------------
void CMenuBar::State(const bool state)
  {
   if(state)
      m_menubar_state=true;
   else
     {
      m_menubar_state=false;
      //--- Durchlaufen aller Elemente des Hauptmenüs um
      //    den Status eines inaktiven Kontextmenüs zu setzen
      int items_total=ItemsTotal();
      for(int i=0; i<items_total; i++)
         m_items[i].ContextMenuState(false);
      //--- Die Form entsperren
      m_wnd.IsLocked(false);
     }
  }

Für das Festlegen der besonderen Eigenschaften jedes Menüpunktes wird ein Array benötigt. Die besonderen Eigenschaften sind:

  • Die Breite des Menüpunktes;
  • Der dargestellte Text.

Diese Eigenschaften werden vor dem Hinzufügen des Hauptmenüs zum Chart festgelegt. Dafür wird die CMenuBar::AddItem() Methode verwendet, welche ähnlich der zuvor besprochenen Methode in der CContextMenu Klasse ist. Der einzige Unterschied besteht in den zu übergebenden Parametern. 

Lassen Sie uns die CMenuBar::AddContextMenuPointer() Methode für das Hinzufügen von Kontextmenüs zu jedem Menüpunkt des Hauptmenüs erzeugen. Dieser Methode muss der Index des Hauptmenüs und das Objekt des Kontextmenüs übergeben werden. Der Pointer zu dem Objekt des Kontextmenüs wird in dem m_contextmenus[] Array abgespeichert.

class CMenuBar : public CElement
  {
private:
   //--- Arrays mit den besonderen Eigenschaften der Menüpunkte:
   //    (1) Breite, (2) Text
   int               m_width[];
   string            m_label_text[];
   //---
public:
   //--- Fügt ein Menüpunkt mit den spezifizierten Eigenschaften vor der Erzeugung des Hauptmenüs hinzu
   void              AddItem(const int width,const string text);
   //--- Fügt das übergebene Kontextmenü den angegebenen Menüpunkt des Hauptmenüs hinzu
   void              AddContextMenuPointer(const int index,CContextMenu &object);
   //---
  };
//+----------------------------------------------------------------
//| Fügt einen Menüpunkt hinzu                                       |
//+----------------------------------------------------------------
void CMenuBar::AddItem(const int width,const string text)
  {
//--- Die Größe des Arrays um einen erhöhen  
   int array_size=::ArraySize(m_items);
   ::ArrayResize(m_items,array_size+1);
   ::ArrayResize(m_contextmenus,array_size+1);
   ::ArrayResize(m_width,array_size+1);
   ::ArrayResize(m_label_text,array_size+1);
//--- Abspeichern der übergebenen Werte
   m_width[array_size]      =width;
   m_label_text[array_size] =text;
  }
//+----------------------------------------------------------------
//| Fügt den Kontextmenü-Pointer hinzu                                    |
//+----------------------------------------------------------------
void CMenuBar::AddContextMenuPointer(const int index,CContextMenu &object)
  {
//--- Überprüfung auf Überschreitung der Grenzen
   int size=::ArraySize(m_contextmenus);
   if(size<1 || index<0 || index>=size)
      return;
//--- Abspeichern des Pointers
   m_contextmenus[index]=::GetPointer(object);
  }

Wir benötigen zudem Methoden für die Abfrage des Pointers des Hauptmenü-Elementes und den Pointer zu dem Kontextmenüs, welches zu diesem Menüpunkt hinzugefügt wurde. Jede dieser Methoden überprüft die Größe des Arrays und passt entsprechend den Index an, falls die Größe des Arrays überschritten wurde. Das Durchlaufen der Elemente des Hauptmenüs und der Kontextmenüs wird sehr häufig durchgeführt. Aus diesem Grunde benötigen wir die Methoden um die Größe deren Arrays abzufragen.

class CMenuBar : public CElement
  {
public:
   //--- (1) Abfrage des Pointers zu dem angegebenen Menüpunkt, (2) Abfrage des pointers zu dem angegebenen Kontextmenü
   CMenuItem        *ItemPointerByIndex(const int index);
   CContextMenu     *ContextMenuPointerByIndex(const int index);

   //--- Anzahl von (1) Menüpunkten und (2) Kontextmenüs
   int               ItemsTotal(void)               const { return(::ArraySize(m_items));        }
   int               ContextMenusTotal(void)        const { return(::ArraySize(m_contextmenus)); }
   //---
  };
//+----------------------------------------------------------------
//| Gibt über den Index einen Menüpunkt-Pointer zurück           |
//+----------------------------------------------------------------
CMenuItem *CMenuBar::ItemPointerByIndex(const int index)
  {
   int array_size=::ArraySize(m_items);
//--- Falls das Menü kein Element besitzt, dann berichten
   if(array_size<1)
     {
      ::Print(__FUNCTION__," > This method is to be called, "
      "when the main menu contains at least one item!");
     }
//--- Korrekturen, falls die Größe überschritten wird
   int i=(index>=array_size)? array_size-1 : (index<0)? 0 : index;
//--- Rückgabe des Pointers
   return(::GetPointer(m_items[i]));
  }
//+----------------------------------------------------------------
//| Gibt über den Index einen Pointer zum Kontextmenü zurück      |
//+----------------------------------------------------------------
CContextMenu *CMenuBar::ContextMenuPointerByIndex(const int index)
  {
   int array_size=::ArraySize(m_contextmenus);
//--- Falls das Menü kein Element besitzt, dann berichten
   if(array_size<1)
     {
      ::Print(__FUNCTION__," > This method is to be called, "
      "when the main menu contains at least one item!");
     }
//--- Korrekturen, falls die Größe überschritten wird
   int i=(index>=array_size)? array_size-1 : (index<0)? 0 : index;
//--- Rückgabe des Pointers
   return(::GetPointer(m_contextmenus[i]));
  }

Der Prozess für die Erzeugung des Hauptmenüs hat keine fundamentalen Unterschiede zu der Erzeugung des Kontextmenüs in der CContextMenu Klasse. Zurzeit ist die Erzeugung des Hauptmenüs sogar noch ein wenig einfacher, da dieses keinen Pointer zu einem vorherigen Knotenpunkt benötigt. Und es enthält zudem keine Trennlinien. Wir werden hier den Programmcode nicht weiter betrachten, um ein wenig Platz in diesem Artikel zu sparen. Sie können diesen in der MenuBar.mqh Datei nachschlagen.

Zuvor haben wir, um sicherzustellen dass die Elemente des Kontextmenüs zu der Basis aller Elemente in der CWndContainer Klasse hinzugefügt werden, haben wir die spezielle Methode AddContextMenuElements() geschrieben. Diese wird in der CWndContainer::AddToElementsArray() Hauptmethode für das Hinzufügen von Elementen in der Basis aufgerufen. Die gleiche Methode muss nun auch für das Hauptmenü Element geschrieben werden, da sich ansonsten die Menüpunkte nicht zusammen mit dem Formular bewegen und sie auch nicht ihre Farbe ändern, sobald sich der Mauszeiger über ihnen befindet. 

Nachfolgend ist eine kurze Liste von Aktionen, die durchgeführt werden müssen, um die Komponenten von Hauptelementen zu der Basis und den Hauptelement-Pointer zum private Array hinzuzufügen.

  • Beziehen Sie die Datei mit der Elementn-Klasse in der WndContainer.mqh Datei mit ein.
  • Fügen Sie das Elementen-Array der WindowElements Struktur hinzu.
  • Fügen sie die Methode für die Abfrage der Anzahl der Hauptmenüs in dem privaten Array hinzu.
  • Deklarieren und implementieren Sie die private Methode für das Abspeichern von Pointern zu den Elementen, welche Teile von einem anderen Hauptelement sind.
  • Platzieren Sie den Aufruf der neuen Methode in der gemeinsamen Methode , welche dafür gedacht ist, in der Anwendung dafür zu ,sorgen dass die Hauptelement-Pointer der Basis hinzugefügt werden.

Nachfolgend ist eine verkürzte Version des Programmcodes der WndContainer.mqh Datei, welcher nur zeigt, was dieser Datei hinzugefügt werden muss:

//+----------------------------------------------------------------
//|                                                 WndContainer.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#include "MenuBar.mqh"
//+----------------------------------------------------------------
//| Klasse für das Abspeichern aller Interface Objekte                          |
//+----------------------------------------------------------------
class CWndContainer
  {
protected:
   //--- Struktur der Element-Arrays
   struct WindowElements
     {
      //--- Hauptmenü - Array
      CMenuBar         *m_menu_bars[];
     };
   //---
public:
   //--- Anzahl der Hauptmenüs
   int               MenuBarsTotal(const int window_index);
   //---
private:
   //--- Speichert die Pointer der Hauptmenü-Elemente in der Basis
   bool              AddMenuBarElements(const int window_index,CElement &object);
  };
//+----------------------------------------------------------------
//| Gibt die Anzahl der Hauptmenüs über den angegebenen Fenster-Index zurück   |
//+----------------------------------------------------------------
int CWndContainer::MenuBarsTotal(const int window_index)
  {
   if(window_index>=::ArraySize(m_wnd))
     {
      ::Print(PREVENTING_OUT_OF_RANGE);
      return(WRONG_VALUE);
     }
//---
   return(::ArraySize(m_wnd[window_index].m_menu_bars));
  }
//+----------------------------------------------------------------
//| Fügt einen Pointer zu dem Array der Elemente hinzu               |
//+----------------------------------------------------------------
void CWndContainer::AddToElementsArray(const int window_index,CElement &object)
  {
//--- Falls die Basis keine Formulare für Controls enthält
//--- Falls es eine Anfrage für eine nicht existierende Form gibt
//--- Hinzufügen zu dem gemeinsamen Array von Elementen
//--- Hinzufügen von Element-Objekten zu dem gemeinsamen Array von Objekten
//--- Abspeichern der ID von dem letzten Element in allen Forms
//--- Erhöhen des Zählers für die Elemente
//--- Abspeichern der Pointer zu den Kontextmenü Objekten in der Basis
//--- Abspeichern der Pointer zu den Hauptmenü Objekten in der Basis
   if(AddMenuBarElements(window_index,object))
      return;
  }
//+----------------------------------------------------------------
//| Speichert die Pointer zu den Objekten des Hauptmenüs in der Basis         |
//+----------------------------------------------------------------
bool CWndContainer::AddMenuBarElements(const int window_index,CElement &object)
  {
//--- Abbrechen, wenn dieses kein Hauptmenü ist
   if(object.ClassName()!="CMenuBar")
      return(false);
//--- Abfrage des Pointers des Hauptmenüs
   CMenuBar *mb=::GetPointer(object);
//--- Abspeichern der Pointer zu den Objekten in der Basis
   int items_total=mb.ItemsTotal();
   for(int i=0; i<items_total; i++)
     {
      //--- Vergrößern des Elementen Arrays
      int size=::ArraySize(m_wnd[window_index].m_elements);
      ::ArrayResize(m_wnd[window_index].m_elements,size+1);
      //--- Erhalt des menu-item pointers
      CMenuItem *mi=mb.ItemPointerByIndex(i);
      //--- Abspeichern des pointers in dem Array
      m_wnd[window_index].m_elements[size]=mi;
      //--- Hinzufügen aller Pointer von allen Objekten eines Menüelementes zu dem gemeinsamen Array
      AddToObjectsArray(window_index,mi);
     }
//--- Hinzufügen des Pointers zu dem privaten Array
   AddToRefArray(mb,m_wnd[window_index].m_menu_bars);
   return(true);
  }

 

 

Test der Einrichtung des Hauptmenüs

An dieser Stelle können wir nur das Einrichten eines Hauptmenüs testen. Wir werden ein solches Element mit drei Menüpunkten bauen. Wir werden nur die Breite und den darzustellenden Text angeben und die restlichen Eigenschaften bei ihren Standardwerten lassen.

Fügen Sie den Programmcode für die Erzeugung des Hauptmenüs in der CProgram Anwendungsklasse, wie nachfolgend gezeigt, hinzu. Korrigieren Sie die Koordinaten der anderen Elemente die wir dem Formular zuvor hinzugefügt haben. Und zum Schluss platzieren Sie den Aufruf der CProgram::CreateMenuBar() Methode innerhalb Methode für das Erzeugen des grafischen Interfaces.

class CProgram : public CWndEvents
  {
private:
   //--- Hauptmenü
   CMenuBar          m_menubar;
   //---
private:
   //---
#define MENUBAR_GAP_X    (1)
#define MENUBAR_GAP_Y    (20)
   bool              CreateMenuBar(void);
   //---
#define MENU_ITEM1_GAP_X (6)
#define MENU_ITEM1_GAP_Y (45)
   //---
#define SEP_LINE_GAP_X   (6)
#define SEP_LINE_GAP_Y   (75)
   //---
  };
//+----------------------------------------------------------------
//| Erzeugung des Trading-Panels                                     |
//+----------------------------------------------------------------
bool CProgram::CreateTradePanel(void)
  {
//--- Erzeugung einer Form für Controls
//---Erzeugung der Controls:
//    Hauptmenü
   if(!CreateMenuBar())
      return(false);
//--- Menüelement
//--- Trennlinie
//--- Neuzeichnen auf dem Chart
   return(true);
  }
//+----------------------------------------------------------------
//| Erzeugt das Hauptmenü                                            |
//+----------------------------------------------------------------
bool CProgram::CreateMenuBar(void)
  {
//--- 3 Elemente in dem Hauptmenü
#define MENUBAR_TOTAL 3
//--- Abspeichern des Fenster-Pointers
   m_menubar.WindowPointer(m_window);
//--- Koordinaten
   int x=m_window.X()+MENUBAR_GAP_X;
   int y=m_window.Y()+MENUBAR_GAP_Y;
//--- Arrays mit den besonderen Eigenschaften jedes Elementes
   int    width[MENUBAR_TOTAL] ={50,55,53};
   string text[MENUBAR_TOTAL]  ={"File","View","Help"};
//--- Hinzufügen der Menüpunkt zu dem Hauptmenü
   for(int i=0; i<MENUBAR_TOTAL; i++)
      m_menubar.AddItem(width[i],text[i]);
//--- Erzeugen eines Controls
   if(!m_menubar.CreateMenuBar(m_chart_id,m_subwin,x,y))
      return(false);
//--- Fügen Sie das Objekt zu dem gemeinsamen Array von Objektgruppen hinzu
   CWndContainer::AddToElementsArray(0,m_menubar);
   return(true);
  }

Kompilieren Sie die Dateien und laden Sie den EA auf einen Chart. Das Ergebnis sollte so aussehen, wie es in dem nachfolgenden Screenshot gezeigt wird. Das Hauptmenü bewegt sich zusammen mit dem Formular und die Elemente ändern ihre Farbe, sobald sich der Mauszeiger über ihnen befindet.

Abbildung  2. Test des Hauptmenü-Elementes.

Abbildung 2. Test des Hauptmenü-Elementes.

 

 


Blockieren inaktiver Controls

Bevor wir Kontextmenüs erzeugen und diese dem Hauptmenü hinzufügen können, benötigt unsere Bibliothek noch weitere Funktionalitäten, die das Formular und andere Elemente sperren, sobald einer der Menüelemente aktiviert wird. Warum müssen wir dieses tun? Aktivierte Elemente sind diejenigen Elemente, die durch den Aufruf von anderen Elementen sichtbar gemacht werden - und versteckt sind, wenn diese nicht mehr benötigt werden. Zu dieser Gruppe zählen zum Beispiel Dropdownlisten, Kontextmenüs und Kalender. Versuchen Sie einmal ein Kontextmenü oder eine Dropdownliste in dem MetaTrader Terminal zu aktivieren. Sie werden feststellen, dass sobald eines dieser Elemente aktiviert ist, alle anderen Controls in den gesamten Terminal deaktiviert sind. Dieses wird zum Beispiel dadurch sichtbar, dass wenn man den Mauszeiger über sie bewegt, sie ihre Farbe nicht mehr ändern. Der Grund für ein solches Sperren von Elementen ist das ausschließen der Situation, dass ein Element auf einen Mauszeiger reagiert, obwohl es von einem anderen Element verdeckt ist.

Alles was wir nun tun müssen um dieses Verhalten nachzuahmen, ist, dass wir das Formular blockieren müssen, zu welchem das aktivierte Control hinzugefügt worden ist. Jedes andere Element dieses Formulars hat über die Pointer jederzeit Zugriff zu diesem Element und kann daher herausfinden, in welchem Status es sich befindet. Dies ist ein sehr einfaches Prinzip - wenn das Formular gesperrt ist, dann braucht die Methode für das Ändern der Farbe des Elementes nicht aufgerufen werden.

Wir fügen der CWindow Klasse für das Erzeugen des Formulars spezielle Variablen und Methoden für das setzen und Abfragen des Status des Formulars hinzu. Die m_is_locked Variable muss in den Konstruktor mit dem Wert false initialisiert werden. Das bedeutet, dass das Formular standardmäßig nicht gesperrt ist. Wir können jetzt noch die Bedingung definieren, dass die Farbe des Formulars und seine Elemente nur verändert werden können, wenn das Formular nicht gesperrt ist.

class CWindow : public CElement
  {
private:
   //--- Status des gesperrten Fensters
   bool              m_is_locked;
   //---
public:
   //--- Status des gesperrten Fensters
   bool              IsLocked(void)                                    const { return(m_is_locked);                }
   void              IsLocked(const bool flag)                               { m_is_locked=flag;                   }
   //---
  };
//+----------------------------------------------------------------
//| Konstruktor                                                      |
//+----------------------------------------------------------------
CWindow::CWindow(void) : m_is_locked(false)
  {
  }
//+----------------------------------------------------------------
//| Timer                                                            |
//+----------------------------------------------------------------
void CWindow::OnEventTimer(void)
  {
//--- Falls das Fenster nicht gesperrt ist
   if(!m_is_locked)
     {
      //--- Die Veränderung der Farbe der Objekte des Formulars
      ChangeObjectsColor();
     }
  }

Zur Zeit haben wir nur ein anklickbares Element, mit welchem wir die Funktionalität testen können: einen Menüpunkt Ein Farbwechsel des Menüpunktes, falls sich der Mauszeiger darüber befindet, hängt von dem Status des Formulars ab, zu welchem dieser Menüpunkt gehört. Dafür muss eine entsprechende Überprüfung in seiner Klasse CMenuItem durchgeführt werden.

//+----------------------------------------------------------------
//| Timer                                                            |
//+----------------------------------------------------------------
void CMenuItem::OnEventTimer(void)
  {
//--- Falls das Fenster verfügbar ist
   if(!m_wnd.IsLocked())
     {
      //--- Für den Status eines deaktivierten Kontextmenüs
      if(!m_context_menu_state)
         //--- Die Veränderung der Farbe der Objekte des Formulars
         ChangeObjectsColor();
     }
  }

Das Formular Muss in dem Moment gesperrt werden, sobald das Kontextmenü sichtbar wird. Das passiert in der CContextMenu::Show() Methode.

//+----------------------------------------------------------------
//| Anzeigen eines Kontextmenüs                                             |
//+----------------------------------------------------------------
void CContextMenu::Show(void)
  {
//--- Verlassen, falls das Element bereits sichtbar ist
//--- Anzeigen der Objekte des Kontextmenüs
//--- Anzeige der Menüpunkte
//--- Den Status eines sichtbaren Elementes zuweisen
//--- Status des Kontextmenüs
//--- Registrieren des Status in dem vorherigen Knoten.
//--- Blockieren der Form
   m_wnd.IsLocked(true);
  }

Es sieht so aus als würde der Aufruf der CWindow::IsLocked() Methode in der CContextMenu::Hide() Methode dafür ausreichend sein. Dieses ist aber leider nicht der Fall, da mehrere Kontextmenüs zur selben Zeit geöffnet sein können. Nicht alle diese Kontextmenüs werden gleichzeitig geschlossen. Erinnern wir uns in welchen Fällen alle Kontextmenüs gleichzeitig geschlossen werden. Hierfür müssen einige Bedingungen erfüllt sein. Zum Beispiel wird in der CContextMenu::CheckHideContextMenus() Methode, nach der Überprüfung aller Bedingungen, ein Signal für das Schließen aller Kontextmenüs gesendet. Der zweite Fall ist in der CContextMenu::ReceiveMessageFromMenuItem() Methode, wenn der ON_CLICK_MENU_ITEM Event behandelt wird. 

Wir werden diesen Methoden das Entsperren des Formulars hinzufügen. Nachfolgend sind die gekürzten Versionen dieser Methoden. Anhand der Kommentare und des hervorgehobenen Programmcodes können Sie sehen was hinzugefügt werden muss.

//+----------------------------------------------------------------
//| Prüfen der Bedingungen für das Schließen aller Kontextmenüs      |
//+----------------------------------------------------------------
void CContextMenu::CheckHideContextMenus(void)
  {
//--- Abbrechen, falls sich der Mauszeiger in dem Bereich des Kontextmenüs oder in dem Bereich des vorherigen Knotenpunktes befindet
//--- Falls sich der Mauszeiger außerhalb des Bereiches dieser Elemente befindet, dann...
//    ... muss überprüft werden, ob es offene Kontextmenüs gibt, die anschließend aktiviert wurden
//--- Dafür laufen wir die Liste der Kontextmenüs durch ...
//    ... für die Identifizierung, ob es ein Menüelement welches ein Kontextmenü besitzt
//--- Die Form entsperren
   m_wnd.IsLocked(false);
//--- Ein Signal für das Verstecken aller Kontextmenüs senden
  }
//+----------------------------------------------------------------
//| Empfangen einer Nachricht von einem Menüelement              |
//+----------------------------------------------------------------
void CContextMenu::ReceiveMessageFromMenuItem(const int id_item,const int index_item,const string message_item)
  {
//--- Falls es einen Hinweis darauf gibt, dass diese Nachricht von diesem Programm gesendet wurde und die Element ID uebereinstimmt
//--- Verstecken des Kontextmenüs
//--- Die Form entsperren
   m_wnd.IsLocked(false);
  }

Nachdem wir alle Dateien kompiliert und diesen EA auf den Chart geladen haben, sehen wir sofort, das nachdem das Kontextmenü geöffnet worden ist, alles etwas anders arbeitet, als wir uns das vorgestellt haben. Alle Menüpunkte, auch diejenigen, die sich in einem aktivierten Zustand befinden, werden daran gehindert die Farben zu ändern. Diese sollte eigentlich nicht passieren. In diesen Fällen sollte ein Kontextmenü seine eigene Methoden für das Wechseln der Farben seiner Elemente haben. Lassen Sie uns eine solche Methode in der CContextMenu Klasse erzeugen und den Aufruf in dem Timer platzieren .

class CContextMenu : public CElement
  {
public:
   //--- Ändert die Farben der Menüpunkte, wenn sich der Mauszeiger über ihnen befindet
   void              ChangeObjectsColor(void);
  };
//+----------------------------------------------------------------
//| Timer                                                            |
//+----------------------------------------------------------------
void CContextMenu::OnEventTimer(void)
  {
//--- Ändert die Farben der Menüpunkte, wenn sich der Mauszeiger über ihnen befindet
   ChangeObjectsColor();
  }
//+----------------------------------------------------------------
//| Ändern der Objektfarbe, wenn sich der Mauszeiger darüber befindet|
//+----------------------------------------------------------------
void CContextMenu::ChangeObjectsColor(void)
  {
//--- Abbrechen, falls das Kontextmenü deaktiviert ist
   if(!m_context_menu_state)
      return;
//--- Durchlaufen aller Menüelemente
   int items_total=ItemsTotal();
   for(int i=0; i<items_total; i++)
     {
      //--- Ändern der Farbe des Menüpunktes
      m_items[i].ChangeObjectsColor();
     }
  }

Nun sollte alles so funktionieren wie wir uns das vorgestellt haben.

Abbildung 3. Test über das Blockieren des Formulars und aller Controls, mit Ausnahme des zurzeit aktivierten Controls.

Abbildung 3. Test über das Blockieren des Formulars und aller Controls, mit Ausnahme des zurzeit aktivierten Controls.

 

 


Methoden für die Kommunikation mit dem Hauptmenü

Wir fahren nun mit der Entwicklung der CMenuBar Klasse für das Hauptmenü fort. Der verbleibende Teil betrifft die Verwaltung dieses Elementes. Lassen Sie uns im Detail betrachten wie dieses Element funktioniert indem wir uns Beispiel von anderen Programmen ansehen. Nachdem das Programm geladen worden ist, ist das Hauptmenü standardmäßig deaktiviert. In diesem Zustand werden die Menüpunkte hervorgehoben, sobald sich der Mauszeiger über ihnen befindet. Bin auf eines dieser Menüpunkt geklickt wird, dann wird das entsprechende Kontextmenü aktiviert und angezeigt. Wenn das Hauptmenü auf diese Weise aktiviert worden ist, dann wird je nach Position des Mauszeigers das entsprechende Kontextmenü, über welchen sich der Mauszeiger gerade befindet, geöffnet.

Bevor wir ein solches Verhalten implementieren, erzeugen wir drei Kontextmenüs und fügen Sie dem Hauptmenü hinzu. Um Platz zu sparen, betrachten wir hier eine verkürzte Version. Die vollständigen Dateien finden Sie am Ende dieses Artikels. 

Der nachfolgende Programmcode zeigt nur die wichtigen Stellen. Bitte achten Sie darauf wie der Pointer zu dem vorherigen Knotenpunkt dem Kontextmenü übergeben wird und wie der Kontext-Menü-Pointer in dem Hauptmenü abgespeichert wird. Die Berechnung der Koordinaten von dem unteren Teil des Elementes muss durchgeführt werden, wenn die Eigenschaften des Kontextmenüs für das Hauptmenü eingestellt werden. In allen anderen Aspekten unterscheidet sich die Erzeugung des Kontextmenüs nicht von den anderen Elementen, die wir zuvor besprochen haben.

//+----------------------------------------------------------------
//| Erzeugt ein Kontextmenü                                         |
//+----------------------------------------------------------------
bool CProgram::CreateMBContextMenu1(void)
  {
//--- Drei Punkte im Kontextmenü
//--- Abspeichern des Fenster-Pointers
   m_mb_contextmenu1.WindowPointer(m_window);
//--- Den Pointer des vorherigen Knotenpunktes speichern
   m_mb_contextmenu1.PrevNodePointer(m_menubar.ItemPointerByIndex(0));
//--- Hinzufügen des Kontextmenüs zu dem spezifizierten Menüpunkt
   m_menubar.AddContextMenuPointer(0,m_mb_contextmenu1);
//--- Array Mit den Namen der Elemente
//--- Label Array Für die verfügbaren Modi
//--- Label Array Für den blockierten Modus
//--- Array mit Elementtypen
//--- Festlegen der Eigenschaften bevor er erzeugt wird
   m_mb_contextmenu1.FixSide(FIX_BOTTOM);
//--- Hinzufügen von Menüpunkten zu dem Kontextmenü
//--- Trennlinie nach dem zweiten Element
//--- Deaktivierung des zweiten Elementes
//--- Erzeugen eines Kontextmenüs
   if(!m_mb_contextmenu1.CreateContextMenu(m_chart_id,m_subwin))
      return(false);
//--- Fügen Sie das Objekt zu dem gemeinsamen Array von Objektgruppen hinzu
   CWndContainer::AddToElementsArray(0,m_mb_contextmenu1);
   return(true);
  }

Lassen Sie uns nun die Eventhandler in der СMenuBar Klasse des Hauptmenüs einrichten. Wir starten mit der Verarbeitung eines Klicks auf einen Menüpunkt. Zuvor benötigen wir, ähnlich wie in den CMenuItem und CContextMenu Klassen, die OnClickMenuItem() Methoden für die Extrahierung des Index und des Bezeichners des Menüpunktes über den Namen des Objektes, auf welchen geklickt wurde. 

Die Methoden für die Identifizierung sind die gleichen wie in der CContextMenu Klasse. Aber die Verarbeitung eines Klicks auf einen Menüpunkt hat seine Besonderheiten in der СMenuBar  Klase. Die Überprüfung des Bezeichners wird gefolgt von einer Überprüfung der Korrektheit das Kontextmenü-Pointers über den Index, den wir über den Objektnamen erhalten haben. Wenn es keinen Pointer gibt, dann wird ein Signal für das Schliessen aller offenen Kontextmenüs gesendet. Wenn es einen Pointer gibt, dann wird das Signal zum Schließen aller Kontextmenüs nur gesendet, falls es einen Klick für das Schließen des aktuellen Kontextmenüs gab. 

class CMenuBar : public CElement
  {
private:
   //--- Die Verarbeitung eines Klicks auf einen Menüpunkt
   bool              OnClickMenuItem(const string clicked_object);
   //--- Abfragen (1) des Bezeichners (2) Index aus dem Namen des Menüpunktes
   int               IdFromObjectName(const string object_name);
   int               IndexFromObjectName(const string object_name);
   //---
  };
//+----------------------------------------------------------------
//| Event handler                                                    |
//+----------------------------------------------------------------
void CMenuBar::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeitung eines Klicks mit der linken Maustaste auf das Hauptmenü-Element
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      if(OnClickMenuItem(sparam))
         return;
     }
  }
//+----------------------------------------------------------------
//| Ein Klick auf das Hauptmenü Element                                   |
//+----------------------------------------------------------------
bool CMenuBar::OnClickMenuItem(const string clicked_object)
  {
//--- Abbrechen, falls der Click nicht zu diesem Menüpunkt gehört
   if(::StringFind(clicked_object,CElement::ProgramName()+"_menuitem_",0)<0)
      return(false);
//--- Abfragen des Bezeichners und des Index aus dem Objekt-Namen
   int id    =IdFromObjectName(clicked_object);
   int index =IndexFromObjectName(clicked_object);
//--- Abbrechen, falls der Bezeichner nicht übereinstimmt
   if(id!=CElement::Id())
      return(false);
//--- Falls es einen Kontext-Menü Pointer gibt
   if(CheckPointer(m_contextmenus[index])!=POINTER_INVALID)
     {
      //--- Der Status des Hauptmenüs hängt von der Sichtbarkeit des Kontextmenüs ab
      m_menubar_state=(m_contextmenus[index].ContextMenuState())? false : true;
      //--- Setzen des Status des Formulars
      m_wnd.IsLocked(m_menubar_state);
      //--- Falls das Hauptmenü deaktiviert ist
      if(!m_menubar_state)
         //--- Ein Signal für das Verstecken aller Kontextmenüs senden
         ::EventChartCustom(m_chart_id,ON_HIDE_CONTEXTMENUS,0,0,"");
     }
//--- Falls es keinen Kontext-Menü Pointer gibt
   else
     {
      //--- Ein Signal für das Verstecken aller Kontextmenüs senden
      ::EventChartCustom(m_chart_id,ON_HIDE_CONTEXTMENUS,0,0,"");
     }
//---
   return(true);
  }

Wir erinnern uns, dass die Verarbeitung des ON_HIDE_CONTEXTMENUS Events in der CWndEvents Klasse stattfindet. Wir müssen der CWndEvents::OnHideContextMenus() Methode einen weiteren Zyklus hinzufügen, welcher das Ausschalten aller Hauptmenüs erzwingt, die sich in der Basis befinden.

//+----------------------------------------------------------------
//| ON_HIDE_CONTEXTMENUS event                                       |
//+----------------------------------------------------------------
bool CWndEvents::OnHideContextMenus(void)
  {
//--- Falls es sich um ein Signal für das Verstecken aller Kontextmenüs handelt
   if(m_id!=CHARTEVENT_CUSTOM+ON_HIDE_CONTEXTMENUS)
      return(false);
//--- Verstecken aller Kontextmenüs
   int cm_total=CWndContainer::ContextMenusTotal(0);
   for(int i=0; i<cm_total; i++)
      m_wnd[0].m_context_menus[i].Hide();
//--- Deaktivieren der Hauptmenüs
   int menu_bars_total=CWndContainer::MenuBarsTotal(0);
   for(int i=0; i<menu_bars_total; i++)
      m_wnd[0].m_menu_bars[i].State(false);
//---
   return(true);
  }

Wenn wir jetzt alle Dateien kompilieren und den EA auf den Chart laden, dann werden die Kontextmenüs geöffnet, sobald auf einen Menüpunkt geklickt wird und sie werden wieder geschlossen sobald ein zweites Mal auf den Menüpunkt geklickt wird.

Abbildung 4. Test für den Aufruf von Kontextmenüs über das Hauptmenü.

Abbildung 4. Test für den Aufruf von Kontextmenüs über das Hauptmenü.

 

Anschließend werden wir die Methoden implementieren, die es uns erlauben zwischen den Kontextmenüs hin und her zu schalten, indem wir die Maus über die Menüpunkte bewegen, so wie es auch in allen anderen Windows Anwendungen geschieht. Hierfür benötigen wir eine Methode Für das Hervorheben der Hauptmenü Elemente, Wenn sie aktiviert wurden und eine zusätzliche Methode für das definieren eines aktiven Elementes (das in-focus Element) des aktivierten Hauptmenüs. 

class CMenuBar : public CElement
  {
public:
   //--- Ändert die Farbe, wenn sich der Mauszeiger darüber befindet
   void              ChangeObjectsColor(void);
   //---
private:
   //--- Gibt das aktive Element des Hauptmenü zurück
   int               ActiveItemIndex(void);
   //---
  };
//+----------------------------------------------------------------
//| Ändern der Objektfarbe, wenn sich der Mauszeiger darüber befindet|
//+----------------------------------------------------------------
void CMenuBar::ChangeObjectsColor(void)
  {
   int items_total=ItemsTotal();
   for(int i=0; i<items_total; i++)
      m_items[i].ChangeObjectsColor();
  }
//+----------------------------------------------------------------
//| Gibt den Index des aktivierten Menüelementes zurück                     |
//+----------------------------------------------------------------
int CMenuBar::ActiveItemIndex(void)
  {
   int active_item_index=WRONG_VALUE;
//---
   int items_total=ItemsTotal();
   for(int i=0; i<items_total; i++)
     {
      //--- Falls ich das Element im Fokus befindet
      if(m_items[i].MouseFocus())
        {
         //--- Speichere den Index ab und stoppe die Schleife
         active_item_index=i;
         break;
        }
     }
//---
   return(active_item_index);
  }

Jetzt werden wir noch ein Verfahren schaffen, dass das Schalten zwischen Kontextmenüs erleichtert, sobald sich die Maus über einem aktivierten Hauptmenü bewegt. Lassen Sie uns diese Methode SwitchContextMenuByFocus() nennen. Der Index des aktivierten Elementes des Hauptmenüs muss dieser Methode übergeben werden. Der Index erlaubt es uns zu definieren, welches Kontextmenü sichtbar gemacht werden muss. Alle anderen Kontextmenüs werden versteckt. Zur gleichen Zeit wird eine Überprüfung durchgeführt, ob es andere offene Kontextmenüs gibt, die von dem Hauptmenü-Element aufgerufen wurden. Falls sich herausstellt, dass es solche Elemente gibt, dann wird das benutzerdefinierte ON_HIDE_BACK_CONTEXTMENUS Event generiert. Wir haben dieses Event schon im Detail besprochen.

Nachdem das Kontext-Menü versteckt wurde, Muss die Farbe des Menüpunktes zurückgesetzt werden damit nicht zwei Elemente gleichzeitig hervorgehoben werden.

class CMenuBar : public CElement
  {
private:
   //--- Wechseln zwischen Kontextmenü des Hauptmenüs durch das Bewegen des Mauszeigers
   void              SwitchContextMenuByFocus(const int active_item_index);
   //---
  };
//+----------------------------------------------------------------
//| Wechsel zwischen Kontextmenüs durch das Bewegen des Mauszeigers  |
//+----------------------------------------------------------------
void CMenuBar::SwitchContextMenuByFocus(const int active_item_index)
  {
   int items_total=ItemsTotal();
   for(int i=0; i<items_total; i++)
     {
      //--- Mit dem nächsten Element fortschreiten, falls dieses kein Kontextmenü besitzt
      if(::CheckPointer(m_contextmenus[i])==POINTER_INVALID)
         continue;
      //--- Wenn wir bei dem spezifizierten Menüpunkt angekommen sind, machen wir seinen Kontextmenü sichtbar
      if(i==active_item_index)
         m_contextmenus[i].Show();
      //--- Die restlichen Kontextmenüs verstecken
      else
        {
         CContextMenu *cm=m_contextmenus[i];
         //--- Kontextmenüs, die durch andere Kontextmenüs geöffnet worden sind, verstecken.
         //    Durchlaufen der Elemente des aktuellen Kontextmenüs, um herauszufinden ob es welche gib.
         int cm_items_total=cm.ItemsTotal();
         for(int c=0; c<cm_items_total; c++)
           {
            CMenuItem *mi=cm.ItemPointerByIndex(c);
            //--- Gehe zu dem nächsten Menüpunkt, falls der Pointer zu diesem nicht korrekt ist.
            if(::CheckPointer(mi)==POINTER_INVALID)
               continue;
            //--- Gehe zu dem nächsten Menüpunkt, falls dieser kein Kontextmenü besitzt
            if(mi.TypeMenuItem()!=MI_HAS_CONTEXT_MENU)
               continue;
            //--- Falls es ein Kontext-Menü gibt und es aktiviert ist
            if(mi.ContextMenuState())
              {
               //--- Sende ein Signal für das Schließen aller Kontextmenüs, die durch dieses geöffnet worden sind
               ::EventChartCustom(m_chart_id,ON_HIDE_BACK_CONTEXTMENUS,CElement::Id(),0,"");
               break;
              }
           }
         //--- Verstecke das Kontextmenü des Hauptmenüs
         m_contextmenus[i].Hide();
         //--- Setze die Farbe des Menüpunktes zurück
         m_items[i].ResetColors();
        }
     }
  }

Nun müssen wir nur noch neue Methoden dem CHARTEVENT_MOUSE_MOVE Eventhandler der CMenuBar Klasse hinzufügen um das Event für die Bewegung des Mauszeigers zu überprüfen:

//+----------------------------------------------------------------
//| Event handler                                                    |
//+----------------------------------------------------------------
void CMenuBar::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Abbrechen, falls das Hauptmenü nicht aktiviert wurde
      if(!m_menubar_state)
         return;
      //--- Abfrage des Index von dem aktivierten Element des Hauptmenüs
      int active_item_index=ActiveItemIndex();
      if(active_item_index==WRONG_VALUE)
         return;
      //--- Wechseln der Farbe, falls sich der Fokus geändert hat
      ChangeObjectsColor();
      //--- Wechseln des Kontextmenüs über das aktivierte Element des Hauptmenüs
      SwitchContextMenuByFocus(active_item_index);
      return;
     }
  }

 


Abschließender Test des Hauptmenüs

Jetzt können wir alles testen, was wir in diesem Artikel geleistet haben. Fügen Sie dem Formular verschiedene unabhängige Menüpunkte hinzu. Fügen Sie ein weiteres internes Kontextmenü dem Hauptmenü hinzu und fügen Sie dieses dem zweiten Element des dritten Kontextmenü hinzu, so wie es in dem nachfolgenden Bild gezeigt ist

Kompilieren Sie die Dateien und laden Sie den EA auf einen Chart. Damit Sie das gleiche Ergebnis bekommen, (so wie es in dem Nachfolgenden Screenshot gezeigt ist), können Sie die am Ende dieses Artikels gelisteten Dateien laden und ausführen.

Abbildung 5. Genereller Test des Hauptmenüs.

Abbildung 5. Genereller Test des Hauptmenüs.


Die Dateien, die am Ende dieses Artikels aufgelistet sind, beinhalten zudem einen Indikator für einen Test mit einem ähnlichen grafischen Interface. Zudem gibt es auch Versionen für einen Test mit der MetaTrader 4 Trading-Platform.

 

 


Schlussfolgerung

Dieses ist der letzte Artikel des zweiten Teils dieser Serie. Dieser ist sehr groß, aber wir haben damit fast alle wichtigen Bestandteile für die Bibliothek, die für die Entwicklung von grafischen Interfaces gedacht ist, besprochen. Die aktuelle Struktur der Bibliothek, die wir hier entwickelt haben, wird in dem Nachfolgenden Diagramm dargestellt. Die detaillierte Beschreibung finden Sie in den letzten Kapitel des ersten Teils.

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

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


Wenn sie es bis hierhin geschafft haben, dann ist die gute Nachricht die, dass der schwierigste Part dieses Jobs nun erledigt ist. Der erste und zweite Teil dieser Serie hat sich mit den schwierigsten Elementen, bezüglich der Entwicklung des grafischen Interfaces, befasst. Die nachfolgenden Artikel werden sich hauptsächlich mit der Erzeugung von Controls (Steuerelementen) beschäftigen. Dieses Material wird um einiges einfacher sein und es wird auch nicht so viele verschiedene Klassen geben.

Die unten aufgelisteten Archive enthalten die Dateien der Bibliothek zu dem aktuellen Stand der Entwicklung, sowie Bilder und Dateien der besprochenen Programme (Der EA, die Indicatoren und das Skript). Sie können für Tests in dem MetaTrader 4 und MetaTrader 5 Terminal heruntergeladen werden. Wenn Sie fragen zur Verwendung dieses Materials haben, dann können Sie zunächst auf die detaillierte Beschreibung in dem Artikel zu dieser Bibliothek zurückgreifen oder Sie stellen Ihre Frage(n) in den Kommentaren zu diesem Artikel. 

Liste der Artikeln (Kapitel) des zweiten Teils:


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

Beigefügte Dateien |
Grafische Interfaces II: Einrichtung des Eventhandlers für die Bibliothek (Kapitel 3) Grafische Interfaces II: Einrichtung des Eventhandlers für die Bibliothek (Kapitel 3)

Der vorherige Artikel beinhaltet die Implementation der Klassen für das Erzeugen der Bestandteile des Hauptmenüs. Nun ist es an der Zeit, dass wir uns die Eventhandler in den Basisklassen und in den Klassen für die Controls näher betrachten. Wir werden unsere Aufmerksamkeit auch auf das Verwalten des Status des Charts, in Abhängigkeit der Position des Mauszeigers, richten.

Grafische Interfaces II: Die Trennlinien und Context-Menüelemente (Kapitel 2) Grafische Interfaces II: Die Trennlinien und Context-Menüelemente (Kapitel 2)

In diesem Artikel erzeugen wir das Trendlinien-Element Es kann nicht nur als unabhängiges Interface-Element verwendet werden, sondern auch als ein Teil von vielen anderen Elementen. Anschließend haben wir alles, was für die Entwicklung der Kontextmenü Klasse benötigt wird. Diese Klasse werden wir in diesem Artikel im Detail besprechen. Zudem werden wir alle notwendigen Ergänzungen dieser Klasse hinzufügen, die für das Abspeichern von Pointern aller Elemente des grafischen Interfaces dieser Anwendung benötigt werden.

Graphische Interfaces III: Einfache und multifunktionale Buttons (Kapitel 1) Graphische Interfaces III: Einfache und multifunktionale Buttons (Kapitel 1)

Lassen Sie uns das Control "Button" näher ansehen. Wir werden über Klassen für die Erzeugung von einfachen Buttons diskutieren, sowie auch über Buttons mit erweiterter Funktionalität (Icon-Button und Split-Button) und Buttons, die miteinander interagieren (Gruppen von Buttons und Radio-Buttons). Zusätzlich werden wir noch einige Ergänzungen zu schon existierenden Klassen für Controls hinzufügen, um sie in ihren Möglichkeiten zu erweitern.

Graphische Interfaces III: Gruppen von einfachen und multifunktionalen Buttons (Kapitel 2) Graphische Interfaces III: Gruppen von einfachen und multifunktionalen Buttons (Kapitel 2)

In dem ersten Kapitel dieser Serie ging es um einfache und multifunktionelle Buttons. Der zweite Artikel handelt über Gruppen von interagierenden Buttons, mit denen der Programmierer Elemente erzeugen kann, bei der der Anwender ein Element aus der Gruppe auswählen kann.