MetaTrader 5 herunterladen

Grafische Interfaces V: Das Combobox Control (Kapitel 3)

17 August 2016, 16:52
Anatoli Kazharski
0
417

Inhalt


Einleitung

Der erste Artikel  Grafische Interfaces I: Vorbereiten der Bibliotheks-Struktur(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 Entwicklungsstand, herunterzuladen. Die Dateien müssen in den gleichen Verzeichnissen untergebracht werden, so, wie Sie auch in dem Archiv abgelegt sind.   

In den ersten zwei Kapiteln des fünften Teils dieser Serie, haben wir Klassen für die Erzeugung einer Scrollbar und einer ListView entwickelt. Hier haben wir demonstriert, wie wir eine Scrollbar einem Element hinzufügen, falls die Datenmenge nicht in den dafür vorgesehenen sichtbaren Platz passt. In diesem Kapitel werden wir über die Erzeugung einer Klasse für eine ComboBox sprechen. Hierbei handelt es sich ebenfalls um ein Komponenten-Control, welches neben anderen Elementen auch Elemente enthält, die wir in den vorherigen Kapiteln des 5. Teils besprochen haben.


Das Combobox Control

Eine Combobox ist ein Komponenten-Control, dessen Hauptbestandteile(1) ein Button und (2) eine ListView sind. In diesem Falle ist die ListView ein Dropdown-Element und sie wird über den Klick auf den Button aufgerufen. Nachdem aus der ListView ein Element selektiert wurde, wird der Text des selektierten Elementes im Button dargestellt und die ListView wird wieder versteckt. Wenn ein Programm mit vielen Parametern arbeitet, dann kann die Verwendung einer ComboBox diese sehr kompakt innerhalb eines grafischen Interfaces darstellen.

Nachfolgend sind die einfachen Objekte für die Zusammenstellung der Combobox aufgelistet:

  1. Der Hintergrund des Elementes
  2. Label (Beschreibung des Elementes)
  3. Button
  4. Anzeige einer Dropdown ListView


Abbildung 1. Komponenten des Combobox Controls


Im nächsten Teil dieses Artikels werden wir eine Klasse für die Erzeugung dieses Controls schreiben.

Schreiben einer Klasse für die Erzeugung des Combobox Controls

Wir werden hier alle Stufen der Entwicklung der Combobox beschreiben, damit auch in Zukunft dieser Artikel als ein Beispiel für das Erstellen von ähnlichen Klassen verwendet werden kann. Zunächst erzeugen wir die (ComboBox.mqh) .mqh Datei Und beziehen Sie in alle notwendigen Dateien, die Klassen für die Erzeugung einer ComboBox beinhalten, mit ein. In unserem Fall sind das drei Dateien mit den Klassen:

  • CElement — Basisklasse für das Erzeugen von Controls.
  • CWindow — Die Klasse des Formulars, zu welchem das Control hinzugefügt wird.
  • CListView — Die Klasse der ListView, deren Sichtbarkeit durch die Combobox verwaltet wird.
//+----------------------------------------------------------------
//|                                                     ComboBox.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#include "Element.mqh"
#include "Window.mqh"
#include "ListView.mqh"

Anschließend erzeugen wir die CComboBox Klasse und die Standardmethoden für jedes Element der Bibliothek in der ComboBox.mqh Datei:

//+----------------------------------------------------------------
//| Klasse für das Erzeugen einer ComboBox                                    |
//+----------------------------------------------------------------
class CComboBox : public CElement
  {
private:
   //--- Der Pointer zu dem Formular, zu welchem dieses Element hinzugefügt wurde
   CWindow          *m_wnd;
   //---
public:
                     CComboBox(void);
                    ~CComboBox(void);
   //--- Speichert den Pointer
   void              WindowPointer(CWindow &object)                   { m_wnd=::GetPointer(object);                      }
   //---
public:
   //--- Chart Eventhandler
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Timer
   virtual void      OnEventTimer(void);
   //--- 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);
   //--- Zurücksetzen der Farbe
   virtual void      ResetColors(void);
  };
//+----------------------------------------------------------------
//| Konstruktor                                                      |
//+----------------------------------------------------------------
CComboBox::CComboBox(void)
  {
//--- Abspeichern des namens der Elementklasse in der Basisklasse
   CElement::ClassName(CLASS_NAME);
  }
//+----------------------------------------------------------------
//| Destruktor                                                       |
//+----------------------------------------------------------------
CComboBox::~CComboBox(void)
  {
  }

Der Anwender sollte die Möglichkeit haben, sein eigenes Farbschema für das graphische Interface zu wählen. Dafür braucht er Zugriff auf die Eigenschaften der Objekte, die für die Zusammenstellung des Controls notwendig sind. Nachfolgend sind die Eigenschaften aufgelistet, die eingerichtet werden müssen, bevor das Control erzeugt wird:

  • Die Farbe des Control-Hintergrundes
  • Die angezeigte Beschreibung der Combobox (text label)
  • Die Ränder für das Textlabel entlang derX und Y Achse
  • Die Farben für das Textlabel für die unterschiedlichen Zustände
  • Text des Buttons (Der Text des ausgewählten Elementes der ListView)
  • Die Größe des Buttons
  • Die Farbe des Buttons in den unterschiedlichen Zuständen
  • Die Farbe der Rahmen der Buttons in den unterschiedlichen Zuständen
  • Die Farbe des Textes des Buttons in den unterschiedlichen Zuständen
  • Icons für den Pfeil, der ein Hinweis auf eine Dropdown-Liste für den aktiven und blockierten Modus gibt.
  • Abstände für die Pfeil-Icons entlang der X und Y Achse

Der nachfolgende Programmcode beinhaltet alle Variablen und Methoden für die Einrichtung der Eigenschaften. die wir oben aufgelistet haben: 

class CComboBox : public CElement
  {
private:
   //--- Combobox Eigenschaften:
   //    Farbe des generellen Hintergrundes
   color             m_area_color;
   //--- Text und Ränder des Text-Label
   string            m_label_text;
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Die Farben für das Textlabel für die unterschiedlichen Zustände
   color             m_label_color;
   color             m_label_color_off;
   color             m_label_color_hover;
   color             m_label_color_array[];
   //--- (1) Button Text und (2) seine Größe
   string            m_button_text;
   int               m_button_x_size;
   int               m_button_y_size;
   //--- Die Farbe des Buttons in den unterschiedlichen Zuständen
   color             m_button_color;
   color             m_button_color_off;
   color             m_button_color_hover;
   color             m_button_color_pressed;
   color             m_button_color_array[];
   //--- Die Farbe der Rahmen der Buttons in den unterschiedlichen Zuständen
   color             m_button_border_color;
   color             m_button_border_color_off;
   //--- Die Farbe des Textes des Buttons in den unterschiedlichen Zuständen
   color             m_button_text_color;
   color             m_button_text_color_off;
   //--- Label Abstände
   int               m_drop_arrow_x_gap;
   int               m_drop_arrow_y_gap;
   //--- Die Labels eines Buttons mit einem Dropdown Menü in dem aktiven und gesperrten Status
   string            m_drop_arrow_file_on;
   string            m_drop_arrow_file_off;
   //--- Priorität eines Klicks mit der linken Maustaste
   int               m_area_zorder;
   int               m_button_zorder;
   int               m_zorder;
   //---
public:
   //--- (1) Hintergrundfarbe, (2) setzt und (3) Gibt den Wert des Textlabel zurück
   void              AreaColor(const color clr)                       { m_area_color=clr;                                }
   void              LabelText(const string label_text)               { m_label_text=label_text;                         }
   string            LabelText(void)                            const { return(m_label_text);                            }
   //--- Abstände 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;                             }
   //--- (1) Gibt den Text des Buttons zurück, (2) legt die Größe des Buttons fest
   string            ButtonText(void)                           const { return(m_button_text);                           }
   void              ButtonXSize(const int x_size)                    { m_button_x_size=x_size;                          }
   void              ButtonYSize(const int y_size)                    { m_button_y_size=y_size;                          }
   //--- (1) Hintergrundfarbe, (2) Die Farbe des Text-Labels
   void              LabelColor(const color clr)                      { m_label_color=clr;                               }
   void              LabelColorOff(const color clr)                   { m_label_color_off=clr;                           }
   void              LabelColorHover(const color clr)                 { m_label_color_hover=clr;                         }
   //--- Farbe der Buttons
   void              ButtonBackColor(const color clr)                 { m_button_color=clr;                              }
   void              ButtonBackColorOff(const color clr)              { m_button_color_off=clr;                          }
   void              ButtonBackColorHover(const color clr)            { m_button_color_hover=clr;                        }
   void              ButtonBackColorPressed(const color clr)          { m_button_color_pressed=clr;                      }
   //--- Farbe des Rahmens des Buttons
   void              ButtonBorderColor(const color clr)               { m_button_border_color=clr;                       }
   void              ButtonBorderColorOff(const color clr)            { m_button_border_color_off=clr;                   }
   //--- Farbe des Textes des Buttons
   void              ButtonTextColor(const color clr)                 { m_button_text_color=clr;                         }
   void              ButtonTextColorOff(const color clr)              { m_button_text_color_off=clr;                     }
   //--- Festlegen der Icons für einen Button mit einem Dropdown Menü in dem aktiven und gesperrten Status
   void              DropArrowFileOn(const string file_path)          { m_drop_arrow_file_on=file_path;                  }
   void              DropArrowFileOff(const string file_path)         { m_drop_arrow_file_off=file_path;                 }
   //--- Label Abstände
   void              DropArrowXGap(const int x_gap)                   { m_drop_arrow_x_gap=x_gap;                        }
   void              DropArrowYGap(const int y_gap)                   { m_drop_arrow_y_gap=y_gap;                        }
  };

Die Initialisierung mit Standardwerten der oben aufgelisteten Eigenschaften findet in dem Konstruktor der Klasse statt: 

//+----------------------------------------------------------------
//| Konstruktor                                                      |
//+----------------------------------------------------------------
CComboBox::CComboBox(void) : m_area_color(C'15,15,15'),
                             m_label_text("combobox: "),
                             m_label_x_gap(0),
                             m_label_y_gap(2),
                             m_label_color(clrWhite),
                             m_label_color_off(clrGray),
                             m_label_color_hover(C'85,170,255'),
                             m_button_text(""),
                             m_button_y_size(18),
                             m_button_text_color(clrBlack),
                             m_button_text_color_off(clrDarkGray),
                             m_button_color(clrGainsboro),
                             m_button_color_off(clrLightGray),
                             m_button_color_hover(C'193,218,255'),
                             m_button_color_pressed(C'153,178,215'),
                             m_button_border_color(clrWhite),
                             m_button_border_color_off(clrWhite),
                             m_drop_arrow_x_gap(16),
                             m_drop_arrow_y_gap(1),
                             m_drop_arrow_file_on(""),
                             m_drop_arrow_file_off("")
  {
//--- Setzen der Priorität eines Klicks mit der linken Maustaste
   m_zorder        =0;
   m_area_zorder   =1;
   m_button_zorder =2;
  }

Eine ComboBox wird durch 5 private Methoden, die in der öffentlichen Hauptmethode CComboBox::CreateComboBox() aufgerufen werden, erzeugt. Um Zugriff auf die Einstellungen der ListView- und der Scrollbar-Eigenschaften zu bekommen, erzeugen wir die Methode für die Anfrage der Pointer zu diesen Elementen: 

class CComboBox : public CElement
  {
private:
   //--- Objekte für die Erzeugung einer ComboBox
   CRectLabel        m_area;
   CLabel            m_label;
   CEdit             m_button;
   CBmpLabel         m_drop_arrow;
   CListView         m_listview;
   //---
public:
   //--- Methoden für die Erzeugung einer ComboBox
   bool              CreateComboBox(const long chart_id,const int subwin,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateLabel(void);
   bool              CreateButton(void);
   bool              CreateDropArrow(void);
   bool              CreateList(void);
   //---
public:
   //--- Gibt die Pointer zu (1) der ListView und (2) der Scrollbar zurück
   CListView        *GetListViewPointer(void)                         { return(::GetPointer(m_listview));                }
   CScrollV         *GetScrollVPointer(void)                          { return(m_listview.GetScrollVPointer());          }
  };

Von den oben genannten Methoden werden wir nur die CComboBox::CreateList() Methode für die Erzeugung einer ListView im Detail besprechen. Die anderen Methoden beinhalten nichts, was wir nicht schon in den vorherigen Artikeln dieser Serie besprochen haben. Bevor wir aber fortfahren, müssen wir noch einige Änderungen an der CListView Klasse der ListView vornehmen. 

Eine Dropdown ListView ist immer eine Komponente eines anderen Elementes. Das bedeutet, dass sein Eventhandler den Fokus des Elementes, zu welchem es hinzugefügt worden ist, nachverfolgen muss. In unserem Fall ist es die Combobox. Fügen Sie eine Variable und eine Methode der CListView Klasse für das Abspeichern des Pointers zu der Combobox, zu welchem die Liste hinzugefügt worden ist, hinzu. 

class CListView : public CElement
  {
private:
   //--- Pointer zu dem Element, welches die Sichtbarkeit der ListView verwaltet
   CElement         *m_combobox;
   //---
public:
   //--- Speicher den Pointer der Combobox
   void              ComboBoxPointer(CElement &object)                   { m_combobox=::GetPointer(object); }
  };

Falls es sich bei der ListView um eine Dropdown-ListView handelt, wird eine Überprüfung des Pointers zu der Hauptmethode für die Erzeugung der ListView hinzugefügt. Wenn sich während der Erzeugung der Liste herausstellt, dass es keinen Pointer gibt, dann wird die Erzeugung des grafischen Interfaces abgebrochen und es wird eine entsprechende Nachricht ausgegeben.

Nachfolgend sehen Sie die abgekürzte Version der CListView::CreateListView() Methode: 

//+----------------------------------------------------------------
//| Erzeugt eine ListView                                              |
//+----------------------------------------------------------------
bool CListView::CreateListView(const long chart_id,const int window,const int x,const int y)
  {
//--- Verlassen, wenn es keinen Pointer zu einer Form gibt

//--- Falls es sich bei der ListView um eine Dropdown-ListView handelt, dann wird ein Pointer zu der Combobox, zu welchem diese ListView hinzugefügt worden ist, benötigt.
   if(CElement::IsDropdown())
     {
      //--- Abbrechen, falls es keinen Pointer zu einer ComboBox gibt
      if(::CheckPointer(m_combobox)==POINTER_INVALID)
        {
         ::Print(__FUNCTION__," > Before creating a drop-down list view, the class must be passed "
                 "a pointer to the combobox: CListView::ComboBoxPointer(CElement &object)");
         return(false);
        }
     }
//--- Initialisierung der Variablen
//--- Ränder von den Kanten
//--- Erzeugen eines Buttons
//--- Verstecke das Element, falls es sich um ein Dialogfenster handelt oder es minimiert ist
//---
   return(true);
  }

Nun kehren wir zu der Entwicklung der Combobox Klasse zurück(CComboBox). Die Eigenschaft, die darauf hinweist, dass es sich bei dieser ListView um eine DropDown-ListView handelt, muss sehr früh festgelegt werden. Dieses passiert am besten in dem Konstruktor der Klasse: 

CComboBox::CComboBox(void)
  {
//--- Drop-down list view mode
   m_listview.IsDropdown(true);
  }

Wenn wir eine ListView erzeugen, dann müssen die Pointer von dem Formular und der Combobox , zu welchen die ListView hinzugefügt worden ist, ganz am Anfang der Methode abgespeichert werden. Bitte beachten Sie, dass Die ListView und die Combobox einen gemeinsamen Bezeichner haben müssen da sie nur in diesem Fall zusammen ein Control ergeben. Nachdem die ListView erzeugt worden ist, muss sie versteckt werden

//+----------------------------------------------------------------
//| Erzeugt eine ListView                                              |
//+----------------------------------------------------------------
bool CComboBox::CreateList(void)
  {
//--- Abspeichern der Pointer des Formulars und der Combobox
   m_listview.WindowPointer(m_wnd);
   m_listview.ComboBoxPointer(this);
//--- Koordinaten
   int x=CElement::X2()-m_button_x_size;
   int y=CElement::Y()+m_button_y_size;
//--- Festlegen der Eigenschaften
   m_listview.Id(CElement::Id());
   m_listview.XSize(m_button_x_size);
//--- Erzeugen des Controls
   if(!m_listview.CreateListView(m_chart_id,m_subwin,x,y))
      return(false);
//--- Verstecken in der ListView
   m_listview.Hide();
   return(true);
  }

Um die ListView mit einer Anzahl von Elementen füllen zu können, fügen Sie dafür eine entsprechende Methode der CComboBox Klasse hinzu: 

class CListView : public CElement
  {
public:
   //--- Festlegen (1) der Größe der ListView (Anzahl der Elemente) und (2) des sichtbaren Bereiches
   void              ItemsTotal(const int items_total)                { m_listview.ListSize(items_total);                }
   void              VisibleItemsTotal(const int visible_items_total) { m_listview.VisibleListSize(visible_items_total); }
   
   //--- Speichert den übergebenen Wert in der ListView über den angegebenen Index
   void              ValueToList(const int item_index,const string item_text);
  };
//+----------------------------------------------------------------
//| Speichert den übergebenen Wert in der ListView über den angegebenen Index          |
//+----------------------------------------------------------------
void CComboBox::ValueToList(const int item_index,const string item_text)
  {
   m_listview.ValueToList(item_index,item_text);
  }

Um ein Element der ListView selektieren (hervorheben) zu können, erzeugen wir die CComboBox::SelectedItemByIndex() Methode. Dieser Methode muss lediglich der Index des Elementes übergeben werden, welches hervorgehoben werden soll. Anschließend wird das Hervorheben des Elementes in der gleichnamigen Methode der ListView (CListView) ausgefphrt, wo auch der Index angepasst wird, falls er den erlaubten Bereich überschreitet. Anschließend wird der Text des Elementes abgespeichert und indem Combobox-Button dargestellt. 

class CListView : public CElement
  {
public:
   //--- Hervorheben des Elementes über den angegebenen Index
   void              SelectedItemByIndex(const int index);
  };
//+----------------------------------------------------------------
//| Hervorheben des Elementes über den angegebenen Index                         |
//+----------------------------------------------------------------
void CComboBox::SelectedItemByIndex(const int index)
  {
//--- Hervorheben des Elementes in der ListView
   m_listview.SelectedItemByIndex(index);
//--- Abspeichern und darstellen des Textes in dem Button
   m_button_text=m_listview.SelectedItemText();
   m_button.Description(m_listview.SelectedItemText());
  }

Wir benötigen zudem eine Methode für das Sperren und Entsperren des Elementes und zudem eine Methode für die Abfrage des aktuellen Status. In Abhängigkeit von dem neuen Status des Elementes, werden die entsprechenden Farben für diese Objekte gesetzt. Hierfür werden wir in diesem Artikel noch Beispiele zeigen. 

class CListView : public CElement
  {
public:
   //--- Setzen und Abfragen des Status des Elementes
   bool              ComboBoxState(void)                        const { return(m_combobox_state);                        }
   void              ComboBoxState(const bool state);
  };
//+----------------------------------------------------------------
//| Ändern des Combobox Status                                      |
//+----------------------------------------------------------------
void CComboBox::ComboBoxState(const bool state)
  {
   m_combobox_state=state;
//--- Farben entsprechend dem aktuellen Status setzen
   m_label.Color((state)? m_label_color : m_label_color_off);
   m_button.Color((state)? m_button_text_color : m_button_text_color_off);
   m_button.BackColor((state)? m_button_color : m_button_color_off);
   m_button.BorderColor((state)? m_button_border_color : m_button_border_color_off);
   m_drop_arrow.State(state);
  }

Wenn sich der Mauszeiger über einem der Elemente befindet, dann findet der Farbwechsel unter Verwendung der CComboBox::ChangeObjectsColor() Methode nur dann statt, wenn das Element verfügbar ist

class CListView : public CElement
  {
public:
   //--- Ändern der Objektfarbe, wenn sich der Mauszeiger darüber befindet
   void              ChangeObjectsColor(void);
  };
//+----------------------------------------------------------------
//| Ändern der Objektfarbe, wenn sich der Mauszeiger darüber befindet|
//+----------------------------------------------------------------
void CComboBox::ChangeObjectsColor(void)
  {
//--- Abbrechen, falls das Element gesperrt ist
   if(!m_combobox_state)
      return;
//--- Ändern der Objektfarbe
   CElement::ChangeObjectColor(m_label.Name(),CElement::MouseFocus(),OBJPROP_COLOR,m_label_color,m_label_color_hover,m_label_color_array);
   CElement::ChangeObjectColor(m_button.Name(),CElement::MouseFocus(),OBJPROP_BGCOLOR,m_button_color,m_button_color_hover,m_button_color_array);
  }

Die CComboBox::ChangeObjectsColor() Methode muss in dem Timer des Controls CComboBox::OnEventTimer() aufgerufen werden. Vorausschauender Weise sollten wir bedenken, dass eine ComboBox auch eine Komponente eines noch komplexeren Elementes sein kann, welches ebenfalls ein Dropdown-Element ist. In einem der zukünftigen Artikel werden wir über einen Dropdown-Kalender, welches ein Beispiel für ein solches Element ist, sprechen. Eine Komponente davon ist eine ComboBox. Die Bedingungen für das Ändern der Farbe in dem Timer eines solchen Elementes, werden wie in den nachfolgenden Programmcode gezeigt, gebildet:

  1. Falls es sich um einen DropDown-Element handelt und die ListView versteckt ist.
  2. Falls die erste Bedingung nicht zutrifft, dann überprüfe die Verfügbarkeit des Formulars und des Elementes selbst. 
//+----------------------------------------------------------------
//| Timer                                                            |
//+----------------------------------------------------------------
void CComboBox::OnEventTimer(void)
  {
//--- Falls es sich um einen DropDown-Element handelt und die ListView versteckt ist
   if(CElement::IsDropdown() && !m_listview.IsVisible())
      ChangeObjectsColor();
   else
     {
      //--- Falls das Formular und das Element nicht gesperrt sind
      if(!m_wnd.IsLocked() && m_combobox_state)
         ChangeObjectsColor();
     }
  }

Lassen Sie uns die CComboBox::ChangeComboboxListState() Methode für die Verwaltung der Sichtbarkeit der ListView der Combobox erzeugen. Diese Methode ändert den aktuellen Status der Combobox in den entgegengesetzten Zustand. Zu Beginn der Methode findet eine Überprüfung der Verfügbarkeit des Elementes statt. Falls die Combobox gesperrt ist, dann verlässt das Programm die Methode. Anschließend verzweigt der Programmcode in zwei Bereiche:

  1. Falls die ListView bereits sichtbar ist, dann wird sie versteckt und es werden entsprechende Farben für den Button der Combobox gesetzt. Anschliessend, falls es sich nicht um ein DropDown-Element handelt, muss das Formular entsperrt werden und der Bezeichner des aktiven Elementes muss zurückgesetzt werden. 
  2. Falls die Liste versteckt ist, muss sie wieder sichtbar gemacht werden und es werden die entsprechenden Farben des Buttons der Combobox gesetzt. An dem Ende dieser Verzweigung, muss das Formular gesperrt und der Bezeichner des aktivierenden Elementes muss abgespeichert werden. 
class CListView : public CElement
  {
public:
   //--- Diese Methode ändert den aktuellen Status der Combobox in den entgegengesetzten Zustand
   void              ChangeComboBoxListState(void);
  };
//+----------------------------------------------------------------
//| Diese Methode ändert den aktuellen Status der Combobox in den entgegengesetzten Zustand       |
//+----------------------------------------------------------------
void CComboBox::ChangeComboBoxListState(void)
  {
//--- Abbrechen, falls das Element gesperrt ist
   if(!m_combobox_state)
      return;
//--- Falls die ListView sichtbar ist
   if(m_listview.IsVisible())
     {
      //--- Verstecken in der ListView
      m_listview.Hide();
      //--- Setzen der Farben
      m_label.Color(m_label_color_hover);
      m_button.BackColor(m_button_color_hover);
      //--- Falls es sich nicht um ein Dropdown Element handelt
      if(!CElement::IsDropdown())
        {
         //--- Die Form entsperren
         m_wnd.IsLocked(false);
         m_wnd.IdActivatedElement(WRONG_VALUE);
        }
     }
//--- Falls die ListView versteckt ist
   else
     {
      //--- Anzeigen der ListView
      m_listview.Show();
      //--- Setzen der Farben
      m_label.Color(m_label_color_hover);
      m_button.BackColor(m_button_color_pressed);
      //--- Blockieren der Form
      m_wnd.IsLocked(true);
      m_wnd.IdActivatedElement(CElement::Id());
     }
  }



Methoden für das Event-Handling

Wir können nun mit der Einrichtung des CComboBox::OnEvent() Eventhandlers fortfahren. Hierfür benötigen wir zwei private Hilfsmethoden:

  • CComboBox::OnClickButton() – In dieser Methode wird ein Klick auf den Combobox Button verfolgt.
  • CComboBox::CheckPressedOverButton() – In dieser Methode wird der Status der linken Maustaste über der Combobox verfolgt.
class CListView : public CElement
  {
private:
   //--- Verarbeitung eines Klicks auf den Button
   bool              OnClickButton(const string clicked_object);
   //--- Überprüfung eines Klicks mit der linken Maustaste über dem ComboBox-Button
   void              CheckPressedOverButton(void);
  };

Der Programmcode der CComboBox::OnClickButton() Methode ist sehr einfach. Sie beinhaltet nur eine Überprüfung des Objektnamens, auf welchen der Klick stattgefunden hat und einen Aufruf der CComboBox::ChangeComboBoxListState() Methode, die wir zuvor schon besprochen haben, welche die Sichtbarkeit der Combobox-ListView verwaltet. 

//+----------------------------------------------------------------
//| Klick auf den Combobox-Button                                  |
//+----------------------------------------------------------------
bool CComboBox::OnClickButton(const string clicked_object)
  {
//--- Abbrechen, falls die Objektnamen nicht übereinstimmen  
   if(clicked_object!=m_button.Name())
      return(false);
//--- Änderung des Status der ListView
   ChangeComboboxListState();
   return(true);
  }

Der Programmcode der CComboBox::CheckPressedOverButton() Methode wird nachfolgend gezeigt. Am Anfang der Methode wird eine Überprüfung der Verfügbarkeit des Formulares und des Bezeichners des aktivierenden Elementes durchgeführt. Das Programm wird an dieser Stelle abbrechen, falls das Formular gesperrt ist und die Bezeichner nicht übereinstimmen. 

Anschließen, falls es keinen Fokus über dem Element gibt, überprüfen wir die Anwesenheit eines Focus über der ListView und den Status der Scrollbar. Falls sich herausstellt, dass es keinen Fokus über der ListView gibt oder sich die Scrollbar in dem Modus des bewegenden Schiebereglers befindet, dann bricht das Programm an dieser stelle die Methode ab. Sie wissen bereits, dass sich der Schieberegler der Scrollbar auch dann bewegen kann, wenn der Mauszeiger bereits den Bereich des Schiebereglers verlassen hat. Falls keine dieser Bedingungen zutrifft, dann:

(1) Wird die ListView versteckt,

(2) Werden die Farben der Objekte wiederhergestellt,

und am ende dieses Bloks, falls die Bezeichner nicht übereinstimmen und es sich bei dem Element nicht um einen DropDown-Element handelt, dann, (3) muss das Formular wieder entsperrt werden. Lassen Sie mich Sie daran erinnern, dass ein Formular nur durch das Element entsperrt werden kann, welches es auch gesperrt hat.

Falls es einen Focus über dem Element gibt, wird zunächst eine Überprüfung der Sichtbarkeit der ListView durchgeführt. Falls die ListView sichtbar ist, dann gibt es keinen Grund hier fortzufahren und das Programm verlässt die Methode. Falls die Liste versteckt ist, dann werden die entsprechenden Farben in Abhängigkeit des Fokus über den Combobox-Button gesetzt. 

//+----------------------------------------------------------------
//| Überprüfung einer gedrückten Maustaste über dem Button           |
//+----------------------------------------------------------------
void CComboBox::CheckPressedOverButton(void)
  {
//--- Abbrechen, falls das Formular gesperrt ist und die Identifizierer nicht übereinstimmen
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return;
//--- Falls es keinen Fokus gibt
   if(!CElement::MouseFocus())
     {
      //--- Abbrechen, falls es keinen Focus über der ListView gibt oder die Scrollbar aktiv ist
      if(m_listview.MouseFocus() || m_listview.ScrollState())
         return;
      //--- Verstecken in der ListView
      m_listview.Hide();
      //--- Wiederherstellen der Farben
      ResetColors();
      //--- Falls die Bezeichner übereinstimmen und es sich bei dem Element nicht um einen DropDown-Element handelt
      if(m_wnd.IdActivatedElement()==CElement::Id() && !CElement::IsDropdown())
         //--- Die Form entsperren
         m_wnd.IsLocked(false);
     }
//--- Falls er den Fokus besitzt
   else
     {
      //--- Abbrechen, falls die ListView sichtbar ist
      if(m_listview.IsVisible())
         return;
      //--- Entsprechend dem Fokus die Farben setzen
      if(m_button.MouseFocus())
         m_button.BackColor(m_button_color_pressed);
      else
         m_button.BackColor(m_button_color_hover);
     }
  }

Der Aufruf der CComboBox::OnClickButton() Methode muss dem Block für die Klick-Verwaltung der grafischen Objekte übergeben werden, welche über denCHARTEVENT_OBJECT_CLICK Bezeichner identifiziert werden können: 

//+----------------------------------------------------------------
//| Event handler                                                    |
//+----------------------------------------------------------------
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten eines Tastendruck der linken Maustaste
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Ein Klick auf den Combobox-Button
      if(OnClickButton(sparam))
         return;
     }
  }

Vor dem Aufruf der CComboBox::CheckPressedOverButton() Methode, müssen die folgende Überprüfungen dem Block für die Verwaltung der Events über die Bewegung des MauszeigersCHARTEVENT_MOUSE_MOVE übergeben werden:

  • Die Sichtbarkeit des Elementes;
  • Die Verfügbarkeit des Elementes;
  • Der Status der linken Maustaste. 
//+----------------------------------------------------------------
//| Event handler                                                    |
//+----------------------------------------------------------------
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten des Mauszeiger Bewegungs Events
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Abbrechen, falls das Element versteckt ist
      if(!CElement::IsVisible())
         return;
      //--- Koordinaten
      int  x=(int)lparam;
      int  y=(int)dparam;
      //--- Überprüfen des Fokus über den Elementen
      CElement::MouseFocus(x>CElement::X() && x<CElement::X2() && 
                           y>CElement::Y() && y<CElement::Y2());
      m_button.MouseFocus(x>m_button.X() && x<m_button.X2() && 
                          y>m_button.Y() && y<m_button.Y2());
      //--- Abbrechen, falls das Element gesperrt ist
      if(!m_combobox_state)
         return;
      //--- Abbrechen, falls die linke Maustaste losgelassen wurde
      if(sparam=="0")
         return;
      //--- Überprüfung, ob die linke Maustaste über einem Split Button gedrückt wurde
      CheckPressedOverButton();
      return;
     }
  }

In dem Moment, wo auf einer der ListView Elemente gedrückt wird, wird das benutzerdefinierte ON_CLICK_LIST_ITEM Event erzeugt. Diese Nachricht muss in dem Combobox Eventhandler empfangen werden. Falls die Elementbezeichner übereinstimmen, das heißt, dass die Nachricht von einer ListView stammt, die einer ComboBox hinzugefügt worden ist, dann wird der Text des hervorgehobenen Elementes der ListView abgespeichert und die ListView wird mit der Methode CComboBox::ChangeComboBoxListState() versteckt.

Um sicherzustellen, dass es eine Verbindung zu der zu entwickelnden Anwendung gibt, kann die Nachricht mit dem ON_CLICK_LIST_ITEM Bezeichner in der benutzerdefinierten CProgram Klasse empfangen werden. Es kann auch eine Nachricht von einer ComboBox mit seinem eindeutigen (1) Event Bezeichner, (2) Element Bezeichner(3) und der Combobox-Beschreibung gesendet werden. Um die Kapazität der Steuerereignisidentifizierung zu erweitern, werden wir auch eine solche Option anbieten. Fügen Sie der Defines.mqh Datei einen eindeutigen Bezeichner für die Combobox hinzu. 

//+----------------------------------------------------------------
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#define ON_CLICK_COMBOBOX_ITEM    (17) // Auswahl eines Elementes in der Combobox ListView

In diesem Fall fügen Sie die in blau hervorgehobene Programmzeile dem Eventhandler hinzu: 

//+----------------------------------------------------------------
//| Event handler                                                    |
//+----------------------------------------------------------------
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten des Events von einem Klick auf ein ListView Element
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
     {
      //--- Wenn die Bezeichner übereinstimmen
      if(lparam==CElement::Id())
        {
         //--- Abspeichern und darstellen des Textes in dem Button
         m_button_text=m_listview.SelectedItemText();
         m_button.Description(m_listview.SelectedItemText());
         //--- Änderung des Status der ListView
         ChangeComboBoxListState();
         //--- Eine Nachricht darüber senden
         ::EventChartCustom(m_chart_id,ON_CLICK_COMBOBOX_ITEM,CElement::Id(),0,m_label_text);
        }
      //---
      return;
     }
  }

Wir können zudem festlegen, dass die ListView versteckt wird, wenn sich die Chart-Eigenschaften ändern. Dafür muss das Event mit dem CHARTEVENT_CHART_CHANGE Bezeichner behandelt werden: 

//+----------------------------------------------------------------
//| Event handler                                                    |
//+----------------------------------------------------------------
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten des Events, wenn sich die Chart-Eigenschaften ändern
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- Abbrechen, falls das Element gesperrt ist
      if(!m_combobox_state)
         return;
      //--- Verstecken in der ListView
      m_listview.Hide();
      //--- Wiederherstellen der Farben
      ResetColors();
      //--- Die Form entsperren
      m_wnd.IsLocked(false);
      m_wnd.IdActivatedElement(WRONG_VALUE);
      return;
     }
  }

Die Klasse für die Erzeugung des Combobox-Controls ist bereit für einen Test, aber vorher muss sie noch mit der Bibliotheks-Engine verbunden werden, damit alles korrekt funktioniert. 


Verbinden der Control-Klasse mit der Bibliotheks-Engine

Das Verbinden eines Controls mit der Bibliotheks-Engine benötigt lediglich ein paar wenige Aktionen:

1.Beziehen Sie die Datei mit der Control-Klasse in der WndContainer.mqh Datei der Bibliothek mit ein.

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

2.Falls nötig, erzeugen Sie ein privates Array für das Element und Eine Methode für die Erzeugung der Größe dieses Arrays. In unserem Fall benötigen wir ein privates Array für die DropDown ListViews. 

class CWndContainer
  {
protected:
   //--- Struktur des Elementenarrays
   struct WindowElements
     {
      //--- Gemeinsames Array von allen Objekten
      //--- Gemeinsames Array aller Elemente

      //--- Ein privates Array mit Elementen:
      //    Array mit Kontextmenüs
      //--- Array der Hauptmenüs
      //--- Tooltips
      //--- Array mit Dropdown ListViews von unterschiedlichen Typen
      CElement         *m_drop_lists[];
     };
   //--- Ein ABC mit Element ABCs für jedes Fenster
   WindowElements    m_wnd[];
   //---
public:
   //--- Anzahl der DropDown ListViews
   int               DropListsTotal(const int window_index);
  };
//+----------------------------------------------------------------
//| Gibt die Anzahl der DropDown ListViews über den angegebenen Fenster-Index zurück|
//+----------------------------------------------------------------
int CWndContainer::DropListsTotal(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_drop_lists));
  }

3.Erzeugen sie eine private Methode für das Hinzufügen von Pointern zu dem privaten Array. In unserem Falle benötigen wir den ListView Pointer von dem Combobox Control und fügen ihn dem privaten Array hinzu. Zudem müssen noch die ListView object Pointer und die ListView Scrollbars dem gemeinsamen Array der Objekte hinzugefügt werden. Der Programmcode der CWndContainer::AddComboBoxElements() Methode wird nachfolgend gezeigt. 

class CWndContainer
  {
private:
   //--- Speichert die Pointer der Kontextmenü-Elemente in der Basis
   //--- Speichert die Pointer der Hauptmenü-Elemente in der Basis
   //--- Speichert die Pointer zu den Split-Button-Elementen in der Basis ab
   //--- Speichert die Pointer zu Tooltip-Elementen in der Basis
   //--- Speichert den Pointer zu den ListView Objekten in der Basis ab

   //--- Speichert den Pointer zu den DropDown ListView Objekten in der Basis ab
   bool              AddComboBoxElements(const int window_index,CElement &object);
  };
//+----------------------------------------------------------------
//| Speichert den Pointer der DropDown ListView in einem privaten array |
//+----------------------------------------------------------------
bool CWndContainer::AddComboBoxElements(const int window_index,CElement &object)
  {
//--- Abbrechen, falls es kein Tooltip ist
   if(object.ClassName()!="CComboBox")
      return(false);
//--- Abfrage des Combobox Pointers
   CComboBox *cb=::GetPointer(object);
//---
   for(int i=0; i<2; i++)
     {
      //--- Vergrößern des Elementen Arrays
      int size=::ArraySize(m_wnd[window_index].m_elements);
      ::ArrayResize(m_wnd[window_index].m_elements,size+1);
      //--- Die Liste der Basis hinzufügen
      if(i==0)
        {
         CListView *lv=cb.GetListViewPointer();
         m_wnd[window_index].m_elements[size]=lv;
         AddToObjectsArray(window_index,lv);
         //--- Hinzufügen des Pointers zu dem privaten Array
         AddToRefArray(lv,m_wnd[window_index].m_drop_lists);
        }
      //--- Die Scrollbar der Basis hinzufügen
      else if(i==1)
        {
         CScrollV *sv=cb.GetScrollVPointer();
         m_wnd[window_index].m_elements[size]=sv;
         AddToObjectsArray(window_index,sv);
        }
     }
//---
   return(true);
  }

4.Falls die Aktionen für das dritte Element benötigt werden, vergessen Sie nicht die CWndContainer::AddComboBoxElements() Methode in der Hauptmethode CWndContainer::AddToElementsArray(), wo die Aufrufe solcher Methoden stattfindet, aufzurufen.

//+----------------------------------------------------------------
//| 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öhung des Zählers der Element-Bezeichners

//--- Speichert die Pointer zu den Kontextmenü-Objekten in der Basis
//--- Speichert die Pointer zu den Hauptmenü-Objekten in der Basis
//--- Speichert die Pointer zu den Splitbutton-Objekten in der Basis
//--- Speichert die Pointer zu den Tooltip-Objekten in der Basis
//--- Speichert den Pointer zu den ListView Objekten in der Basis ab

//--- Speichert die Pointer der ComboBox-Controls in der Basis ab
   if(AddComboBoxElements(window_index,object))
      return;
  }

Falls es sich um einen DropDown-Element handelt, kann es vorkommen, dass es manchmal die Grenzen des Formulars überschreitet, je nachdem, wo sich das Element auf dem Formular befindet. Die Position des Mauszeigers muss jederzeit kontrolliert werden und das Scrollen des Charts muss deaktiviert werden, wenn sich der Chart über einem dieser Elemente befindet. Dieses erlaubt es uns das Scrollen des Charts zu verhindern, wenn sich die linke Maustaste im gedrückten Zustand über dem Dropdown-Element befindet. Dafür haben wir bereits die CWndEvents::SetChartState() Methode in der CWndEvents Klasse geschrieben. Nun muss sie erweitert werden, damit sie auch eine Dropdown-Liste überprüft. In den nachfolgenden Programmcode wird dieser Teil in gelb hervorgehoben: 

//+----------------------------------------------------------------
//| Legt den Status des Chart fest                                   |
//+----------------------------------------------------------------
void CWndEvents::SetChartState(void)
  {
   int awi=m_active_window_index;
//--- Um den Event zu identifizieren, bei dem die Verwaltung deaktiviert werden muss
   bool condition=false;
//--- Überprüfen der Fenster
   int windows_total=CWndContainer::WindowsTotal();
   for(int i=0; i<windows_total; i++)
     {
      //--- Fahre mit den nächsten fort, falls dieses Formular versteckt ist
      if(!m_windows[i].IsVisible())
         continue;
      //--- Überprüfen der Bedingungen in dem internen Handler des Formulars
      m_windows[i].OnEvent(m_id,m_lparam,m_dparam,m_sparam);
      //--- Falls es einen Fokus gibt, markiere ihn
      if(m_windows[i].MouseFocus())
        {
         condition=true;
         break;
        }
     }
//--- Überprüfe die DropDown-ListViews
   if(!condition)
     {
      //--- Abfrage der Gesamtzahl der DropDown-ListViews
      int drop_lists_total=CWndContainer::DropListsTotal(awi);
      for(int i=0; i<drop_lists_total; i++)
        {
         //--- Abfrage des Pointers zu der Dropdown-ListViews
         CListView *lv=m_wnd[awi].m_drop_lists[i];
         //--- Falls die ListView aktiviert ist (sichtbar)
         if(lv.IsVisible())
           {
            //--- Überprüfe den Fokus über der ListView und den Status seiner Scrollbar
            if(m_wnd[awi].m_drop_lists[i].MouseFocus() || lv.ScrollState())
              {
               condition=true;
               break;
              }
           }
        }
     }
//--- Überprüfe den Fokus des Kontextmenüs
   if(!condition)
     {
      //--- Überprüfe die Gesamtzahl der Dropdown-Kontextmenüs
      int context_menus_total=CWndContainer::ContextMenusTotal(awi);
      for(int i=0; i<context_menus_total; i++)
        {
         //--- Falls sich der Fokus über dem Kontextmenü befindet
         if(m_wnd[awi].m_context_menus[i].MouseFocus())
           {
            condition=true;
            break;
           }
        }
     }
//--- Setze den Chart-Status in allen Formularen
   for(int i=0; i<windows_total; i++)
      m_windows[i].CustomEventChartState(condition);
  }

Nun ist alles bereit um das Combobox-Control zu testen. 

Testen des Combobox Controls in dem grafischen Interface der benutzerdefinierten Anwendung

Lassen Sie uns nun alles testen, was wir bisher in dem grafischen Interface der benutzerdefinierten Anwendung in dem fünften Teil dieser Serie implementiert haben. Wir haben den Test in dem letzten Artikel mit drei ListViews abgeschlossen. Wir behalten die ListViews und fügen noch vier Comboboxen dem grafischen Interface unserer Anwendung hinzu. Platzieren Sie zwei Comboboxen so, dass es uns möglich wird, den Einfluss der DropDown-ListViews auf die statischen ListViews, die sich unterhalb befinden, zu überprüfen. Zudem müssen wir die Funktionsweise de CWndEvents::SetChartState() Methode testen. Dafür platzieren wir die Comboboxen so, dass wenn die dropDown-ListViews sichtbar werden, diese die Grenzen des Formulars, zu welchem sie hinzugefügt worden sind, überschreiten.

In der benutzerdefinierten Klasse CProgram unserer Test-Anwendung, ist die Klasse der Combobox bereits über die Basisklasse verfügbar. Erzeugen sie nun 4 Instanzen der Klasse CComboBox und deklarieren Sie vier Methoden für jede von ihnen, mit der Angabe der Abstände von der oberen linken Ecke des Formulars, so wie es in dem Nachfolgenden Programmcode gezeigt wird.

//+----------------------------------------------------------------
//| Kasse für das erzeugende Anwendung                               |
//+----------------------------------------------------------------
class CProgram : public CWndEvents
  {
private:
   //--- Comboboxes
   CComboBox         m_combobox1;
   CComboBox         m_combobox2;
   CComboBox         m_combobox3;
   CComboBox         m_combobox4;
   //---
private:
   //--- Combobox 1
#define COMBOBOX1_GAP_X       (7)
#define COMBOBOX1_GAP_Y       (50)
   bool              CreateComboBox1(const string text);
   //--- Combobox 2
#define COMBOBOX2_GAP_X       (160)
#define COMBOBOX2_GAP_Y       (50)
   bool              CreateComboBox2(const string text);
   //--- Combobox 3
#define COMBOBOX3_GAP_X       (7)
#define COMBOBOX3_GAP_Y       (202)
   bool              CreateComboBox3(const string text);
   //--- Combobox 4
#define COMBOBOX4_GAP_X       (160)
#define COMBOBOX4_GAP_Y       (202)
   bool              CreateComboBox4(const string text);
  };

Wir betrachten jetzt nur eine dieser Methoden, da alle von ihnen identisch sind, mit der Ausnahme der Eigenschaften, die von den Benutzer angegeben wurden. Zum Beispiel werden wir die Viertel Combobox direkt nach ihrer Erzeugung sperren. Nachfolgend ist die Reihenfolge der Aktionen für die Erzeugung des Combobox-Controls

  • Abspeichern des Formular-Pointers in der Control-Klasse.
  • Berechnung der Koordinaten.
  • Deklarieren und initialisieren sie direkt das text Array für die ListView Elemente.
  • Legen Sie die Eigenschaften des Controls fest. Die meisten von ihnen werden mit Standardwerten initialisiert. Falls nötig, können diese neu definiert werden, bevor das Control erzeugt wird.
  • Speichern Sie die Element-Werte in der Combobox ListView.
  • Falls nötig, legen Sie die Eigenschaften für die ListView und der Scrollbar fest.
  • Heben Sie das Element in der ListView hervor. Das erste Element (0) wird standardmäßig hervorgehoben.
  • Erzeugen des Controls.
  • Das Control kann bei Bedarf gesperrt werden. Wir werden beispielhaft die vierte Combobox in unserer Test-Anwendung sperren
  • Am Ende dieser Methode übergeben wir das Objekt der Basisklasse, um den Pointer abzuspeichern.

Die Reihenfolge der Aktionen kann unterschiedlich sein. Wichtig ist nur, dass sie die Abfolge von drei wichtigen Aktionen einhalten:

  1. Hinzufügen des Pointers des Formulras zu der Control-Klasse. Andernfalls wird die Erzeugung des grafischen Interfaces abgebrochen. Es wird eine entsprechende Begründung in dem Journal herausgegeben.
  2. Erzeugen des Controls.
  3. Abspeichern des Control-Pointers in der Basis.
//+----------------------------------------------------------------
//| Erzeugt combobox 1                                               |
//+----------------------------------------------------------------
bool CProgram::CreateComboBox1(const string text)
  {
//--- Gesamte Anzahl an Elementen in der ListView
#define ITEMS_TOTAL1 8
//--- Übergabe des Formular-Objektes
   m_combobox1.WindowPointer(m_window1);
//--- Koordinaten
   int x=m_window1.X()+COMBOBOX1_GAP_X;
   int y=m_window1.Y()+COMBOBOX1_GAP_Y;
//--- Array mit den Elementwerten in der ListView
   string items_text[ITEMS_TOTAL1]={"FALSE","item 1","item 2","item 3","item 4","item 5","item 6","item 7"};
//--- Festlegen der Eigenschaften vor der Erzeugung
   m_combobox1.XSize(140);
   m_combobox1.YSize(18);
   m_combobox1.LabelText(text);
   m_combobox1.ButtonXSize(70);
   m_combobox1.AreaColor(clrWhiteSmoke);
   m_combobox1.LabelColor(clrBlack);
   m_combobox1.LabelColorHover(clrCornflowerBlue);
   m_combobox1.ButtonBackColor(C'206,206,206');
   m_combobox1.ButtonBackColorHover(C'193,218,255');
   m_combobox1.ButtonBorderColor(C'150,170,180');
   m_combobox1.ButtonBorderColorOff(C'178,195,207');
   m_combobox1.ItemsTotal(ITEMS_TOTAL1);
   m_combobox1.VisibleItemsTotal(5);
//--- Speichern der Element-Werte in der Combobox ListView.
   for(int i=0; i<ITEMS_TOTAL1; i++)
      m_combobox1.ValueToList(i,items_text[i]);
//--- Abfrage des ListView pointers
   CListView *lv=m_combobox1.GetListViewPointer();
//--- Festlegen der ListView Eigenschaften
   lv.LightsHover(true);
   lv.SelectedItemByIndex(lv.SelectedItemIndex()==WRONG_VALUE ? 2 : lv.SelectedItemIndex());
//--- Erzeugen des Controls
   if(!m_combobox1.CreateComboBox(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_combobox1);
   return(true);
  }

Der Aufruf der Methoden für das Erzeugen der Controls muss in der Hauptmethode für das Erzeugen des grafischen Interfaces stattfinden. In unserem Fall ist das die CProgram::CreateTradePanel() Methode. Nachfolgend ist die abgekürzte Version der Methode: 

//+----------------------------------------------------------------
//| Erzeugung des Trading-Panels                                     |
//+----------------------------------------------------------------
bool CProgram::CreateTradePanel(void)
  {
//--- Erzeugen des Formulars 1 für die Controls

//---Erzeugung der Controls:
//    Hauptmenü
//--- Kontextmenüs
//--- Erzeugen der Statusbar

//--- Comboboxes
   if(!CreateComboBox1("Combobox 1:"))
      return(false);
   if(!CreateComboBox2("Combobox 2:"))
      return(false);
   if(!CreateComboBox3("Combobox 3:"))
      return(false);
   if(!CreateComboBox4("Combobox 4:"))
      return(false);

//--- List views

//--- Neuzeichnen auf dem Chart
   m_chart.Redraw();
   return(true);
  }

Fügen Sie den Block für die Identifizierung der Nachrichten von den Comboboxen mit dem ON_CLICK_COMBOBOX_ITEM Bezeichner dem Eventhandler der CProgram Klasse hinzu. Lassen Sie uns festlegen, dass wenn eine Nachricht von der dritten Combobox empfangen wird, dass dann in Abhängigkeit von dem Element, welches in der ListView selektiert ist, sich der Status der vierten Combobox ändert. In unserem Fall, führt das Auswählen von irgendeinem Element in der ListView mit Ausnahme des Ersten (0) dazu, dass es die vierte Combobox verfügbar macht. Die Auswahl des ersten Elementes wird die Combobox sperren. 

//+----------------------------------------------------------------
//| Event handler                                                    |
//+----------------------------------------------------------------
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Auswahl eines Elementes in dem Combobox-Event
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM)
     {
      if(sparam==m_combobox1.LabelText())
         ::Print(__FUNCTION__," > This message is from combobox 1 > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      else if(sparam==m_combobox2.LabelText())
         ::Print(__FUNCTION__," > This message is from combobox 2 > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Verarbeiten der Nachricht der dritten Combobox
      else if(sparam==m_combobox3.LabelText())
        {
         ::Print(__FUNCTION__," > This message is from combobox 3 > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
         //--- Falls der angegebene Wert ausgewählt wurde, dann deaktiviere Combobox 4
         if(m_combobox3.ButtonText()=="FALSE")
            m_combobox4.ComboBoxState(false);
         //--- Falls ein anderer Wert ausgewählt wurde, dann aktiviere Combobox 4
         else
            m_combobox4.ComboBoxState(true);
        }
      else if(sparam==m_combobox4.LabelText())
         ::Print(__FUNCTION__," > This message is from combobox 4 > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
  }

Nachdem wir das Programm kompiliert und es auf einen Chart geladen haben, sollte das Ergebnis so wie in dem nachfolgenden Screenshot aussehen:

 Abbildung  2. Test des Combobox Controls.

Abbildung 2. Test des Combobox Controls.

Wir haben hiermit die Entwicklung der CComboBox Klasse für die Erzeugung einer ComboBox abgeschlossen.


Schlussfolgerung

In diesem Artikel haben wir das Komponenten-Control Combobox besprochen. Zur Zeit sieht das schematische Diagramm unserer Bibliothek für das Erzeugen von grafischen Interfaces wie folgt aus:

 Abbildung 3. Die Struktur unserer Bibliothek zum aktuellen Stand der Entwicklung

Abbildung 3. Die Struktur unserer Bibliothek zum aktuellen Stand der Entwicklung

Der nächste Artikel stellt den Beginn des sechsten Teils dieser Serie dar, der sich mit der Entwicklung der Bibliothek für die Erzeugung von grafischen Interfaces beschäftigt. Hier werden wir die Klassen für die Erzeugung der Checkbox und des Edit-Controls besprechen, sowie deren gemischte Typen.

Sie können das gesamte Material des fünften Teils herunterladen und testen. 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 Artikel des fünften Teils:

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

Beigefügte Dateien |
Testen von Strategien mit echten Ticks Testen von Strategien mit echten Ticks

Der Artikel enthält die Ergebnisse der Prüfung einer einfachen Trading-Strategie in drei Modi: "1 Minute OHLC", "Jeder Tick" und "Jeder Tick basierend auf echten Ticks" mit tatsächlichen historischen Daten.

Universal Expert Advisor: Einbindung der Standard MetaTrader Module für Signale (Teil 7) Universal Expert Advisor: Einbindung der Standard MetaTrader Module für Signale (Teil 7)

Dieser Teil des Artikels beschreibt die Möglichkeiten der Einbindung der Signal-Module, Teil der Standard-Bibliothek des MetaTraders, durch CStrategy. Der Artikel beschreibt, wie man mit Signalen arbeitet und wie man eigene Strategien auf ihrer Basis erstellt.

LifeHack für Trader: ein back-Test ist gut, und vier – ist besser LifeHack für Trader: ein back-Test ist gut, und vier – ist besser

Vor jedem Trader bei dem ersten einzelnen Test steht eine und derselbe Frage — "Welchen von vier Modus ich verwenden soll?" Jeder des angebotenen Modus hat eigene Vorteile und Besonderheiten, deshalb machen wir es einfacher — wir werden direkt alle Modus durch eine Taste starten! Im Artikel ist es vorgeführt, wie man mit Hilfe Win API und der kleinen Magie gleichzeitig alle vier Graphik des Tests sehen kann.

Welche Überprüfungen der Handelsroboter vor der Veröffentlichung in Market bestehen soll Welche Überprüfungen der Handelsroboter vor der Veröffentlichung in Market bestehen soll

Alle Markets Produkte vor der Veröffentlichung bestehen eine obligatorische vorläufige Überprüfung, um eine Standarte Qualität zu haben. In diesem Artikel werden wir von den häufigsten Fehlern erzählen, die die Hersteller in den Handelsrobotern und den technischen Indikatoren machen. Auch werden wir zeigen, wie man sein Produkt vor der Sendung in Market selbständig überprüfen soll.