Graphische Interfaces VI: Das Checkbox Control, Das Edit Control und deren gemischte Typen (Kapitel 1)

Anatoli Kazharski | 14 Juli, 2016

Inhalt

Einleitung

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

Der sechste Teil dieser Serie  wird aus zwei Kapiteln bestehen. In dem ersten Kapitel, werden wir vier Controls (Steuerelemente) erzeugen:

Wir werden hier nur die Checkbox und das Edit-Control besprechen, da ein Edit mit Checkbox und eine Checkcombobox nichts beinhaltet, was zuvor nicht schon betrachtet wurde. 

Der zweite Artikel wird den folgenden Elementen gewidmet:

 


Das Checkbox-Control

Die Checkbox wird für die Verwaltung und Steuerung von Parameter entworfen, die nur zwei Zustände annehmen können. Hierfür wird ein Button mit zwei Icons verwendet, damit der aktuelle Status des Parameters, mit welchem dieses Control verbunden wurde, angezeigt werde kann. Das Icon mit dem Check-Symbol bedeutet, dass der Parameter aktiviert ist (an). Das Icon ohne dem Check-Symbol bedeutet, dass der Parameter deaktiviert ist (aus) Neben dem Button befindet sich eine kurze Beschriftung. 

Dieses Element wird aus drei grafischen Objekten zusammengesetzt. :Diese sind:

  1. Hintergrund
  2. Icon (Button)
  3. Text Label

Abbildung  1. Die zusammengesetzten Teile des Checkbox-Controls

Abbildung 1. Die zusammengesetzten Teile des Checkbox-Controls

Lassen Sie uns die Klasse dieses Controls näher anschauen.

 


Entwicklung einer Klasse für die Erzeugung des Checkbox-Controls

In den dritten Teil dieser Serie haben wir über ein ähnliches Control gesprochen - einen Icon-Button und seine Klasse CIconButton  (Sehen Sie hierzu den Artikel Graphische Interfaces III: Einfache und multifunktionale Buttons (Kapitel 1)). Das Checkbox-Control ist dem Icon-Button mit seinen zwei Zuständen sehr ähnlich. Der einzige Unterschied ist hier, dass ein Button in seinen unterschiedlichen Zuständen unterschiedliche Hintergrundfarben und Textfarben besitzt (Falls diese angegeben wurden), und im Falle einer Checkbox kann sich nur das Icon und die Textfarbe ändern (Falls diese angegeben wurden). Die Hintergrundfarbe der Checkbox wird die gleiche sein, wie die Hintergrundfarbe des Fensters, zu welchem sie hinzugefügt wurde. Der Hintergrund wird hier dafür verwendet, um den Bereich für den Maus-Cursor zu identifizieren und um den den Status der linken Maustaste zu erfassen. Das Checkbox Control ist einfacher als ein Icon-Button, da er weniger Eigenschaften besitzt, die ein User festlegen kann.

Erzeugen Sie die CheckBox.mqh Datei und beziehen Sie diese Datei mit in der WndContainer.mqh Datei unserer Bibliothek mit ein:

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

Erzeugen Sie die CCheckBox Klasse mit den Standardmethoden für alle Elemente der Bibliothek in der CheckBox.mqh Datei:

//+------------------------------------------------------------------+
//|                                                     CheckBox.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
//+------------------------------------------------------------------+
 //| Klasse für das Erzeugen einer Checkbox                          |
//+------------------------------------------------------------------+
class CCheckBox : public CElement
  {
private:
   //--- Ein Pointer zu der Form zu welchem das Element hinzugefügt worden ist
   CWindow          *m_wnd;
   //---
public:
                     CCheckBox(void);
                    ~CCheckBox(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ät der linken Maustaste
   virtual void      SetZorders(void);
   virtual void      ResetZorders(void);
   //--- Zurücksetzen der Farbe
   virtual void      ResetColors(void);
  };

Bevor dieses Control erzeugt wird, kann der User noch über verschiedene Methoden die nachfolgenden Eigenschaften festlegen:

Es wird vier Icons für die Checkbox geben, zwei Icons für den aktiven Status und zwei für den gesperrten Status. Alle hier verwendeten Icons können wir am Ende dieses Artikels herunterladen und verwenden. 

class CCheckBox : public CElement
  {
private:
   //--- Hintergrundfarbe der Checkbox
   color             m_area_color;
   //--- Die Icons für den aktiven und gesperrten Status
   string            m_check_bmp_file_on;
   string            m_check_bmp_file_off;
   string            m_check_bmp_file_on_locked;
   string            m_check_bmp_file_off_locked;
   //--- Text der Checkbox
   string            m_label_text;
   //--- Die Ränder des Text Labels
   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_locked;
   color             m_label_color_array[];
   //--- Priorität für die linke Maustaste
   int               m_zorder;
   int               m_area_zorder;
   //---
public:
   //--- Festlegen der Labels für den Button in dem aktiven und in dem gesperrten Status
   void              CheckFileOn(const string file_path)            { m_check_bmp_file_on=file_path;         }
   void              CheckFileOff(const string file_path)           { m_check_bmp_file_off=file_path;        }
   void              CheckFileOnLocked(const string file_path)      { m_check_bmp_file_on_locked=file_path;  }
   void              CheckFileOffLocked(const string file_path)     { m_check_bmp_file_off_locked=file_path; }
   //--- (1) Hintergrundfarbe, (2) Abstände für das Text-Label
   void              AreaColor(const color clr)                     { m_area_color=clr;                      }
   void              LabelXGap(const int x_gap)                     { m_label_x_gap=x_gap;                   }
   void              LabelYGap(const int y_gap)                     { m_label_y_gap=y_gap;                   }
   //--- Die Farbe für den Text in den unterschiedlichen Zuständen
   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;               }
   void              LabelColorLocked(const color clr)              { m_label_color_locked=clr;              }
   //--- Beschreibung der Checkbox
   string            LabelText(void)                          const { return(m_label.Description());         }
  };

Für die Erzeugung der Checkbox, benötigen wir drei private Methoden und eine public Methode:

class CCheckBox : public CElement
  {
private:
   //--- Objekte für das Erzeugen einer Checkbox
   CRectLabel        m_area;
   CBmpLabel         m_check;
   CLabel            m_label;
   //---
public:
   //--- Methoden für das Erzeugen einer Checkbox
   bool              CreateCheckBox(const long chart_id,const int subwin,const string text,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateCheck(void);
   bool              CreateLabel(void);
  };

Lassen Sie uns die CCheckBox::CheckButtonState() und die CCheckBox::CheckBoxState() Methoden für das Verwalten des Status der Checkbox erzeugen:

class CCheckBox : public CElement
  {
private:
   //--- Status des Checkbox button
   bool              m_check_button_state;
   //--- Checkbox Status (Verfügbar/gesperrt)
   bool              m_checkbox_state;
   //---
public:
   //--- Setzen und Abfragen des Status der Checkbox
   bool              CheckBoxState(void)                      const { return(m_checkbox_state);              }
   void              CheckBoxState(const bool state);
   //--- Setzen und Abfragen des Status des Checkbox-Buttons
   bool              CheckButtonState(void)                   const { return(m_check.State());               }
   void              CheckButtonState(const bool state);
  };

Um das Control zu blockieren und zu entsperren, verwenden Sie die CCheckBox::CheckBoxState() Methode:

//+-----------------------------------------------------------------+
//| Festlegen des Status des Controls                               |
//+-----------------------------------------------------------------+
void CCheckBox::CheckBoxState(const bool state)
  {
//--- Status des Controls
   m_checkbox_state=state;
//--- Icon
   m_check.BmpFileOn((state)? "::"+m_check_bmp_file_on : "::"+m_check_bmp_file_on_locked);
   m_check.BmpFileOff((state)? "::"+m_check_bmp_file_off : "::"+m_check_bmp_file_off_locked);
//--- Farbe des Text Labels
   m_label.Color((state)? m_label_color : m_label_color_locked);
  }

Um den Status des Checkbox-Buttons zu setzen, verwenden Sie die CCheckBox::CheckButtonState() Methode: 

//+-----------------------------------------------------------------+
//| Setzen des Status des Checkbox-Buttons                          |
//+-----------------------------------------------------------------+
void CCheckBox::CheckButtonState(const bool state)
  {
//--- Verlassen, falls das Control gesperrt ist
   if(!m_checkbox_state)
      return;
//--- Setzen des Status des Buttons
   m_check.State(state);
   m_check_button_state=state;
//--- Wechseln der Farbe, entsprechend dem aktuellen Status
   m_label.Color((state)? m_label_color : m_label_color_off);
   CElement::InitColorArray((state)? m_label_color : m_label_color_off,m_label_color_hover,m_label_color_array);
  }

Wir müssen lediglich noch eine Methode für das Verwalten eines Klicks auf das Control erzeugen. Diese Methode wird indem Haupt-Eventhandler des Controls CCheckBox::OnEvent() Über das Event mit dem CHARTEVENT_OBJECT_CLICK Bezeichner aufgerufen. Lassen Sie sie uns CCheckBox::OnClickLabel() nennen. Zunächst wird eine Überprüfung vorgenommen, ob der Klick über dem Bereich des Controls lag (dem Hintergrund). Um eindeutig unterscheiden zu können, über welchen Control ein Klick stattgefunden hat, bekommt der Hintergrund die Priorität (der linken Maustatse) eins und die anderen Objekte den Wert 0. Daher wird auch ein Klick auf den Checkbox-Button oder auf das Text-Label wie ein Klick auf das Control behandelt, da der Hintergrund die höchste Priorität hat. Anschließend verwenden wir die CCheckBox::CheckButtonState() Methode um den Status entgegengesetzt des Checkbox-Buttons zu setzen. Am Ende der Methode senden wir ein a custom event mit (1) dem Bezeichner ON_CLICK_LABEL, (2) dem Bezeichner des Elementes (3) Und der Beschreibung des Elementes.

class CCheckBox : public CElement
  {
private:
   //--- Verarbeitung eines Klicks auf das Element
   bool              OnClickLabel(const string clicked_object);
  };
//+-----------------------------------------------------------------+
//| Event handling                                                  |
//+-----------------------------------------------------------------+
void CCheckBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten eines Klicks mit der linken Maustaste auf ein Objekt
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Klick auf eine Checkbox
      if(OnClickLabel(sparam))
         return;
     }
  }
//+-----------------------------------------------------------------+
//| Klick auf ein Element Label                                     |
//+-----------------------------------------------------------------+
bool CCheckBox::OnClickLabel(const string clicked_object)
  {
//--- Abbrechen, falls die Namen unterschiedlich sind
   if(m_area.Name()!=clicked_object)
      return(false);
//--- Verlassen, falls das Control gesperrt ist
   if(!m_checkbox_state)
      return(false);
//--- In den entgegengesetzten Zustand wechseln
   CheckButtonState(!m_check.State());
//--- Der Mauszeiger befindet sich aktuell über dem Element
   m_label.Color(m_label_color_hover);
//--- Eine Nachricht darüber senden
   ::EventChartCustom(m_chart_id,ON_CLICK_LABEL,CElement::Id(),0,m_label.Description());
   return(true);
  }

 

 


Test des Checkbox-Controls

Alle Methoden für die CCheckBox Klasse sind nun fertig und somit können wir jetzt testen, ob dieses Control funktioniert. Die Datei mit der Klasse dieses Kontos muss bereits in der Bibliothek mit einbezogen sein. Für den Test kann der EA aus dem vorherigen Artikel kopiert werden. Entfernen Sie hier alle Controls, mit Ausnahme des Hauptmenüs und der Statusbar. Erzeugen sie für den Test zwei Checkboxen Stellen Sie sicher, dass die zweite Checkbox blockiert ist, während das Programm startet. Die erste Checkbox ist für die Interaktion mit dem User verfügbar, aber sie befindet sich in einem deaktivierten Status. Das Aktivieren der ersten Checkbox ist ein Signal für das Entsperren der zweiten Checkbox. Das gleiche soll auch entgegengesetzt funktionieren - Das Deaktivieren der ersten Checkbox führt zu einem Signal, welches die zweite Checkbox blockiert.

Erzeugen sie in der benutzerdefinierten CProgram Klasse zwei Instanzen der CCheckBox und deklarieren Sie zwei Methoden für das Erzeugen der Checkboxen und spezifizieren Sie die Abstände von der Ecke des Formulars, zu welchem diese hinzugefügt werden: 

//+-----------------------------------------------------------------+
//| Kasse für das erzeugende Anwendung                              |
//+-----------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
   //--- Checkboxen
   CCheckBox         m_checkbox1;
   CCheckBox         m_checkbox2;
   //---
private:
   //--- Checkboxen
#define CHECKBOX1_GAP_X       (7)
#define CHECKBOX1_GAP_Y       (50)
   bool              CreateCheckBox1(const string text);
#define CHECKBOX2_GAP_X       (30)
#define CHECKBOX2_GAP_Y       (75)
   bool              CreateCheckBox2(const string text);
  };

Der einzige Unterschied bei der Implementation der Methoden ist, dass Die Verfügbarkeit der zweiten Checkbox von dem Status der ersten Checkbox abhängt:

//+-----------------------------------------------------------------+
//| Erzeugt Checkbox 2                                              |
//+-----------------------------------------------------------------+
bool CProgram::CreateCheckBox2(string text)
  {
//--- Übergabe des Panel Objektes
   m_checkbox2.WindowPointer(m_window1);
//--- Koordinaten
   int x=m_window1.X()+CHECKBOX2_GAP_X;
   int y=m_window1.Y()+CHECKBOX2_GAP_Y;
//--- Festlegen der Eigenschaften vor der Erzeugung
   m_checkbox2.XSize(90);
   m_checkbox2.YSize(18);
   m_checkbox2.AreaColor(clrWhiteSmoke);
   m_checkbox2.LabelColor(clrBlack);
   m_checkbox2.LabelColorOff(clrBlack);
   m_checkbox2.LabelColorLocked(clrSilver);
//--- Erzeugung des Controls
   if(!m_checkbox2.CreateCheckBox(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- Die Verfügbarkeit hängt von dem aktuellen Status der ersten Checkbox ab
   m_checkbox2.CheckBoxState(m_checkbox1.CheckButtonState()); 
//--- Fügen Sie das Objekt zu dem gemeinsamen Array von Objektgruppen hinzu
   CWndContainer::AddToElementsArray(0,m_checkbox2);
   return(true);
  }

Fügen Sie den Aufruf der Methoden für das Erzeugen der Checkboxen in der Hauptmethode für das Erzeugen des grafischen Interfaces hinzu. Nachfolgend wird eine abgekürzte Version das Programmcodes gezeigt:

//+-----------------------------------------------------------------+
//| Erzeugt das Trading-Panel                                       |
//+-----------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Erzeugen des Formulars 1 für die Controls
//---Erzeugung der Controls:
//    Hauptmenü
//--- Kontextmenüs
//--- Erzeugen der Statusbar

//--- Checkboxen
   if(!CreateCheckBox1("Checkbox 1"))
      return(false);
   if(!CreateCheckBox2("Checkbox 2"))
      return(false);
//--- Neuzeichnen des Charts
   m_chart.Redraw();
   return(true);
  }

Wir empfangen und verarbeiten die Nachricht mit dem ON_CLICK_LABEL Bezeichner in dem Eventhandler von der CProgram Klasse. Die Verfügbarkeit der zweiten Checkbox wird über den Status der ersten Checkbox definiert, wie ist auch in dem nachfolgenden Code gezeigt wird: 

//+-----------------------------------------------------------------+
//| Eventhandler                                                    |
//+-----------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Der Event für einen Klick auf die Checkbox
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Falls es sich um einen Klick auf die erste Checkbox handelt
      if(lparam==m_checkbox1.Id())
        {
         //--- Setzen des Status der zweiten Checkbox
         m_checkbox2.CheckBoxState(m_checkbox1.CheckButtonState());
        }
     }
  }

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.

Abbildung  2. Test this Checkbox-Controls.

Abbildung 2. Test this Checkbox-Controls.

Der Screenshot zeigt, dass die zweite Checkbox gesperrt ist. Den Hinweis darauf sehen wir in der Textfarbe und dem entsprechenden Icon des Buttons (verblasste Fraben). Alles arbeitet einwandfrei und wir fahren daher mit der Entwicklung der Klasse für die Erzeugung eines Edit-Controls fort. 

 


Das Edit-Control

Ein Edit-Control wird dafür verwendet, um einen numerischen Wert in einem Textfeld einzugeben. Der Wert kann manuell eingegeben werden oder mit der Hilfe von Buttons. Der User kann Minimum- und Maximumwerte festlegen, sowie auch die Schrittweite für die Eingabe mit den Buttons. Falls die Buttons mit den Pfeilen einmal gedrückt werden, dann ändert sich der Wert mit der angegebenen Schrittweite. Wenn die Pfeile gedrückt und gehalten werden, dann ändert sich der Wert in dem Edit-Control schnell. Das Verändern des Wertes stoppt, sobald das Minimum oder Maximum erreicht ist.

Dieses Control wird aus fünf grafischen Objekten zusammengesetzt. :Diese sind:

  1. Hintergrund
  2. Text Label
  3. Edit
  4. Zwei Buttons für das Scrollen der Werte in dem Edit-Control

Abbildung 3. Die Komponenten Edit-Controls

Abbildung 3. Die Komponenten Edit-Controls

In den nächsten Teil des Artikels, werden wir die Klasse für die Erzeugung dieses Interface Elementes schreiben.

 


Entwickeln einer Klasse für die Erzeugung des Edit-Controls

Ähnlich wie bei dem Checkbox-Control, ist die Entwicklung des Edit-Controls einfach. Mit anderen Worten, dieses Control wird aus einfachen Objekten zusammengesetzt und beinhaltet keine weiteren Controls. Dieses ist auch der Grund dafür, warum keine weiteren Ergänzungen in der WndContainer.mqh Datei notwendig sind. Wir müssen lediglich die Datei mit der Klasse für das Edit-Control mit einbeziehen.

Erzeugen Sie jetzt die Datei SpinEdit.mqh und binden Sie diese mit in der WndContainer.mqh Datei mit ein:

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

Erzeugen sie in der SpinEdit.mqh Datei die CSpinEdit Klasse mit den Standard-Methoden für alle Elemente dieser Bibliothek, so wie in der oben gezeigten Beschreibung der CCheckBox Klasse. Das ist der Grund, warum dir direkt mit der Beschreibung der Eigenschaften des Edit-Controls fortfahren. 

Nachfolgend ist eine Liste aller Eigenschaften des Edit-Controls, welche für den Anwender zugänglich sind.

Der Nachfolgende Programmcode präsentiert die Variablen und Methoden der Klasse für das Setzen der Eigenschaften des Controls: 

//+-----------------------------------------------------------------+
//| Klasse für die Erzeugung des Edit-Controls                      |
//+-----------------------------------------------------------------+
class CSpinEdit : public CElement
  {
private:
   //--- Farbe des Control-Hintergrundes
   color             m_area_color;
   //--- Text der Beschreibung des Edit-Controls
   string            m_label_text;
   //--- Die Ränder des Text Labels
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Die Farbe für den Text in den unterschiedlichen Zuständen
   color             m_label_color;
   color             m_label_color_hover;
   color             m_label_color_locked;
   color             m_label_color_array[];
   //--- Die Größe
   int               m_edit_x_size;
   int               m_edit_y_size;
   //--- Die Abstände des Controls von der rechten Seite
   int               m_edit_x_gap;
   //--- Die Farbe und der Text des Controls in den unterschiedlichen Zuständen
   color             m_edit_color;
   color             m_edit_color_locked;
   color             m_edit_text_color;
   color             m_edit_text_color_locked;
   color             m_edit_text_color_highlight;
   //--- Die Farbe des Rahmens des controles in den unterschiedlichen Zuständen
   color             m_edit_border_color;
   color             m_edit_border_color_hover;
   color             m_edit_border_color_locked;
   color             m_edit_border_color_array[];
   //--- Die Labels der Schalter in dem aktiven und dem gesperrten Status
   string            m_inc_bmp_file_on;
   string            m_inc_bmp_file_off;
   string            m_inc_bmp_file_locked;
   string            m_dec_bmp_file_on;
   string            m_dec_bmp_file_off;
   string            m_dec_bmp_file_locked;
   //--- Abstände der Buttons (Von der rechten Seite)
   int               m_inc_x_gap;
   int               m_inc_y_gap;
   int               m_dec_x_gap;
   int               m_dec_y_gap;
   //--- Der Modus für das Zurücksetzen des Wertes zum Minimum
   bool              m_reset_mode;
   //--- Minimum/maximum Wert
   double            m_min_value;
   double            m_max_value;
   //--- Schrittweise für die Veränderung des Wertes
   double            m_step_value;
   //--- Modus der Textausrichtung
   ENUM_ALIGN_MODE   m_align_mode;
   //--- Anzahl der Nachkommastellen
   int               m_digits;
   //---
public:
   //--- (1) Hintergrundfarbe, (2) Text der Beschreibung, (3) Abstände des Text-Labels
   void              AreaColor(const color clr)                     { m_area_color=clr;                   }
   string            LabelText(void)                          const { return(m_label.Description());      }
   void              LabelXGap(const int x_gap)                     { m_label_x_gap=x_gap;                }
   void              LabelYGap(const int y_gap)                     { m_label_y_gap=y_gap;                }
   //--- Die Farben für das Textlabel für die unterschiedlichen Zustände
   void              LabelColor(const color clr)                    { m_label_color=clr;                  }
   void              LabelColorHover(const color clr)               { m_label_color_hover=clr;            }
   void              LabelColorLocked(const color clr)              { m_label_color_locked=clr;           }
   //--- (1) Die Größe des Controls, (2) Abstände für das Control von der rechten Seite
   void              EditXSize(const int x_size)                    { m_edit_x_size=x_size;               }
   void              EditYSize(const int y_size)                    { m_edit_y_size=y_size;               }
   void              EditXGap(const int x_gap)                      { m_edit_x_gap=x_gap;                 }
   //--- Farbe des Controls in den unterschiedlichen Zuständen
   void              EditColor(const color clr)                     { m_edit_color=clr;                   }
   void              EditColorLocked(const color clr)               { m_edit_color_locked=clr;            }
   //--- Farbe des Control-Textes in den unterschiedlichen Zuständen
   void              EditTextColor(const color clr)                 { m_edit_text_color=clr;              }
   void              EditTextColorLocked(const color clr)           { m_edit_text_color_locked=clr;       }
   void              EditTextColorHighlight(const color clr)        { m_edit_text_color_highlight=clr;    }
   //--- Die Farbe des Rahmens des controles in den unterschiedlichen Zuständen
   void              EditBorderColor(const color clr)               { m_edit_border_color=clr;            }
   void              EditBorderColorHover(const color clr)          { m_edit_border_color_hover=clr;      }
   void              EditBorderColorLocked(const color clr)         { m_edit_border_color_locked=clr;     }
   //--- Festlegen der Labels für den Button in dem aktiven und in dem gesperrten Status
   void              IncFileOn(const string file_path)              { m_inc_bmp_file_on=file_path;        }
   void              IncFileOff(const string file_path)             { m_inc_bmp_file_off=file_path;       }
   void              IncFileLocked(const string file_path)          { m_inc_bmp_file_locked=file_path;    }
   void              DecFileOn(const string file_path)              { m_dec_bmp_file_on=file_path;        }
   void              DecFileOff(const string file_path)             { m_dec_bmp_file_off=file_path;       }
   void              DecFileLocked(const string file_path)          { m_dec_bmp_file_locked=file_path;    }
   //--- Abstände für die Buttons
   void              IncXGap(const int x_gap)                       { m_inc_x_gap=x_gap;                  }
   void              IncYGap(const int y_gap)                       { m_inc_y_gap=y_gap;                  }
   void              DecXGap(const int x_gap)                       { m_dec_x_gap=x_gap;                  }
   void              DecYGap(const int y_gap)                       { m_dec_y_gap=y_gap;                  }
   //--- Der Reset Modus, wenn ein Klick auf das Textlabel stattfindet
   bool              ResetMode(void)                                { return(m_reset_mode);               }
   void              ResetMode(const bool mode)                     { m_reset_mode=mode;                  }
   //--- Minimum-Wert
   double            MinValue(void)                           const { return(m_min_value);                }
   void              MinValue(const double value)                   { m_min_value=value;                  }
   //--- Maximum-Wert
   double            MaxValue(void)                           const { return(m_max_value);                }
   void              MaxValue(const double value)                   { m_max_value=value;                  }
   //--- Die Schrittweite des Wertes
   double            StepValue(void)                          const { return(m_step_value);               }
   void              StepValue(const double value)                  { m_step_value=(value<=0)? 1 : value; }
   //--- (1) Anzahl der Nachkommastellen, (2) Modus der Textausrichtung
   void              SetDigits(const int digits)                    { m_digits=::fabs(digits);            }
   void              AlignMode(ENUM_ALIGN_MODE mode)                { m_align_mode=mode;                  }
  };

Für die Erzeugung des Kontos, benötigen wir fünf private Methoden für die Erzeugung des einfachen grafischen Objektes und eine public Methode, die in der benutzerdefinierten Klasse aufgerufen wird, wenn das grafische Interface erzeugt wird. Die Icons für die scrolling Buttons können am Ende des Artikels heruntergeladen werden. Diese werden standardmäßig verwendet. Sie können natürlich auch ihre Eigenen verwenden.

class CSpinEdit : public CElement
  {
private:
   //--- Objekte für die Erzeugung des Controls
   CRectLabel        m_area;
   CLabel            m_label;
   CEdit             m_edit;
   CBmpLabel         m_spin_inc;
   CBmpLabel         m_spin_dec;
   //---
public:
   //--- Methoden für die Erzeugung des Controls
   bool              CreateSpinEdit(const long chart_id,const int subwin,const string label_text,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateLabel(void);
   bool              CreateEdit(void);
   bool              CreateSpinInc(void);
   bool              CreateSpinDec(void);
  };

Nun werden wir die Modi und die Methoden für das Verwalten des Status und die Eigenschaften des Controls besprechen. Lassen Sie uns mit der CSpinEdit::SetValue() Methode für das Einstellen und Speichern des Wertes des Controls und der externen CSpinEdit::HighlightLimit() Methode für das Hervorheben (Aufblitzen) des Textes in dem Control, sobald das Minimum oder das Maximum erreicht ist, beginnen.

Am Anfang der CSpinEdit::SetValue() Methode, können wir die Schrittweite für das Verändern des Wertes einstellen. Anschließend werden Überprüfungen für das Überschreiten der Limits (Maximum/Minimum) vorgenommen. Falls die Limits überschritten werden, dann wird ein Wert entsprechen dieser Überprüfung gesetzt und die CSpinEdit::HighlightLimit() Methode für das Hervorheben des Textes wird aufgerufen. Falls sich nach diesen Überprüfungen der Wert im Vergleich zu dem Wert, welcher zuvor gespeichert wurde, verändert hat, dann wird der alte Wert mit dem neuen überschrieben.

Die CSpinEdit::HighlightLimit() Methode ist recht einfach. Zunächst wird die Farbe für das Hervorheben gesetzt. Standardmäßig wird hier Rot verwendet, aber der User kann natürlich eine eigene Farbe wählen. Anschließend gibt es eine Pause von 100 Millisekunden. Dieses ist ausreichend, damit ein Farbwechsel auch bemerkt wird. Danach wird wieder die ursprüngliche Textfarbe gesetzt.

Nachfolgend nun der Programmcode der beschriebenen Methoden: 

class CSpinEdit : public CElement
  {
private:
   //--- Aktueller Wert des Controls
   double            m_edit_value;
   //---
public:
   //--- Rückgabe und setzen des Wertes
   double            GetValue(void)                           const { return(m_edit_value);               }
   bool              SetValue(const double value);
   //--- Blinken, wenn das Limit erreicht wird
   void              HighlightLimit(void);
  };
//+-----------------------------------------------------------------+
//| Überprüfung des aktuellen Wertes                                |
//+-----------------------------------------------------------------+
bool CSpinEdit::SetValue(double value)
  {
//--- Für die Einstellungen
   double corrected_value =0.0;
//--- Einstellung unter Berücksichtigung der Schrittweite
   corrected_value=::MathRound(value/m_step_value)*m_step_value;
//--- Überprüfung auf Minimum/Maximum
   if(corrected_value<m_min_value)
     {
      //--- Setzen des minimalen Wertes
      corrected_value=m_min_value;
      //--- Setzen des Status auf "An"
      m_spin_dec.State(true);
      //--- Blinken, für den Hinweis auf ein erreichtes Limit
      HighlightLimit();
     }
   if(corrected_value>m_max_value)
     {
      //--- Setzen des maximalen Wertes
      corrected_value=m_max_value;
      //--- Setzen des Status auf "An"
      m_spin_inc.State(true);
      //--- Blinken, für den Hinweis auf ein erreichtes Limit
      HighlightLimit();
     }
//--- Falls sich der Wert geändert hat
   if(m_edit_value!=corrected_value)
     {
      m_edit_value=corrected_value;
      m_edit.Color(m_edit_text_color);
      return(true);
     }
//--- Wert ist unverändert
   return(false);
  }
//+-----------------------------------------------------------------+
//| Hervorheben des Limits                                          |
//+-----------------------------------------------------------------+
void CSpinEdit::HighlightLimit(void)
  {
//--- Temporäre Veränderung der Textfarbe
   m_edit.Color(m_edit_text_color_highlight);
//--- Aktualisierung
   ::ChartRedraw();
//--- Pause bis zur Rückkehr zur alten Farbe
   ::Sleep(100);
//--- Zur vorherigen Textfarbe zurückkehren
   m_edit.Color(m_edit_text_color);
  }

Die CSpinEdit::SetValue() Methode ist nur dafür gedacht, den Wert neu einzustellen, falls ein Limit erreicht wurde. Die CSpinEdit:: ChangeValue() Methode wird für die Veränderung des Wertes in dem Control benötigt:

class CSpinEdit : public CElement
  {
private:
   //--- Verändern des Wertes in dem Control
   void              ChangeValue(const double value);
  };
//+-----------------------------------------------------------------+
//| Verändern des Wertes in dem Edit                                |
//+-----------------------------------------------------------------+
void CSpinEdit::ChangeValue(const double value)
  {
//--- Überprüfen, Einstellen und Abspeichern des neuen Wertes
   SetValue(value);
//--- In dem Edit den neuen Wert setzen
   m_edit.Description(::DoubleToString(GetValue(),m_digits));
  }

Ähnlich wie bei den anderen Elementen, benötigen wir eine Methode für das Verwalten der Verfügbarkeit des Edit-Controls, so wie es in dem nachfolgenden Code gezeigt wird:

class CSpinEdit : public CElement
  {
private:
   //--- Checkbox Status (Verfügbar/gesperrt)
   bool              m_spin_edit_state;
   //---
public:
   //--- Rückgabe/ setzen Des Status der Verfügbarkeit des Edit
   bool              SpinEditState(void)                      const { return(m_spin_edit_state);          }
   void              SpinEditState(const bool state);
  };
//+-----------------------------------------------------------------+
//| Festlegen des Status des Controls                               |
//+-----------------------------------------------------------------+
void CSpinEdit::SpinEditState(const bool state)
  {
   m_spin_edit_state=state;
//--- Farbe des Text Labels
   m_label.Color((state)? m_label_color : m_label_color_locked);
//--- Farbe des Edit
   m_edit.Color((state)? m_edit_text_color : m_edit_text_color_locked);
   m_edit.BackColor((state)? m_edit_color : m_edit_color_locked);
   m_edit.BorderColor((state)? m_edit_border_color : m_edit_border_color_locked);
//--- Icons der Schalter
   m_spin_inc.BmpFileOn((state)? "::"+m_inc_bmp_file_on : "::"+m_inc_bmp_file_locked);
   m_spin_dec.BmpFileOn((state)? "::"+m_dec_bmp_file_on : "::"+m_dec_bmp_file_locked);
//--- Setzen des aktuellen Status
   if(!m_spin_edit_state)
     {
      //--- Prioritäten
      m_edit.Z_Order(-1);
      m_spin_inc.Z_Order(-1);
      m_spin_dec.Z_Order(-1);
      //--- Edit In "nur lesen"-Modus
      m_edit.ReadOnly(true);
     }
   else
     {
      //--- Prioritäten
      m_edit.Z_Order(m_edit_zorder);
      m_spin_inc.Z_Order(m_spin_zorder);
      m_spin_dec.Z_Order(m_spin_zorder);
      //--- Das Edit-Control im "Edit"-Modus
      m_edit.ReadOnly(false);
     }
  }

Jetzt werden wir Methoden für die Verwaltung der Control-Events betrachten: Ein Klick auf das Textlabel wird ein Benutzerdefiniertes Event generieren mit (1) dem ON_CLICK_LABEL Bezeichner, (2) dem Control-Bezeichner, (3) dem Index des Controlsand (4) der Beschreibung des Text-Labels. Der Modus für das Zurücksetzen des Wertes auf den Minimum-Wert, wurde zuvor schon besprochen. Dieser Modus ist standardmäßig deaktiviert (false). Er kann über die CSpinEdit::ResetMode() Methode aktiviert werden. Dafür muss ihr lediglich das true Argument übergeben werden. Falls dieser Modus aktiviert ist, dann führt ein Klick auf das Text-Label zum Aufruf der Methode für das Setzen des minimalen Wertes.

Der Programmcode der CSpinEdit::OnClickLabel() Methode für das Verarbeiten eines Klicks auf das Textlabel, wird nachfolgend nun gezeigt:

class CSpinEdit : public CElement
  {
private:
   //--- Verarbeiten eines Klicks auf das Text Label
   bool              OnClickLabel(const string clicked_object);
  };
//+-----------------------------------------------------------------+
//| Klick auf ein Element Label                                     |
//+-----------------------------------------------------------------+
bool CSpinEdit::OnClickLabel(const string clicked_object)
  {
//--- Abbrechen, falls die Namen unterschiedlich sind
   if(m_area.Name()!=clicked_object)
      return(false);
//--- Falls der Modus für das Zurücksetzen des Wertes aktiviert ist
   if(m_reset_mode)
     {
      //--- Setzen des minimalen Wertes
      ChangeValue(MinValue());
     }
//--- Eine Nachricht darüber senden
   ::EventChartCustom(m_chart_id,ON_CLICK_LABEL,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }

Der Benutzer kann den Wert in dem Control manuell eingeben oder die Tasten für das Erhöhen und Verringern verwenden. Wir brauchen jetzt neue Bezeichner für benutzerdefinierte Events. Fügen Sie diese der Defines.mqh Datei hinzu:

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#define ON_END_EDIT               (18) // Final editing of the value in the edit
#define ON_CLICK_INC              (19) // Change the counter up
#define ON_CLICK_DEC              (20) // Change the counter down

Um die manuelle Eingabe eines neuen Wertes bearbeiten zu können, schreiben wir die CSpinEdit::OnEndEdit() Methode. Sie wird in dem CSpinEdit::OnEvent() gemeinsamen Eventhandler für das Empfangen eines Events mit dem CHARTEVENT_OBJECT_ENDEDIT Bezeichner aufgerufen. Wenn sich die Notwendigkeit ergibt, kann der neue Wert eingestellt werden. Am Ende der Methode wird ein benutzerdefinierter Event generiert mit (1) dem ON_END_EDIT Event-Bezeichner, (2) dem Element-Bezeichner, (3) dem Element-Index und (4) der Beschreibung des Text-Labels. 

class CSpinEdit : public CElement
  {
private:
   //--- Verarbeiten der manuellen Eingabe eines Wertes
   bool              OnEndEdit(const string edited_object);
  };
//+-----------------------------------------------------------------+
//| Verarbeiten der manuellen Eingabe eines Wertes                  |
//+-----------------------------------------------------------------+
bool CSpinEdit::OnEndEdit(const string edited_object)
  {
//--- Abbrechen, falls die Namen unterschiedlich sind
   if(m_edit.Name()!=edited_object)
      return(false);
//--- Abfrage des eingegebenen Wertes
   double entered_value=::StringToDouble(m_edit.Description());
//--- Überprüfen, Einstellen und Abspeichern des neuen Wertes
   ChangeValue(entered_value);
//--- Eine Nachricht darüber senden
   ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }

Für die Verarbeitung eines Klicks auf die Inkrement- und Dekrement-Buttons müssen wir zwei separate Methoden entwerfen: CSpinEdit::OnClickSpinInc() und CSpinEdit::OnClickSpinDec(). Diese sind recht simpel. Nachdem auf ein grafisches Objekt geklickt wurde, gibt es eine Überprüfung, ob es sich bei dem Namen um einen unserer Buttons handelt. Anschließend fragen wir den aktuellen Wert ab und erhöhen oder verringern ihn um die gewünschte Schrittweite. Am Ende der Methode wird ein benutzerdefiniertes Event mit (1) dem ON_CLICK_INC/ON_CLICK_DEC Event-Bezeichner, (2) dem Element-Bezeichner, (3) dem Element-Index und (4) der Beschreibung des Text-Labels generiert.

class CSpinEdit : public CElement
  {
private:
   //--- Arbeiten eines Button-Klick Events
   bool              OnClickSpinInc(const string clicked_object);
   bool              OnClickSpinDec(const string clicked_object);
  };
//+-----------------------------------------------------------------+
//| Klick auf Inkrement                                             |
//+-----------------------------------------------------------------+
bool CSpinEdit::OnClickSpinInc(const string clicked_object)
  {
//--- Abbrechen, falls die Namen unterschiedlich sind
   if(m_spin_inc.Name()!=clicked_object)
      return(false);
//--- Abfrage des aktuellen Wertes
   double value=GetValue();
//--- Erhöhung um einen Schritt und anschließende Überprüfung auf Überschreitung des Limits
   ChangeValue(value+m_step_value);
//--- Setzen des Status auf "An"
   m_spin_inc.State(true);
//--- Eine Nachricht darüber senden
   ::EventChartCustom(m_chart_id,ON_CLICK_INC,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }
//+-----------------------------------------------------------------+
//| Klick auf den Decrement-Button                                  |
//+-----------------------------------------------------------------+
bool CSpinEdit::OnClickSpinDec(const string clicked_object)
  {
//--- Abbrechen, falls die Namen unterschiedlich sind
   if(m_spin_dec.Name()!=clicked_object)
      return(false);
//--- Abfrage des aktuellen Wertes
   double value=GetValue();
//--- Verringern um einen Schritt und anschließende Überprüfung auf Überschreitung des Limits
   ChangeValue(value-m_step_value);
//--- Setzen des Status auf "An"
   m_spin_dec.State(true);
//--- Eine Nachricht darüber senden
   ::EventChartCustom(m_chart_id,ON_CLICK_DEC,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }

Wie nachfolgend gezeigt, müssen alle diese Methoden in der Hauptmethode für das Verarbeiten von Events aufgerufen werden. Der Zugriff auf den Körper der Events-Verarbeitungsmethoden, wird über die aktuelle Verfügbarkeit des Controls gesteuert.

//+------------------------------------------------------------------+
//| Event handling                                                   |
//+------------------------------------------------------------------+
void CSpinEdit::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten eines Klicks mit der linken Maustaste auf ein Objekt
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Verlassen, falls das Control gesperrt ist
      if(!m_spin_edit_state)
         return;
      //--- Verarbeiten eines Klicks auf das Text Label
      if(OnClickLabel(sparam))
         return;
      //--- Arbeiten eines Button-Klick Events
      if(OnClickSpinInc(sparam))
         return;
      if(OnClickSpinDec(sparam))
         return;
      //---
      return;
     }
//--- Verarbeiten des "Value change" Events (Wert hat sich geändert)
   if(id==CHARTEVENT_OBJECT_ENDEDIT)
     {
      //--- Verlassen, falls das Control gesperrt ist
      if(!m_spin_edit_state)
         return;
      //--- Verarbeiten der Eingabe des Wertes
      if(OnEndEdit(sparam))
         return;
     }
  }

Für die schnelle Veränderung des Wertes, wenn die linke Maustaste über einen der Buttons gedrückt und gehalten wird, erzeugen wir die CSpinEdit::FastSwitching() Methode, die über den Timer des Controls aufgerufen wird. Wir haben diese Methode schon besprochen, als wir die CListView Klasse für die Erzeugung einer ListView mit Scrollbar entwickelt haben. So wie dort die Methode für das Scrollen durch eine Liste verwendet wurde, wird sie hier für das Erhöhen und Verringern der Werte in dem Edit-Control verwendet. Der detaillierte Programmcode der CSpinEdit::FastSwitching() Methode wird nachfolgend gezeigt: 

class CSpinEdit : public CElement
  {
private:
   //--- Schnelles Scrollen in der Werte in dem Edit
   void              FastSwitching(void);
  };
//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void CSpinEdit::OnEventTimer(void)
  {
//--- Falls es sich um ein drop-down-element handelt
   if(CElement::IsDropdown())
     {
      ChangeObjectsColor();
      FastSwitching();
     }
   else
     {
      //--- Protokolliere die Veränderung der Farbe und der schnell scrollenden Werte 
      //    if the form is not blocked
      if(!m_wnd.IsLocked())
        {
         ChangeObjectsColor();
         FastSwitching();
        }
     }
  }
//+------------------------------------------------------------------+
//| Schnelle Veränderung der Werte in dem Edit                       |
//+------------------------------------------------------------------+
void CSpinEdit::FastSwitching(void)
  {
//--- Abbrechen, falls sich der Fokus nicht auf diesem Control befindet
   if(!CElement::MouseFocus())
      return;
//--- Den Zähler auf den anfänglichen Wert zurücksetzen, falls der Mousebutton losgelassen wird
   if(!m_mouse_state)
      m_timer_counter=SPIN_DELAY_MSC;
//--- Falls die Maustaste gedrückt wird
   else
     {
      //--- Erhöhen des Zählers um den angegebenen Schritt
      m_timer_counter+=TIMER_STEP_MSC;
      //--- Verlassen, falls der kleiner als Null ist
      if(m_timer_counter<0)
         return;
      //--- Abfrage des aktuellen Wertes in dem Control
      double current_value=::StringToDouble(m_edit.Description());
      //--- Falls erhöhen 
      if(m_spin_inc.State())
         SetValue(current_value+m_step_value);
      //--- Falls verringert
      else if(m_spin_dec.State())
         SetValue(current_value-m_step_value);
      //--- Verändere den Wert, falls der Button weiterhin gedrückt ist
      if(m_spin_inc.State() || m_spin_dec.State())
         m_edit.Description(::DoubleToString(GetValue(),m_digits));
     }
  }

 

 


Test des Edit-Control

Alle Methoden für das Edit-Control wurden nun implementiert. Lassen Sie es uns nun in dem Programm, welches wir zuvor schon verwendet haben, testen. In der CProgram Benutzerdefinierten Klasse der Anwendung erzeugen wie eine Instanz der CSpinEdit Klasse und deklarieren Sie eine Methode für die Erzeugung des Edit-Controls.

//+------------------------------------------------------------------+
//| Kasse für das erzeugende Anwendung                               |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
   //--- Edits
   CSpinEdit         m_spin_edit1;
   //---
private:
   //--- Edits
#define SPINEDIT1_GAP_X       (150)
#define SPINEDIT1_GAP_Y       (75)
   bool              CreateSpinEdit1(const string text);
  };

Hier ist ebenfalls die erste Checkbox für die Verwaltung der Verfügbarkeit unseres Controls verantwortlich, genauso wie es auch mit der zweiten Checkbox geschieht. Somit hängt die Verfügbarkeit von dem Status der ersten Checkbox ab, wie es auch in den nachfolgenden Programmcode gezeigt ist.

//+------------------------------------------------------------------+
//| Erzeugt Edit 1                                                   |
//+------------------------------------------------------------------+
bool CProgram::CreateSpinEdit1(string text)
  {
//--- Abspeichern des Fenster-Pointers
   m_spin_edit1.WindowPointer(m_window1);
//--- Koordinaten
   int x=m_window1.X()+SPINEDIT1_GAP_X;
   int y=m_window1.Y()+SPINEDIT1_GAP_Y;
//--- Wert
   double v=(m_spin_edit1.GetValue()==WRONG_VALUE) ? 4 : m_spin_edit1.GetValue();
//--- Festlegen der Eigenschaften vor der Erzeugung
   m_spin_edit1.XSize(150);
   m_spin_edit1.YSize(18);
   m_spin_edit1.EditXSize(76);
   m_spin_edit1.MaxValue(1000);
   m_spin_edit1.MinValue(-1000);
   m_spin_edit1.StepValue(1);
   m_spin_edit1.SetDigits(0);
   m_spin_edit1.SetValue(v);
   m_spin_edit1.ResetMode(true);
   m_spin_edit1.AreaColor(clrWhiteSmoke);
   m_spin_edit1.LabelColor(clrBlack);
   m_spin_edit1.LabelColorLocked(clrSilver);
   m_spin_edit1.EditColorLocked(clrWhiteSmoke);
   m_spin_edit1.EditTextColor(clrBlack);
   m_spin_edit1.EditTextColorLocked(clrSilver);
   m_spin_edit1.EditBorderColor(clrSilver);
   m_spin_edit1.EditBorderColorLocked(clrSilver);
//--- Erzeugung des Controls
   if(!m_spin_edit1.CreateSpinEdit(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- Die Verfügbarkeit hängt von dem aktuellen Status der ersten Checkbox ab
   m_spin_edit1.SpinEditState(m_checkbox1.CheckButtonState());
//--- Fügen Sie das Objekt zu dem gemeinsamen Array von Objektgruppen hinzu
   CWndContainer::AddToElementsArray(0,m_spin_edit1);
   return(true);
  }

Wie auch bei den anderen Controls, muss die CProgram::CreateSpinEdit1() Methode für die Erzeugung des Controls in der Hauptmethode für die Erzeugung des grafischen Interfaces aufgerufen werden. Nachfolgend ist die abgekürzte Version der Methode:

//+------------------------------------------------------------------+
//| Erzeugt das Trading-Panel                                        |
//+------------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Erzeugen des Formulars 1 für die Controls
//---Erzeugung der Controls:
//    Hauptmenü
//--- Kontextmenüs
//--- Erzeugen der Statusbar
//--- Checkboxen
//--- Edits
   if(!CreateSpinEdit1("Spin Edit 1:"))
      return(false);
//--- Neuzeichnen des Charts
   m_chart.Redraw();
   return(true);
  }

In dem CProgram::OnEvent() Eventhandler fügen wir den Programmcode für den Test der Events des Edit-Controls ein und geben zudem an, dass das erste Edit von dem Status der ersten Checkbox abhängt.

//+-----------------------------------------------------------------+
//| Eventhandler                                                    |
//+-----------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Das Event für ein Klick auf das Textlabel
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Falls es sich um einen Klick auf die erste Checkbox handelt
      if(lparam==m_checkbox1.Id())
        {
         //--- Festlegen des Status der zweiten Checkbox und des Edit-Controls
         m_checkbox2.CheckBoxState(m_checkbox1.CheckButtonState());
         m_spin_edit1.SpinEditState(m_checkbox1.CheckButtonState());
        }
     }
//--- Das Event für das Abschließen einer Eingabe
   if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
//--- Die Events der Buttons
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC || id==CHARTEVENT_CUSTOM+ON_CLICK_DEC)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
  }

Kompilieren Sie dieses Programm und laden Sie es auf einen Chart. Die Anwendung sollte nun so aussehen, wie sie es in dem nachfolgenden Screenshot sehen können:

Abbildung 4. Test des Edit-Controls

Abbildung 4. Test des Edit-Controls

 


Andere Controls mit Checkboxen

Am Anfang des Artikels haben wir darüber gesprochen, dass wir neben der Checkbox und den Edit-Control, auch ein Edit-Control mit Checkbox und die Checkcombobox besprechen wollen. Ein Edit mit Checkbox ist eine erweiterte Version der CSpinEdit Klasse, die mit loyal und Methoden der CCheckBox Klasse erweitert wird, die wir schon in diesem Artikel betrachtet haben. 

 Abbildung 5. Komponenten des Edit-Controls mit Checkbox-Control.

Abbildung 5. Komponenten des Edit-Controls mit Checkbox-Control.

Die Checkcombobox ist eine Kombination aus den CComboBox und CCheckBox Klassen:

 Abbildung 6. Komponenten des Check-Combobox-Controls.

Abbildung 6. Komponenten des Check-Combobox-Controls.

Sie finden die Implementationen der CCheckBoxEdit (Edit mit Checkbox) und CCheckComboBox (Check-Combobox) in den Dateien, die diesem Artikel beigefügt sind. Da das Control vom Typ CCheckComboBox Ein Dropdown List View beinhaltet, müssen in der WndContainer.mqh noch Ergänzungen vorgenommen werden, wie es auch bei anderen Elementen mit einer Drop-Down-Liste geschehen ist. In diesem Fall, muss der Pointer der DropDown-List-View in das m_drop_lists[] Pointer-Array. Eine genau Beschreibung, wie dieses gelöst werden kann, finden Sie in dem Artikel Graphical Interfaces V: Das Combobox Control (Kapitel 3).

Lassen Sie uns beispielhaft dieser Test-Anwendung diese Controls hinzufügen, damit Sie sehen können, wie sie funktionieren. Lassen Sie uns zwei Checkboxen vom Typ CCheckBox und eine vom Typ CCheckBoxEdit und CCheckComboBox hinzufügen. Die Verfügbarkeit des controles vom Typ CCheckBoxEdit hängt von dem Status der dritten Checkbox ab und die Verfügbarkeit des Controls vom Typ CCheckComboBox wird über den Status der vierten Combobox definiert.

 Fig. 7. Test der Controls mit gemischten Typen.

Fig. 7. Test der Controls mit gemischten Typen.

 


Schlussfolgerung

In diesem Artikel haben wir die weitverbreiteten Controls: checkbox, edit, edit with checkbox and check combobox entwickelt. In dem zweiten Kapitel werden wir den Slider und den Doppel-Slider entwickeln. 

Sie können das gesamte Material des sechsten 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 (Kapitel) des sechten Teils: