English Русский 中文 Español 日本語 Português
Grafische Interfaces IX: Das Farbauswahl Control (Kapitel 1)

Grafische Interfaces IX: Das Farbauswahl Control (Kapitel 1)

MetaTrader 5Beispiele | 14 September 2016, 17:32
665 0
Anatoli Kazharski
Anatoli Kazharski

Inhalt

 

Einleitung

Bitte lesen Sie dazu auch den ersten Artikel Grafische Interfaces I: Vorbereiten der Bibliotheks-Struktur (Kapitel 1), damit Sie die Anwendung dieser Bibliothek besser verstehen können. Am Ende dieses Artikels finden Sie eine Liste aller Kapitel mit den dazugehörigen Links und Sie können die vollständige Version dieser Bibliothek herunterladen. Die Dateien müssen in den gleichen Verzeichnissen untergebracht werden, so, wie Sie auch in dem Archiv abgelegt sind.

Der IX Teil Dieser Serie beschreibt die folgenden Elemente (Controls) und Interfaces:

1. Erstes Kapitel:

  • Farbauswahl-Control (CColorPicker Klasse).
  • Farb-Button-Control (CColorButton Klasse).

2. Zweites Kapitel:

  • Fortschrittsanzeige-Control (CProgressBar Klasse).
  • Linien-Graph-Control (CLineGraph Klasse).

Es werden umfassende Beispiele für alle oben genannten Controls aufgezeigt, so, wie sie auch in den benutzerdefinierten Anwendungen verwendet werden können.

 

Das Farbauswahl-Control

Eine Farbpalette findet man in sehr vielen Anwendungen, wo es die Möglichkeit geben soll, einem Objekt eine Farbe zuweisen zu können. In den Metatrader Trading-Terminals kann eine Farbpalette dazu verwendet werden, um ganz einfach die Farben von Controls innerhalb einer MQL Anwendung verändern zu können. Wenn Sie zum Beispiel die Möglichkeit bieten wollen, die grafische Oberfläche farbig anzupassen, dann wäre es sehr unbequem, dieses ohne ein solches Tool durchführen zu müssen.

Eine Farbauswahl-Palette ist ein sehr komplexes Control, welches aus verschiedenen Komponenten besteht. Außer der tatsächlichen Palette besitzt dieses Control auch noch andere Objekte und weitere Gruppen von Controls. Die Komponenten dieses Controls werden nachfolgend aufgelistet:

  1. Hintergrund
  2. Die Farbpaletten, die ein spezielles Farbmodell anzeigt
  3. Marker für die festgelegte Farbe
  4. Marker für die ausgewählte Farbe
  5. Marker für die Farbe, wenn sich der Mauszeiger über einem Objekt befindet
  6. Eine Gruppe von Radiobuttons mit Edit-Boxen für die manuelle Konfiguration der Farbkomponenten.
  7. Eine Button um die Auswahl einer Farbe abzubrechen
  8. Ein Button um die angegebene Farbe des zweiten Markers zu fixieren.

 

Abbildung 1. Komponenten des Controls für die Farbauswahl.

Der oben dargestellte Screenshot zeigt eine Gruppe von Radiobuttons, die in drei Untergruppen mit je drei Radiobuttons aufgeteilt ist. Jede Untergruppe stellt ein Farbmodell dar, und jeder Radiobutton ist eine Komponente dieses Modells (Koordinate des Farbbereichs). Die folgende Liste zeigt die Abkürzungen aller Farb-Modelle, die in der Bibliothek verwendet werden.

1. HSL Farbmodell:

  • H - Farbton. Werte von 0 bis 360
  • S - Sättigung. Werte von 0 bis 100.
  • L - Helligkeit (Lightness). Werte von 0 bis 100.

2. RGB Farbmodell:

  • R - Rot. Werte von 0 bis 255.
  • G - Grün. Werte von 0 bis 255.
  • B - Blau. Werte von 0 bis 255.

3. Lab Farbmodell:

  • L - Helligkeit (luminance). Werte von 0 bis 100.
  • a – Die erste chromatische Koordinate, die die Farbe zwischen Grün und Lila definiert. Werte von 128 bis 127.
  • b – Die zweite chromatische Koordinate, die die Farbe zwischen Blau und Gelb definiert. Werte von 128 bis 127.

Wir schauen uns nun für die Erzeugung einer Farbpalette die CColorPicker Klasse an.

 

Die Entwicklung der CColorPicker Klasse

Wir erzeugen die ColorPicker.mqh Datei in dem gleichen Verzeichnis in welchem auch alle anderen Controls abgespeichert sind (<data folder>\MQLX\Include\EasyAndFastGUI\Controls). In dieser Datei erzeugen wir die CColorPicker Klasse mit den Standardmethoden und Variablen, wie ist das nachfolgende Listing zeigt:

//+----------------------------------------------------------------
//|                                                  ColorPicker.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#include "Element.mqh"
#include "Window.mqh"
//+----------------------------------------------------------------
//| Klasse für die Erzeugung des Controls für die Farbauswahl                                  |
//+----------------------------------------------------------------
class CColorPicker : public CElement
  {
private:
   //--- Pointer zu dem Formular, zu welchem das Control hinzugefügt wurde
   CWindow          *m_wnd;
   //---
public:
                     CColorPicker(void);
                    ~CColorPicker(void);
   //---
public:
   //--- Abspeichern des Pointers der Form
   void              WindowPointer(CWindow &object)           { m_wnd=::GetPointer(object);            }
   //---
public:
   //--- Der Eventhandler für Chart-Events
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Timer
   virtual void      OnEventTimer(void);
   //--- Verschieben eines Controls
   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) {}
  };

Die folgenden Eigenschaften sollten für das festlegen eines grafischen Objektes verfügbar sein:

  • Control-Bereichsfarbe
  • Die Rahmenfarbe des Bereiches des Controls
  • Die Rahmenfarbe der Farbpalette und Marker

Die Eigenschaften von den grafischen Objekten anderer Controls können verändert werden, sobald wir die Pointer erhalten haben. 

class CColorPicker : public CElement
  {
private:
   //--- Farbe des (1) Bereiches und (2) des Rahmens
   color             m_area_color;
   color             m_area_border_color;
   //--- Farbe des Rahmens der Palette
   color             m_palette_border_color;
   //---
public:
   //--- Setzen der Farbe (1) des Bereiches und (2) des Rahmens, (3) des Rahmens der Palette
   void              AreaBackColor(const color clr)           { m_area_color=clr;                      }
   void              AreaBorderColor(const color clr)         { m_area_border_color=clr;               }
   void              PaletteBorderColor(const color clr)      { m_palette_border_color=clr;            }
  };

Da wir in diesem Control auch andere Controls als Komponenten der Farbpalette benutzen, müssen wir die Dateien mit den entsprechenden Klassen dieser Controls der ColorPicker.mqh Datei hinzufügen. Für die Erzeugung der Farbpalette, benötigen wir 17 private Methoden und eine public Methode.

//+----------------------------------------------------------------
//|                                                  ColorPicker.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#include "Element.mqh"
#include "Window.mqh"
#include "SpinEdit.mqh"
#include "SimpleButton.mqh"
#include "RadioButtons.mqh"
//+----------------------------------------------------------------
//| Klasse für die Erzeugung der Farbpalette                |
//+----------------------------------------------------------------
class CColorPicker : public CElement
  {
private:
   //--- Objekte für die Erzeugung des Controls
   CRectLabel        m_area;
   CRectCanvas       m_canvas;
   CRectLabel        m_current;
   CRectLabel        m_picked;
   CRectLabel        m_hover;
   //---
   CRadioButtons     m_radio_buttons;
   CSpinEdit         m_hsl_h_edit;
   CSpinEdit         m_hsl_s_edit;
   CSpinEdit         m_hsl_l_edit;
   //---
   CSpinEdit         m_rgb_r_edit;
   CSpinEdit         m_rgb_g_edit;
   CSpinEdit         m_rgb_b_edit;
   //---
   CSpinEdit         m_lab_l_edit;
   CSpinEdit         m_lab_a_edit;
   CSpinEdit         m_lab_b_edit;
   //---
   CSimpleButton     m_button_ok;
   CSimpleButton     m_button_cancel;
   //---
public:
   //--- Methoden für die Erzeugung des Controls
   bool              CreateColorPicker(const long chart_id,const int subwin,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreatePalette(void);
   bool              CreateCurrentSample(void);
   bool              CreatePickedSample(void);
   bool              CreateHoverSample(void);
   bool              CreateRadioButtons(void);
   bool              CreateHslHEdit(void);
   bool              CreateHslSEdit(void);
   bool              CreateHslLEdit(void);
   bool              CreateRgbREdit(void);
   bool              CreateRgbGEdit(void);
   bool              CreateRgbBEdit(void);
   bool              CreateLabLEdit(void);
   bool              CreateLabAEdit(void);
   bool              CreateLabBEdit(void);
   bool              CreateButtonOK(const string text);
   bool              CreateButtonCancel(const string text);
  };

Wenn Sie einen der Radio-Buttons neben der Farbpalette ändern, dann werden zweidimensionale Schnitte von Farbflächen, in Übereinstimmung mit den angegebenen Werten, einer ausgewählten Komponente angezeigt. Mit anderen Worten, für das Zeichnen eines Schnitts müssen wir zunächst eine Berechnung in Bezug auf den aktuellen Wert der Komponente durchführen. Hierfür schreiben wir drei separate Methoden für jedes Farbmodell. Der Index des ausgewählten Radiobuttons wird allen diesen Methoden übergeben(selected index).

Für den Farbwechsel verwenden wir Methoden der Klasse CColors die in der Basisklasse der Controls deklariert ist.(CElement). Es gibt aber in der CColors Klasse keine passende Methode um eine Konvertierung von dem RGB Format zu dem Lab-Format durchzuführen. Daher müssen wir an der Stelle, wo eine Konvertierung von RGB->Lab benötigt wird, eine doppelte Korrektur über das Master-FarbmodellXYZ hinzufügen: RGB->XYZ->Lab. Für die Berechnung und das Abspeichern der Werte der Komponenten aller Farbmodelle innerhalb der CColorPicker Klasse, benötigen wir die Deklaration von weiteren Variablen.

class CColorPicker : public CElement
  {
private:
   //--- Werte der Komponenten in den unterschiedlichen Farbmodellen:
   //    HSL
   double            m_hsl_h;
   double            m_hsl_s;
   double            m_hsl_l;
   //--- RGB
   double            m_rgb_r;
   double            m_rgb_g;
   double            m_rgb_b;
   //--- Lab
   double            m_lab_l;
   double            m_lab_a;
   double            m_lab_b;
   //--- XYZ
   double            m_xyz_x;
   double            m_xyz_y;
   double            m_xyz_z;
   //---
private:
   //--- Zeichnen der Palette basierend auf dem HSL Farbmodell (0: H, 1: S, 2: L)
   void              DrawHSL(const int index);
   //--- Zeichnen der Palette basierend auf dem RGB-Farbmodell (3: R, 4: G, 5: B)
   void              DrawRGB(const int index);
   //--- Zeichnen der Palette basierend auf dem LAB Farbmodell (6: L, 7: a, 8: b)
   void              DrawLab(const int index);
  };

Wir zeigen hier beispielhaft nur den Programmcode von einer dieser Methoden CColorPicker::DrawHSL(), da der einzige Unterschied in der vorläufigen Berechnung vor der Änderung zu finden ist. Der Programmcode der anderen Methoden kann über die an diesen Artikel angehängten Dateien heruntergeladen werden. 

Die Berechnungen und das Zeichnen werden für jeden Pixel durchgeführt. Bitte beachten Sie, dass die Berechnungen relativ zu der Größe der Farbpalette durchgeführt werden. Zum Beispiel können sie unter Verwendung dieses Programmcodes auch ein ähnliches Control mit einer Farbpalette, die eine andere Form hat, erzeugen. (Sie muss nicht unbedingt ein Quadrat sein).

 Abbildung  2. Ein Beispiel einer Farbpalette mit der Größe von 500x255 Pixeln.

Abbildung 2. Ein Beispiel einer Farbpalette mit der Größe von 500x255 Pixeln. 


//+----------------------------------------------------------------
//| Zeichnen der HSL-Palette                                                |
//+----------------------------------------------------------------
void CColorPicker::DrawHSL(const int index)
  {
   switch(index)
     {
      //--- Hue (H) - Der Farbton mit Werten von 0 bis 360
      case 0 :
        {
         //--- Berechnung der H-Komponente
         m_hsl_h=m_hsl_h_edit.GetValue()/360.0;
         //---
         for(int ly=0; ly<m_canvas.YSize(); ly++)
           {
            //--- Berechnung der L-Komponente
            m_hsl_l=ly/(double)m_canvas.YSize();
            //---
            for(int lx=0; lx<m_canvas.XSize(); lx++)
              {
               //--- Berechnung der S-Komponente
               m_hsl_s=lx/(double)m_canvas.XSize();
               //--- Konvertierung von HSL zu RGB
               m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b);
               //--- Verbinden der Kanäle
               uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b);
               m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color);
              }
           }
         break;
        }
      //--- Sättigung(S) - Sättigung mit den Werten von 0 bis 100
      case 1 :
        {
         //--- Berechnung der S-Komponente
         m_hsl_s=m_hsl_s_edit.GetValue()/100.0;
         //---
         for(int ly=0; ly<m_canvas.YSize(); ly++)
           {
            //--- Berechnung der L-Komponente
            m_hsl_l=ly/(double)m_canvas.YSize();
            //---
            for(int lx=0; lx<m_canvas.XSize(); lx++)
              {
               //--- Berechnung der H-Komponente
               m_hsl_h=lx/(double)m_canvas.XSize();
               //--- Konvertierung von HSL zu RGB
               m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b);
               //--- Verbinden der Kanäle
               uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b);
               m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color);
              }
           }
         break;
        }
      //--- Helligkeit (Lightness) (L) - Helligkeit mit den Werten von 0 bis 100
      case 2 :
        {
         //--- Berechnung der L-Komponente
         m_hsl_l=m_hsl_l_edit.GetValue()/100.0;
         //---
         for(int ly=0; ly<m_canvas.YSize(); ly++)
           {
            //--- Berechnung der S-Komponente
            m_hsl_s=ly/(double)m_canvas.YSize();
            //---
            for(int lx=0; lx<m_canvas.XSize(); lx++)
              {
               //--- Berechnung der H-Komponente
               m_hsl_h=lx/(double)m_canvas.XSize();
               //--- Konvertierung von HSL zu RGB
               m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b);
               //--- Verbinden der Kanäle
               uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b);
               m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color);
              }
           }
         break;
        }
     }
  }

Um einen Rahmen um das Canvas der Farbpalette zeichnen zu können, schreiben wir die CColorPicker::DrawPaletteBorder() Methode: 

class CColorPicker : public CElement
  {
private:
   //--- Zeichnen des Rahmens der Platte
   void              DrawPaletteBorder(void);
  };
//+----------------------------------------------------------------
//| Zeichnen des Rahmens der Palette                                              |
//+----------------------------------------------------------------
void CColorPicker::DrawPaletteBorder(void)
  {
//--- Größe der Palette
   int x_size=m_canvas.XSize()-1;
   int y_size=m_canvas.YSize()-1;
//--- Zeichnen des Rahmens
   m_canvas.Line(0,0,x_size,0,m_palette_border_color);
   m_canvas.Line(0,y_size,x_size,y_size,m_palette_border_color);
   m_canvas.Line(0,0,0,y_size,m_palette_border_color);
   m_canvas.Line(x_size,0,x_size,y_size,m_palette_border_color);
  }

Alle oben aufgeführten Methoden werden in der Hauptmethode für das Zeichnen, der CColorPicker::DrawPalette() Methode aufgerufen.

class CColorPicker : public CElement
  {
private:
   //--- Zeichnen der Palette
   void              DrawPalette(const int index);
  };
//+----------------------------------------------------------------
//| Zeichnen der Palette                                                     |
//+----------------------------------------------------------------
void CColorPicker::DrawPalette(const int index)
  {
   switch(index)
     {
      //--- HSL (0: H, 1: S, 2: L)
      case 0 : case 1 : case 2 :
        {
         DrawHSL(index);
         break;
        }
      //--- RGB (3: R, 4: G, 5: B)
      case 3 : case 4 : case 5 :
        {
         DrawRGB(index);
         break;
        }
      //--- LAB (6: L, 7: a, 8: b)
      case 6 : case 7 : case 8 :
        {
         DrawLab(index);
         break;
        }
     }
//--- Zeichnen des Rahmens der Palette
   DrawPaletteBorder();
//--- Aktualisieren der Palette
   m_canvas.Update();
  }

Wenn eine Farbe aus der Palette ausgewählt wird oder eine zu konfigurierende Komponente in dem Control dargestellt wird, werden die Werte aller Edit-Boxen automatisch neu berechnet. Wir benötigen Methoden, die die Komponenten aller Farbmodelle eines Controls berechnen können unter Berücksichtigung des Controls, dessen Schnitt grade auf der Palette dargestellt wird. 

Zunächst brauchen wir Methoden für die Korrektur der RGB Komponenten und HSL Modelle, die in vielen anderen Methoden dieser Klasse benötigt werden:

class CColorPicker : public CElement
  {
private:
   //--- Korrektur der RGB Komponenten
   void              AdjustmentComponentRGB(void);
   //--- Korrektur der HSL Komponenten
   void              AdjustmentComponentHSL(void);
  };
//+----------------------------------------------------------------
//| Korrektur der RGB Komponenten                                        |
//+----------------------------------------------------------------
void CColorPicker::AdjustmentComponentRGB(void)
  {
   m_rgb_r=::fmin(::fmax(m_rgb_r,0),255);
   m_rgb_g=::fmin(::fmax(m_rgb_g,0),255);
   m_rgb_b=::fmin(::fmax(m_rgb_b,0),255);
  }
//+----------------------------------------------------------------
//| Korrektur der HSL Komponenten                                        |
//+----------------------------------------------------------------
void CColorPicker::AdjustmentComponentHSL(void)
  {
   m_hsl_h*=360;
   m_hsl_s*=100;
   m_hsl_l*=100;
  }

Nach der Berechnung aller Komponenten, müssen wir neue Werte in die Edit-Boxen schreiben. In einigen Fällen müssen wir (1) die Werte aller Komponenten, und manchmal die Werte (2) für alle außer der aktuell selektierten Komponente setzen. Für diese Situationen werden wir die CColorPicker::SetControls() Methode schreiben, die in zwei Modi arbeiten kann.

class CColorPicker : public CElement
  {
private:
   //--- Setzen der aktuellen Parameter in den Edit-Boxen
   void              SetControls(const int index,const bool fix_selected);
  };
//+----------------------------------------------------------------
//| Setzen der aktuellen Parameter in den Edit-Boxen                         |
//+----------------------------------------------------------------
void CColorPicker::SetControls(const int index,const bool fix_selected)
  {
//--- Falls ein Wert in einer Editbox des ausgewählten Radio-Buttons fixiert werden muss
   if(fix_selected)
     {
      //--- HSL components
      if(index!=0)
         m_hsl_h_edit.ChangeValue(m_hsl_h);
      if(index!=1)
         m_hsl_s_edit.ChangeValue(m_hsl_s);
      if(index!=2)
         m_hsl_l_edit.ChangeValue(m_hsl_l);
      //--- RGB Komponenten
      if(index!=3)
         m_rgb_r_edit.ChangeValue(m_rgb_r);
      if(index!=4)
         m_rgb_g_edit.ChangeValue(m_rgb_g);
      if(index!=5)
         m_rgb_b_edit.ChangeValue(m_rgb_b);
      //--- Lab Komponenten
      if(index!=6)
         m_lab_l_edit.ChangeValue(m_lab_l);
      if(index!=7)
         m_lab_a_edit.ChangeValue(m_lab_a);
      if(index!=8)
         m_lab_b_edit.ChangeValue(m_lab_b);
      return;
     }
//--- Falls es notwendig ist, alle Werte aller Edith Boxen von allen Farbmodellen zu korrigieren
   m_hsl_h_edit.ChangeValue(m_hsl_h);
   m_hsl_s_edit.ChangeValue(m_hsl_s);
   m_hsl_l_edit.ChangeValue(m_hsl_l);
//---
   m_rgb_r_edit.ChangeValue(m_rgb_r);
   m_rgb_g_edit.ChangeValue(m_rgb_g);
   m_rgb_b_edit.ChangeValue(m_rgb_b);
//---
   m_lab_l_edit.ChangeValue(m_lab_l);
   m_lab_a_edit.ChangeValue(m_lab_a);
   m_lab_b_edit.ChangeValue(m_lab_b);
  }

Für die Berechnung aller Komponenten aller Farbmodelle des Controls, dessen Schnitt gerade auf der Palette dargestellt wird, schreiben wir drei unterschiedliche Methoden: CColorPicker::SetHSL(), CColorPicker::SetRGB() und CColorPicker::SetLab(). Da sich diese Methoden sehr ähnlich sind, werden wir hier nur die — CColorPicker::SetRGB() Methode besprechen. Am Anfang der Methode, fragen wir die Werte der Edit-Boxen des RGB Modells ab. Die Werte werden dann nach HSLund Lab konvertiert. Am Ende rufen wir die CColorPicker::SetControls() Methode in dem Modus für das Setzen der Werte für alle Farbmodelle mit dem false Control. 

class CColorPicker : public CElement
  {
private:
   //--- Setzen der Parameter der Farbmodelle relativ zu (1) HSL, (2) RGB, (3) Lab
   void              SetHSL(void);
   void              SetRGB(void);
   void              SetLab(void);
  };
//+----------------------------------------------------------------
//| Setzen der Parameter der Farbmodelle relativ zu RGB               |
//+----------------------------------------------------------------
void CColorPicker::SetRGB(void)
  {
//--- Abfrage der aktuellen Werte der RGB Komponenten
   m_rgb_r=m_rgb_r_edit.GetValue();
   m_rgb_g=m_rgb_g_edit.GetValue();
   m_rgb_b=m_rgb_b_edit.GetValue();
//--- Konvertierung der RGB Komponenten zu HSL Komponenten
   m_clr.RGBtoHSL(m_rgb_r,m_rgb_g,m_rgb_b,m_hsl_h,m_hsl_s,m_hsl_l);
//--- Korrektur der HSL Komponenten
   AdjustmentComponentHSL();
//--- Konvertierung der RGB Komponenten zu LAB Komponenten
   m_clr.RGBtoXYZ(m_rgb_r,m_rgb_g,m_rgb_b,m_xyz_x,m_xyz_y,m_xyz_z);
   m_clr.XYZtoCIELab(m_xyz_x,m_xyz_y,m_xyz_z,m_lab_l,m_lab_a,m_lab_b);
//--- Setzen der aktuellen Parameter in den Edit-Boxen
   SetControls(0,false);
  }

Zum Schluss benötigen wir noch eine Hauptmethode, in welcher alle oben genannten Methoden für die Berechnung, das Zeichnen und das Setzen der Werte der Komponenten durchgeführt wird. Wir nennen sie CColorPicker::SetComponents(). Sie arbeitet auch in zwei Modi. Falls das fix_selected Argument gleich true ist, dann werden die Komponenten relativ zu der ausgewählten Farbe berechnet, und die Werte in der Editbox werden relativ zu dem ausgewählten Radiobutton der Komponente gesetzt. Wenn das fix_selected Argument gleich false ist, dann wird die Berechnung relativ zu dem ausgewählten Farbmodell durchgeführt. Nach den ganzen Berechnungen, wird die Farbpalette neu gezeichnet

class CColorPicker : public CElement
  {
private:
   //--- Berechnen und setzen der Farbkomponenten
   void              SetComponents(const int index,const bool fix_selected);
  };
//+----------------------------------------------------------------
//| Berechnen und setzen der Farbkomponenten                         |
//+----------------------------------------------------------------
void CColorPicker::SetComponents(const int index=0,const bool fix_selected=true)
  {
//--- Falls es gewünscht ist, die Farben relativ zu dem ausgewählten Radiobutton einer Komponente zu korrigieren
   if(fix_selected)
     {
      //--- Zerlegen der gewählten Farbe in RGB Komponenten
      m_rgb_r=m_clr.GetR(m_picked_color);
      m_rgb_g=m_clr.GetG(m_picked_color);
      m_rgb_b=m_clr.GetB(m_picked_color);
      //--- Konvertierung der RGB Komponenten zu HSL Komponenten
      m_clr.RGBtoHSL(m_rgb_r,m_rgb_g,m_rgb_b,m_hsl_h,m_hsl_s,m_hsl_l);
      //--- Korrektur der HSL Komponenten
      AdjustmentComponentHSL();
      //--- Konvertierung der RGB Komponenten zu LAB Komponenten
      m_clr.RGBtoXYZ(m_rgb_r,m_rgb_g,m_rgb_b,m_xyz_x,m_xyz_y,m_xyz_z);
      m_clr.XYZtoCIELab(m_xyz_x,m_xyz_y,m_xyz_z,m_lab_l,m_lab_a,m_lab_b);
      //--- Setzen der Farben in den Edit-Boxen
      SetControls(m_radio_buttons.SelectedButtonIndex(),true);
      return;
     }
//--- Festlegen der Parameter des Farbmodells
   switch(index)
     {
      case 0 : case 1 : case 2 :
         SetHSL();
         break;
      case 3 : case 4 : case 5 :
         SetRGB();
         break;
      case 6 : case 7 : case 8 :
         SetLab();
         break;
     }
//--- Zeichnen der Palette relativ zu dem ausgewählten Radiobutton
   DrawPalette(m_radio_buttons.SelectedButtonIndex());
  }

Um einem Marker Objekt die aktuell ausgewählte Farbe der Farbpalette zuweisen zu können, schreiben wir die, CColorPicker::CurrentColor() Methode. Im weiteren Verlauf des Artikels werden wir zeigen wo sie verwendet wird. 

class CColorPicker : public CElement
  {
public:
   //--- Setzen einer vom Anwender ausgewählten Farbe aus der Palette
   void              CurrentColor(const color clr);
  };
//+----------------------------------------------------------------
//| Setzen der aktuellen Farbe                                            |
//+----------------------------------------------------------------
void CColorPicker::CurrentColor(const color clr)
  {
   m_hover_color=clr;
   m_hover.Color(clr);
   m_hover.BackColor(clr);
   m_hover.Tooltip(::ColorToString(clr));
//---
   m_picked_color=clr;
   m_picked.Color(clr);
   m_picked.BackColor(clr);
   m_picked.Tooltip(::ColorToString(clr));
//---
   m_current_color=clr;
   m_current.BackColor(clr);
   m_current.Tooltip(::ColorToString(clr));
  }

Alle Methoden für die Berechnungen sind nun fertig. Wir werden jetzt mit den Methoden für die Verarbeitung von Events fortfahren.

 

Methoden für die Verarbeitung der Events des Controls

Die folgenden Methoden werden für die Verarbeitung von Events und das Verwalten der Farbpalette benötigt:

  • Die CColorPicker::OnHoverColor() Methode — Abfrage der Farbe (über der Palette) am Mauszeiger. Das Programm verlässt diese Methode, falls sich der Mauszeiger außerhalb des Bereiches der Palette befindet. Wenn sich der Mauszeiger über der Palette befindet, dann definieren wir die Koordinaten und fragen die Farbe an der Position des Mauszeigers ab. Anschließend wird die ausgewählte Farbe dem selektierten Marker zugewiesen und mit der ColorToString() Methode, bekommen die grafischen Objekte des Markers und der Farbpalette einen Tooltip – einen String mit der Farbe in dem RGB-Format. 
//+----------------------------------------------------------------
//| Abfrage der Farbe am Mauszeiger                                    |
//+----------------------------------------------------------------
bool CColorPicker::OnHoverColor(const int x,const int y)
  {
//--- Abbrechen, falls ich den Mauszeiger nicht über der Palette befindet
   if(!m_canvas.MouseFocus())
      return(false);
//--- Definition der Farbe der Palette am Mauszeiger
   int lx =x-m_canvas.X();
   int ly =y-m_canvas.Y();
   m_hover_color=(color)::ColorToARGB(m_canvas.PixelGet(lx,ly),0);
//--- Setzen der Farbe und des Tooltips am ausgewählten Marker 
   m_hover.Color(m_hover_color);
   m_hover.BackColor(m_hover_color);
   m_hover.Tooltip(::ColorToString(m_hover_color));
//--- Setzen des Tooltips für die Palette
   m_canvas.Tooltip(::ColorToString(m_hover_color));
   return(true);
  }

  • Die CColorPicker::OnClickPalette() Methode — Verarbeitet einen Klick auf die Farbpalette. Zu Beginn der Methode wird der Objektname überprüft. Falls ein Klick auf der Palette stattgefunden hat, dann wird die Farbe am Mauszeiger und ein Tooltip für den ausgewählten Marker gespeichert und gesetzt. Am Ende wird die CColorPicker::SetComponents() Methode für die Berechnung und Einstellung der Komponenten der Farbmodelle, relativ zu dem ausgewählten Radiobutton der Komponente, aufgerufen.
//+----------------------------------------------------------------
//| Verarbeiten eines Klicks auf die Farbpalette                                 |
//+----------------------------------------------------------------
bool CColorPicker::OnClickPalette(const string clicked_object)
  {
//--- Abbrechen, falls der Objektname nicht übereinstimmt
   if(clicked_object!=m_canvas.Name())
      return(false);
//--- Setzen der Farbe und des Tooltips am ausgewählten Marker 
   m_picked_color=m_hover_color;
   m_picked.Color(m_picked_color);
   m_picked.BackColor(m_picked_color);
   m_picked.Tooltip(::ColorToString(m_picked_color));
//--- Berechnen und setzen der Farbkomponenten relativ zu dem ausgewählten Radiobutton
   SetComponents();
   return(true);
  }

  • Die CColorPicker::OnClickRadioButton() Methode behandelt einen Klick auf einen Radiobutton. Zunächst müssen zwei Überprüfungen vorgenommen werden: (1) Der Bezeichner des Elementes und (2) der dargestellte Text des Radiobuttons. Wenn diese Überprüfungen erfolgreich waren, dann wird die Farbpalette neu gezeichnet (relativ zu der selektierten Komponente des Farbmodells, zu welchem sie gehört)
//+----------------------------------------------------------------
//| Verarbeiten eines Klicks auf den Radiobutton                              |
//+----------------------------------------------------------------
bool CColorPicker::OnClickRadioButton(const long id,const int button_index,const string button_text)
  {
//--- Abbrechen, falls die Bezeichner nicht übereinstimmen
   if(id!=CElement::Id())
      return(false);
//--- Abbrechen, falls der Text des Radiobuttons nicht überein stimmt
   if(button_text!=m_radio_buttons.SelectedButtonText())
      return(false);
//--- Aktualisierung der Palette unter Berücksichtigung der letzten Veränderungen
   DrawPalette(button_index);
   return(true);
  }

  • Die CColorPicker::OnEndEdit() Methode behandelt die Eingabe eines neuen Wertes in die Editbox. Hier ist eine einfache Überprüfung des Bezeichners ausreichend und anschließend werden die Komponenten aller Farbmodelle berechnet(Relativ zu der einen, die den selektierten Radio-Button besitzt.) 
//+----------------------------------------------------------------
//| Verarbeitung der Eingabe eines neuen Wertes in eine EditBox                            |
//+----------------------------------------------------------------
bool CColorPicker::OnEndEdit(const long id,const int button_index)
  {
//--- Abbrechen, falls die Bezeichner nicht übereinstimmen
   if(id!=CElement::Id())
      return(false);
//--- Berechnen und setzen aller Farbkomponenten für alle Farbmodelle 
   SetComponents(button_index,false);
   return(true);
  }

  • Die CColorPicker::OnClickButtonOK() Methode behandelt einen Klick auf den 'OK' Button. Dieses ist nicht die endgültige Version dieser Methode. Sie wird später in dem Artikel noch geändert. Das einzige, was wir zur Zeit nur wissen müssen ist, dass in dem Moment wo auf den Button geklickt wird, die ausgewählte Farbe als aktuelle Farbe abgespeichert wird.  
//+----------------------------------------------------------------
//| Verarbeitung eines Klicks auf den OK-Button                               |
//+----------------------------------------------------------------
bool CColorPicker::OnClickButtonOK(const string clicked_object)
  {
//--- Abbrechen, falls der Objektname nicht übereinstimmt
   if(clicked_object!=m_button_ok.Text())
      return(false);
//--- Abspeichern der selektierten Farbe
   m_current_color=m_picked_color;
   m_current.BackColor(m_current_color);
   m_current.Tooltip(::ColorToString(m_current_color));
   return(true);
  }

  • Die CColorPicker::OnClickButtonCancel() Methode verarbeitet einen Klick auf den 'Cancel' Button. Es gibt hier nur eine Überprüfung des Objektnamens. Anschließend, falls das Formular, zu welchem das Control hinzugefügt worden ist vom Typ 'Dialogfenster' ist, wird es geschlossen
//+----------------------------------------------------------------
//| Verarbeitung eines Klicks auf den 'Cancel' Button                           |
//+----------------------------------------------------------------
bool CColorPicker::OnClickButtonCancel(const string clicked_object)
  {
//--- Abbrechen, falls der Objektname nicht übereinstimmt
   if(clicked_object!=m_button_cancel.Text())
      return(false);
//--- Schließe das Fenster, falls es sich um ein Dialogfenster handelt
   if(m_wnd.WindowType()==W_DIALOG)
      m_wnd.CloseDialogBox();
//---
   return(true);
  }

In dem Eventhandler der CColorPicker::OnEvent() Farbpalette gibt es sechs Blöcke. Jede der oben aufgeführten Methoden wird bei dem Eintreffen des zugehörigen Bezeichners aufgerufen. Der gesamte Programmcode des Eventhandlers wird in dem nachfolgenden Listing gezeigt:

//+----------------------------------------------------------------
//| Eventhandler der Chart-Events                                           |
//+----------------------------------------------------------------
void CColorPicker::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten der Events von Mausbewegungen
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Abbrechen, falls das Control versteckt ist
      if(!CElement::IsVisible())
         return;
      //--- Koordinaten und der Status der linken Maustaste
      int x=(int)lparam;
      int y=(int)dparam;
      m_mouse_state=(bool)int(sparam);
      CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2());
      m_canvas.MouseFocus(x>m_canvas.X() && x<m_canvas.X2()-1 && y>m_canvas.Y() && y<m_canvas.Y2()-1);
      //--- Abfrage der Farbe am Mauszeiger
      if(OnHoverColor(x,y))
         return;
      //---
      return;
     }
//--- Verarbeitung eines Klicks mit der linken Maustaste auf ein Objekt
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Falls auf die Farbpalette geklickt wurde
      if(OnClickPalette(sparam))
         return;
      //---
      return;
     }
//--- Verarbeiten einer Eingabe eines Wertes in eine EditBox
   if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
     {
      //--- Überprüfung des neuen Wertes
      if(OnEndEdit(lparam,(int)dparam))
         return;
      //---
      return;
     }
//--- Verarbeiten eines Klicks auf ein Control
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      //--- Falls auf ein Radiobutton geklickt wurde
      if(OnClickRadioButton(lparam,(int)dparam,sparam))
         return;
      //---
      return;
     }
//--- Verarbeiten eines Klicks auf die Schalter von EditBoxen
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC || id==CHARTEVENT_CUSTOM+ON_CLICK_DEC)
     {
      //--- Überprüfung des neuen Wertes
      if(OnEndEdit(lparam,(int)dparam))
         return;
      //---
      return;
     }
//--- Verarbeiten eines Klicks auf den Control-Button
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     {
      //--- Abbrechen, falls die Bezeichner nicht übereinstimmen
      if(lparam!=CElement::Id())
         return;
      //--- Falls auf "OK" geklickt wurde
      if(OnClickButtonOK(sparam))
         return;
      //--- Falls auf "CANCEL" geklickt wurde
      if(OnClickButtonCancel(sparam))
         return;
      //---
      return;
     }
  }

Viele Controls der Bibliothek besitzen die FastSwitching() Methode. Diese wird normalerweise für das schnelle verändern von Werten in EditBoxen, Scrollbars oder Listen von Tabellen verwendet. Hier wird sie dazu verwendet, um die Farbpalette neu zu zeichnen, falls ein schnelles Verändern des Zählers einer EditBox aktiviert wurde. Den Programmcode der CColorPicker::FastSwitching() Methode finden Sie in den Dateien, die diesem Artikel beigefügt sind.

 

 

Farbiger Button

Die Klasse für die Erzeugung der Farbpalette ist fertig, aber ein Element für die vollständige Nutzung fehlt noch. Wir benötigen noch einen Button, der dazu verwendet wird, das Fenster mit der Farbpalette aufzurufen. Der Button sollte die Möglichkeit besitzen, das aktuelle Farbschema sichtbar zu machen. Wir werden jetzt für einen solchen Button eine Klasse schreiben. Die nachfolgende Liste zeigt die Komponenten dieses Buttons

  1. Bereich des Controls
  2. Textlabel mit einer Beschreibung
  3. Der Indikator für die ausgewählte Farbe
  4. Der Bereich des Buttons
  5. Die Beschreibung der ausgewählten Farbe im RGB Format


Abbildung 3. Die Komponenten des Buttons für den Aufruf der Farbpalette.


Wir sind bereits in den vorangegangenen Artikeln auf ähnliche Controls eingegangen. Daher werden wir hier keine weitere Beschreibung dieser Klasse aufführen. Stattdessen werden wir mit der Interaktion zwischen dem Button und der Farbpalette weitermachen. Sehen Sie sich dazu die ColorButton.mqh Datei mit der CColorButton Klasse an, um mehr darüber zu lernen. 

Wir müssen nun die Farbpalette mit dem Button verbinden, damit sie aufgerufen werden kann. Wir machen dieses mithilfe des Button-Pointers, welcher in der CColorPicker Klasse abgespeichert ist. Dafür verbinden wir die ColorButton.mqh Date mit der ColorPicker.mqh Datei und deklarieren eine CColorButton Klasse, in welcher der Pointer zu dem Button abgespeichert wird.

//+----------------------------------------------------------------
//|                                                  ColorPicker.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+----------------------------------------------------------------
#include "Element.mqh"
#include "Window.mqh"
#include "SpinEdit.mqh"
#include "SimpleButton.mqh"
#include "RadioButtons.mqh"
#include "ColorButton.mqh"
//+----------------------------------------------------------------
//| Klasse für die Erzeugung des Controls für die Farbauswahl                                  |
//+----------------------------------------------------------------
class CColorPicker : public CElement
  {
private:
   //--- Der Pointer zu dem Button, der das Control für die Farbauswahl aufruft
   CColorButton     *m_color_button;
  };

Dazu benötigen wir noch eine öffentliche Methode. Um die Interaktion zwischen dem Button und der Farbpalette einfacher gestalten zu können, werden allen Markern der Palette die aktuelle Farbe des Buttons zugewiesen, währen der Pointer abgespeichert wird. Anschließend wird ein Fenster mit der Farbpalette geöffnet. Sehen Sie sich dazu das nachfolgende Programmbeispiel an.  

class CColorPicker : public CElement
  {
public:
   //--- Abspeichern des Pointers von dem Button, der die Farbpalette aufgerufen hat
   void              ColorButtonPointer(CColorButton &object);
  };
//+----------------------------------------------------------------
//| Abspeichern des Pointers von dem Button, der die Farbpalette aufgerufen hat          |
//| Öffnen des Fensters, zu welchem die Palette gehört                     |
//+----------------------------------------------------------------
void CColorPicker::ColorButtonPointer(CColorButton &object)
  {
//--- Pointer des Buttons abspeichern
   m_color_button=::GetPointer(object);
//--- Allen Marken der Palette die Farbe des Buttons zuweisen
   CurrentColor(object.CurrentColor());
//--- Öffnen des Fensters, zu welchem die Palette gehört
   m_wnd.Show();
  }

Hierzu benötigen wir noch Methoden, um die Farbe des Buttons abzufragen und zu setzen. Die festgelegte Farbe erscheint auf dem Marker des Buttons und als zusätzliche Informationen enthält der Text des Buttons einen String der die Farbe in dem RGB Format darstellt.

class CColorButton : public CElement
  {
public:
   //--- Abfrage und setzen der aktuellen Farbe der Parameter
   color             CurrentColor(void)                 const { return(m_current_color);       }
   void              CurrentColor(const color clr);
  };
//+----------------------------------------------------------------
//| Verändern der aktuellen Farbe des Parameters                                |
//+----------------------------------------------------------------
void CColorButton::CurrentColor(const color clr)
  {
   m_current_color=clr;
   m_button_icon.BackColor(clr);
   m_button_label.Description(::ColorToString(clr));
  }

Und jetzt noch eine kleine Erweiterung in der CColorPicker::OnClickButtonOK() Methode. Wenn ein Pointer zu dem Button gesetzt wurde, dann:

  • Dann wird die von der Palette ausgewählte Farbe auf dem Button gezeigt;
  • Das Fenster, zu welchem die Farbpalette gehört, kann nun geschlossen werden
  • Eine Nachricht wird generiert, dass eine neue Farbe aus der Palette gewählt wurde. Hierfür benötigen wir in der Defines.mqh Datei einen neuen Event-Bezeichner ON_CHANGE_COLOR. Diese Nachricht beinhaltet zudem (1) Control-Bezeichner (2) Element-Index und(3) Den Text des Buttons der die Palette aufgerufen hat. Auf diese Weise sind wir in der Lage zu verstehen, welcher Button mit dem Event gemeint ist und das wird uns später helfen, das Event korrekt zu verarbeiten.
  • Der Pointer zu dem Button wird zurückgesetzt. 

Wenn es keinen Pointer zu einem Button gibt, dann wird für den Entwickler eine Nachricht mit einem Tooltip und im Log gezeigt.  

//+----------------------------------------------------------------
//| Verarbeitung eines Klicks auf den OK-Button                               |
//+----------------------------------------------------------------
bool CColorPicker::OnClickButtonOK(const string clicked_object)
  {
//--- Abbrechen, falls der Objektname nicht übereinstimmt
   if(clicked_object!=m_button_ok.Text())
      return(false);
//--- Abspeichern der selektierten Farbe
   m_current_color=m_picked_color;
   m_current.BackColor(m_current_color);
   m_current.Tooltip(::ColorToString(m_current_color));
//--- Wenn es einen Pointer zu einem Button gibt
   if(::CheckPointer(m_color_button)!=POINTER_INVALID)
     {
      //--- Lege die ausgewählte Farbe für den Button fest
      m_color_button.CurrentColor(m_current_color);
      //--- Schließe das Fenster
      m_wnd.CloseDialogBox();
      //--- Eine Nachricht darüber senden
      ::EventChartCustom(m_chart_id,ON_CHANGE_COLOR,CElement::Id(),CElement::Index(),m_color_button.LabelText());
      //--- Setze die Pointer zurück
      m_color_button=NULL;
     }
   else
     {
      //--- Falls es sich um ein Dialogfenster handelt und es keinen Pointer gibt,
      //    ...dann zeige eine Nachricht, dass es keinen Pointer zu dem Button gibt, der das Control aufgerufen hat
      if(m_wnd.WindowType()==W_DIALOG)
         ::Print(__FUNCTION__," > Non-valid pointer of calling control (CColorButton).");
     }
//---
   return(true);
  }

Nun ist alles für einen Test der Farbpalette bereit 

 

Test der Controls

Sie können irgendeinen Expert Advisor auf den vorangegangenen Artikeln dafür verwenden. Machen Sie von diesem eine Kopie und behalten sie nur das Hauptmenü und den Status-String In dem Hauptfenster (W_MAIN) des grafischen Interfaces erzeugen wir fünf Buttons für den Aufruf des Dialogfensters (W_DIALOG) mit der Farbpalette. Mit anderen Worten, es reicht aus, nur eine Farbpalette für die gesamte MQL Anwendung zu erzeugen. Jedes Mal wenn ein Button für den Aufruf eines Dialogfensters mit einer Farbpalette geklickt wird, wird das selbe Fenster geöffnet. Aber der Pointer des Buttons muss während des Aufrufs der CColorPicker Klasse übergeben werden. Dieses Implementation zeigen wir später in der benutzerdefinierten Klasse der Anwendung.

In der benutzerdefinierten Klasse mit dem Namen CProgram benötigen wir die Deklaration von Klassen für die Erzeugung von zusätzlichen Fenstern(CWindow), fünf Buttons für den Aufruf der Farbpaletten CColorButton und CColorPicker, und zudem Methoden für deren Erzeugung mit Abständen von dem aüßersten Punkt des Formulars.

class CProgram : public CWndEvents
  {
private:
   //--- Form 2 - Fenster mit der Farbpalette für die Farbauswahl
   CWindow           m_window2;
   //--- Buttons für den Aufruf des Fensters mit der Farbpalette
   CColorButton      m_color_button1;
   CColorButton      m_color_button2;
   CColorButton      m_color_button3;
   CColorButton      m_color_button4;
   CColorButton      m_color_button5;
   //--- Farbpalette
   CColorPicker      m_color_picker;
   //---
private:
   //--- Form 2
   bool              CreateWindow2(const string text);
   //--- Buttons für den Aufruf der Palette
#define COLORBUTTON1_GAP_X    (7)
#define COLORBUTTON1_GAP_Y    (50)
   bool              CreateColorButton1(const string text);
#define COLORBUTTON2_GAP_X    (7)
#define COLORBUTTON2_GAP_Y    (75)
   bool              CreateColorButton2(const string text);
#define COLORBUTTON3_GAP_X    (7)
#define COLORBUTTON3_GAP_Y    (100)
   bool              CreateColorButton3(const string text);
#define COLORBUTTON4_GAP_X    (7)
#define COLORBUTTON4_GAP_Y    (125)
   bool              CreateColorButton4(const string text);
#define COLORBUTTON5_GAP_X    (7)
#define COLORBUTTON5_GAP_Y    (150)
   bool              CreateColorButton5(const string text);
   //--- Farbpalette
#define COLORPICKER_GAP_X     (1)
#define COLORPICKER_GAP_Y     (20)
   bool              CreateColorPicker(void);
  };

Die Methoden für die Erzeugung der Buttons für den Aufruf der Farbpalette sind fast alle identisch, und daher werden wir hier nur das Beispiel für einen Button zeigen. Ein Unterschied liegt lediglich bei dem Festlegen der anfänglichen Farbe, die in dem Indikator des Buttons dargestellt wird und in dem Text der Beschreibung

//+----------------------------------------------------------------
//| Erzeugung des Buttons für den Aufruf der Farbpalette 1                            |
//+----------------------------------------------------------------
bool CProgram::CreateColorButton1(const string text)
  {
//--- Abspeichern des Pointers des Fensters
   m_color_button1.WindowPointer(m_window1);
//--- Koordinaten
   int x=m_window1.X()+COLORBUTTON1_GAP_X;
   int y=m_window1.Y()+COLORBUTTON1_GAP_Y;
//--- Festlegen der Eigenschaften vor der Erzeugung
   m_color_button1.XSize(195);
   m_color_button1.YSize(18);
   m_color_button1.ButtonXSize(100);
   m_color_button1.ButtonYSize(18);
   m_color_button1.AreaColor(clrWhiteSmoke);
   m_color_button1.LabelColor(clrBlack);
   m_color_button1.BackColor(C'220,220,220');
   m_color_button1.BorderColor(clrSilver);
   m_color_button1.CurrentColor(clrRed);
//--- Erzeugen des Elementes
   if(!m_color_button1.CreateColorButton(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- Den Pointer zum Control in der Basis hinzufügen
   CWndContainer::AddToElementsArray(0,m_color_button1);
   return(true);
  }

Der Programmcode für die Erzeugung des Formulars des Dialogfensters für die Farbpalette unterscheidet sich von dem Hauptfenster nur durch die Festlegung des Fenstertyps (W_DIALOG). Zusätzlich legen wir noch ein, eindeutiges Bild für dieses Fenster fest, dass seinen Verwendungszweck verdeutlicht. Alle hier verwendeten Bilder finden Sie am Ende des Artikels. 

//+----------------------------------------------------------------
//| Erzeugen des Formulars 2 für die Farbpalette                                  |
//+----------------------------------------------------------------
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\color_picker.bmp"
//---
bool CProgram::CreateWindow2(const string caption_text)
  {
//--- Abspeichern des Pointers des Fensters
   CWndContainer::AddWindow(m_window2);
//--- Koordinaten
   int x=(m_window2.X()>0) ? m_window2.X() : 30;
   int y=(m_window2.Y()>0) ? m_window2.Y() : 30;
//--- Eigenschaften
   m_window2.Movable(true);
   m_window2.XSize(350);
   m_window2.YSize(286);
   m_window2.WindowType(W_DIALOG);
   m_window2.WindowBgColor(clrWhiteSmoke);
   m_window2.WindowBorderColor(clrLightSteelBlue);
   m_window2.CaptionBgColor(clrLightSteelBlue);
   m_window2.CaptionBgColorHover(clrLightSteelBlue);
   m_window2.IconFile("Images\\EasyAndFastGUI\\Icons\\bmp16\\color_picker.bmp");
//--- Erzeugen der Form
   if(!m_window2.CreateWindow(m_chart_id,m_subwin,caption_text,x,y))
      return(false);
//---
   return(true);
  }

Das nachfolgende Listing beinhaltet den Programmcode der CProgram::CreateColorPicker() Methode für die Erzeugung der Farbpalette. Es ist wichtig, den Pointer des Dialogfensters abzuspeichern, zu welchem ein Control hinzugefügt wird. Wenn ein Pointer eines Controls zu der Basis der Controls hinzugefügt wird, muss der Index des Fensters, zu welchem das Element hinzugefügt werden muss, gesendet werden. In unserem Fall ist das der Index des Dialogfensters [1].

//+----------------------------------------------------------------
//| Erzeugen der Farbpalette für die Farbwahl                         |
//+----------------------------------------------------------------
bool CProgram::CreateColorPicker(void)
  {
//--- Abspeichern des Pointers des Fensters
   m_color_picker.WindowPointer(m_window2);
//--- Koordinaten
   int x=m_window2.X()+COLORPICKER_GAP_X;
   int y=m_window2.Y()+COLORPICKER_GAP_Y;
//--- Erzeugung des Controls
   if(!m_color_picker.CreateColorPicker(m_chart_id,m_subwin,x,y))
      return(false);
//--- Den Pointer zum Control in der Basis hinzufügen
   CWndContainer::AddToElementsArray(1,m_color_picker);
   return(true);
  }

Wir müssen sicherstellen, dass wenn auf den Button geklickt wird, sein Pointer auch der Farbpalette übergeben wird. Dieses könnten wir in dem Eventhandler der benutzerdefinierten Klasse CProgram::OnEvent() erledigen. Wenn auf einen Button geklickt wird, dann wird eine Nachricht mit dem ON_CLICK_BUTTON Eventbezeichner generiert. Die Nachricht beinhaltet zudem den Text der Beschreibung des Buttons der dazu verwendet wird festzustellen, welches Objekt vom Typ CColorButton der Farbpalette gesendet werden muss. Direkt nach dem Senden des Objektes des Buttons, wird ein Fenster mit der Farbpalette geöffnet und alle Marker erhalten die Farbe des Objektes, welches gerade gesendet worden ist. Dieses wird mit den nachfolgenden Programmlisting demonstriert:

//+----------------------------------------------------------------
//| Event handler                                                    |
//+----------------------------------------------------------------
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Button click event
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     {
      //--- Falls Button 1 geklickt wurde
      if(sparam==m_color_button1.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button1);
         return;
        }
      //--- Falls Button 2 geklickt wurde
      if(sparam==m_color_button2.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button2);
         return;
        }
      //--- Falls Button 3 geklickt wurde
      if(sparam==m_color_button3.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button3);
         return;
        }
      //--- Falls Button 4 geklickt wurde
      if(sparam==m_color_button4.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button4);
         return;
        }
      //--- Falls Button 5 geklickt wurde
      if(sparam==m_color_button5.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button5);
         return;
        }
     }
  }

Nachdem die Farbauswahl durch einen Klick auf den "ОК" Button der Farbpalette bestätigt wurde, wird eine Nachricht mit dem ON_CHANGE_COLOR Bezeichner verarbeitet:

void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Event über die Veränderung einer Farbe unter Verwendung der Farbpalette
   if(id==CHARTEVENT_CUSTOM+ON_CHANGE_COLOR)
     {
      //---Wenn die Bezeichnung der Controls übereinstimmen
      if(lparam==m_color_picker.Id())
        {
         //--- Falls die Antwort von Button 1 ist
         if(sparam==m_color_button1.LabelText())
           {
            //--- Ändere die Farbe des Objektes die zu dem Button1 gehört...
            return;
           }
         //--- Falls die Antwort von Button 2 ist
         if(sparam==m_color_button2.LabelText())
           {
            //--- Ändere die Farbe des Objektes die zu dem Button 2 gehört...
            return;
           }
         //--- Falls die Antwort von Button 3 ist
         if(sparam==m_color_button3.LabelText())
           {
            //--- Ändere die Farbe des Objektes die zu dem Button 3 gehört...
            return;
           }
         //--- Falls die Antwort von Button 4 ist
         if(sparam==m_color_button4.LabelText())
           {
            //--- Ändere die Farbe des Objektes die zu dem Button 4 gehört...
            return;
           }
         //--- Falls die Antwort von Button 5 ist
         if(sparam==m_color_button5.LabelText())
           {
            //--- Ändere die Farbe des Objektes die zu dem Button 5 gehört...
            return;
           }
        }
      return;
     }
  }

Kompilieren Sie dieses Programm und laden Sie es auf einen Chart. Das Ergebnis zeigt der nachfolgende Screenshot:

 Abbildung 4. Test der Buttons für den Aufruf der Farbpalette

Abbildung 4. Test der Buttons für den Aufruf der Farbpalette

Durch einen Klick auf einer der fünf Buttons, die in dem Hauptfenster gezeigt werden, öffnet sich das Fenster mit der Farbauswahl:

 Abbildung 5. Test des Farbauswahl-Elementes

Abbildung 5. Test des Farbauswahl-Elementes

Nun funktioniert alles wie geplant. 

 


Schlussfolgerung

In diesem Artikel haben wir ein komplexes Control, welches aus verschiedenen Komponenten besteht, präsentiert. (Erstes Kapitel des 9. Teils dieser Serie der Artikel). Als zusätzliches Control haben wir einen speziellen Button für den Aufruf der Farbpalette generiert. Nun haben die Anwender der hier entwickelten Bibliothek die Möglichkeit, die Farben von Objekten über die Verwendung eines grafischen Interfaces innerhalb einer MQL Anwendung zu verändern.

Die folgenden Artikel beinhalten Beschreibungen für Klassen von weiteren Controls, wie zum Beispiel die Fortschrittsanzeige und den Linienchart.

Unterhalb dieses Artikels finden Sie das gesamte Material, welches sie herunterladen können, um ist auf Ihrem PC zu 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 neunten Teils:


Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/2579

Beigefügte Dateien |
Grafische Interfaces IX: Die Fortschrittsanzeige und das Linienchart-Control (Kapitel 2) Grafische Interfaces IX: Die Fortschrittsanzeige und das Linienchart-Control (Kapitel 2)
Das zweite Kapitel des neuen Teils dieser Serie widmet sich der Fortschrittsanzeige und dem Linienchart-Control Wie immer, gibt es auch hier detaillierte Beispiele, um deutlich zu machen, wie die Controls in den benutzerdefinierten MQL Anwendungen verwendet werden können.
Grafische Interfaces VIII: Das Datei-Navigator Control (Kapitel 3) Grafische Interfaces VIII: Das Datei-Navigator Control (Kapitel 3)
In den vorherigen Kapiteln des 8 Teils dieser Serie, haben wir unsere Bibliothek um mehrere Klassen für die Entwicklung von Mauszeigern, Kalendern und Baum-Ansichten erweitert. In dem aktuellen Artikel beschäftigen wir uns mit dem Datei-Navigator-Control, welcher auch als Teil eines grafischen Interfaces einer MQL Anwendung verwendet werden kann.
Grafische Interfaces X: Updates für die Easy And Fast Bibliothek (Build 2) Grafische Interfaces X: Updates für die Easy And Fast Bibliothek (Build 2)
Seit der Veröffentlichung des vorangegangenen Artikels dieser Serie, hat die Easy And Fast Bibliothek einige neue Features bekommen. Die Bibliotheksstruktur und der Programmcode wurden teilweise optimiert, was die CPU-Auslastung leicht reduziert hat. Einige wiederkehrende Methoden in vielen Control-Klassen wurden in die CElement Basisklasse bewegt.
Grafische Interfaces VIII: Die Baumansicht (Kapitel 2) Grafische Interfaces VIII: Die Baumansicht (Kapitel 2)
Das vorherige Kapitel VIII der grafischen Schnittstellen hat sich mit den Elementen eines statischen und eines Dropdown-Kalenders beschäftigt. Das zweite Kapitel beschäftigt sich mit einem nicht weniger komplexen Element — der Baumansicht, die Teil aller kompletten Bibliotheken graphischer Schnittstellen ist. Die Baumansicht in diesem Artikel beinhaltet mehrere flexible Einstellungen und Modi und erlaubt daher die Elemente ganz Ihren Zielen anzupassen.