English Русский 中文 Español 日本語 Português
Grafiken in der Bibliothek DoEasy (Teil 75): Methoden zur Handhabung von Primitiven und Text im grafischen Grundelement

Grafiken in der Bibliothek DoEasy (Teil 75): Methoden zur Handhabung von Primitiven und Text im grafischen Grundelement

MetaTrader 5Beispiele | 12 Juli 2021, 13:41
506 0
Artyom Trishkin
Artyom Trishkin

Inhalt


Konzept

Ich setze die Entwicklung der Objektklasse des grafischen Basiselements fort, die als Grundlage für die Erstellung komplexerer grafischer Objekte der Bibliothek dient. Im vorherigen Artikel habe ich das Konzept der Konstruktion des grafischen Basisobjekts erstellt, das grafische Element erzeugt und es mit grundlegenden Eigenschaften ausgestattet, die bereits gesetzt, geändert und empfangen werden können.
Da die Klasse CCanvas für das Zeichnen "auf der Leinwand" (canvas) gedacht ist, verfügt sie über die Methoden zum Arbeiten mit grafischen Primitiven und einem Text. In diesem Artikel werde ich die Methoden des Elementobjekts erstellen, mit denen wir auf die Methoden der Klasse CCanvas zum Zeichnen zugreifen und diese behandeln können. Diese Methoden sollen einfach sein. Sie werden verwendet, um erweiterte Zeichenmethoden in den Nachfolgeobjekten der Elementobjektklasse zu erstellen.

Zusätzlich zum Erstellen der Methoden für die Arbeit mit Primitiven werde ich auch die Methoden für die Arbeit mit Dateien erstellen. Unsere grafischen Objekte, die die GUI-Elemente der benutzerdefinierten Programme sind, sollen sich ihre Eigenschaften, ihren Status und ihre Position im Chart "merken", z. B. beim Wechsel zu einem anderen Zeitrahmen. Um dies zu erreichen, werde ich die Objekteigenschaften in einer Datei speichern. Beim Konstruieren eines Objekts werden die Eigenschaften daraus gelesen.
Da Dateien jedoch in der grafischen Objektsammelklasse behandelt werden sollen und ich diese noch nicht entwickelt habe, werde ich einfach die Methoden zum Speichern und Hochladen von grafischen Objekteigenschaften hinzufügen. Beim Erstellen der grafischen Objektsammelklasse werden wir die Methoden zum Speichern und Hochladen der Eigenschaften verwenden, die ich hier für das grafische Elementobjekt entwickeln werde.

Außerdem werde ich die Klasse für die Arbeit mit Farbe benötigen. Ich werde sie ebenfalls in die Bibliothek aufnehmen.
Die Klasse wird aus der MQL5.com-Codebibliothek stammen, die von Dmitry Fedoseev entwickelt und der Community zur Verfügung gestellt wurde.

Das Endergebnis wird ein grafisches Element sein, das als Basis für weitere grafische Objekte der Bibliothek verwendet werden kann.


Verbesserung der Klassenbibliothek

Wenn wir ein Objekt der Klasse CCanvas, das Transparenz besitzt, löschen müssen, sollten wir die Methode Erase() verwenden, die standardmäßig Null erhält:

   //--- clear/fill color
   void              Erase(const uint clr=0);

In unserem Fall ist dies eine falsche Lösung. Wenn wir die Leinwand mit Null löschen, verlieren wir seinen Alphakanal (Farbtransparenzkanal), was letztendlich zu Artefakten führt, wenn wir auf der Leinwand mit auf diese Weise gelöschtem Alphakanal zeichnen.
Um die Leinwand mit dem Alphakanal zu löschen, verwenden Sie 0x00FFFFFF anstelle von Null.
Dies ist eine vollständig transparente schwarze Farbe im ARGB-Format (Alpha = 0, Rot = 255, Grün = 255, Blau = 255).

Wir fügen in \MQL5\Include\DoEasy\Defines.mqh die Makro-Ersetzung für die Angabe einer solchen Farbe hinzu:

//--- Canvas parameters
#define PAUSE_FOR_CANV_UPDATE          (16)                       // Canvas update frequency
#define NULL_COLOR                     (0x00FFFFFF)               // Zero for the canvas with the alpha channel
//+------------------------------------------------------------------+

Bei der Anzeige eines Textes auf der Leinwand mit der Methode TextOut() können wir den Ankerwinkel (Textausrichtungspunkt) für die Textnachricht setzen — das begrenzende Rechteck, relativ zu dem sich die Nachricht befinden soll. Die Ankerpunkte werden mit Hilfe von sechs Flags gesetzt — Kombinationen von zwei Flags, die im Folgenden aufgelistet sind:

Flags für die horizontale Textausrichtung:

  • TA_LEFT — Ankerpunkt auf der linken Seite des Begrenzungsrechtecks
  • TA_CENTER  horizontaler Ankerpunkt in der Mitte des Begrenzungsrechtecks
  • TA_RIGHT  Ankerpunkt auf der rechten Seite des Begrenzungsrechtecks

Vertikale Textausrichtungsflags:

  • TA_TOP  Ankerpunkt an der oberen Seite des Begrenzungsrechtecks
  • TA_VCENTER  vertikaler Ankerpunkt in der Mitte des Begrenzungsrechtecks
  • TA_BOTTOM  Ankerpunkt an der Unterseite des Begrenzungsrechtecks

Die möglichen Kombinationen der Flags und der durch sie gesetzten Verankerungsmethoden sind unten dargestellt:


Um eine Verwirrung darüber zu vermeiden, welches Flag zuerst kommt, setzen wir einfach eine nutzerdefinierte Enumeration, die alle möglichen Flag-Kombinationen für die Ausrichtung eines Textes relativ zu seinem Ankerpunkt angibt:

//+------------------------------------------------------------------+
//| Data for handling graphical elements                             |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of anchoring methods                                        |
//| (horizontal and vertical text alignment)                         |
//+------------------------------------------------------------------+
enum ENUM_TEXT_ANCHOR
  {
   TEXT_ANCHOR_LEFT_TOP       =  0,                   // Text anchor point at the upper left corner of the bounding rectangle
   TEXT_ANCHOR_CENTER_TOP     =  1,                   // Text anchor point at the top center side of the bounding rectangle
   TEXT_ANCHOR_RIGHT_TOP      =  2,                   // Text anchor point at the upper right corner of the bounding rectangle
   TEXT_ANCHOR_LEFT_CENTER    =  4,                   // Text anchor point at the left center side of the bounding rectangle
   TEXT_ANCHOR_CENTER         =  5,                   // Text anchor point at the center of the bounding rectangle
   TEXT_ANCHOR_RIGHT_CENTER   =  6,                   // Text anchor point at the right center side of the bounding rectangle
   TEXT_ANCHOR_LEFT_BOTTOM    =  8,                   // Text anchor point at the bottom left corner of the bounding rectangle
   TEXT_ANCHOR_CENTER_BOTTOM  =  9,                   // Text anchor point at the bottom center side of the bounding rectangle
   TEXT_ANCHOR_RIGHT_BOTTOM   =  10,                  // Text anchor point at the bottom right corner of the bounding rectangle
  };
//+------------------------------------------------------------------+
//| The list of graphical element types                              |
//+------------------------------------------------------------------+

Hier haben wir drei Flags für jede Textverankerungsebene gesetzt:

  1. oberer vertikaler Ankerpunkt (TA_TOP) — 0:
    • linker horizontaler Ankerpunkt (TA_LEFT) — 0,
    • mittlerer horizontaler Ankerpunkt (TA_CENTER) — 1,
    • rechter horizontaler Ankerpunkt (TA_RIGHT) — 2.
  2. Vertikaler Ankerpunkt Mitte (TA_VCENTER) — 4:
    • linker horizontaler Ankerpunkt (TA_LEFT) — 0,
    • mittlerer horizontaler Ankerpunkt (TA_CENTER) — 1,
    • rechter horizontaler Ankerpunkt (TA_RIGHT) — 2.
  3. Unterer vertikaler Ankerpunkt (TA_BOTTOM) — 8:
    • linker horizontaler Ankerpunkt (TA_LEFT) — 0,
    • mittlerer horizontaler Ankerpunkt (TA_CENTER) — 1,
    • rechter horizontaler Ankerpunkt (TA_RIGHT) — 2.

Jeder der Werte der Enumeration ENUM_TEXT_ANCHOR entspricht der oben beschriebenen Kombination von korrekt gesetzten Flags:

  • TEXT_ANCHOR_LEFT_TOP = (TA_LEFT | TA_TOP) = 0,
  • TEXT_ANCHOR_CENTER_TOP = (TA_CENTER | TA_TOP) = 1,
  • TEXT_ANCHOR_RIGHT_TOP = (TA_RIGHT | TA_TOP) = 2,
  • TEXT_ANCHOR_LEFT_CENTER = (TA_LEFT | TA_VCENTER) = 4,
  • TEXT_ANCHOR_CENTER = (TA_CENTER | TA_VCENTER) = 5,
  • TEXT_ANCHOR_RIGHT_CENTER = (TA_RIGHT | TA_VCENTER) = 6,
  • TEXT_ANCHOR_LEFT_BOTTOM = (TA_LEFT | TA_BOTTOM) = 8,
  • TEXT_ANCHOR_CENTER_BOTTOM = (TA_CENTER | TA_BOTTOM) = 9,
  • TEXT_ANCHOR_RIGHT_BOTTOM = (TA_RIGHT | TA_BOTTOM) = 10.

Diese Enumeration werde ich im weiteren Verlauf verwenden, um die Ausrichtung des Textes relativ zu seinem Ankerpunkt festzulegen.

Da ich gerade den grafischen Teil der Bibliothek entwickle, benötige ich verschiedene Methoden für die Arbeit mit Farbe.
Die Bibliothek der MQL5.com-Quellcodes enthält die bemerkenswerte Bibliothek von Funktionen für die Arbeit mit Farben, die freundlicherweise von Dmitry Fedoseev für den allgemeinen Gebrauch bereitgestellt wurde.

Verbessern wir die Klasse CColors noch etwas — wir machen sie statisch, nicht um das Klassenobjekt zu setzen, sondern direkt auf seine Methoden zuzugreifen, zum Beispiel mit dem Kontextauflösungsoperator (::):

class_name::variable

Die in der Bibliothek enthaltene Klasse CColors erlaubt es uns also, auf die Methoden der Klasse überall im Code zuzugreifen (auch in einem benutzerdefinierten Programm), um zum Beispiel zwei Farben zu mischen — Blau mit der Deckkraft von 128 und Rot mit der Deckkraft von 64:

CColors::BlendColors(ColorToARGB(clrBlue,128),ColorToARGB(clrRed,64));

Speichern wir die Klassendatei im Bibliotheksverzeichnis \MQL5\Include\DoEasy\Services\ in Colors.mqh.

//+------------------------------------------------------------------+
//|                                                       Colors.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/integer"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Class for working with color                                     |
//+------------------------------------------------------------------+
class CColors
  {
private:
   static double     Arctan2(const double x,const double y);
   static double     Hue_To_RGB(double v1,double v2,double vH);
public:
//+--------------------------------------------------------------------+
//| The list of functions from http://www.easyrgb.com/index.php?X=MATH |
//+--------------------------------------------------------------------+
   static void       RGBtoXYZ(const double aR,const double aG,const double aB,double &oX,double &oY,double &oZ);
   static void       XYZtoRGB(const double aX,const double aY,const double aZ,double &oR,double &oG,double &oB);
   static void       XYZtoYxy(const double aX,const double aY,const double aZ,double &oY,double &ox,double &oy);
   static void       YxyToXYZ(const double aY,const double ax,const double ay,double &oX,double &oY,double &oZ);
   static void       XYZtoHunterLab(const double aX,const double aY,const double aZ,double &oL,double &oa,double &ob);
   static void       HunterLabToXYZ(const double aL,const double aa,const double ab,double &oX,double &oY,double &oZ);
   static void       XYZtoCIELab(const double aX,const double aY,const double aZ,double &oCIEL,double &oCIEa,double &oCIEb);
   static void       CIELabToXYZ(const double aCIEL,const double aCIEa,const double aCIEb,double &oX,double &oY,double &oZ);
   static void       CIELabToCIELCH(const double aCIEL,const double aCIEa,const double aCIEb,double &oCIEL,double &oCIEC,double &oCIEH);
   static void       CIELCHtoCIELab(const double aCIEL,const double aCIEC,const double aCIEH,double &oCIEL,double &oCIEa,double &oCIEb);
   static void       XYZtoCIELuv(const double aX,const double aY,const double aZ,double &oCIEL,double &oCIEu,double &oCIEv);
   static void       CIELuvToXYZ(const double aCIEL,const double aCIEu,const double aCIEv,double &oX,double &oY,double &oZ);
   static void       RGBtoHSL(const double aR,const double aG,const double aB,double &oH,double &oS,double &oL);
   static void       HSLtoRGB(const double aH,const double aS,const double aL,double &oR,double &oG,double &oB);
   static void       RGBtoHSV(const double aR,const double aG,const double aB,double &oH,double &oS,double &oV);
   static void       HSVtoRGB(const double aH,const double aS,const double aV,double &oR,double &oG,double &oB);
   static void       RGBtoCMY(const double aR,const double aG,const double aB,double &oC,double &oM,double &oY);
   static void       CMYtoRGB(const double aC,const double aM,const double aY,double &oR,double &oG,double &oB);
   static void       CMYtoCMYK(const double aC,const double aM,const double aY,double &oC,double &oM,double &oY,double &oK);
   static void       CMYKtoCMY(const double aC,const double aM,const double aY,const double aK,double &oC,double &oM,double &oY);
   static void       RGBtoLab(const double aR,const double aG,const double aB,double &oL,double &oa,double &ob);
//+------------------------------------------------------------------+
//| Other functions for working with color                           |
//+------------------------------------------------------------------+
   static void       ColorToRGB(const color aColor,double &aR,double &aG,double &aB);
   static double     GetR(const color aColor);
   static double     GetG(const color aColor);
   static double     GetB(const color aColor);
   static double     GetA(const color aColor);
   static color      RGBToColor(const double aR,const double aG,const double aB);
   static color      MixColors(const color aCol1,const color aCol2,const double aK);
   static color      BlendColors(const uint lower_color,const uint upper_color);
   static void       Gradient(color &aColors[],color &aOut[],int aOutCount,bool aCycle=false);
   static void       RGBtoXYZsimple(double aR,double aG,double aB,double &oX,double &oY,double &oZ);
   static void       XYZtoRGBsimple(const double aX,const double aY,const double aZ,double &oR,double &oG,double &oB);
   static color      Negative(const color aColor);
   static color      StandardColor(const color aColor,int &aIndex);
   static double     RGBtoGray(double aR,double aG,double aB);
   static double     RGBtoGraySimple(double aR,double aG,double aB);
  };
//+------------------------------------------------------------------+
//| Class methods                                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Arctan2                                                          |
//+------------------------------------------------------------------+
double CColors::Arctan2(const double x,const double y)
  {
   if(y==0)
      return(x<0 ? M_PI : 0);
   else
     {
      if(x>0)
         return(::atan(y/x));
      if(x<0)
         return(y>0 ? atan(y/x)+M_PI : atan(y/x)-M_PI);
      else
         return(y<0 ? -M_PI_2 : M_PI_2);
     }
  }
//+------------------------------------------------------------------+
//| Hue_To_RGB                                                       |
//+------------------------------------------------------------------+
double CColors::Hue_To_RGB(double v1,double v2,double vH)
  {
   if(vH<0)
      vH+=1.0;
   if(vH>1.0)
      vH-=1;
   if((6.0*vH)<1.0)
      return(v1+(v2-v1)*6.0*vH);
   if((2.0*vH)<1.0)
      return(v2);
   if((3.0*vH)<2.0)
      return(v1+(v2-v1)*((2.0/3.0)-vH)*6.0);
//---
   return(v1);
  }
//+------------------------------------------------------------------+
//| Conversion of RGB into XYZ                                       |
//+------------------------------------------------------------------+
void CColors::RGBtoXYZ(const double aR,const double aG,const double aB,double &oX,double &oY,double &oZ)
  {
   double var_R=aR/255;
   double var_G=aG/255;
   double var_B=aB/255;
//---
   if(var_R>0.04045)
      var_R=::pow((var_R+0.055)/1.055,2.4);
   else
      var_R=var_R/12.92;
//---
   if(var_G>0.04045)
      var_G=::pow((var_G+0.055)/1.055,2.4);
   else
      var_G=var_G/12.92;
//---
   if(var_B>0.04045)
      var_B=::pow((var_B+0.055)/1.055,2.4);
   else
      var_B=var_B/12.92;
//---
   var_R =var_R*100.0;
   var_G =var_G*100.0;
   var_B =var_B*100.0;
   oX    =var_R*0.4124+var_G*0.3576+var_B*0.1805;
   oY    =var_R*0.2126+var_G*0.7152+var_B*0.0722;
   oZ    =var_R*0.0193+var_G*0.1192+var_B*0.9505;
  }
//+------------------------------------------------------------------+
//| Conversion of XYZ into RGB                                       |
//+------------------------------------------------------------------+
void CColors::XYZtoRGB(const double aX,const double aY,const double aZ,double &oR,double &oG,double &oB)
  {
   double var_X =aX/100;
   double var_Y =aY/100;
   double var_Z =aZ/100;
   double var_R =var_X*3.2406+var_Y*-1.5372+var_Z*-0.4986;
   double var_G =var_X*(-0.9689)+var_Y*1.8758+var_Z*0.0415;
   double var_B =var_X*0.0557+var_Y*(-0.2040)+var_Z*1.0570;
//---
   if(var_R>0.0031308)
      var_R=1.055*(::pow(var_R,1.0/2.4))-0.055;
   else
      var_R=12.92*var_R;
//---
   if(var_G>0.0031308)
      var_G=1.055*(::pow(var_G,1.0/2.4))-0.055;
   else
      var_G=12.92*var_G;
//---
   if(var_B>0.0031308)
      var_B=1.055*(::pow(var_B,1.0/2.4))-0.055;
   else
      var_B=12.92*var_B;
//---
   oR =var_R*255.0;
   oG =var_G*255.0;
   oB =var_B*255.0;
  }
//+------------------------------------------------------------------+
//| Conversion of XYZ into Yxy                                       |
//+------------------------------------------------------------------+
void CColors::XYZtoYxy(const double aX,const double aY,const double aZ,double &oY,double &ox,double &oy)
  {
   oY =aY;
   ox =aX/(aX+aY+aZ);
   oy =aY/(aX+aY+aZ);
  }
//+------------------------------------------------------------------+
//| Conversion of Yxy into XYZ                                       |
//+------------------------------------------------------------------+
void CColors::YxyToXYZ(const double aY,const double ax,const double ay,double &oX,double &oY,double &oZ)
  {
   oX =ax*(aY/ay);
   oY =aY;
   oZ =(1.0-ax-ay)*(aY/ay);
  }
//+------------------------------------------------------------------+
//| Conversion of XYZ into HunterLab                                 |
//+------------------------------------------------------------------+
void CColors::XYZtoHunterLab(const double aX,const double aY,const double aZ,double &oL,double &oa,double &ob)
  {
   oL =10.0*::sqrt(aY);
   oa =17.5*(((1.02*aX)-aY)/::sqrt(aY));
   ob =7.0*((aY-(0.847*aZ))/::sqrt(aY));
  }
//+------------------------------------------------------------------+
//| Conversion of HunterLab into XYZ                                 |
//+------------------------------------------------------------------+
void CColors::HunterLabToXYZ(const double aL,const double aa,const double ab,double &oX,double &oY,double  &oZ)
  {
   double var_Y =aL/10.0;
   double var_X =aa/17.5*aL/10.0;
   double var_Z =ab/7.0*aL/10.0;
//---
   oY =::pow(var_Y,2);
   oX =(var_X+oY)/1.02;
   oZ =-(var_Z-oY)/0.847;
  }
//+------------------------------------------------------------------+
//| Conversion of XYZ into CIELab                                    |
//+------------------------------------------------------------------+
void CColors::XYZtoCIELab(const double aX,const double aY,const double aZ,double &oCIEL,double &oCIEa,double &oCIEb)
  {
   double ref_X =95.047;
   double ref_Y =100.0;
   double ref_Z =108.883;
   double var_X =aX/ref_X;
   double var_Y =aY/ref_Y;
   double var_Z =aZ/ref_Z;
//---
   if(var_X>0.008856)
      var_X=::pow(var_X,1.0/3.0);
   else
      var_X=(7.787*var_X)+(16.0/116.0);
//---
   if(var_Y>0.008856)
      var_Y=::pow(var_Y,1.0/3.0);
   else
      var_Y=(7.787*var_Y)+(16.0/116.0);
//---
   if(var_Z>0.008856)
      var_Z=::pow(var_Z,1.0/3.0);
   else
      var_Z=(7.787*var_Z)+(16.0/116.0);
//---
   oCIEL =(116.0*var_Y)-16.0;
   oCIEa =500.0*(var_X-var_Y);
   oCIEb =200*(var_Y-var_Z);
  }
//+------------------------------------------------------------------+
//| Conversion of CIELab into ToXYZ                                  |
//+------------------------------------------------------------------+
void CColors::CIELabToXYZ(const double aCIEL,const double aCIEa,const double aCIEb,double &oX,double &oY,double &oZ)
  {
   double var_Y =(aCIEL+16.0)/116.0;
   double var_X =aCIEa/500.0+var_Y;
   double var_Z =var_Y-aCIEb/200.0;
//---
   if(::pow(var_Y,3)>0.008856)
      var_Y=::pow(var_Y,3);
   else
      var_Y=(var_Y-16.0/116.0)/7.787;
//---
   if(::pow(var_X,3)>0.008856)
      var_X=::pow(var_X,3);
   else
      var_X=(var_X-16.0/116.0)/7.787;
//---
   if(::pow(var_Z,3)>0.008856)
      var_Z=::pow(var_Z,3);
   else
      var_Z=(var_Z-16.0/116.0)/7.787;
//---
   double ref_X =95.047;
   double ref_Y =100.0;
   double ref_Z =108.883;
//---
   oX =ref_X*var_X;
   oY =ref_Y*var_Y;
   oZ =ref_Z*var_Z;
  }
//+------------------------------------------------------------------+
//| Conversion of CIELab into CIELCH                                 |
//+------------------------------------------------------------------+
void CColors::CIELabToCIELCH(const double aCIEL,const double aCIEa,const double aCIEb,double &oCIEL,double &oCIEC,double &oCIEH)
  {
   double var_H=Arctan2(aCIEb,aCIEa);
//---
   if(var_H>0)
      var_H=(var_H/M_PI)*180.0;
   else
      var_H=360.0-(::fabs(var_H)/M_PI)*180.0;
//---
   oCIEL =aCIEL;
   oCIEC =::sqrt(::pow(aCIEa,2)+::pow(aCIEb,2));
   oCIEH =var_H;
  }
//+------------------------------------------------------------------+
//| Conversion of CIELCH into CIELab                                 |
//+------------------------------------------------------------------+
void CColors::CIELCHtoCIELab(const double aCIEL,const double aCIEC,const double aCIEH,double &oCIEL,double &oCIEa,double &oCIEb)
  {
//--- Arguments from 0 to 360°
   oCIEL =aCIEL;
   oCIEa =::cos(M_PI*aCIEH/180.0)*aCIEC;
   oCIEb =::sin(M_PI*aCIEH/180)*aCIEC;
  }
//+------------------------------------------------------------------+
//| Conversion of XYZ into CIELuv                                    |
//+------------------------------------------------------------------+
void CColors::XYZtoCIELuv(const double aX,const double aY,const double aZ,double &oCIEL,double &oCIEu,double &oCIEv)
  {
   double var_U =(4.0*aX)/(aX+(15.0*aY)+(3.0*aZ));
   double var_V =(9.0*aY)/(aX+(15.0*aY)+(3.0*aZ));
   double var_Y =aY/100.0;
//---
   if(var_Y>0.008856)
      var_Y=::pow(var_Y,1.0/3.0);
   else
      var_Y=(7.787*var_Y)+(16.0/116.0);
//---
   double ref_X =95.047;
   double ref_Y =100.000;
   double ref_Z =108.883;
   double ref_U =(4.0*ref_X)/(ref_X+(15.0*ref_Y)+(3.0*ref_Z));
   double ref_V =(9.0*ref_Y)/(ref_X+(15.0*ref_Y)+(3.0*ref_Z));
//---
   oCIEL =(116.0*var_Y)-16.0;
   oCIEu =13.0*oCIEL*(var_U-ref_U);
   oCIEv =13.0*oCIEL*(var_V-ref_V);
  }
//+------------------------------------------------------------------+
//| Conversion of CIELuv into XYZ                                    |
//+------------------------------------------------------------------+
void CColors::CIELuvToXYZ(const double aCIEL,const double aCIEu,const double aCIEv,double &oX,double &oY,double &oZ)
  {
   double var_Y=(aCIEL+16.0)/116.0;
//---
   if(::pow(var_Y,3)>0.008856)
      var_Y=::pow(var_Y,3);
   else
      var_Y=(var_Y-16.0/116.0)/7.787;
//---
   double ref_X =95.047;
   double ref_Y =100.000;
   double ref_Z =108.883;
   double ref_U =(4.0*ref_X)/(ref_X+(15.0*ref_Y)+(3.0*ref_Z));
   double ref_V =(9.0*ref_Y)/(ref_X+(15.0*ref_Y)+(3.0*ref_Z));
   double var_U =aCIEu/(13.0*aCIEL)+ref_U;
   double var_V =aCIEv/(13.0*aCIEL)+ref_V;
//---
   oY=var_Y*100.0;
   oX=-(9.0*oY*var_U)/((var_U-4.0)*var_V-var_U*var_V);
   oZ=(9.0*oY-(15.0*var_V*oY)-(var_V*oX))/(3.0*var_V);
  }
//+------------------------------------------------------------------+
//| Conversion of RGB into HSL                                       |
//+------------------------------------------------------------------+
void CColors::RGBtoHSL(const double aR,const double aG,const double aB,double &oH,double &oS,double &oL)
  {
   double var_R   =(aR/255);
   double var_G   =(aG/255);
   double var_B   =(aB/255);
   double var_Min =::fmin(var_R,::fmin(var_G,var_B));
   double var_Max =::fmax(var_R,::fmax(var_G,var_B));
   double del_Max =var_Max-var_Min;
//---
   oL=(var_Max+var_Min)/2;
//---
   if(del_Max==0)
     {
      oH=0;
      oS=0;
     }
   else
     {
      if(oL<0.5)
         oS=del_Max/(var_Max+var_Min);
      else
         oS=del_Max/(2.0-var_Max-var_Min);
      //---
      double del_R =(((var_Max-var_R)/6.0)+(del_Max/2.0))/del_Max;
      double del_G =(((var_Max-var_G)/6.0)+(del_Max/2.0))/del_Max;
      double del_B =(((var_Max-var_B)/6.0)+(del_Max/2.0))/del_Max;
      //---
      if(var_R==var_Max)
         oH=del_B-del_G;
      else if(var_G==var_Max)
         oH=(1.0/3.0)+del_R-del_B;
      else if(var_B==var_Max)
         oH=(2.0/3.0)+del_G-del_R;
      //---
      if(oH<0)
         oH+=1.0;
      //---
      if(oH>1)
         oH-=1.0;
     }
  }
//+------------------------------------------------------------------+
//| Conversion of HSL into RGB                                       |
//+------------------------------------------------------------------+
void CColors::HSLtoRGB(const double aH,const double aS,const double aL,double &oR,double &oG,double &oB)
  {
   if(aS==0)
     {
      oR=aL*255;
      oG=aL*255;
      oB=aL*255;
     }
   else
     {
      double var_2=0.0;
      //---
      if(aL<0.5)
         var_2=aL*(1.0+aS);
      else
         var_2=(aL+aS)-(aS*aL);
      //---
      double var_1=2.0*aL-var_2;
      oR =255.0*Hue_To_RGB(var_1,var_2,aH+(1.0/3.0));
      oG =255.0*Hue_To_RGB(var_1,var_2,aH);
      oB =255.0*Hue_To_RGB(var_1,var_2,aH-(1.0/3.0));
     }
  }
//+------------------------------------------------------------------+
//| Conversion of RGB into HSV                                       |
//+------------------------------------------------------------------+
void CColors::RGBtoHSV(const double aR,const double aG,const double aB,double &oH,double &oS,double &oV)
  {
   const double var_R   =(aR/255.0);
   const double var_G   =(aG/255.0);
   const double var_B   =(aB/255.0);

   const double var_Min =::fmin(var_R,::fmin(var_G, var_B));
   const double var_Max =::fmax(var_R,::fmax(var_G,var_B));
   const double del_Max =var_Max-var_Min;
//---
   oV=var_Max;
//---
   if(del_Max==0)
     {
      oH=0;
      oS=0;
     }
   else
     {
      oS=del_Max/var_Max;
      const double del_R =(((var_Max-var_R)/6.0)+(del_Max/2))/del_Max;
      const double del_G =(((var_Max-var_G)/6.0)+(del_Max/2))/del_Max;
      const double del_B =(((var_Max-var_B)/6.0)+(del_Max/2))/del_Max;
      //---
      if(var_R==var_Max)
         oH=del_B-del_G;
      else if(var_G==var_Max)
         oH=(1.0/3.0)+del_R-del_B;
      else if(var_B==var_Max)
         oH=(2.0/3.0)+del_G-del_R;
      //---
      if(oH<0)
         oH+=1.0;
      //---
      if(oH>1.0)
         oH-=1.0;
     }
  }
//+------------------------------------------------------------------+
//| Conversion of HSV into RGB                                       |
//+------------------------------------------------------------------+
void CColors::HSVtoRGB(const double aH,const double aS,const double aV,double &oR,double &oG,double &oB)
  {
   if(aS==0)
     {
      oR =aV*255.0;
      oG =aV*255.0;
      oB =aV*255.0;
     }
   else
     {
      double var_h=aH*6.0;
      //---
      if(var_h==6)
         var_h=0;
      //---
      int    var_i =int(var_h);
      double var_1 =aV*(1.0-aS);
      double var_2 =aV*(1.0-aS*(var_h-var_i));
      double var_3 =aV*(1.0-aS*(1.0-(var_h-var_i)));
      double var_r =0.0;
      double var_g =0.0;
      double var_b =0.0;
      //---
      if(var_i==0)
        {
         var_r =aV;
         var_g =var_3;
         var_b =var_1;
        }
      else if(var_i==1.0)
        {
         var_r=var_2;
         var_g=aV;
         var_b=var_1;
        }
      else if(var_i==2.0)
        {
         var_r=var_1;
         var_g=aV;
         var_b=var_3;
        }
      else if(var_i==3)
        {
         var_r=var_1;
         var_g=var_2;
         var_b=aV;
        }
      else if(var_i==4)
        {
         var_r=var_3;
         var_g=var_1;
         var_b=aV;
        }
      else
        {
         var_r=aV;
         var_g=var_1;
         var_b=var_2;
        }
      //---
      oR =var_r*255.0;
      oG =var_g*255.0;
      oB =var_b*255.0;
     }
  }
//+------------------------------------------------------------------+
//| Conversion of RGB into CMY                                       |
//+------------------------------------------------------------------+
void CColors::RGBtoCMY(const double aR,const double aG,const double aB,double &oC,double &oM,double &oY)
  {
   oC =1.0-(aR/255.0);
   oM =1.0-(aG/255.0);
   oY =1.0-(aB/255.0);
  }
//+------------------------------------------------------------------+
//| Conversion of CMY into RGB                                       |
//+------------------------------------------------------------------+
void CColors::CMYtoRGB(const double aC,const double aM,const double aY,double &oR,double &oG,double &oB)
  {
   oR =(1.0-aC)*255.0;
   oG =(1.0-aM)*255.0;
   oB =(1.0-aY)*255.0;
  }
//+------------------------------------------------------------------+
//| Conversion of CMY into CMYK                                      |
//+------------------------------------------------------------------+
void CColors::CMYtoCMYK(const double aC,const double aM,const double aY,double &oC,double &oM,double &oY,double &oK)
  {
   double var_K=1;
//---
   if(aC<var_K)
      var_K=aC;
   if(aM<var_K)
      var_K=aM;
   if(aY<var_K)
      var_K=aY;
//---
   if(var_K==1.0)
     {
      oC =0;
      oM =0;
      oY =0;
     }
   else
     {
      oC =(aC-var_K)/(1.0-var_K);
      oM =(aM-var_K)/(1.0-var_K);
      oY =(aY-var_K)/(1.0-var_K);
     }
//---
   oK=var_K;
  }
//+------------------------------------------------------------------+
//| Conversion of CMYK into CMY                                      |
//+------------------------------------------------------------------+
void CColors::CMYKtoCMY(const double aC,const double aM,const double aY,const double aK,double &oC,double &oM,double &oY)
  {
   oC =(aC*(1.0-aK)+aK);
   oM =(aM*(1.0-aK)+aK);
   oY =(aY*(1.0-aK)+aK);
  }
//+------------------------------------------------------------------+
//| Conversion of RGB into Lab                                       |
//+------------------------------------------------------------------+
void CColors::RGBtoLab(const double aR,const double aG,const double aB,double &oL,double &oa,double &ob)
  {
   double X=0,Y=0,Z=0;
   RGBtoXYZ(aR,aG,aB,X,Y,Z);
   XYZtoHunterLab(X,Y,Z,oL,oa,ob);
  }
//+------------------------------------------------------------------+
//| Getting values of the RGB components                             |
//+------------------------------------------------------------------+
void CColors::ColorToRGB(const color aColor,double &aR,double &aG,double &aB)
  {
   aR =GetR(aColor);
   aG =GetG(aColor);
   aB =GetB(aColor);
  }
//+------------------------------------------------------------------+
//| Getting the R component value                                    |
//+------------------------------------------------------------------+
double CColors::GetR(const color aColor)
  {
   return(aColor&0xff);
  }
//+------------------------------------------------------------------+
//| Getting the G component value                                    |
//+------------------------------------------------------------------+
double CColors::GetG(const color aColor)
  {
   return((aColor>>8)&0xff);
  }
//+------------------------------------------------------------------+
//| Getting the B component value                                    |
//+------------------------------------------------------------------+
double CColors::GetB(const color aColor)
  {
   return((aColor>>16)&0xff);
  }
//+------------------------------------------------------------------+
//| Getting the A component value                                    |
//+------------------------------------------------------------------+
double CColors::GetA(const color aColor)
  {
   return(double(uchar((aColor)>>24)));
  }
//+------------------------------------------------------------------+
//| Conversion of RGB into const color                               |
//+------------------------------------------------------------------+
color CColors::RGBToColor(const double aR,const double aG,const double aB)
  {
   int int_r =(int)::round(aR);
   int int_g =(int)::round(aG);
   int int_b =(int)::round(aB);
   int Color =0;
//---
   Color=int_b;
   Color<<=8;
   Color|=int_g;
   Color<<=8;
   Color|=int_r;
//---
   return((color)Color);
  }
//+------------------------------------------------------------------+
//| Getting the value of the intermediary color between two colors   |
//+------------------------------------------------------------------+
color CColors::MixColors(const color aCol1,const color aCol2,const double aK)
  {
//--- aK - from 0 to 1
   double R1=0.0,G1=0.0,B1=0.0,R2=0.0,G2=0.0,B2=0.0;
//---
   ColorToRGB(aCol1,R1,G1,B1);
   ColorToRGB(aCol2,R2,G2,B2);
//---
   R1+=(int)::round(aK*(R2-R1));
   G1+=(int)::round(aK*(G2-G1));
   B1+=(int)::round(aK*(B2-B1));
//---
   return(RGBToColor(R1,G1,B1));
  }
//+------------------------------------------------------------------+
//| Blending two colors considering the transparency of color on top |
//+------------------------------------------------------------------+
color CColors::BlendColors(const uint lower_color,const uint upper_color)
  {
   double r1=0,g1=0,b1=0;
   double r2=0,g2=0,b2=0,alpha=0;
   double r3=0,g3=0,b3=0;
//--- Convert the colors in ARGB format
   uint pixel_color=::ColorToARGB(upper_color);
//--- Get the components of the lower and upper colors
   ColorToRGB(lower_color,r1,g1,b1);
   ColorToRGB(pixel_color,r2,g2,b2);
//--- Get the transparency percentage from 0.00 to 1.00
   alpha=GetA(upper_color)/255.0;
//--- If there is transparency
   if(alpha<1.0)
     {
      //--- Blend the components taking the alpha channel into account
      r3=(r1*(1-alpha))+(r2*alpha);
      g3=(g1*(1-alpha))+(g2*alpha);
      b3=(b1*(1-alpha))+(b2*alpha);
      //--- Adjustment of the obtained values
      r3=(r3>255)? 255 : r3;
      g3=(g3>255)? 255 : g3;
      b3=(b3>255)? 255 : b3;
     }
   else
     {
      r3=r2;
      g3=g2;
      b3=b2;
     }
//--- Combine the obtained components and return the color
   return(RGBToColor(r3,g3,b3));
  }
//+------------------------------------------------------------------+
//| Getting an array of the specified size with a color gradient     |
//+------------------------------------------------------------------+
void CColors::Gradient(color &aColors[],   // List of colors
                       color &aOut[],      // Return array
                       int   aOutCount,    // Set the size of the return array
                       bool  aCycle=false) // Closed-loop cycle. Return array ends with the same color as it starts with
  {
   ::ArrayResize(aOut,aOutCount);
//---
   int    InCount =::ArraySize(aColors)+aCycle;
   int    PrevJ   =0;
   int    nci     =0;
   double K       =0.0;
//---
   for(int i=1; i<InCount; i++)
     {
      int J=(aOutCount-1)*i/(InCount-1);
      //---
      for(int j=PrevJ; j<=J; j++)
        {
         if(aCycle && i==InCount-1)
           {
            nci =0;
            K   =1.0*(j-PrevJ)/(J-PrevJ+1);
           }
         else
           {
            nci =i;
            K   =1.0*(j-PrevJ)/(J-PrevJ);
           }
         aOut[j]=MixColors(aColors[i-1],aColors[nci],K);
        }
      PrevJ=J;
     }
  }
//+------------------------------------------------------------------+
//| One more variant of conversion of RGB into XYZ and               |
//| corresponding conversion of XYZ into RGB                         |
//+------------------------------------------------------------------+
void CColors::RGBtoXYZsimple(double aR,double aG,double aB,double &oX,double &oY,double &oZ)
  {
   aR/=255;
   aG/=255;
   aB/=255;
   aR*=100;
   aG*=100;
   aB*=100;
//---
   oX=0.431*aR+0.342*aG+0.178*aB;
   oY=0.222*aR+0.707*aG+0.071*aB;
   oZ=0.020*aR+0.130*aG+0.939*aB;
  }
//+------------------------------------------------------------------+
//| XYZtoRGBsimple                                                   |
//+------------------------------------------------------------------+
void CColors::XYZtoRGBsimple(const double aX,const double aY,const double aZ,double &oR,double &oG,double &oB)
  {
   oR=3.063*aX-1.393*aY-0.476*aZ;
   oG=-0.969*aX+1.876*aY+0.042*aZ;
   oB=0.068*aX-0.229*aY+1.069*aZ;
  }
//+------------------------------------------------------------------+
//| Negative color                                                   |
//+------------------------------------------------------------------+
color CColors::Negative(const color aColor)
  {
   double R=0.0,G=0.0,B=0.0;
   ColorToRGB(aColor,R,G,B);
//---
   return(RGBToColor(255-R,255-G,255-B));
  }
//+------------------------------------------------------------------+
//| Search for the most similar color                                |
//| in the set of standard colors of the terminal                    |
//+------------------------------------------------------------------+
color CColors::StandardColor(const color aColor,int &aIndex)
  {
   color m_c[]=
     {
      clrBlack,clrDarkGreen,clrDarkSlateGray,clrOlive,clrGreen,clrTeal,clrNavy,clrPurple,clrMaroon,clrIndigo,
      clrMidnightBlue,clrDarkBlue,clrDarkOliveGreen,clrSaddleBrown,clrForestGreen,clrOliveDrab,clrSeaGreen,
      clrDarkGoldenrod,clrDarkSlateBlue,clrSienna,clrMediumBlue,clrBrown,clrDarkTurquoise,clrDimGray,
      clrLightSeaGreen,clrDarkViolet,clrFireBrick,clrMediumVioletRed,clrMediumSeaGreen,clrChocolate,clrCrimson,
      clrSteelBlue,clrGoldenrod,clrMediumSpringGreen,clrLawnGreen,clrCadetBlue,clrDarkOrchid,clrYellowGreen,
      clrLimeGreen,clrOrangeRed,clrDarkOrange,clrOrange,clrGold,clrYellow,clrChartreuse,clrLime,clrSpringGreen,
      clrAqua,clrDeepSkyBlue,clrBlue,clrFuchsia,clrRed,clrGray,clrSlateGray,clrPeru,clrBlueViolet,clrLightSlateGray,
      clrDeepPink,clrMediumTurquoise,clrDodgerBlue,clrTurquoise,clrRoyalBlue,clrSlateBlue,clrDarkKhaki,clrIndianRed,
      clrMediumOrchid,clrGreenYellow,clrMediumAquamarine,clrDarkSeaGreen,clrTomato,clrRosyBrown,clrOrchid,
      clrMediumPurple,clrPaleVioletRed,clrCoral,clrCornflowerBlue,clrDarkGray,clrSandyBrown,clrMediumSlateBlue,
      clrTan,clrDarkSalmon,clrBurlyWood,clrHotPink,clrSalmon,clrViolet,clrLightCoral,clrSkyBlue,clrLightSalmon,
      clrPlum,clrKhaki,clrLightGreen,clrAquamarine,clrSilver,clrLightSkyBlue,clrLightSteelBlue,clrLightBlue,
      clrPaleGreen,clrThistle,clrPowderBlue,clrPaleGoldenrod,clrPaleTurquoise,clrLightGray,clrWheat,clrNavajoWhite,
      clrMoccasin,clrLightPink,clrGainsboro,clrPeachPuff,clrPink,clrBisque,clrLightGoldenrod,clrBlanchedAlmond,
      clrLemonChiffon,clrBeige,clrAntiqueWhite,clrPapayaWhip,clrCornsilk,clrLightYellow,clrLightCyan,clrLinen,
      clrLavender,clrMistyRose,clrOldLace,clrWhiteSmoke,clrSeashell,clrIvory,clrHoneydew,clrAliceBlue,clrLavenderBlush,
      clrMintCream,clrSnow,clrWhite,clrDarkCyan,clrDarkRed,clrDarkMagenta,clrAzure,clrGhostWhite,clrFloralWhite
     };
//---
   double m_rv=0.0,m_gv=0.0,m_bv=0.0;
//---
   ColorToRGB(aColor,m_rv,m_gv,m_bv);
//---
   double m_md=0.3*::pow(255,2)+0.59*::pow(255,2)+0.11*::pow(255,2)+1;
   aIndex=0;
//---
   for(int i=0; i<138; i++)
     {
      double m_d=0.3*::pow(GetR(m_c[i])-m_rv,2)+0.59*::pow(GetG(m_c[i])-m_gv,2)+0.11*::pow(GetB(m_c[i])-m_bv,2);
      //---
      if(m_d<m_md)
        {
         m_md   =m_d;
         aIndex =i;
        }
     }
//---
   return(m_c[aIndex]);
  }
//+------------------------------------------------------------------+
//| Conversion into gray color                                       |
//+------------------------------------------------------------------+
double CColors::RGBtoGray(double aR,double aG,double aB)
  {
   aR/=255;
   aG/=255;
   aB/=255;
//---
   aR=::pow(aR,2.2);
   aG=::pow(aG,2.2);
   aB=::pow(aB,2.2);
//---
   double rY=0.21*aR+0.72*aG+0.07*aB;
   rY=::pow(rY,1.0/2.2);
//---
   return(rY);
  }
//+------------------------------------------------------------------+
//| Simple conversion into gray color                                |
//+------------------------------------------------------------------+
double CColors::RGBtoGraySimple(double aR,double aG,double aB)
  {
   aR/=255;
   aG/=255;
   aB/=255;
   double rY=0.3*aR+0.59*aG+0.11*aB;
//---
   return(rY);
  }
//+------------------------------------------------------------------+

Alle vorgenommenen Änderungen beschränken sich auf das Setzen der Modifikation 'static' für jede der Methoden sowie auf einige rein kosmetische Änderungen (abgesehen von den Variablennamen in den Methodenargumenten), die meinem Codierungsstil entsprechen. Außerdem habe ich die Methode RGBtoLab() zum Konvertieren des RGB-Farbmodells in Lab hinzugefügt. Die Methode konvertiert einfach das RGB-Modell in XYZ, das wiederum in das Lab-Farbmodell umgewandelt wird. Dieser Sachverhalt wurde einst von Anatoli Kazharski in seinem Artikel "Graphical Interfaces IX: The Color Picker Control (Chapter 1)" betrachtet:

Es gibt keine geeignete Methode in der Klasse CColors für die Konvertierung vom Format RGB nach Lab. Wenn die Konvertierung RGB->Lab erforderlich ist, muss daher eine doppelte Korrektur über das Farbmaster-Modell XYZ vorgenommen werden: RGB->XYZ->Lab.

Ich habe einfach den Rat des Autors befolgt.

Um die CColors Klasse für die gesamte Bibliothek und darauf basierende Programme sichtbar zu machen, müssen wir die Klassendatei in die Datei der Bibliotheksdienstfunktionen in \MQL5\Include\DoEasy\Services\DELib.mqh einbinden:

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property strict  // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\Defines.mqh"
#include "Message.mqh"
#include "TimerCounter.mqh"
#include "Pause.mqh"
#include "Colors.mqh"
//+------------------------------------------------------------------+
//| Service functions                                                |
//+------------------------------------------------------------------+

Ich werde die Klasse hier nicht benötigen, aber ich werde sie später beim Erstellen der Nachfolgeklassen der grafischen Elementobjekte verwenden.

Jedes grafische Objekt verfügt zumindest über seine Größe und die Koordinaten seiner Position auf dem Chart. Außerdem sind unsere Objekte mit vielen Eigenschaften ausgestattet, die bei laufendem Programm geändert werden können. Wenn wir jedoch das Programm neu starten oder den Zeitrahmen wechseln, werden alle Änderungen, die wir an grafischen Objekten vorgenommen haben, während das Programm läuft, zurückgesetzt. Damit sich jedes Objekt den Zustand seiner Eigenschaften merken kann, müssen wir sie außerhalb speichern. In diesem Fall lesen nach dem Neustart des Programms alle grafischen Objekte, die während seines Betriebs konstruiert und geändert wurden, ihre entsprechenden Eigenschaften (die ab dem Zeitpunkt des Zurücksetzens relevant sind) aus der Datei und stellen sie wieder her. Um dies zu erreichen, müssen wir der Objektklasse des grafischen Elements zwei Methoden hinzufügen — die Methode zum Schreiben der Objekteigenschaften in die Datei und die zum Lesen der Objekteigenschaften aus der Datei.

Um die Objekteigenschaften zu lesen und zu schreiben, werde ich die Objekteigenschaften in der Struktur speichern, während die Struktur mit den Standardfunktionen StructToCharArray() und CharArrayToStruct() sowohl in der Datei gespeichert als auch aus ihr gelesen werden kann.

Jedes grafische Objekt soll die Methoden zum Speichern von Eigenschaften in die Datei und zum Lesen aus der Datei aufweisen, da jedes grafische Objekt, das auf dem Canvas basiert, ein Nachkomme des grafischen Elementobjekts sein soll, in dem die Methoden gesetzt werden sollen. Wenn das Objekt also zusammengesetzt ist (d. h. es besteht aus anderen Objekten, die auf dem grafischen Element basieren), können wir die Zustände aller seiner untergeordneten Objekte nacheinander entsprechend dem Objektindex in der Liste der untergeordneten Objekte wiederherstellen (der Index ist in der Konstante CANV_ELEMENT_PROP_NUM der Enumeration ENUM_CANV_ELEMENT_PROP_INTEGER der Eigenschaften des Elementobjekts gespeichert).

In diesem Artikel werde ich die Eigenschaften nicht in der Datei speichern/aus der Datei lesen, da dies von der Klasse der grafischen Objektkollektion aus geschehen soll. Ich werde dies später — nach der Erstellung des grafischen Elements — berücksichtigen. Wie auch immer, die Schreib- und Lesemethoden werden hier hinzugefügt.

Da das grafische Element vom Basisobjekts aller grafischen Objekte der CGBaseObj-Bibliothek abgeleitet ist, setzen wir zunächst die virtuelle Methode zum Erzeugen der Struktur aus den Objekteigenschaften und die virtuelle Methode zum Wiederherstellen der Objekteigenschaften aus der Struktur in den geschützten Abschnitt der Objektklassendatei (\MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh):

protected:
   string            m_name_prefix;                      // Object name prefix
   string            m_name;                             // Object name
   long              m_chart_id;                         // Chart ID
   int               m_subwindow;                        // Subwindow index
   int               m_shift_y;                          // Subwindow Y coordinate shift
   int               m_type;                             // Object type

//--- Create (1) the object structure and (2) the object from the structure
   virtual bool      ObjectToStruct(void)                      { return true; }
   virtual void      StructToObject(void){;}

public:

Diese Methoden machen hier nichts — sie müssten in den abgeleiteten Klassen neu definiert werden. Der nächste Nachfahre der Klasse ist die Klasse des grafischen Elementobjekts in \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh. Deklarieren wir dieselben virtuellen Methoden in seinem geschützten Abschnitt:

//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CGCnvElement : public CGBaseObj
  {
protected:
   CCanvas           m_canvas;                                 // CCanvas class object
   CPause            m_pause;                                  // Pause class object
//--- Return the cursor position relative to the (1) entire element and (2) the element active area
   bool              CursorInsideElement(const int x,const int y);
   bool              CursorInsideActiveArea(const int x,const int y);
//--- Create (1) the object structure and (2) the object from the structure
   virtual bool      ObjectToStruct(void);
   virtual void      StructToObject(void);

private:

Im privaten Bereich deklarieren wir die Struktur zur Speicherung aller Objekteigenschaften, das Objekt mit dem Strukturtyp und das Objektstruktur-Array:

private:
   struct SData
     {
      //--- Object integer properties
      int            id;                                       // Element ID
      int            type;                                     // Graphical element type
      int            number;                                   // Element index in the list
      long           chart_id;                                 // Chart ID
      int            subwindow;                                // Chart subwindow index
      int            coord_x;                                  // Form's X coordinate on the chart
      int            coord_y;                                  // Form's Y coordinate on the chart
      int            width;                                    // Element width
      int            height;                                   // Element height
      int            edge_right;                               // Element right border
      int            edge_bottom;                              // Element bottom border
      int            act_shift_left;                           // Active area offset from the left edge of the element
      int            act_shift_top;                            // Active area offset from the top edge of the element
      int            act_shift_right;                          // Active area offset from the right edge of the element
      int            act_shift_bottom;                         // Active area offset from the bottom edge of the element
      uchar          opacity;                                  // Element opacity
      color          color_bg;                                 // Element background color
      bool           movable;                                  // Element moveability flag
      bool           active;                                   // Element activity flag
      int            coord_act_x;                              // X coordinate of the element active area
      int            coord_act_y;                              // Y coordinate of the element active area
      int            coord_act_right;                          // Right border of the element active area
      int            coord_act_bottom;                         // Bottom border of the element active area
      //--- Object real properties

      //--- Object string properties
      uchar          name_obj[64];                             // Graphical element object name
      uchar          name_res[64];                             // Graphical resource name
     };
   SData             m_struct_obj;                             // Object structure
   uchar             m_uchar_array[];                          // uchar array of the object structure
   
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];    // Integer properties
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];   // Real properties
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];   // String properties

Im öffentlichen Abschnitt der Klasse deklarieren wir die Methoden zum Schreiben und Lesen von Objekteigenschaften aus der Datei:

public:
//--- Set object (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                   }
   void              SetProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value; }
   void              SetProperty(ENUM_CANV_ELEMENT_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value; }
//--- Return object (1) integer, (2) real and (3) string property from the properties array
   long              GetProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property)        const { return this.m_long_prop[property];                  }
   double            GetProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];}
   string            GetProperty(ENUM_CANV_ELEMENT_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];}

//--- Return the flag of the object supporting this property
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property)          { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)           { return false;}
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)           { return true; }

//--- Compare CGCnvElement objects with each other by all possible properties (for sorting the lists by a specified object property)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CGCnvElement objects with each other by all properties (to search equal objects)
   bool              IsEqual(CGCnvElement* compared_obj) const;

//--- (1) Save the object to file and (2) upload the object from the file
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);

//--- Create the element

Da das Objekt keine realen Eigenschaften hat, sollte die virtuelle Methode, die das Flag der Unterstützung realer Eigenschaften durch das Objekt zurückgibt, false zurückgeben.

Implementieren wir die deklarierten Methoden außerhalb des Klassenkörpers.

Die Methode, die die Struktur des Objekts aus seinen Eigenschaften erzeugt:

//+------------------------------------------------------------------+
//| Create the object structure                                      |
//+------------------------------------------------------------------+
bool CGCnvElement::ObjectToStruct(void)
  {
//--- Save integer properties
   this.m_struct_obj.id=(int)this.GetProperty(CANV_ELEMENT_PROP_ID);                            // Element ID
   this.m_struct_obj.type=(int)this.GetProperty(CANV_ELEMENT_PROP_TYPE);                        // Graphical element type
   this.m_struct_obj.number=(int)this.GetProperty(CANV_ELEMENT_PROP_NUM);                       // Eleemnt ID in the list
   this.m_struct_obj.chart_id=this.GetProperty(CANV_ELEMENT_PROP_CHART_ID);                     // Chart ID
   this.m_struct_obj.subwindow=(int)this.GetProperty(CANV_ELEMENT_PROP_WND_NUM);                // Chart subwindow index
   this.m_struct_obj.coord_x=(int)this.GetProperty(CANV_ELEMENT_PROP_COORD_X);                  // Form's X coordinate on the chart
   this.m_struct_obj.coord_y=(int)this.GetProperty(CANV_ELEMENT_PROP_COORD_Y);                  // Form's Y coordinate on the chart
   this.m_struct_obj.width=(int)this.GetProperty(CANV_ELEMENT_PROP_WIDTH);                      // Element width
   this.m_struct_obj.height=(int)this.GetProperty(CANV_ELEMENT_PROP_HEIGHT);                    // Element height
   this.m_struct_obj.edge_right=(int)this.GetProperty(CANV_ELEMENT_PROP_RIGHT);                 // Element right edge
   this.m_struct_obj.edge_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_BOTTOM);               // Element bottom edge
   this.m_struct_obj.act_shift_left=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT);    // Active area offset from the left edge of the element
   this.m_struct_obj.act_shift_top=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP);      // Active area offset from the top edge of the element
   this.m_struct_obj.act_shift_right=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT);  // Active area offset from the right edge of the element
   this.m_struct_obj.act_shift_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM);// Active area offset from the bottom edge of the element
   this.m_struct_obj.opacity=(uchar)this.GetProperty(CANV_ELEMENT_PROP_OPACITY);                // Element opacity
   this.m_struct_obj.color_bg=(color)this.GetProperty(CANV_ELEMENT_PROP_COLOR_BG);              // Element background color
   this.m_struct_obj.movable=(bool)this.GetProperty(CANV_ELEMENT_PROP_MOVABLE);                 // Element moveability flag
   this.m_struct_obj.active=(bool)this.GetProperty(CANV_ELEMENT_PROP_ACTIVE);                   // Element activity flag
   this.m_struct_obj.coord_act_x=(int)this.GetProperty(CANV_ELEMENT_PROP_COORD_ACT_X);          // X coordinate of the element active area
   this.m_struct_obj.coord_act_y=(int)this.GetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y);          // Y coordinate of the element active area
   this.m_struct_obj.coord_act_right=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_RIGHT);        // Right border of the element active area
   this.m_struct_obj.coord_act_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM);      // Bottom border of the element active area
//--- Save real properties

//--- Save string properties
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_OBJ),this.m_struct_obj.name_obj);// Graphical element object name
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_RES),this.m_struct_obj.name_res);// Graphical resource name
   //--- Save the structure to the uchar array
   ::ResetLastError();
   if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY),(string)::GetLastError());
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+

Hier ist alles ganz einfach: Jedes ganzzahlige Strukturfeld erhält die entsprechende Objekt-Eigenschaft, während Texteigenschaften des Objekts in einen entsprechenden uchar-Array der Struktur gespeichert werden. Als Nächstes speichern wir einfach die neu erstellte Struktur der Objekteigenschafts in das uchar-Array mit StructToCharArray().
Wenn das Speichern der Struktur in das Array fehlgeschlagen ist, wird über den Fehler informiert und false zurückgegeben. Sonst wird als Ergebnis true zurückgegeben.

Die Methode restauriert die Objekteigenschaften aus der Struktur:

//+------------------------------------------------------------------+
//| Create the object from the structure                             |
//+------------------------------------------------------------------+
void CGCnvElement::StructToObject(void)
  {
//--- Save integer properties
   this.SetProperty(CANV_ELEMENT_PROP_ID,this.m_struct_obj.id);                                 // Element ID
   this.SetProperty(CANV_ELEMENT_PROP_TYPE,this.m_struct_obj.type);                             // Graphical element type
   this.SetProperty(CANV_ELEMENT_PROP_NUM,this.m_struct_obj.number);                            // Element index in the list
   this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,this.m_struct_obj.chart_id);                     // Chart ID
   this.SetProperty(CANV_ELEMENT_PROP_WND_NUM,this.m_struct_obj.subwindow);                     // Chart subwindow index
   this.SetProperty(CANV_ELEMENT_PROP_COORD_X,this.m_struct_obj.coord_x);                       // Form's X coordinate on the chart
   this.SetProperty(CANV_ELEMENT_PROP_COORD_Y,this.m_struct_obj.coord_y);                       // Form's Y coordinate on the chart
   this.SetProperty(CANV_ELEMENT_PROP_WIDTH,this.m_struct_obj.width);                           // Element width
   this.SetProperty(CANV_ELEMENT_PROP_HEIGHT,this.m_struct_obj.height);                         // Element height
   this.SetProperty(CANV_ELEMENT_PROP_RIGHT,this.m_struct_obj.edge_right);                      // Element right edge
   this.SetProperty(CANV_ELEMENT_PROP_BOTTOM,this.m_struct_obj.edge_bottom);                    // Element bottom edge
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,this.m_struct_obj.act_shift_left);         // Active area offset from the left edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,this.m_struct_obj.act_shift_top);           // Active area offset from the upper edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,this.m_struct_obj.act_shift_right);       // Active area offset from the right edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,this.m_struct_obj.act_shift_bottom);     // Active area offset from the bottom edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_OPACITY,this.m_struct_obj.opacity);                       // Element opacity
   this.SetProperty(CANV_ELEMENT_PROP_COLOR_BG,this.m_struct_obj.color_bg);                     // Element background color
   this.SetProperty(CANV_ELEMENT_PROP_MOVABLE,this.m_struct_obj.movable);                       // Element moveability flag
   this.SetProperty(CANV_ELEMENT_PROP_ACTIVE,this.m_struct_obj.active);                         // Element activity flag
   this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_X,this.m_struct_obj.coord_act_x);               // X coordinate of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y,this.m_struct_obj.coord_act_y);               // Y coordinate of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.m_struct_obj.coord_act_right);             // Right border of the element active area
   this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.m_struct_obj.coord_act_bottom);           // Bottom border of the element active area
//--- Save real properties

//--- Save string properties
   this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,::CharArrayToString(this.m_struct_obj.name_obj));// Graphical element object name
   this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,::CharArrayToString(this.m_struct_obj.name_res));// Graphical resource name
  }
//+------------------------------------------------------------------+

Hier erhält jede ganzzahlige Objekteigenschaft den Wert aus dem entsprechenden Strukturfeld, während der Inhalt der entsprechenden uchar-Array-Struktur mittels CharArrayToString() als Text in die Objekt-Eigenschaften eingetragen wird.

Die Methode speichert das Objekt in der Datei:

//+------------------------------------------------------------------+
//| Save the object to the file                                      |
//+------------------------------------------------------------------+
bool CGCnvElement::Save(const int file_handle)
  {
   if(!this.ObjectToStruct())
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT));
      return false;
     }
   if(::FileWriteArray(file_handle,this.m_uchar_array)==0)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_WRITE_UARRAY_TO_FILE));
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+

Die Methode erhält das Handle der Datei, in der die Objekteigenschaften gespeichert werden sollen. Die Objekteigenschaften werden dann mit der oben betrachteten Methode ObjectToStruct() in der Struktur gespeichert. Das beim Konstruieren der Struktur erzeugte uchar-Array wird mit FileWriteArray() in die Datei geschrieben und true zurückgegeben. Im Falle eines Fehlers zeigt die Methode die Fehlermeldung im Journal an und gibt false zurück.

Die Methode lädt die Objekteigenschaften aus der Datei hoch:

//+------------------------------------------------------------------+
//| Upload the object from the file                                  |
//+------------------------------------------------------------------+
bool CGCnvElement::Load(const int file_handle)
  {
   if(::FileReadArray(file_handle,this.m_uchar_array)==0)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_LOAD_UARRAY_FROM_FILE));
      return false;
     }
   if(!::CharArrayToStruct(this.m_struct_obj,this.m_uchar_array))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT_FROM_UARRAY));
      return false;
     }
   this.StructToObject();
   return true;
  }
//+------------------------------------------------------------------+

Die Methode erhält das Handle der Datei mit den gespeicherten Objekteigenschaften. Anschließend werden die Objekteigenschaften aus der Datei mit FileReadArray() in das uchar-Array hochgeladen. Die hochgeladenen Eigenschaften werden mit CharArrayToStruct() in die Struktur kopiert. Die aus der Datei ausgefüllte Struktur wird mit der oben genannten Methode StructToObject() in den Objekteigenschaften gesetzt und true zurückgegeben. Wenn das Lesen aus der Datei oder das Kopieren des erhaltenen Arrays in die Struktur mit einem Fehler endet, teilt die Methode dies mit und gibt false zurück.

Der Methodenblock für einen vereinfachten Zugriff auf Objekteigenschaften erhält die Methoden zur Rückgabe des rechten und unteren Elementrandes, die Methoden zum Setzen und zurückgeben der Element-Hintergrundfarbe, sowie die Methoden zur Rückgabe der Element-ID und dessen Index in der Liste der Elemente im zusammengesetzten Objekt:

//+------------------------------------------------------------------+
//| The methods of simplified access to object properties            |
//+------------------------------------------------------------------+
//--- Set the (1) X, (2) Y coordinates, (3) element width, (4) height, (5) right (6) and bottom edge,
   bool              SetCoordX(const int coord_x);
   bool              SetCoordY(const int coord_y);
   bool              SetWidth(const int width);
   bool              SetHeight(const int height);
   void              SetRightEdge(void)                        { this.SetProperty(CANV_ELEMENT_PROP_RIGHT,this.RightEdge());           }
   void              SetBottomEdge(void)                       { this.SetProperty(CANV_ELEMENT_PROP_BOTTOM,this.BottomEdge());         }
//--- Set the shift of the (1) left, (2) top, (3) right, (4) bottom edge of the active area relative to the element,
//--- (5) all shifts of the active area edges relative to the element, (6) the element background color and (7) the element opacity
   void              SetActiveAreaLeftShift(const int value)   { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,fabs(value));       }
   void              SetActiveAreaRightShift(const int value)  { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,fabs(value));      }
   void              SetActiveAreaTopShift(const int value)    { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,fabs(value));        }
   void              SetActiveAreaBottomShift(const int value) { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,fabs(value));     }
   void              SetActiveAreaShift(const int left_shift,const int bottom_shift,const int right_shift,const int top_shift);
   void              SetColorBG(const color colour)            { this.SetProperty(CANV_ELEMENT_PROP_COLOR_BG,colour);                  }
   void              SetOpacity(const uchar value,const bool redraw=false);
   
//--- Return the shift (1) of the left, (2) right, (3) top and (4) bottom edge of the element active area
   int               ActiveAreaLeftShift(void)           const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT);       }
   int               ActiveAreaRightShift(void)          const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT);      }
   int               ActiveAreaTopShift(void)            const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP);        }
   int               ActiveAreaBottomShift(void)         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM);     }
//--- Return the coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the element active area
   int               ActiveAreaLeft(void)                const { return int(this.CoordX()+this.ActiveAreaLeftShift());                 }
   int               ActiveAreaRight(void)               const { return int(this.RightEdge()-this.ActiveAreaRightShift());             }
   int               ActiveAreaTop(void)                 const { return int(this.CoordY()+this.ActiveAreaTopShift());                  }
   int               ActiveAreaBottom(void)              const { return int(this.BottomEdge()-this.ActiveAreaBottomShift());           }
//--- Return (1) the background color, (2) the opacity, coordinate (3) of the right and (4) bottom element edge
   color             ColorBG(void)                       const { return (color)this.GetProperty(CANV_ELEMENT_PROP_COLOR_BG);           }
   uchar             Opacity(void)                       const { return (uchar)this.GetProperty(CANV_ELEMENT_PROP_OPACITY);            }
   int               RightEdge(void)                     const { return this.CoordX()+this.m_canvas.Width();                           }
   int               BottomEdge(void)                    const { return this.CoordY()+this.m_canvas.Height();                          }
//--- Return the (1) X, (2) Y coordinates, (3) element width and (4) height,
   int               CoordX(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_COORD_X);              }
   int               CoordY(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_COORD_Y);              }
   int               Width(void)                         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_WIDTH);                }
   int               Height(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_HEIGHT);               }
//--- Return the element (1) moveability and (2) activity flag
   bool              Movable(void)                       const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_MOVABLE);             }
   bool              Active(void)                        const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_ACTIVE);              }
//--- Return (1) the object name, (2) the graphical resource name, (3) the chart ID and (4) the chart subwindow index
   string            NameObj(void)                       const { return this.GetProperty(CANV_ELEMENT_PROP_NAME_OBJ);                  }
   string            NameRes(void)                       const { return this.GetProperty(CANV_ELEMENT_PROP_NAME_RES);                  }
   long              ChartID(void)                       const { return this.GetProperty(CANV_ELEMENT_PROP_CHART_ID);                  }
   int               WindowNum(void)                     const { return (int)this.GetProperty(CANV_ELEMENT_PROP_WND_NUM);              }
//--- Return (1) the element ID and (2) index in the list
   int               ID(void)                            const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ID);                   }
   int               Number(void)                        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_NUM);                  }

//+------------------------------------------------------------------+

Alle diese Methoden geben einfach die entsprechende Eigenschaft des Elementobjekts zurück.


Die Methoden für das Arbeit mit den Primitiven

Die Klasse CCanvas bietet eine Vielzahl von Möglichkeiten, um verschiedene grafische Primitive auf der Leinwand bzw. Canvas zu zeichnen. Wir sind in der Lage, entweder die Farbe jedes Pixels auszulesen oder ihm die gewünschte Farbe und Transparenz zuzuweisen. Neben dem einfachen Setzen einer Farbe auf ein Pixel bietet die Klasse die Möglichkeit, verschiedene Figuren entweder Pixel für Pixel (ohne Glättung) oder mit Hilfe verschiedener Glättungsmethoden zu zeichnen.

Die Objektklasse des grafischen Elements soll dem Anwender den Zugriff auf die Zeichenmethoden der Klasse CCanvas ermöglichen. Unsere Methoden werden den Aufruf der Methoden der Klasse CCanvas nur geringfügig vereinfachen. Die Vereinfachung besteht darin, dass die Farbe auf die übliche Art und Weise eingestellt wird — durch Angabe der notwendigen Farbe im color Format und Einstellung des Grades der Farbopazität (0 — transparent, 255 — völlig undurchsichtig), während die Methoden der CCanvas-Klasse "bitten", die Farbe sofort im uint ARGB-Format anzugeben, das nur eine Zahl ist. Nicht jeder ist mit der Angabe der gewünschten Farbe in diesem Format zufrieden (halbtransparentes Grau: 0x7F7F7F7F). In den abgeleiteten Klassen, die von dem Objekt des grafischen Elements abgeleitet werden sollen, werde ich die Palette der Zeichenfunktionen erweitern, indem ich die komfortable Funktionalität, die jeder erstellten Klasse innewohnt, hinzufüge. In der gleichen Klasse, die die Grundlage für die Erstellung der übrigen grafischen Objekte bildet, sollen die Zeichenmethoden einfach und überschaubar sein.

Auf den Methodenblock für den vereinfachten Zugriff auf die Objekteigenschaften folgen neue Codeblöcke. Ich habe versucht, sie entsprechend ihrem Zweck zu verteilen.
Methoden zum Empfangen von Daten beginnen mit "Get", während Methoden zum Setzen von Daten mit "Set" beginnen.

Die Methode empfängt die Farbe des Punktes mit den angegebenen Koordinaten:

//+------------------------------------------------------------------+
//| The methods of receiving raster data                             |
//+------------------------------------------------------------------+
//--- Get a color of the dot with the specified coordinates
   uint              GetPixel(const int x,const int y)   const { return this.m_canvas.PixelGet(x,y);                                   }

//+------------------------------------------------------------------+

Hier wird das Ergebnis des Aufrufs der Methode PixelGet() der Klasse CCanvas zurückgegeben. Die Methode gibt die Farbe im ARGB-Format zurück.

Die Methoden des Füllens, Löschens und Aktualisierens von Rasterdaten:

//+------------------------------------------------------------------+
//| The methods of filling, clearing and updating raster data        |
//+------------------------------------------------------------------+
//--- Clear the element filling it with color and opacity
   void              Erase(const color colour,const uchar opacity,const bool redraw=false);
//--- Clear the element completely
   void              Erase(const bool redraw=false);
//--- Update the element
   void              Update(const bool redraw=false)           { this.m_canvas.Update(redraw);                                         }
   
//+------------------------------------------------------------------+

Die Methode Update() aktualisiert einfach das Objekt und das Chart mit der Methode Update() der Klasse CCanvas.

Die Erase()-Methoden werden außerhalb des Hauptteils der Klasse implementiert:

//+------------------------------------------------------------------+
//| Clear the element filling it with color and opacity              |
//+------------------------------------------------------------------+
void CGCnvElement::Erase(const color colour,const uchar opacity,const bool redraw=false)
  {
   this.m_canvas.Erase(::ColorToARGB(colour,opacity));
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }
//+------------------------------------------------------------------+
//| Clear the element completely                                     |
//+------------------------------------------------------------------+
void CGCnvElement::Erase(const bool redraw=false)
  {
   this.m_canvas.Erase(NULL_COLOR);
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }
//+------------------------------------------------------------------+

Dies sind zwei überladene Methoden.
In der ersten übergeben wir die gewünschte Farbe und Transparenz, mit der das gesamte Element mit Hilfe der Erase()-Methode der CCanvas-Klasse gefüllt werden soll. Bitte beachten Sie, dass die Methode die Farbe und die Transparenz, die an die Methode Erase() der Klasse CCanvas übergeben wurden, mit Hilfe der Funktion ColorToARGB() in das ARGB-Format umwandelt. Das werde ich in allen Zeichenmethoden tun.
In der zweiten Methode füllen wir einfach den gesamten Hintergrund mit einer komplett transparenten schwarzen Farbe. Der Wert wurde zuvor mit der Makro-Substitution NULL_COLOR definiert.
Jede der Methoden erhält das Flag, das die Notwendigkeit anzeigt, das Chart neu zu zeichnen. Wenn das Flag gesetzt ist, wird das Chart neu gezeichnet.

Es folgt der Methodenblock zum Zeichnen von Primitiven ohne Glättung. Alle Methoden sind identisch und rufen die entsprechenden Methoden der Klasse CCanvas auf. Diese Methoden erhalten die in den Methodenargumenten angegebenen Parameter und die in das ARGB-Format konvertierte Farbe aus den an die Methoden übergebenen Farb- und Transparenzwerten:

//+------------------------------------------------------------------+
//| The methods of drawing primitives without smoothing              |
//+------------------------------------------------------------------+
//--- Set the color of the dot with the specified coordinates
   void              SetPixel(const int x,const int y,const color clr,const uchar opacity=255)
                       { this.m_canvas.PixelSet(x,y,::ColorToARGB(clr,opacity));                                                       }
                       
//--- Draw a segment of a vertical line
   void              DrawLineVertical(const int x,                // X coordinate of the segment
                                      const int y1,               // Y coordinate of the segment first point
                                      const int y2,               // Y coordinate of the segment second point
                                      const color clr,            // Color
                                      const uchar opacity=255)    // Opacity
                       { this.m_canvas.LineVertical(x,y1,y2,::ColorToARGB(clr,opacity));                                               }
                       
//--- Draw a segment of a horizontal line
   void              DrawLineHorizontal(const int x1,             // X coordinate of the segment first point
                                        const int x2,             // X coordinate of the segment second point
                                        const int y,              // Segment Y coordinate
                                        const color clr,          // Color
                                        const uchar opacity=255)  // Opacity
                       { this.m_canvas.LineHorizontal(x1,x2,y,::ColorToARGB(clr,opacity));                                             }
                       
//--- Draw a segment of a freehand line
   void              DrawLine(const int x1,                       // X coordinate of the segment first point
                              const int y1,                       // Y coordinate of the segment first point
                              const int x2,                       // X coordinate of the segment second point
                              const int y2,                       // Y coordinate of the segment second point
                              const color clr,                    // Color
                              const uchar opacity=255)            // Opacity
                       { this.m_canvas.Line(x1,y1,x2,y2,::ColorToARGB(clr,opacity));                                                   }
                       
//--- Draw a polyline
   void              DrawPolyline(int &array_x[],                 // Array with the X coordinates of polyline points
                                  int & array_y[],                // Array with the Y coordinates of polyline points
                                  const color clr,                // Color
                                  const uchar opacity=255)        // Opacity
                       { this.m_canvas.Polyline(array_x,array_y,::ColorToARGB(clr,opacity));                                           }
                       
//--- Draw a polygon
   void              DrawPolygon(int &array_x[],                  // Array with the X coordinates of polygon points
                                 int &array_y[],                  // Array with the Y coordinates of polygon points
                                 const color clr,                 // Color
                                 const uchar opacity=255)         // Opacity
                       { this.m_canvas.Polygon(array_x,array_y,::ColorToARGB(clr,opacity));                                            }
                       
//--- Draw a rectangle using two points
   void              DrawRectangle(const int x1,                  // X coordinate of the first point defining the rectangle
                                   const int y1,                  // Y coordinate of the first point defining the rectangle
                                   const int x2,                  // X coordinate of the second point defining the rectangle
                                   const int y2,                  // Y coordinate of the second point defining the rectangle
                                   const color clr,               // color
                                   const uchar opacity=255)       // Opacity
                       { this.m_canvas.Rectangle(x1,y1,x2,y2,::ColorToARGB(clr,opacity));                                              }
                       
//--- Draw a circle
   void              DrawCircle(const int x,                      // X coordinate of the circle center
                                const int y,                      // Y coordinate of the circle center
                                const int r,                      // Circle radius
                                const color clr,                  // Color
                                const uchar opacity=255)          // Opacity
                       { this.m_canvas.Circle(x,y,r,::ColorToARGB(clr,opacity));                                                       }
                       
//--- Draw a triangle
   void              DrawTriangle(const int x1,                   // X coordinate of the triangle first vertex
                                  const int y1,                   // Y coordinate of the triangle first vertex
                                  const int x2,                   // X coordinate of the triangle second vertex
                                  const int y2,                   // Y coordinate of the triangle second vertex
                                  const int x3,                   // X coordinate of the triangle third vertex
                                  const int y3,                   // Y coordinate of the triangle third vertex
                                  const color clr,                // Color
                                  const uchar opacity=255)        // Opacity
                       { m_canvas.Triangle(x1,y1,x2,y2,x3,y3,::ColorToARGB(clr,opacity));                                              }
                       
//--- Draw an ellipse using two points
   void              DrawEllipse(const int x1,                    // X coordinate of the first point defining the ellipse
                                 const int y1,                    // Y coordinate of the first point defining the ellipse
                                 const int x2,                    // X coordinate of the second point defining the ellipse
                                 const int y2,                    // Y coordinate of the second point defining the ellipse
                                 const color clr,                 // Color
                                 const uchar opacity=255)         // Opacity
                       { this.m_canvas.Ellipse(x1,y1,x2,y2,::ColorToARGB(clr,opacity));                                                }
                       
//--- Draw an arc of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2).
//--- The arc boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4)
   void              DrawArc(const int x1,                        // X coordinate of the top left corner forming the rectangle
                             const int y1,                        // Y coordinate of the top left corner forming the rectangle
                             const int x2,                        // X coordinate of the bottom right corner forming the rectangle
                             const int y2,                        // Y coordinate of the bottom right corner forming the rectangle
                             const int x3,                        // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                             const int y3,                        // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                             const int x4,                        // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                             const int y4,                        // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary
                             const color clr,                     // Color
                             const uchar opacity=255)             // Opacity
                       { m_canvas.Arc(x1,y1,x2,y2,x3,y3,x4,y4,::ColorToARGB(clr,opacity));                                             }
                       
//--- Draw a filled sector of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2).
//--- The sector boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4)
   void              DrawPie(const int x1,                        // X coordinate of the upper left corner of the rectangle
                             const int y1,                        // Y coordinate of the upper left corner of the rectangle
                             const int x2,                        // X coordinate of the bottom right corner of the rectangle
                             const int y2,                        // Y coordinate of the bottom right corner of the rectangle
                             const int x3,                        // X coordinate of the first point to find the arc boundaries
                             const int y3,                        // Y coordinate of the first point to find the arc boundaries
                             const int x4,                        // X coordinate of the second point to find the arc boundaries
                             const int y4,                        // Y coordinate of the second point to find the arc boundaries
                             const color clr,                     // Line color
                             const color fill_clr,                // Fill color
                             const uchar opacity=255)             // Opacity
                       { this.m_canvas.Pie(x1,y1,x2,y2,x3,y3,x4,y4,::ColorToARGB(clr,opacity),ColorToARGB(fill_clr,opacity));          }
                       
//+------------------------------------------------------------------+


Der Methodenblock zum Zeichnen gefüllter Primitive ohne Glättung:

//+------------------------------------------------------------------+
//| The methods of drawing filled primitives without smoothing       |
//+------------------------------------------------------------------+
//--- Fill in the area
   void              Fill(const int x,                            // X coordinate of the filling start point
                          const int y,                            // Y coordinate of the filling start point
                          const color clr,                        // Color
                          const uchar opacity=255,                // Opacity
                          const uint threshould=0)                // Threshold
                       { this.m_canvas.Fill(x,y,::ColorToARGB(clr,opacity),threshould);                                                }
                       
//--- Draw a filled rectangle
   void              DrawRectangleFill(const int x1,              // X coordinate of the first point defining the rectangle
                                       const int y1,              // Y coordinate of the first point defining the rectangle
                                       const int x2,              // X coordinate of the second point defining the rectangle
                                       const int y2,              // Y coordinate of the second point defining the rectangle
                                       const color clr,           // Color
                                       const uchar opacity=255)   // Opacity
                       { this.m_canvas.FillRectangle(x1,y1,x2,y2,::ColorToARGB(clr,opacity));                                          }

//--- Draw a filled circle
   void              DrawCircleFill(const int x,                  // X coordinate of the circle center
                                    const int y,                  // Y coordinate of the circle center
                                    const int r,                  // Circle radius
                                    const color clr,              // Color
                                    const uchar opacity=255)      // Opacity
                       { this.m_canvas.FillCircle(x,y,r,::ColorToARGB(clr,opacity));                                                   }
                       
//--- Draw a filled triangle
   void              DrawTriangleFill(const int         x1,      // X coordinate of the triangle first vertex
                                      const int         y1,      // Y coordinate of the triangle first vertex
                                      const int         x2,      // X coordinate of the triangle second vertex
                                      const int         y2,      // Y coordinate of the triangle second vertex
                                      const int         x3,      // X coordinate of the triangle third vertex
                                      const int         y3,      // Y coordinate of the triangle third vertex
                                      const color clr,           // Color
                                      const uchar opacity=255)   // Opacity
                       { this.m_canvas.FillTriangle(x1,y1,x2,y2,x3,y3,::ColorToARGB(clr,opacity));                                     }
                       
//--- Draw a filled polygon
   void              DrawPolygonFill(int &array_x[],              // Array with the X coordinates of polygon points
                                     int &array_y[],              // Array with the Y coordinates of polygon points
                                     const color clr,             // Color
                                     const uchar opacity=255)     // Opacity
                       { this.m_canvas.FillPolygon(array_x,array_y,::ColorToARGB(clr,opacity));                                        }
                       
//--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates
   void              DrawEllipseFill(const int x1,                // X coordinate of the top left corner forming the rectangle
                                     const int y1,                // Y coordinate of the top left corner forming the rectangle
                                     const int x2,                // X coordinate of the bottom right corner forming the rectangle
                                     const int y2,                // Y coordinate of the bottom right corner forming the rectangle
                                     const color clr,             // Color
                                     const uchar opacity=255)     // Opacity
                       { this.m_canvas.FillEllipse(x1,y1,x2,y2,::ColorToARGB(clr,opacity));                                            }
                       
//+------------------------------------------------------------------+


Die Methoden zum Zeichnen von Primitiven mit Glättung:

//+------------------------------------------------------------------+
//| The methods of drawing primitives using smoothing                |
//+------------------------------------------------------------------+
//--- Draw a point using AntiAliasing algorithm
   void              SetPixelAA(const double x,                   // Point X coordinate
                                const double y,                   // Point Y coordinate
                                const color clr,                  // Color
                                const uchar opacity=255)          // Opacity
                       { this.m_canvas.PixelSetAA(x,y,::ColorToARGB(clr,opacity));                                                     }
                       
//--- Draw a segment of a freehand line using AntiAliasing algorithm
   void              DrawLineAA(const int   x1,                   // X coordinate of the segment first point
                                const int   y1,                   // Y coordinate of the segment first point
                                const int   x2,                   // X coordinate of the segment second point
                                const int   y2,                   // Y coordinate of the segment second point
                                const color clr,                  // Color
                                const uchar opacity=255,          // Opacity
                                const uint  style=UINT_MAX)       // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.LineAA(x1,y1,x2,y2,::ColorToARGB(clr,opacity),style);                                           }
                       
//--- Draw a segment of a freehand line using Wu algorithm
   void              DrawLineWu(const int   x1,                   // X coordinate of the segment first point
                                const int   y1,                   // Y coordinate of the segment first point
                                const int   x2,                   // X coordinate of the segment second point
                                const int   y2,                   // Y coordinate of the segment second point
                                const color clr,                  // Color
                                const uchar opacity=255,          // Opacity
                                const uint  style=UINT_MAX)       // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.LineWu(x1,y1,x2,y2,::ColorToARGB(clr,opacity),style);                                           }
                       
//--- Draws a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration
   void              DrawLineThick(const int   x1,                // X coordinate of the segment first point
                                   const int   y1,                // Y coordinate of the segment first point
                                   const int   x2,                // X coordinate of the segment second point
                                   const int   y2,                // Y coordinate of the segment second point
                                   const int   size,              // Line width
                                   const color clr,               // Color
                                   const uchar opacity=255,       // Opacity
                                   const uint  style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                                   ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration values
                       { this.m_canvas.LineThick(x1,y1,x2,y2,::ColorToARGB(clr,opacity),size,style,end_style);                         }
 
//--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration
   void              DrawLineThickVertical(const int   x,         // X coordinate of the segment
                                           const int   y1,        // Y coordinate of the segment first point
                                           const int   y2,        // Y coordinate of the segment second point
                                           const int   size,      // Line width
                                           const color clr,       // Color
                                           const uchar opacity=255,// Opacity
                                           const uint  style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                                           const ENUM_LINE_END end_style=LINE_END_ROUND)  // Line style is one of the ENUM_LINE_END enumeration values
                       { this.m_canvas.LineThickVertical(x,y1,y2,::ColorToARGB(clr,opacity),size,style,end_style);                     }
                       
//--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration
   void              DrawLineThickHorizontal(const int   x1,      // X coordinate of the segment first point
                                             const int   x2,      // X coordinate of the segment second point
                                             const int   y,       // Segment Y coordinate
                                             const int   size,    // Line width
                                             const color clr,     // Color
                                             const uchar opacity=255,// Opacity
                                             const uint  style=STYLE_SOLID,  // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                                             const ENUM_LINE_END end_style=LINE_END_ROUND)  // Line style is one of the ENUM_LINE_END enumeration values
                       { this.m_canvas.LineThickHorizontal(x1,x2,y,::ColorToARGB(clr,opacity),size,style,end_style);                   }

//--- Draws a polyline using AntiAliasing algorithm
   void              DrawPolylineAA(int        &array_x[],        // Array with the X coordinates of polyline points
                                    int        &array_y[],        // Array with the Y coordinates of polyline points
                                    const color clr,              // Color
                                    const uchar opacity=255,      // Opacity
                                    const uint  style=UINT_MAX)   // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.PolylineAA(array_x,array_y,::ColorToARGB(clr,opacity),style);                                   }
                       
//--- Draws a polyline using Wu algorithm
   void              DrawPolylineWu(int        &array_x[],        // Array with the X coordinates of polyline points
                                    int        &array_y[],        // Array with the Y coordinates of polyline points
                                    const color clr,              // Color
                                    const uchar opacity=255,      // Opacity
                                    const uint  style=UINT_MAX)   // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.PolylineWu(array_x,array_y,::ColorToARGB(clr,opacity),style);                                   }
                       
//--- Draw a polyline with a specified width consecutively using two antialiasing algorithms.
//--- First, individual line segments are smoothed based on Bezier curves.
//--- Then, the raster antialiasing algorithm is applied to the polyline built from these segments to improve the rendering quality
   void              DrawPolylineSmooth(const int   &array_x[],   // Array with the X coordinates of polyline points
                                        const int   &array_y[],   // Array with the Y coordinates of polyline points
                                        const int    size,        // Line width
                                        const color  clr,         // Color
                                        const uchar  opacity=255, // Opacity
                                        const double tension=0.5, // Smoothing parameter value
                                        const double step=10,     // Approximation step
                                        const ENUM_LINE_STYLE style=STYLE_SOLID,// Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                                        const ENUM_LINE_END   end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration values
                       { this.m_canvas.PolylineSmooth(array_x,array_y,::ColorToARGB(clr,opacity),size,style,end_style,tension,step);   }
                       
//--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration
   void              DrawPolylineThick(const int     &array_x[],  // Array with the X coordinates of polyline points
                                       const int     &array_y[],  // Array with the Y coordinates of polyline points
                                       const int      size,       // Line width
                                       const color    clr,        // Color
                                       const uchar    opacity=255,// Opacity
                                       const uint     style=STYLE_SOLID,         // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                                       ENUM_LINE_END  end_style=LINE_END_ROUND)  // Line style is one of the ENUM_LINE_END enumeration values
                       { this.m_canvas.PolylineThick(array_x,array_y,::ColorToARGB(clr,opacity),size,style,end_style);                 }
                       
//--- Draw a polygon using AntiAliasing algorithm
   void              DrawPolygonAA(int        &array_x[],         // Array with the X coordinates of polygon points
                                   int        &array_y[],         // Array with the Y coordinates of polygon points
                                   const color clr,               // Color
                                   const uchar opacity=255,       // Opacity
                                   const uint  style=UINT_MAX)    // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.PolygonAA(array_x,array_y,::ColorToARGB(clr,opacity),style);                                    }
                       
//--- Draw a polygon using Wu algorithm
   void              DrawPolygonWu(int        &array_x[],         // Array with the X coordinates of polygon points
                                   int        &array_y[],         // Array with the Y coordinates of polygon points
                                   const color clr,               // Color
                                   const uchar opacity=255,       // Opacity
                                   const uint  style=UINT_MAX)    // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.PolygonWu(array_x,array_y,::ColorToARGB(clr,opacity),style);                                    }
                       
//--- Draw a polygon with a specified width consecutively using two smoothing algorithms.
//--- First, individual segments are smoothed based on Bezier curves.
//--- Then, the raster smoothing algorithm is applied to the polygon built from these segments to improve the rendering quality. 
   void              DrawPolygonSmooth(int         &array_x[],    // Array with the X coordinates of polyline points
                                       int         &array_y[],    // Array with the Y coordinates of polyline points
                                       const int    size,         // Line width
                                       const color  clr,          // Color
                                       const uchar  opacity=255,  // Opacity
                                       const double tension=0.5,  // Smoothing parameter value
                                       const double step=10,      // Approximation step
                                       const ENUM_LINE_STYLE style=STYLE_SOLID,// Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                                       const ENUM_LINE_END   end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration values
                       { this.m_canvas.PolygonSmooth(array_x,array_y,::ColorToARGB(clr,opacity),size,style,end_style,tension,step);    }
                       
//--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration
   void              DrawPolygonThick(const int  &array_x[],      // array with the X coordinates of polygon points
                                      const int  &array_y[],      // array with the Y coordinates of polygon points
                                      const int   size,           // line width
                                      const color clr,            // Color
                                      const uchar opacity=255,    // Opacity
                                      const uint  style=STYLE_SOLID,// line style
                                      ENUM_LINE_END end_style=LINE_END_ROUND) // line ends style
                       { this.m_canvas.PolygonThick(array_x,array_y,::ColorToARGB(clr,opacity),size,style,end_style);                  }
                       
//--- Draw a triangle using AntiAliasing algorithm
   void              DrawTriangleAA(const int   x1,               // X coordinate of the triangle first vertex
                                    const int   y1,               // Y coordinate of the triangle first vertex
                                    const int   x2,               // X coordinate of the triangle second vertex
                                    const int   y2,               // Y coordinate of the triangle second vertex
                                    const int   x3,               // X coordinate of the triangle third vertex
                                    const int   y3,               // Y coordinate of the triangle third vertex
                                    const color clr,              // Color
                                    const uchar opacity=255,      // Opacity
                                    const uint  style=UINT_MAX)   // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.TriangleAA(x1,y1,x2,y2,x3,y3,::ColorToARGB(clr,opacity),style);                                 }
                       
//--- Draw a triangle using Wu algorithm
   void              DrawTriangleWu(const int   x1,               // X coordinate of the triangle first vertex
                                    const int   y1,               // Y coordinate of the triangle first vertex
                                    const int   x2,               // X coordinate of the triangle second vertex
                                    const int   y2,               // Y coordinate of the triangle second vertex
                                    const int   x3,               // X coordinate of the triangle third vertex
                                    const int   y3,               // Y coordinate of the triangle third vertex
                                    const color clr,              // Color
                                    const uchar opacity=255,      // Opacity
                                    const uint  style=UINT_MAX)   // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.TriangleWu(x1,y1,x2,y2,x3,y3,::ColorToARGB(clr,opacity),style);                                 }
                       
//--- Draw a circle using AntiAliasing algorithm
   void              DrawCircleAA(const int    x,                 // X coordinate of the circle center
                                  const int    y,                 // Y coordinate of the circle center
                                  const double r,                 // Circle radius
                                  const color  clr,               // Color
                                  const uchar opacity=255,        // Opacity
                                  const uint  style=UINT_MAX)     // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.CircleAA(x,y,r,::ColorToARGB(clr,opacity),style);                                               }
                       
//--- Draw a circle using Wu algorithm
   void              DrawCircleWu(const int    x,                 // X coordinate of the circle center
                                  const int    y,                 // Y coordinate of the circle center
                                  const double r,                 // Circle radius
                                  const color  clr,               // Color
                                  const uchar opacity=255,        // Opacity
                                  const uint  style=UINT_MAX)     // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.CircleWu(x,y,r,::ColorToARGB(clr,opacity),style);                                               }
                       
//--- Draw an ellipse by two points using AntiAliasing algorithm
   void              DrawEllipseAA(const double x1,               // X coordinate of the first point defining the ellipse
                                   const double y1,               // Y coordinate of the first point defining the ellipse
                                   const double x2,               // X coordinate of the second point defining the ellipse
                                   const double y2,               // Y coordinate of the second point defining the ellipse
                                   const color  clr,              // Color
                                   const uchar opacity=255,       // Opacity
                                   const uint  style=UINT_MAX)    // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.EllipseAA(x1,y1,x2,y2,::ColorToARGB(clr,opacity),style);                                        }
                       
//--- Draw an ellipse by two points using Wu algorithm
   void              DrawEllipseWu(const int   x1,                // X coordinate of the first point defining the ellipse
                                   const int   y1,                // Y coordinate of the first point defining the ellipse
                                   const int   x2,                // X coordinate of the second point defining the ellipse
                                   const int   y2,                // Y coordinate of the second point defining the ellipse
                                   const color clr,               // Color
                                   const uchar opacity=255,       // Opacity
                                   const uint  style=UINT_MAX)    // Line style is one of the ENUM_LINE_STYLE enumeration values or a custom value
                       { this.m_canvas.EllipseWu(x1,y1,x2,y2,::ColorToARGB(clr,opacity),style);                                        }

//+------------------------------------------------------------------+

Die Logik aller hinzugefügten Methoden ist vollständig klar. Alle an die Methoden übergebenen Parameter sind signiert. Der Zweck der einzelnen Methoden ist in den Kommentaren angegeben. Ich glaube also, dass hier alles klar ist. In jedem Fall können Sie gerne den Abschnitt Kommentare verwenden.


Die Methoden für die Arbeit mit Texten

Die Klasse CCanvas merkt sich die Einstellungen des zuletzt angezeigten Textes, einschließlich seiner Schriftart, Farbe, Transparenz usw. Um die Textgröße herauszufinden, können wir die Methode TextSize() verwenden, die die aktuellen Schrifteinstellungen verwendet, um die Breite und Höhe des textbegrenzenden Rechtecks zu messen. Das können wir bei verschiedenen Gelegenheiten brauchen, z. B. wenn wir den vorherigen Text mit der Hintergrundfarbe überschreiben und ihn mit neuen Koordinaten schreiben — Text-Offset. In diesem Fall benötigen wir nicht nur Textkoordinaten, sondern auch Textankerpunkte (links-oben, Mitte-oben, rechts-oben usw.). Wir müssen genau wissen, welcher Ankerwinkel des Begrenzungsrechtecks dem Text gegeben wird, sonst werden die Koordinaten des zu löschenden Rechtecks falsch gesetzt. Um dies zu erreichen, müssen wir die Klassenvariable hinzufügen, die den zuletzt angegebenen Ankerpunkt speichert.

Deklarieren wir die Variable im privaten Bereich der Klasse:

   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];    // Integer properties
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];   // Real properties
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];   // String properties
   
   ENUM_TEXT_ANCHOR  m_text_anchor;                            // Current text alignment

//--- Return the index of the array the order (1) double and (2) string properties are located at
   int               IndexProp(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  const { return(int)property-CANV_ELEMENT_PROP_INTEGER_TOTAL;                                 }
   int               IndexProp(ENUM_CANV_ELEMENT_PROP_STRING property)  const { return(int)property-CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_DOUBLE_TOTAL;  }

Ganz am Anfang des parametrischen Klassenkonstruktors initialisieren wir die Werte für den Objekttyp und den Textankerpunkt:

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           const int      element_id,
                           const int      element_num,
                           const long     chart_id,
                           const int      wnd_num,
                           const string   name,
                           const int      x,
                           const int      y,
                           const int      w,
                           const int      h,
                           const color    colour,
                           const uchar    opacity,
                           const bool     movable=true,
                           const bool     activity=true,
                           const bool     redraw=false)
                                          
  {
   this.m_name=this.m_name_prefix+name;
   this.m_chart_id=chart_id;
   this.m_subwindow=wnd_num;
   this.m_type=element_type;
   this.m_text_anchor=0;
   if(this.Create(chart_id,wnd_num,this.m_name,x,y,w,h,colour,opacity,redraw))
     {

Fügen wir in die Variable m_type der übergeordneten Klasse, die von ihrer virtuellen Methode Type() zurückgegeben wird, den in den Konstruktorparametern übergebenen Objekttyp ein, während die m_text_anchor Variable mit dem Standardwert initialisiert wird — der linken oberen Ecke des begrenzenden Rechtecks.

Ganz am Ende des Hauptteils der Klasse (nämlich nach dem Codeblock für die Arbeit mit Primitiven) fügen wir den Codeblock für die Arbeit mit Text ein:

//+------------------------------------------------------------------+
//| The methods of working with text                                 |
//+------------------------------------------------------------------+
//--- Return text the alignment type (anchor method)
   ENUM_TEXT_ANCHOR  TextAnchor(void)                       const { return this.m_text_anchor;                                         }

//--- Set the current font
   bool              SetFont(const string name,                   // Font name. For example, "Arial"
                             const int    size,                   // Font size
                             const uint   flags=0,                // Font creation flags
                             const uint   angle=0,                // Font slope angle in tenths of a degree
                             const bool   relative=true)          // Relative font size flag
                       { return this.m_canvas.FontSet(name,(relative ? size*-10 : size),flags,angle);                                  }

//--- Set a font name
   bool              SetFontName(const string name)               // Font name. For example, "Arial"
                       { return this.m_canvas.FontNameSet(name);                                                                       }

//--- Set a font size
   bool              SetFontSize(const int size,                  // Font size
                                 const bool relative=true)        // Relative font size flag
                       { return this.m_canvas.FontSizeSet(relative ? size*-10 : size);                                                 }

//--- Set font flags
//--- FONT_ITALIC - Italic, FONT_UNDERLINE - Underline, FONT_STRIKEOUT - Strikeout
   bool              SetFontFlags(const uint flags)               // Font creation flags
                       { return this.m_canvas.FontFlagsSet(flags);                                                                     }

//--- Set a font slope angle
   bool              SetFontAngle(const float angle)              // Font slope angle in tenths of a degree
                       { return this.m_canvas.FontAngleSet(uint(angle*10));                                                            }

//--- Set the font anchor angle (alignment type)
   void              SetTextAnchor(const uint flags=0)      { this.m_text_anchor=(ENUM_TEXT_ANCHOR)flags;                              }

//--- Gets the current font parameters and write them to variables
   void              GetFont(string &name,                        // The reference to the variable for returning a font name
                             int    &size,                        // Reference to the variable for returning a font size
                             uint   &flags,                       // Reference to the variable for returning font flags
                             uint   &angle)                       // Reference to the variable for returning a font slope angle
                       { this.m_canvas.FontGet(name,size,flags,angle);                                                                 }

//--- Return (1) the font name, (2) size, (3) flags and (4) slope angle
   string            FontName(void)                         const { return this.m_canvas.FontNameGet();                                }
   int               FontSize(void)                         const { return this.m_canvas.FontSizeGet();                                }
   int               FontSizeRelative(void)                 const { return(this.FontSize()<0 ? -this.FontSize()/10 : this.FontSize()); }
   uint              FontFlags(void)                        const { return this.m_canvas.FontFlagsGet();                               }
   uint              FontAngle(void)                        const { return this.m_canvas.FontAngleGet();                               }

//--- Return the text (1) width, (2) height and (3) all sizes (the current font is used to measure the text)
   int               TextWidth(const string text)                 { return this.m_canvas.TextWidth(text);                              }
   int               TextHeight(const string text)                { return this.m_canvas.TextHeight(text);                             }
   void              TextSize(const string text,                  // Text for measurement
                              int         &width,                 // Reference to the variable for returning a text width
                              int         &height)                // Reference to the variable for returning a text height
                       { this.m_canvas.TextSize(text,width,height);                                                                    }

//--- Display the text in the current font
   void              Text(int         x,                          // X coordinate of the text anchor point
                          int         y,                          // Y coordinate of the text anchor point
                          string      text,                       // Display text
                          const color clr,                        // Color
                          const uchar opacity=255,                // Opacity
                          uint        alignment=0)                // Text anchoring method
                       { 
                        this.m_text_anchor=(ENUM_TEXT_ANCHOR)alignment;
                        this.m_canvas.TextOut(x,y,text,::ColorToARGB(clr,opacity),alignment);
                       }

  };
//+------------------------------------------------------------------+

Hier ist alles so wie beim Umgang mit Primitiven. Alle Methoden sind mit Kommentaren versehen, die ihren Zweck, ihre Eingänge und Ausgänge offenlegen.
Ich möchte die Methode zum Setzen der aktuellen Schriftparameter kommentieren:

//--- Set the current font
   bool              SetFont(const string name,                   // Font name. For example, "Arial"
                             const int    size,                   // Font size
                             const uint   flags=0,                // Font creation flags
                             const uint   angle=0,                // Font slope angle in tenths of a degree
                             const bool   relative=true)          // Relative font size flag
                       { return this.m_canvas.FontSet(name,(relative ? size*-10 : size),flags,angle);  

Hier gibt size die Schriftgröße an und wird immer entsprechend der Schriftgröße gesetzt, die wir bei der Anzeige eines Textes mit Hilfe des gewöhnlichen OBJ_LABEL Text-Label-Objekts einstellen würden. Die Größe wird darin als positiver Integer-Wert gesetzt. Im Gegensatz dazu wird beim Zeichnen des Textes auf der Leinwand die Schriftgröße auf die gleiche Weise gesetzt wie in der TextSetFont()-Funktion:

Die Schriftgröße wird mit positiven oder negativen Werten eingestellt. Das Vorzeichen legt fest, ob die Textgröße von den Einstellungen des Betriebssystems (Schriftskala) abhängt.

  • Wenn die Größe positiv ist, wird sie bei der Darstellung des logischen Fonts als physischer Font in die physikalischen Einheiten des Gerätes, in Pixel, umgerechnet. Die Größe entspricht der Höhe von Symbolzellen aus verfügbaren Fonts. Die gemeinsame Verwendung von Texten, die mit der Funktion TextOut() angezeigt werden, und Texten, die mit dem grafischen Objekt OBJ_LABEL ("Textlabel") angezeigt werden, ist nicht empfehlenswert.
  • Wenn die Größe negativ ist, wird sie in Zehntel eines logischen Punktes angenommen (der Wert -350 entspricht 35 logischen Punkten) und durch 10 geteilt. Der resultierende Wert wird in physikalische Einheiten des Geräts (Pixel) umgerechnet und entspricht dem absoluten Wert der Zeichenhöhe aus verfügbaren Fonts. Um einen Text der Objektgröße OBJ_LABEL auf dem Bildschirm zu erhalten, multiplizieren Sie die in den Objekteigenschaften angegebene Schriftgröße mit -10.

Das Flag für die relative Schriftgröße wird in der Methode geprüft. Standardmäßig wird der Wert der Größe mit -10 multipliziert, damit die Schriftart mit einem korrekten Wert für die Übergabe der CCanvas-Klasse an die Methode FontSet() angegeben wird.

Im Konstruktor der parametrischen Klasse fügen wir eine Schriftinitialisierung hinzu (setzen des Standardnamen und Größe):

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           const int      element_id,
                           const int      element_num,
                           const long     chart_id,
                           const int      wnd_num,
                           const string   name,
                           const int      x,
                           const int      y,
                           const int      w,
                           const int      h,
                           const color    colour,
                           const uchar    opacity,
                           const bool     movable=true,
                           const bool     activity=true,
                           const bool     redraw=false)
                                          
  {
   this.m_name=this.m_name_prefix+name;
   this.m_chart_id=chart_id;
   this.m_subwindow=wnd_num;
   this.m_type=element_type;
   this.SetFont("Calibri",8);
   this.m_text_anchor=0;
   if(this.Create(chart_id,wnd_num,this.m_name,x,y,w,h,colour,opacity,redraw))
     {

Dies sind alle Verbesserungen, die ich für den aktuellen Artikel geplant habe. Lassen Sie uns die Ergebnisse testen.


Test


Wir haben den EA aus dem vorherigen Artikel, der zwei grafische Elementobjekte im Chart anzeigt. Nehmen wir den gleichen EA, speichern ihn im neuen Ordner \MQL5\Experts\TestDoEasy\TestDoEasyPart75\ als TestDoEasyPart75.mq5 und gehen wie folgt vor:

Wenn wir auf das erste (obere) Objekt klicken, zeichnen wir abwechselnd ein Rechteck und einen Kreis auf das Objekt. Mit jedem neuen Klick auf das Objekt verringert sich die Größe des Rechtecks um 2 Pixel auf jeder Seite und der Radius des Kreises verringert sich ebenfalls um 2 Pixel. Das Rechteck wird auf die übliche Weise gezeichnet, während der Kreis mit Hilfe der Glättung gezeichnet wird. Mit jedem neuen Klick wird die Transparenz des Objekts in einer Schleife, von 0 auf 255 erhöht.

Wenn man auf das zweite (untere) Objekt klickt, wird ein Text angezeigt, der abwechselnd den Ankerpunkt ändert. Schreiben Sie selbst den Namen des Ankerpunkts in den Text. Die Transparenz des Objekts bleibt unverändert.

Bestimmung der Anzahl der erzeugten Elemente:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart75.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//--- includes
#include <Arrays\ArrayObj.mqh>
#include <DoEasy\Services\Select.mqh>
#include <DoEasy\Objects\Graph\GCnvElement.mqh>
//--- defines
#define        ELEMENTS_TOTAL (2)   // Number of created graphical elements
//--- input parameters
sinput   bool  InpMovable  = true;  // Movable flag
//--- global variables
CArrayObj      list_elements;
//+------------------------------------------------------------------+

Um zu vermeiden, dass bei jeder Änderung des Zeitrahmens identische Objekte erzeugt werden, leeren wir die Liste der bereits erzeugten Objekte in OnInit(), bevor neue Objekte erzeugt werden:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set the permissions to send cursor movement and mouse scroll events
   ChartSetInteger(ChartID(),CHART_EVENT_MOUSE_MOVE,true);
   ChartSetInteger(ChartID(),CHART_EVENT_MOUSE_WHEEL,true);
//--- Set EA global variables

//--- Create the specified number of graphical elements on the canvas
   list_elements.Clear();
   int total=ELEMENTS_TOTAL;
   for(int i=0;i<total;i++)
     {
      //--- When creating an object, pass all the required parameters to it
      CGCnvElement *element=new CGCnvElement(GRAPH_ELEMENT_TYPE_ELEMENT,i,0,ChartID(),0,"Element_0"+(string)(i+1),300,40+(i*80),100,70,clrSilver,200,InpMovable,true,true);
      if(element==NULL)
         continue;
      //--- Add objects to the list
      if(!list_elements.Add(element))
        {
         delete element;
         continue;
        }
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Da die Kollektionsklasse der grafische Objekte noch nicht existiert, um zu prüfen, ob es notwendig ist, ein neues Objekt mit einem bestimmten Namen zu erzeugen, werden diese Objekte hier einfach neu erzeugt, indem die Liste der zuvor erzeugten Objekte vorher gelöscht wird.

In OnChartEvent() werden die Mausklicks auf zwei angelegte Objekte abgearbeitet:

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- If clicking on an object
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- In the new list, get the element object with the name corresponding to the sparam string parameter value of the OnChartEvent() handler
      CArrayObj *obj_list=CSelect::ByGraphCanvElementProperty(GetPointer(list_elements),CANV_ELEMENT_PROP_NAME_OBJ,sparam,EQUAL);
      //--- If the object is received from the list
      if(obj_list!=NULL && obj_list.Total()>0)
        {
         static uchar try0=0, try1=0;
         //--- Get the pointer to the object in the list
         CGCnvElement *obj=obj_list.At(0);
         //--- If this is the first graphical element
         if(obj.ID()==0)
           {
            //--- Set a new opacity level for the object
            uchar opasity=obj.Opacity();
            if((opasity+5)>255)
               opasity=0;
            else 
               opasity+=5;
            //--- Set a new opacity to the object
            obj.SetOpacity(opasity);
            //--- Set rectangle and circle coordinates
            int x1=2,x2=obj.Width()-3;
            int y1=2,y2=obj.Height()-3;
            int xC=(x1+x2)/2;
            int yC=(y1+y2)/2;
            int R=yC-y1;
            //--- Draw a rectangle at each first click
            if(try0%2==0)
               obj.DrawRectangle(x1+try0,y1+try0,x2-try0,y2-try0,clrDodgerBlue,obj.Opacity());
            //--- Display the circle smoothed using AntiAliasing at each second click
            else
               obj.DrawCircleAA(xC,yC,R-try0,clrGreen,obj.Opacity());
            //--- If the number of clicks on the object exceeds 30
            if(try0>30)
              {
               //--- Clear the object setting its current color and transparency
               obj.Erase(obj.ColorBG(),obj.Opacity());
               //--- Re-start the click number countdown
               try0=0;
              }
            //--- Update the chart and the object, and display the comment featuring color values and object opacity
            obj.Update(true); // 'true' is not needed here since the next Comment command redraws the chart anyway
            Comment("Object name: ",obj.NameObj(),", opasity=",obj.Opacity(),", Color BG: ",(string)obj.ColorBG());
            //--- Increase the counter of mouse clicks by object
            try0++;
           }
         //--- If this is the second object
         else if(obj.ID()==1)
           {
            //--- Set the font parameters for it ("Calibri" size 8)
            obj.SetFont("Calibri",8);
            //--- Set the text anchor angle corresponding to the click counter by object
            obj.SetTextAnchor((ENUM_TEXT_ANCHOR)try1);
            //--- Create the text out of the anchor angle name
            string text=StringSubstr(EnumToString(obj.TextAnchor()),12);
            //--- Set the text coordinates relative to the upper left corner of the graphical element
            int xT=2,yT=2;
            //--- Depending on the anchor angle, set the new coordinates of the displayed text
            //--- LEFT_TOP
            if(try1==0)       { xT=2; yT=2;                                   }
            //--- CENTER_TOP
            else if(try1==1)  { xT=obj.Width()/2; yT=2;                       }
            //--- RIGHT_TOP
            //--- since the ENUM_TEXT_ANCHOR enumeration features no 3, increase the counter of object clicks by 1
            else if(try1==2)  { xT=obj.Width()-2; yT=2; try1++;               }
            //--- LEFT_CENTER
            else if(try1==4)  { xT=2; yT=obj.Height()/2;                      }
            //--- CENTER
            else if(try1==5)  { xT=obj.Width()/2; yT=obj.Height()/2;          }
            //--- RIGHT_CENTER
            //--- since the ENUM_TEXT_ANCHOR enumeration features no 7, increase the counter of object clicks by 1
            else if(try1==6)  { xT=obj.Width()-2; yT=obj.Height()/2; try1++;  }
            //--- LEFT_BOTTOM
            else if(try1==8)  { xT=2; yT=obj.Height()-2;                      }
            //--- CENTER_BOTTOM
            else if(try1==9)  { xT=obj.Width()/2; yT=obj.Height()-2;          }
            //--- RIGHT_BOTTOM
            else if(try1==10)    { xT=obj.Width()-2; yT=obj.Height()-2;       }
            //--- Clear the graphical element filling it with the current color and transparency
            obj.Erase(obj.ColorBG(),obj.Opacity());
            //--- Display the text with the calculated coordinates in the cleared element
            obj.Text(xT,yT,text,clrDodgerBlue,255,obj.TextAnchor());
            //--- Update the object and chart
            obj.Update(true); // 'true' is not needed here since the next Comment command redraws the chart anyway
            Comment("Object name: ",obj.NameObj(),", opasity=",obj.Opacity(),", Color BG: ",(string)obj.ColorBG());
            //--- Increase the counter of object clicks
            try1++;
            if(try1>10)
               try1=0;
           }
        }
     }
  }
//+------------------------------------------------------------------+

Der Code der Funktion ist mit ausführlichen Kommentaren versehen. Ich glaube, seine Logik ist klar. Wenn Sie Fragen zum aktuellen Artikel haben, können Sie diese gerne in den Kommentaren unten stellen.

Kompilieren Sie den EA und starten Sie ihn auf dem Chart. Klicken Sie auf die Objekte:


Als Ergebnis habe ich versehentlich ein lustiges Bild auf dem oberen Objekt erhalten, das einer CD ähnelt :)

Was kommt als Nächstes?

Im nächsten Artikel werde ich mit der Entwicklung der Objekte beginnen, die von dem hier erstellten Grafikelement-Objekt abgeleitet werden.

Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit der Test-EA-Datei für MQL5 zum Testen und Herunterladen angehängt.
Ihre Fragen und Vorschläge schreiben Sie bitte in den Kommentarteil.

Zurück zum Inhalt

*Frühere Artikel dieser Serie:

Grafiken in der Bibliothek DoEasy (Teil 73): Das Formularobjekt eines grafischen Elements
Grafiken in der Bibliothek DoEasy (Teil 74): Das grafisches Basiselement, das von der Klasse CCanvas unterstützt wird

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

Beigefügte Dateien |
MQL5.zip (3972.88 KB)
Grafiken in der Bibliothek DoEasy (Teil 76): Das Formularobjekt und vordefinierte Farbschemata Grafiken in der Bibliothek DoEasy (Teil 76): Das Formularobjekt und vordefinierte Farbschemata
In diesem Artikel beschreibe ich das Konzept des Aufbaus verschiedener Designschemata der Bibliotheks-GUI, erstelle das Form-Objekt, das ein Nachkomme des Klassenobjekts für grafische Elemente ist, und bereite Daten für die Erstellung von Schatten der grafischen Bibliotheksobjekte sowie für die weitere Entwicklung der Funktionalität vor.
Grafiken in der Bibliothek DoEasy (Teil 74): Das grafisches Basiselement, das von der Klasse CCanvas unterstützt wird Grafiken in der Bibliothek DoEasy (Teil 74): Das grafisches Basiselement, das von der Klasse CCanvas unterstützt wird
In diesem Artikel werde ich das Konzept des Aufbaus von grafischen Objekten aus dem vorherigen Artikel überarbeiten und die Basisklasse aller grafischen Objekte der Bibliothek vorbereiten, die von der Klasse CCanvas der Standardbibliothek angetrieben wird.
Grafik in der Bibliothek DoEasy (Teil 77): Objektklasse der Schatten Grafik in der Bibliothek DoEasy (Teil 77): Objektklasse der Schatten
In diesem Artikel werde ich eine separate Klasse für das Schattenobjekt erstellen, das ein Nachkomme des grafischen Elementobjekts ist, und die Möglichkeit hinzufügen, den Objekthintergrund mit einem Farbverlauf zu füllen.
Grafiken in der Bibliothek DoEasy (Teil 73): Das Formularobjekt eines grafischen Elements Grafiken in der Bibliothek DoEasy (Teil 73): Das Formularobjekt eines grafischen Elements
Der Artikel erschließt einen neuen großen Bereich der Bibliothek für die Arbeit mit Grafiken. Im aktuellen Artikel werde ich das Mausstatusobjekt, das Basisobjekt aller grafischen Elemente und die Klasse des Formularobjekts der Bibliothek grafische Elemente erstellen.