
Verwendung der Klasse CCanvas in MQL-Anwendungen
Der Artikel befasst sich mit der CCanvas-Klasse und ihrer Verwendung in MQL-Anwendungen. Die Theorie wird von Beispielen begleitet.
Grafiken in Anwendungen
Der Umgang mit Grafiken in Anwendungen erfordert den Zugriff auf Pixeldaten auf einem Bildschirm. Wenn Sie einen solchen Zugriff haben, können Sie Pixelfarben ändern, verschiedene UI-Elemente, Eingabefelder, Schaltflächen, Panels, Fenster und andere Elemente erstellen oder Bilder aus Dateien anzeigen sowie Pixeldaten abrufen und verarbeiten. Im Allgemeinen ist dieser Mechanismus in der Klasse mit dem Wort "Canvas" (Leinwand, der Hintergrund) in ihrem Namen untergebracht. In C-basierten Programmiersprachen ist dies in der Regel CCanvas oder Canvas, je nach dem Stil, in dem der Code geschrieben wird. Jede Anwendung benötigt so eine Canvas, um auf Grafiken zugreifen zu können.
Canvas in MQL-Anwendungen
In MQL wird das Werkzeug in Form der Klasse CCanvas zur Verfügung gestellt, die das Array der Pixel, die Methoden zum Ändern des Pixelarrays und den Mechanismus zum Senden des Arrays an ein Terminal-Chart enthält. Das grafische Objekt OBJ_BITMAP oder OBJ_BITMAP_LABEL wird als Anzeigemittel verwendet. Das verwendete grafische Objekt erhält Daten von der grafischen Ressource, die wiederum Daten vom Pixelarray empfängt.
Die Klasse CCanvas ermöglicht die Implementierung aller Desktop-UI-Funktionen. Zusätzlich zu den Nutzeroberflächen ermöglicht CCanvas das Zeichnen von Indikatorpuffern, OHLC-Balken und vieles mehr. Die Möglichkeiten sind endlos... Ich werde dieses Thema in meinen anderen Artikeln behandeln. Nun ist es an der Zeit, sich wieder der Klasse CCanvas zuzuwenden.
Eintauchen in CCanvas
Jetzt ist es Zeit für den interessantesten Teil - das Eintauchen in die CCanvas-Klasse. Wenn Sie ihre Struktur verstehen, können Sie dieses Werkzeug beherrschen. Die Struktur von CCanvas ist im Folgenden dargestellt.
Wie wir sehen können, ist die Klasse in zwei große Abschnitte unterteilt - Daten und Methoden.
Betrachten wir die Daten:
- Pixeldaten. Das Pixel-Array m_pixels speichert Pixel, die von den Zeichen-Methoden behandelt werden, sowie die Werte von m_width- und m_height, die Bildbreite bzw. -höhe. Die Parameter m_width und m_height sind sehr wichtig für die Handhabung des Arrays m_pixels durch die Zeichenmethoden, sowie für die Übergabe des Array m_pixels an die grafische Ressource in der Update-Methode.
- Schriftdaten für die Darstellung des Textes. Besteht aus den Feldern m_fontname, m_fontsize, m_fontflags und m_fontangle, Schriftartname, Größe, Attribute bzw. Textneigungswinkel. Die Daten werden benötigt, um die Schrifteigenschaften zu setzen und zu empfangen (mit den Methoden zum Lesen/Schreiben der Schrifteigenschaften), bevor die Methode TextOut aufgerufen wird.
- Zeilenzeichnungsdaten. Sie bestehen aus zwei Feldern: m_style, Linienstil, und m_style_idx, der aktuelle Bitindex in der Linienstilvorlage. Sie werden für die Zeichenmethoden benötigt.
- Standarddaten. Hier haben wir ein einzelnes Feld m_default_colors, ein Standard-Farbfeld. Es wird nicht in den Methoden der CCanvas-Klasse selbst verwendet, aber es kann für andere Funktionen oder Methoden von CCanvas-Nachfolgeklassen als Farbpalette nützlich sein.
- Daten zur Chart-Interaktion. Sie enthalten das Folgende: m_chart_id, m_objname, m_objtype, m_rcname und m_format, Chartobjekt-ID, Chartobjektname, Chartobjekttyp, Name der grafischen Ressource bzw. Pixelformat. Die Daten sind für die folgenden Methoden bestimmt: Destroy, Update, Resize. Insbesondere das Feld m_format wird für die Operation der Methode TextOut benötigt.
Betrachten wir nun die Methoden:
- Erstellungs-/Anbringungs-/Entfernungsmethoden. Diese Kategorie enthält verschiedene Methoden, die mit einem Chartobjekt arbeiten. Dies sind die Methoden zur Erstellung eines grafischen Objekts: CreateBitmap und CreateBitmapLabel. Sie sind für die Erstellung eines Chartobjekts und einer damit verbundenen grafischen Ressource gedacht, die wiederum ein Bild im Chart anzeigt. Attachment-Methoden: Attach. Wenn das Chart das grafische Objekt OBJ_BITMAP_LABEL mit einer angehängten grafischen Ressource oder ohne diese enthält, behandelt CCanvas es auf die gleiche Weise wie ein neu erstelltes grafisches Objekt. Fügen Sie es einfach mit der entsprechenden Attach-Methode hinzu. Die Methode zum Entfernen heißt Destroy. Sie entfernt ein grafisches Objekt, gibt den Pixel-Array-Puffer m_pixels frei und entfernt die grafische Ressource, die mit dem Chartobjekt verbunden ist. Daher sollten wir immer die Methode Destroy aufrufen, wenn CCanvas beendet wird, da die Klasse ihr Chartobjekt und die grafische Ressource nicht automatisch entfernt.
- Methoden zum Hochladen von Bildern aus einer Datei. Die statische Methode LoadBitmap ist in der Lage, ein Bild aus einer *.bmp-Datei in ein beliebiges uint-Array hochzuladen, das ihr an einer Adresse als Parameter übergeben wird, wobei die Größe des erhaltenen Bildes in den Variablen 'width' und 'height' gespeichert wird, die der Methode ebenfalls an entsprechenden Adressen als ihre Parameter übergeben werden. Die Methode LoadFromFile lädt ein Bild aus einer *.bmp-Datei in das Array m_pixels und setzt die Bildparameter m_width und m_height. Das Pixelformat m_format sollte gleich COLOR_FORMAT_ARGB_RAW sein.
- Methoden zum Lesen der Eigenschaften von Chartobjekten bestehen aus ChartObjectName, ResourceName, Width und Height und geben den Chartobjektnamen, den grafischen Ressourcennamen, die Bildbreite und -höhe entsprechend zurück. Diese Methoden erlauben es den Nutzern, nur einige Daten für die Interaktion mit dem Chart zu lesen, einschließlich m_objname, m_rcname, sowie m_width und m_height Bilddaten.
- Methoden zum Lesen/Schreiben von Schrifteigenschaften eines angezeigten Textes. Betrachten wir zunächst die Schreibmethoden FontNameSet, FontSizeSet, FontFlagsSet und FontAngleSet. Diese Methoden setzen den Schriftnamen, die Größe, die Attribute und den Neigungswinkel des angezeigten Textes. Betrachten wir nun die Lesemethoden: FontSizeGet, FontFlagsGet und FontAngleGet. Die Methoden geben die Schriftgröße und -attribute bzw. den Neigungswinkel des angezeigten Textes zurück. Außerdem gibt es die Methoden zum Empfangen/Setzen der Schrifteigenschaften, die alle Schrifteigenschaften auf einmal zurückgeben/setzen. Die Methode zum Setzen der Eigenschaften FontSet setzt jeweils den Schriftnamen, die Größe, die Attribute und den Neigungswinkel des angezeigten Textes. Die Methode zum Empfangen der Eigenschaften FontGet gibt den Schriftnamen, die Größe, die Attribute bzw. den Neigungswinkel des angezeigten Textes zurück.
- Methoden zum Lesen/Schreiben des Linienzeichnungsstils. Die Methode LineStyleGet wird zum Lesen und LineStyleSet zum Schreiben verwendet. Der Linienstil ist notwendig für die Handhabung der Zeichenmethoden von LineAA, PolylineAA, PolygonAA, TriangleAA, CircleAA, EllipseAA, LineWu, PolylineWu, PolygonWu, TriangleWu, CircleWu, EllipseWu, LineThickVertical, LineThickHorizontal, LineThick, PolylineThick und PolygonThick grafischen Primitiven.
- Methoden zum Zeichnen im Pixel-Array. Die Klasse CCanvas verfügt über zahlreiche Methoden zum Zeichnen grafischer Primitive unter Verwendung verschiedener Algorithmen, die es dem Nutzer ermöglichen, komplexe Grafiken unter Anwendung progressiver Glättungsmethoden zu erstellen, einschließlich Antialiasing, Wu-Algorithmus und Bézier-Kurven. Lassen Sie uns diese Methoden betrachten. Einfache Primitive ohne Glättung: LineVertical, LineHorizontal, Line, Polyline, Polygon, Rectangle, Triangle, Circle, Ellipse, Arc und Pie. Die Methoden zeichnen die folgenden Primitive: vertikale Linie, horizontale Linie, Freihandlinie, Polylinie, Polygon, Rechteck, Dreieck, Kreis, Ellipse, Bogen bzw. gefüllter Ellipsensektor. Gefüllte Primitive: FillRectangle, FillTriangle, FillPolygon, FillCircle, FillEllipse und Fill. Diese Methoden zeichnen Rechteck, Dreieck, Polygon, Kreis, Ellipse bzw. füllen den Bereich aus. Die Methoden zum Zeichnen von Primitiven mit Glättung durch Antialiasing (AA): PixelSetAA, LineAA, PolylineAA, PolygonAA, TriangleAA, CircleAA und EllipseAA. Die Methoden füllen Pixel aus und stellen solche Primitive wie eine Freihandlinie, Polylinie, Polygon, Dreieck, Kreis und Ellipse dar. Methoden zum Zeichnen von Primitiven unter Verwendung des Wu's Algorithmus: LineWu, PolylineWu, PolygonWu, TriangleWu, CircleWu und EllipseWu. Die Methoden zeichnen eine Freihandlinie, eine Polylinie, ein Polygon, ein Dreieck, einen Kreis bzw. eine Ellipse. Die Methoden zum Zeichnen von Primitiven mit vorsortiertem Antialiasing und einstellbarer Linienbreite: LineThickVertical, LineThickHorizontal, LineThick, PolylineThick and PolygonThick. Sie sind für das Zeichnen der folgenden Primitive gedacht: vertikale Linie, horizontale Linie, Freihandlinie, Polylinie bzw. Polygon. Die Methoden zum Zeichnen von geglätteten Primitiven verwenden Bézier Methoden: PolylineSmooth und PolygonSmooth. Die Methoden zeichnen solche Primitive als geglättete Linie bzw. geglättetes Polygon. Neben den oben beschriebenen Methoden gehört auch die Methode zur Anzeige eines Textes TextOut in diese Kategorie, da sie auch die Farbwerte im Pixelarray ändert, obwohl sie im ursprünglichen Code der Klasse CCanvas in die Gruppe der Methoden zur Textbehandlung fällt.
- Methoden zur Übergabe des Bildes für die Anzeige im Chart. Diese Kategorie umfasst zwei Methoden. Die Methode Update übergibt das Pixel-Array m_pixels an die grafische Ressource, die mit einem Chart-Objekt verbunden ist, das ein Bild anzeigt. Wie bereits erwähnt, ändert sich das Pixelarray m_pixels mit Hilfe der oben erwähnten Zeichenmethoden im Pixelarray. Die Methode Resize ändert die Arraygröße m_pixels (Bildgröße) und übergibt sie ebenfalls an die grafische Ressource.
- Dienste. CCanvas verfügt über zwei Dienstmethoden: GetDefaultColor gibt neu definierte Farben zurück, während TransparentLevelSet die Bildtransparenz ändert, indem es die Alphakanalwerte im Array m_pixels ändert.
- Andere Einstellungen. Hier gibt es eine einzige Methode, FilterFunction, zum Setzen des Antialiasing-Filters, die den Filter für alle Zeichnungsmethoden setzt, die AA-Symbole in ihrem Namen haben.
Die Klasse CCanvas hat Felder und Methoden im Bereich der "privaten" Sichtbarkeit. Ich werde sie in diesem Artikel nicht berücksichtigen, da sie intern sind und nicht in umdefinierten Methoden von CCanvas-Nachfolgeklassen verwendet werden können. Sie können sie im Quellcode des Moduls Canvas.mqh im MetaEditor finden.
Abfolge der Aktionen bei der Verwendung von CCanvas in MQL-Anwendungen
In Anbetracht der obigen Ausführungen ist es nun möglich, eine gemeinsame Abfolge von Aktionen für die Handhabung der CCanvas-Klasse bei ihrer Verwendung in MQL-Anwendungen aufzuzeigen. Betrachten wir die Aktionen, die durchgeführt werden müssen, um ein Bild in einem Chart erscheinen zu lassen.
- Erstellen oder Anhängen eines Chart-Objekts (OBJ_BITMAP oder OBJ_BITMAP_LABEL) oder Anhängen an das bereits vorhandene OBJ_BITMAP_LABEL
- Schriftparameter und primitive Zeichenstile einstellen
- Zeichnen im Array m_pixels unter Verwendung der entsprechenden Methoden
- Aktualisierung der Ressource des grafischen Objekts (OBJ_BITMAP oder OBJ_BITMAP_LABEL)
Als Ergebnis wird das Chart ein Objekt mit grafischen Konstruktionen oder einem Text haben. Betrachten wir nun detailliert die Aktion
Erstellen eines Chart-Objekts und Anhängen an ein bereits vorhandenes Chart-Objekt
Damit eine MQL-Anwendung Grafiken in einem Chart anzeigen kann, müssen wir ein Objekt erstellen, das auf der Klasse CCanvas oder deren abgeleiteten Klassen basiert. Nach dem Erstellen eines CCanvas-Objekts können wir mit der Entwicklung des OBJ_BITMAP- oder OBJ_BITMAP_LABEL-Chart-Objekts beginnen. Alternativ können wir auch das bereits vorhandene OBJ_BITMAP_LABEL an das erstellte CCanvas-Objekt anhängen.
Um ein grafisches Objekt zu erstellen, hat CCanvas die Methoden CreateBitmap und CreateBitmapLabel. Jede von ihnen verfügt über eine eigene Überladungsoption für eine bequemere Verwendung.
bool CreateBitmap(const long chart_id, const int subwin, const string name, const datetime time, const double price, const int width, const int height, ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); bool CreateBitmap(const string name, const datetime time, const double price, const int width, const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); bool CreateBitmapLabel(const long chart_id, const int subwin, const string name, const int x, const int y, const int width, const int height, ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); bool CreateBitmapLabel(const string name,const int x,const int y, const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
Die Methode CreateBitmap erstellt eine Bitmap (Objekttyp OBJ_BITMAP), deren Koordinaten als Zeit und Preis auf einem Chart mit Handelssymbolen festgelegt werden, und enthält die folgenden Parameter:
- chart_id - Chart ID (0 = aktuell)
- window - Index des Chart-Unterfensters (0 - Hauptfenster)
- name - Name eines erstellten grafischen Objekts in einem Chart
- time - Zeitkoordinate eines grafischen Objekts in einem Chart
- price - Preiskoordinate eines grafischen Objekts in einem Chart
- width - Breite des grafischen Objekts in einem Chart
- height - Höhe des grafischen Objekts in einem Chart
Eine weitere Option der Methode CreateBitmap ist eine überladene Methode, die CreateBitmap mit chart_id und window gleich 0 aufruft (was dem aktuellen Chart und Hauptfenster entspricht).
//+------------------------------------------------------------------+ //| Create object on chart with attached dynamic resource | //+------------------------------------------------------------------+ bool CCanvas::CreateBitmap(const string name,const datetime time,const double price, const int width,const int height,ENUM_COLOR_FORMAT clrfmt) { return(CreateBitmap(0,0,name,time,price,width,height,clrfmt)); }
Die Methode CreateBitmapLabel hat die gleichen Parameter wie CreateBitmap, mit Ausnahme von "time" und "price". Stattdessen sind x und y zu sehen.
Eingaben:
- chart_id - Chart ID (0 = aktuell)
- window - Index des Unterfensters des Charts (0 = Hauptfenster)
- name - Name eines erstellten grafischen Objekts in einem Chart
- x - X-Koordinate eines grafischen Objekts in einem Chart
- y - Y-Koordinate eines grafischen Objekts in einem Chart
- width - Breite des erstellten grafischen Objekts
- height - Höhe eines erstellten grafischen Objekts
- clrfmt - Pixel-Farbformat eines erstellten grafischen Objekts
Eine weitere Option der Methode CreateBitmapLabel ist eine überladene Methode, die CreateBitmapLabel mit chart_id und window gleich 0 aufruft (wie CreateBitmap).
//+------------------------------------------------------------------+ //| Create object on chart with attached dynamic resource | //+------------------------------------------------------------------+ bool CCanvas::CreateBitmapLabel(const string name,const int x,const int y, const int width,const int height,ENUM_COLOR_FORMAT clrfmt) { return(CreateBitmapLabel(0,0,name,x,y,width,height,clrfmt)); }
Wenn das Chart über das Objekt OBJ_BITMAP_LABEL verfügt, kann es mit der Methode Attach an CCanvas angehängt werden. Infolgedessen interagiert das Chart-Objekt mit dem CCanvas-Objekt auf die gleiche Weise wie mit dem Chart-Objekt, das mit der Methode CreateBitmap oder CreateBitmapLabel erstellt wurde.
virtual bool Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); virtual bool Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
Die Methode fügt CCanvas an das bereits vorhandene Chart-Objekt OBJ_BITMAP_LABEL an.
Eingaben:
- chart_id - Chart ID (0 = aktuell)
- objname - Name eines angehängten grafischen Objekts
- width - Breite eines angehängten grafischen Objekts
- height - Höhe eines angehängten grafischen Objekts
- clrfmt - Pixel-Farbformat eines angehängten grafischen Objekts
Die erste Option der Methode Attach impliziert, dass ein Chart-Objekt keine grafische Ressource hat und es selbst erstellt, indem es die Parameter objname, width, height und clrfmt verwendet und alle Daten einträgt, die für die weitere Behandlung des angehängten grafischen Objekts erforderlich sind.
Die zweite Option setzt das Vorhandensein einer grafischen Ressource voraus und liest einfach Bildpixeldaten in das Array m_pixels und füllt auch alle Daten, die für die weitere Behandlung des angehängten grafischen Objekts notwendig sind.
Methoden zum Setzen und Empfangen von Schriftparametern, sowie Methoden zum Setzen und Empfangen eines Linienzeichnungsstils
Nachdem das grafische Objekt mit der CreateBitmap- oder CreateBitmapLabel-Methode erstellt oder mit der Attach-Methode angehängt wurde, sollten wir die Schriftparameter und den primitiven Zeichenstil einstellen, um das erforderliche Bild zu erhalten. Die Schriftparameter werden mit den folgenden Methoden eingestellt.
Einfache Methoden zur Einstellung der Schrifteigenschaften:
bool FontNameSet(string name); // Set the font name bool FontSizeSet(int size); // Set the font size bool FontFlagsSet(uint flags); // Set the font attributes bool FontAngleSet(uint angle); // Set the font slope angle
Einfache Methoden zum Lesen der Schrifteigenschaften:
string FontNameGet(void) const; // Return the font name int FontSizeGet(void) const; // Return the font size uint FontFlagsGet(void) const; // Return the font attributes uint FontAngleGet(void) const; // Return the font slope angle
Einfache Methoden zum Setzen der Schrifteigenschaften:
bool FontSet(const string name,const int size,const uint flags=0,const uint angle=0); // Set the font properties
Eingaben:
- name - Name der Schriftart
- size - Schriftgröße
- flags - Attribute der Schriftart
- angle - Neigungswinkel der Schrift
Wie man im Programmcode sehen können, setzt die Methode den Schriftnamen, die Größe, die Attribute und den Neigungswinkel der Schrift gemäß name, size, flags und angle, die als Parameter übergeben werden.
Methode zum Empfang aller Schrifteigenschaften
void FontGet(string &name,int &size,uint &flags,uint &angle); // Get font properties
Eingaben:
- name - Name der Schriftart
- size - Schriftgröße
- flags - Attribute der Schriftart
- angle - Neigungswinkel der Schrift
Wie im Programmcode zu sehen ist, schreibt die Methode den Schriftnamen, die Größe, die Attribute und den Neigungswinkel in die entsprechenden Variablen name, size, flags und angle, die ihr als Parameter an bestimmten Adressen übergeben werden.
Methoden zum Lesen und Schreiben eines grafischen Stils zum Erstellen von Linien:
uint LineStyleGet(void) const; // Return the specified line drawing style void LineStyleSet(const uint style); // Set the line drawing style
Eingaben:
- style - Linienzeichnungsstil
Methoden zum Zeichnen und Darstellen eines Textes
Beginnen wir mit der Methode der Textdarstellung, da sie nur eine ihrer Art ist, während die grafischen primitiven Zeichenmethoden in CCanvas zahlreich sind.
Text-Anzeige
void TextOut(int x,int y,string text,const uint clr,uint alignment=0); // Display text to the m_pixels array
Eingaben:
- x - X-Koordinate eines angezeigten Textes
- y - Y-Koordinate eines angezeigten Textes
- text - angezeigter Text
- clr - Farbe des angezeigten Textes
- alignment - Art der Verankerung des angezeigten Textes
Gemäß des Programmcodes zeigt die Methode Text an den Koordinaten x und y mit der angegebenen clr Farbe und Ausrichtung entsprechend der Methode zur Textverankerung an.
Ändern von Pixeln
In CCanvas können Pixel, die sich im Array m_pixels befinden, geändert werden oder ihre Werte entsprechend den angegebenen Koordinaten empfangen werden.
uint PixelGet(const int x,const int y) const; // Return the pixel color value according to x and y coordinates void PixelSet(const int x,const int y,const uint clr); // Change the pixel color value according to x and y coordinates
Eingaben:
- x - Pixel X-Koordinate
- y - Pixel Y-Koordinate
- clr - Pixelfarbe
Zeichnen von grafischen Primitiven
Da CCanvas über zahlreiche Methoden zum Zeichnen von Primitiven verfügt, werde ich in diesem Artikel nur auf die wichtigsten eingehen. Alle anderen Methoden sind in der Dokumentation zu finden.
Vertikale Linie
void LineVertical(int x,int y1,int y2,const uint clr); // Draw a vertical line according to specified coordinates and color
Eingaben:
- x - X-Koordinate der Vertikalen
- y1 - Y-Koordinate des ersten Punktes
- y2 - Y-Koordinate des zweiten Punktes
- clr - Linienfarbe
Horizontale Linie
void LineHorizontal(int x1,int x2,int y,const uint clr); // Draw a horizontal line according to specified coordinates and color
Eingaben:
- x1 - X-Koordinate des ersten Punktes
- x2 - X-Koordinate des zweiten Punktes
- y - Y-Koordinate der Horizontalen
- clr - Linienfarbe
Freihandlinie
void Line(int x1,int y1,int x2,int y2,const uint clr); // Draw a freehand line according to specified coordinates and color
Eingaben:
- x1 - X-Koordinate des ersten Punktes
- x1 - X-Koordinate des ersten Punktes
- x2 - X-Koordinate des zweiten Punktes
- y1 - Y-Koordinate des ersten Punktes
- clr - Linienfarbe
Polylinie
void Polyline(int &x[],int &y[],const uint clr); // Draw a polyline according to specified coordinates and color
Eingaben:
- x - Punkt im X-Koordinatenfeld
- y - Punkt im Y-Koordinatenfeld
- clr - Linienfarbe
Polygon
void Polygon(int &x[],int &y[],const uint clr); // Draw a polygon according to specified coordinates and color
Eingaben:
- x - Punkt im X-Koordinatenfeld
- y - Punkt im Y-Koordinatenfeld
- clr - Farbe des Polygons
Rechteck
void Rectangle(int x1,int y1,int x2,int y2,const uint clr); // Draw a rectangle according to specified coordinates and color
Eingaben:
- x1 - erste Punkt X-Koordinate
- y1 - erster Punkt Y-Koordinate
- x2 - zweiter Punkt X-Koordinate
- y2 - zweiter Punkt Y-Koordinate
- clr - Farbe des Rechtecks
Dreieck
void Triangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr); // Draw a triangle according to specified coordinates and color
Eingaben:
- x1 - erster Punkt X-Koordinate
- y1 - erster Punkt Y-Koordinate
- x2 - zweiter Punkt X-Koordinate
- y2 - zweiter Punkt Y-Koordinate
- x3 - dritter Punkt X-Koordinate
- y3 - dritter Punkt Y-Koordinate
- clr - Rechteckfarbe
Kreis
void Circle(int x,int y,int r,const uint clr); // Draw a circle according to specified coordinates, radius and color
Eingaben:
- x - X-Koordinate
- y - Y-Koordinate
- r - Kreisradius
- clr - Farbe des Kreises
Ellipse
void Ellipse(int x1,int y1,int x2,int y2,const uint clr); // Draw an ellipse according to specified coordinates and color
Eingaben:
- x1 - erster Punkt X-Koordinate
- y1 - erster Punkt Y-Koordinate
- x2 - zweiter Punkt X-Koordinate
- y2 - zweiter Punkt Y-Koordinate
- clr - Rechteckfarbe
Die Beschreibungen der anderen Methoden, einschließlich Arc und Pie, sind zu umfangreich, um sie hier zu zeigen. Sie finden deren Beschreibungen in der Dokumentation, indem Sie den obigen Links folgen.
Die betrachteten Methoden zeigen einfache Primitive mit einer Linienbreite von 1 Pixel und dem gewöhnlichen Linienstil STYLE_SOLID an. Sie können sie verwenden, wenn Sie mit einfachen Grafiken zurechtkommen.
Wenn Sie jedoch etwas anderes als STYLE_SOLID benötigen, wählen Sie eine der unten beschriebenen Methoden.
//--- Methods for drawing primitives with smoothing using antialiasing void PixelSetAA(const double x,const double y,const uint clr); void LineAA(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style=UINT_MAX); void PolylineAA(int &x[],int &y[],const uint clr,const uint style=UINT_MAX); void PolygonAA(int &x[],int &y[],const uint clr,const uint style=UINT_MAX); void TriangleAA(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,const uint clr,const uint style=UINT_MAX); void CircleAA(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX); void EllipseAA(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style=UINT_MAX); //--- Methods for drawing primitives with smoothing using Wu's algorithm void LineWu(int x1,int y1,int x2,int y2,const uint clr,const uint style=UINT_MAX); void PolylineWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX); void PolygonWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX); void TriangleWu(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,const uint clr,const uint style=UINT_MAX); void CircleWu(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX); void EllipseWu(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style=UINT_MAX);
Alle diese Methoden ähneln den oben genannten, haben aber einen zusätzlichen Stil Parameter, der aus der ENUM_LINE_STYLE Aufzählung ausgewählt werden kann. Er ist im Programmcode gelb hervorgehoben. Ist dieser Parameter style nicht gesetzt (also gleich UINT_MAX), verwendet die aufgerufene Methode den Wert m_style, der mit der LineStyleSet Methode gesetzt wurde. Der Wert kann mit der Methode LineStyleGet abgerufen werden.
Sie haben vielleicht bemerkt, dass die Methoden die Möglichkeit haben, einen Linienstil zu setzen, aber sie sind nicht in der Lage, eine Linienbreite zu ändern. Die folgenden Methoden ermöglichen das Zeichnen von Primitiven mit der Möglichkeit, die Linienstärke einzustellen.
//--- Methods for drawing primitives with preliminarily set antialiasing filter void LineThickVertical(const int x,const int y1,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style); void LineThickHorizontal(const int x1,const int x2,const int y,const uint clr,const int size,const uint style,ENUM_LINE_END end_style); void LineThick(const int x1,const int y1,const int x2,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style); void PolylineThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style); void PolygonThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
Ähnlich wie die oben beschriebenen Methoden bieten die aktuellen Methoden die Möglichkeit, den Zeilenstil style zu setzen. Sie bieten auch die neuen Parameter, wie size zur Festlegung der Linienbreite, sowie end_style, für die Art des Linienendes, der aus der Enumeration ENUM_LINE_END ausgewählt werden kann.
Außerdem verfügt CCanvas über Methoden zum Zeichnen von geglätteten Primitiven unter Verwendung der Bézier-Methode. Um die endgültige Bildqualität zu verbessern, werden die resultierenden Primitive mit dem Bitmap-Glättungsalgorithmus bearbeitet. Anders als bei den vorherigen Methoden bestehen die Primitive hier aus Bézier-Kurven und nicht aus geraden Linien. Lassen Sie uns diese Methoden betrachten.
//--- Methods for drawing a smoothed polyline and smoothed polygon void PolylineSmooth(const int &x[],const int &y[],const uint clr,const int size, ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND, double tension=0.5,double step=10); void PolygonSmooth(int &x[],int &y[],const uint clr,const int size, ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND, double tension=0.5,double step=10);
Zusätzlich zu den bereits bekannten Arrays der primitiven Koordinatenpunkten x und y, der Farbe clr, size für die Linienbreite, style für den Linienstil und end_style für das Ende der Linie, haben wir hier zwei zusätzliche Parameter Spannungs-Parameter, einen Glättungsparameterwert und step für Näherungsschritte.
Abgesehen von den oben beschriebenen Methoden zum Zeichnen von Primitiven bietet CCanvas auch Methoden zum Zeichnen von gefüllten Primitiven.
//--- Methods of drawing filled primitives void FillRectangle(int x1,int y1,int x2,int y2,const uint clr); void FillTriangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr); void FillPolygon(int &x[],int &y[],const uint clr); void FillCircle(int x,int y,int r,const uint clr); void FillEllipse(int x1,int y1,int x2,int y2,const uint clr); void Fill(int x,int y,const uint clr); void Fill(int x,int y,const uint clr,const uint threshould);
Es handelt sich um einfache Methoden ohne Glättungsalgorithmen. Die Zuweisung der Parameter erfolgt analog zu den Parametern der bereits betrachteten Methoden und beinhaltet die Erstellung ähnlicher Primitive, die aus Linien bestehen.
Pixelformat und Farbkomponenten
Kehren wir zu den oben betrachteten Methoden zurück und richten wir unsere Aufmerksamkeit auf das Pixelformat in den Methoden CreateBitmap und CreateBitmapLabel. Für das Format ist der Parameter clrfmt zuständig. Der Parameter legt das Pixelformat fest, das für die grafische Ressource erstellt wird, die sich später mit dem entsprechenden Chart-Objekt verbindet. Das Pixelformat, das für die grafische Ressource während der Canvas-Erstellung mit Hilfe der Methoden CreateBitmap oder CreateBitmapLabel festgelegt wird, beeinflusst die Methode zur Behandlung eines Bildes durch das Terminal, wenn es im Chart angezeigt wird. Um die Bildbearbeitungsmethoden zu definieren, schauen wir uns ENUM_COLOR_FORMAT an. Hier können wir einen von drei möglichen konstanten Werten auswählen.
ENUM_COLOR_FORMAT
- COLOR_FORMAT_XRGB_NOALPHA - XRGB Format (Alphakanal wird ignoriert)
- COLOR_FORMAT_ARGB_RAW - "rohes" ARGB-Format (Farbkomponenten werden vom Terminal nicht verarbeitet)
- COLOR_FORMAT_ARGB_NORMALIZE - ARGB-Format (Farbbestandteile werden vom Terminal verarbeitet)
Betrachten wir nun die Reihenfolge der Bereitstellung von Farbkomponenten in diesen Formaten.
Hier sehen wir im Pixelarray der Zellbytes, m_pixels, die Position der Farbkomponenten, wobei R der rote Kanal, G der grüner Kanal und B der blauer Kanal, A der Alpha-Kanal und X ein unbenutztes Byte ist. uint Pixeldatentyp, 4 Bytes. Ein Byte pro Kanal. Ein Byte kann Zahlen von 0 bis 255 speichern. Wir können die Pixelfarbe einstellen, indem wir die Byte-Werte ändern. Wenn man zum Beispiel 255 für den R-Kanal und 0 für die G- und B-Kanäle einstellt, erhält man die rote Farbe. Setzt man 255 auf den G-Kanal, während die übrigen Werte auf 0 gesetzt werden, erhält man die grüne Farbe. Wenn der B-Kanal auf 255 gesetzt wird, während die übrigen auf 0 gesetzt werden, erhalten wir die blaue Farbe. Auf diese Weise können wir verschiedene Farben erhalten, indem wir die verschiedenen Kombinationen von RGB-Kanalwerten einstellen. Durch Einstellen des Alphakanalwerts von 0 (völlig unsichtbar, transparent) bis 255 (völlig sichtbar, nicht transparent) können wir die Nichttransparenz der Pixel steuern, indem wir den Effekt erzeugen, dass sich die Pixel des Chart-Bildes überlappen. Dies kann im Format COLOR_FORMAT_ARGB_NORMALIZE korrekt durchgeführt werden. Gehen wir nun zu den Farben über und betrachten wir die Farbpalette.
Hier können wir deutlich sehen, wie sich eine Änderung der Kombination von Stufen jedes Kanals auf die resultierende Farbe auswirkt. Die Farben werden in den Formaten RGB und HEX dargestellt. Während ich mich bereits mit RGB beschäftigt habe, bedarf HEX einiger Erläuterungen, insbesondere für Programmieranfänger, die CCanvas beherrschen wollen. Betrachten wir das hexadezimale Zahlensystem, das Zahlen von 0 bis 15 enthält, und vergleichen es mit dem Dezimalsystem (0-9). Das Dezimalsystem hat die folgenden Symbole: 0, 1, 2, 3, 4, 5, 6, 7, 8 und 9. Wie soll man also Zahlen, die größer als 9 sind, im Hexadezimalsystem bezeichnen? In diesem Fall verwendet das System lateinische Buchstaben von A bis F. Das hexadezimale Zahlensystem hat also folgende Symbole: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E und F. Jetzt können wir einfach verstehen, wie das Byte mit dem Kanalwert im HEX-Format aussieht. In C-basierten Programmiersprachen wird HEX als 0x[Wert] bezeichnet. Ein Bereich der einzelnen Bytes haben also folgendes Aussehen: 0x00 bis 0xFF.
Beispiele für die Erstellung von Grafiken mit CCanvas
Kehren wir zum Pixelformat zurück und betrachten wir ein einfaches Beispiel für eine Anwendung, die CCanvas verwendet. Außerdem werden wir mit verschiedenen Pixelformaten spielen, indem wir versuchen, die Werte für Bildfarbe und Alphakanal in verschiedenen Pixelformaten festzulegen. Beginnen wir mit dem universellsten Format COLOR_FORMAT_ARGB_NORMALIZE. Wir werden es verwenden, um unsere erste Anwendung zu entwickeln.
Eine einfache Anwendung mit CCanvas
Erstellen wir ein Skript und nennen es Erase.mq5.
#include <Canvas\Canvas.mqh> //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { CCanvas canvas; canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
In der ersten Zeile sehen wir die Einbindung des Moduls Canvas.mqh. Nun ist es möglich, ein Objekt, eine Instanz der Klasse CCanvas, für die weitere Arbeit zu erstellen, wie im Beispiel gezeigt.
CCanvas canvas;
Als Nächstes wird das Canvas selbst mit dem Parameter clrfmt erstellt: COLOR_FORMAT_ARGB_NORMALIZE.
canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE);
Und füllen wir es mit der Methode "Erase".
canvas.Erase(ColorToARGB(clrWhite, 255));
Nach dem Erstellen von Canvas rufen wir die Methode Update auf.
canvas.Update(true);
Mit redraw: true. Dies ist ein optionaler Parameter, da er ohnehin standardmäßig gesetzt ist, aber ich schlage vor, ihn für mehr Klarheit zu setzen. Als Nächstes warten wir 6 Sekunden um das Ergebnis der Bearbeitung der Anwendung auf dem Chart zu sehen.
Sleep(6000);
Als Nächstes rufen wir die Methode Destroy auf, um den von der grafischen Ressource und dem Chart-Objekt belegten Speicher freizugeben.
canvas.Destroy();
Danach beendet das Skript seine Arbeit. Das Ergebnis ist in der folgenden Abbildung zu sehen.
Hier sehen wir ein ausgefülltes Rechteck, das als Basis oder Hintergrund für das Zeichnen komplexerer grafischer Konstruktionen verwendet werden kann.
Pixelformat und Überlappungsmethoden
Schauen wir uns das bereits betrachtete Beispiel Erase.mq5 an und versuchen wir, die Farbe direkt zu setzen, ohne die Funktion ColorToARGB. Wir kopieren den gesamten Code des Beispiels und erstellen ein Skript namensARGB_NORMALIZE.mq5. Dann legen wir die Farbe fest, indem wir eine der Farben aus der oben erwähnten Palette auswählen, zum Beispiel clrPaleGreen. Wir nehmen den Wert im HEX-Format und fügen den Wert des Alphakanals 0xFF auf der linken Seite hinzu.
#include <Canvas\Canvas.mqh> //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { CCanvas canvas; canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(0xFF98FB98); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Die RGB-Komponenten in der Auflistung sind grün hervorgehoben, die A-Komponente ist grau hervorgehoben. Wir starten das Skript und sehen uns das Ergebnis an.
Wir sehen, wie sich die Farbe des Bildes verändert hat. Versuchen wir nun, die Transparenz zu ändern. Setzen Sie den Wert des Alphakanals auf 0xCC.
void OnStart() { CCanvas canvas; canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(0xCC98FB98); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Werfen wir einen Blick auf das Ergebnis.
Hier sehen wir, dass der gefüllte Bereich halbtransparent geworden ist.
Ändern Sie das Pixelformat in COLOR_FORMAT_ARGB_RAW und machen Sie das Bild wieder völlig undurchsichtig. Dazu erstellen wir ein separates Beispiel ARGB_RAW.mq5.
void OnStart() { CCanvas canvas; canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_RAW); canvas.Erase(0xFF98FB98); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Führen wir das Beispiel aus und sehen uns das Ergebnis an.
Wie wir sehen, unterscheidet sich das Ergebnis nicht von COLOR_FORMAT_ARGB_NORMALIZE.
Wir setzen den Alphakanal auf 0xFB und ändern Sie die Hintergrundfarbe des Charts auf Weiß.
void OnStart() { ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite); CCanvas canvas; canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_RAW); canvas.Erase(0xFB98FB98); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Hier ist nur eine geringfügige Änderung und kein Unterschied zum COLOR_FORMAT_ARGB_NORMALIZE-Pixelformat zu erkennen.
Verringern wir jedoch den Wert des Alphakanals um eins,
canvas.Erase(0xFA98FB98);
stellen wir sofort erhebliche Veränderungen des endgültigen Bildes fest.
Prüfen wir nun, wie sich das Bild bei einer vollständigen Transparenzänderung verhält. Dazu erstellen wir ein neues Beispiel und nennen es ARGB_RAW-2.mq5. Wir kopieren den Code aus dem vorherigen Beispiel dorthin und nehmen leichte Änderungen vor, damit der Alphakanalwert in einem bestimmten Intervall von 255 auf 0 wechseln kann.
void OnStart() { ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite); CCanvas canvas; canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_RAW); canvas.Erase(0xFF98FB98); for(int a = 255; a >= 0; a--) { canvas.TransparentLevelSet((uchar)a); canvas.Update(true); Sleep(100); } canvas.Destroy(); }
Wie wir im Listing sehen können, verfügt die Anwendung über eine for-Schleife, die die Transparenz (a-Schleifenvariable) durch den Aufruf der Methode TrancparentLevelSet und die Transparenz des gesamten Bildes ändert.
canvas.TransparentLevelSet((uchar)a);
Als Nächstes rufen Sie die bereits bekannte Methode Update auf.
canvas.Update(true);
Als Nächstes lässt die Funktion Sleep die Schleife 100 Millisekunden lang warten (damit die Nutzer Zeit haben, die Änderung der Transparenz zu sehen).
Sleep(100);
Dann entfernt die Anwendung Canvas
canvas.Destroy();
und beendet ihre Arbeit. Das Ergebnis ist in der folgenden GIF-Animation zu sehen.
Aus dem folgenden Beispiel sowie aus allen Beispielen, die das Format COLOR_FORMAT_ARGB_RAW anwenden, geht hervor, dass das Bild mit dem Alphakanalwert 255 korrekt angezeigt wird. Verringert man jedoch den Wert, wird das Bild verzerrt, da das Format keine Normalisierung der RGB-Kanalwerte vorsieht. Die Kanäle können überfüllt werden, was zu Artefakten und Verzerrungen führt, da überfüllte Werte, die 255 überschreiten, einfach verworfen werden. Andererseits beschleunigt die Verwendung dieses Formats die Anzeige des Bildes im Vergleich zum COLOR_FORMAT_ARGB_NORMALIZE-Format.
Kommen wir zurück zu unserem Beispiel für die Verwendung des Pixelformats COLOR_FORMAT_ARGB_RAW ARGB_RAW.mq5. Erstellen Sie das Skript mit dem Namen XRGB_NOALPHA.mq5 und kopieren Sie den Code aus ARGB_RAW.mq5 dorthin, indem Sie das Pixelformat auf COLOR_FORMAT_XRGB_NOALPHA setzen. Setzen Sie außerdem den Alphakanalwert in der Löschmethode auf Null.
void OnStart() { CCanvas canvas; canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_XRGB_NOALPHA); canvas.Erase(0x0098FB98); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Starten Sie das Skript, um die Ergebnisse zu sehen.
Wie wir sehen können, unterscheidet sich das Ergebnis nicht von den Formaten COLOR_FORMAT_ARGB_NORMALIZE und COLOR_FORMAT_ARGB_RAW mit dem maximalen Alphakanalwert (0xFF) in der Löschmethode. Man sieht also, dass der Alphakanalwert bei diesem Format vollständig ignoriert wird und das Bild einfach über das Chart-Bild gelegt wird.
Text-Anzeige
Wir wissen, dass CCanvas eine Methode zur Anzeige des TextOut Textes bietet. Lassen Sie uns versuchen, den Text anzuzeigen. Wir erstellen das Skript und nennen es TextOut.mq5. Wir verwenden das oben besprochene Erase.mq5 als Grundlage, indem wir seinen Code kopieren. Wir fügen die Methode zum Setzen der FontSet-Schriftparameter hinzu und setzen Sie die notwendigen Werte, Schriftart "Calibri" und Schriftgröße -210.
Um die Schriftgröße in Pixeln Größe in den Methoden FontSet und FontSizeSet einzustellen, sollte sie mit -10 multipliziert werden. Im Falle einer Schriftgröße von 21 Pixeln ist Größe also gleich -210.
Die übrigen Parameter werden standardmäßig belassen. Als Nächstes fügen wir die Methode TextOut mit dem Parameter text hinzu: "Text". Alle anderen für die Beispieloperation notwendigen Zeichenfolgen bleiben im kopierten Code.
void OnStart() { CCanvas canvas; canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.FontSet("Calibri", -210); canvas.TextOut(15, 15, "Text", ColorToARGB(clrLightSlateGray, 255)); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Schauen wir uns das Ergebnis der Skriptoperation an.
Der Text erscheint auf dem Bild.
Ändern wir das Beispiel so, dass das Bild genau in der Mitte des Charts erscheint und an das Label-Objekt (OBJ_LABEL) erinnert. Erstellen wir jetzt ein neues Beispiel auf der Grundlage des Skripts und nennen es TextOut-2.mq5.
void OnStart() { string text = "Text"; int width, height; const int textXDist = 10, textYDist = 5; int canvasX, canvasY; CCanvas canvas; canvas.FontSet("Calibri", -210); canvas.TextSize(text, width, height); canvasX = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0) / 2 - width / 2; canvasY = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0) / 2 - height / 2; canvas.CreateBitmapLabel("canvas", canvasX, canvasY, width + textXDist * 2, height + textYDist * 2, COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.TextOut(textXDist, textYDist, text, ColorToARGB(clrLightSlateGray, 255)); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Dem Programmcode zufolge wird der angezeigte Text der Text-Variablen zugewiesen (da im Skriptcode zweimal auf sie zugegriffen wird).
string text = "Text";
Die Variablen Breite und Höhe wurden deklariert, um die angezeigte Textgröße zu speichern.
int width, height;
Die beiden deklarierten Konstanten textXDist und textYDist speichern die Abstände des angezeigten Textes vom rechten bzw. oberen Rand des Bildes.
const int textXDist = 10, textYDist = 5;
Als Nächstes werden zwei Variablen canvasX und canvasY deklariert, um die Ergebnisse der Berechnungen der Bildkoordinaten zu speichern.
int canvasX, canvasY;
Danach kommt die Methode FontSet, die die Schriftparameter definiert (um sie vorher zu setzen).
canvas.FontSet("Calibri", -210);
Die Methode TextSize erlaubt es, die Größe eines angezeigten Textes zu definieren (um die Bildgröße zu bestimmen), die in den Variablen width und height gespeichert wird.
canvas.TextSize(text, width, height);
Als Nächstes berechnen wir die Bildkoordinaten, um das Bild in der Mitte eines Charts anzuzeigen.
canvasX = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0) / 2 - width / 2; canvasY = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0) / 2 - height / 2;
Als Nächstes erstellen wir das Bild mit der Funktion CreateBitmapLabel, bei der die zuvor berechneten Koordinaten festgelegt werden.
canvas.CreateBitmapLabel("canvas", canvasX, canvasY,
width + textXDist * 2, height + textYDist * 2,
COLOR_FORMAT_ARGB_NORMALIZE);
Danach wird das Bild mit Hilfe der Methode Erase mit Farbe gefüllt.
canvas.Erase(ColorToARGB(clrWhite, 255));
Anschließend wird der Text (Text) mit der Methode TextOut unter Angabe der zuvor festgelegten Koordinaten textXDist und textYDist angezeigt.
canvas.TextOut(textXDist, textYDist, text, ColorToARGB(clrLightSlateGray, 255));
Als Nächstes haben wir die bereits bekannten Zeichenketten, die keiner Erklärung bedürfen. Starten wir das Skript und sehen wir uns das Ergebnis an.
Das Bild zeigt ein Objekt, das einem Textetikett ähnelt. Aber es fehlt der transparente Hintergrund. Der Hintergrund kann in unserem aktuellen Pixelformat COLOR_FORMAT_ARGB_NORMALIZE eingestellt werden. Aber ich werde einen anderen Weg gehen. Wir setzen das Pixelformat COLOR_FORMAT_ARGB_RAW auf unsere Leinwand, da wir in diesem Fall keine Mischfarben benötigen, während die Farben mit dem Alphakanal 0 und 255 im Format ohne Verzerrung dargestellt werden. Die Farbe mit dem Alphakanalwert von 0 beeinflusst das endgültige Bild nicht. Wir kopieren das Skript LabelExample.mq5, das auf dem vorherigen Beispiel basiert.
void OnStart() { string text = "Text"; int width, height; const int textXDist = 10, textYDist = 5; int canvasX, canvasY; CCanvas canvas; canvas.FontSet("Calibri", -210); canvas.TextSize(text, width, height); canvasX = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0) / 2 - width / 2; canvasY = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0) / 2 - height / 2; canvas.CreateBitmapLabel("canvas", canvasX, canvasY, width + textXDist * 2, height + textYDist * 2, COLOR_FORMAT_ARGB_RAW); canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.FontSet("Calibri", -210); canvas.TextOut(textXDist, textYDist, text, ColorToARGB(clrLightSlateGray, 255)); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Der Alphakanal ist unverändert geblieben, sodass wir sicherstellen können, dass der Alphakanal von 255 die Pixel des Charts vollständig neu zeichnet.
Jetzt setzen wir den Wert des Alphakanals auf 0.
void OnStart() { string text = "Text"; int width, height; const int textXDist = 10, textYDist = 5; int canvasX, canvasY; CCanvas canvas; canvas.FontSet("Calibri", -210); canvas.TextSize(text, width, height); canvasX = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0) / 2 - width / 2; canvasY = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0) / 2 - height / 2; canvas.CreateBitmapLabel("canvas", canvasX, canvasY, width + textXDist * 2, height + textYDist * 2, COLOR_FORMAT_ARGB_RAW); canvas.Erase(ColorToARGB(clrWhite, 0)); canvas.FontSet("Calibri", -210); canvas.TextOut(textXDist, textYDist, text, ColorToARGB(clrLightSlateGray, 255)); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Starten Sioe das Skript und schauen sie sich das Ergebnis an.
Wir können die Textbeschriftung analog sehen (OBJ_LABEL). So können wir Texte über Bildern anzeigen, ohne sie komplett neu zu zeichnen. Dies wird in verschiedenen Nutzeroberflächen häufig zur Hervorhebung von Steuerelementen und zur Anzeige von Textdaten verwendet.
Zeichnen einfacher Primitive ohne Glättung
Schauen wir uns DrawPrimitives.mq5 an, um zu verstehen, wie man Primitive in CCanvas zeichnet.
void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {14, 12, 13, 11, 12, 10}; int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {9, 7, 5, 5, 7, 9}; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.LineHorizontal(point, w - point, h - point, color_); canvas.LineVertical(point, point, h - point, color_); canvas.Line(point * 2, point * 13, point * 8, point * 9, color_); for (int i = 0; i < (int)plX.Size(); i++) plX[i] *= point; for (int i = 0; i < (int)plY.Size(); i++) plY[i] *= point; canvas.Polyline(plX, plY, color_); for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.Polygon(pgX, pgY, color_); canvas.Rectangle(point * 2, point * 5, point * 7, point, color_); canvas.Triangle(point * 2, point * 11, point * 2, point * 6, point * 7, point * 6, color_); canvas.Circle(point * 10, point * 3, point * 2, color_); canvas.Ellipse(point * 8, point * 9, point * 12, point * 6, color_); canvas.Arc(point * 15, point * 2, point * 2, point, 45.0 * M_PI / 180, 180.0 * M_PI / 180, color_); canvas.Pie(point * 16, point * 3, point * 2, point, 180.0 * M_PI / 180, 402.5 * M_PI / 180, color_, fillColor); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Alle Primitive können bequem entlang der Quadrate gezeichnet werden. Ihre Koordinaten und die übrigen Parameter lassen sich mit der gleichen Methode bequem einstellen. Daher habe ich beschlossen, die Aufgabe zu vereinfachen, indem ich das CCanvas-Bild in Teile mit gleicher Breite und Höhe unterteile, sodass es möglich ist, Koordinaten in Quadraten festzulegen und sie in Pixel umzuwandeln, indem man die Koordinaten in Quadraten mit der Größe eines einzelnen Quadrats multipliziert. Um dies zu erreichen, habe ich die Größe des Charts als CCanvas-Bildgröße genommen und den kleinsten Wert durch 15 geteilt.
CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {14, 12, 13, 11, 12, 10}; int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {9, 7, 5, 5, 7, 9}; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15;
Der Code ist in der Auflistung gelb hervorgehoben. Da wir nun die Größe eines einzelnen Quadrats kennen (die Variable Punkt), können wir die in Quadraten festgelegten Koordinaten in ihre tatsächliche Größe in Pixeln umrechnen. Vor der Erstellung des Beispiels habe ich das Chart-Bild in Quadrate unterteilt und diese verwendet, um die Koordinaten aller Primitive im Skript festzulegen.
int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {14, 12, 13, 11, 12, 10}; int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {9, 7, 5, 5, 7, 9};
Hier habe ich die Koordinaten für eine Polylinie (Polylinie) und ein Polygon (Polygon) in das Array gesetzt. Dann habe ich sie in Pixel umgewandelt, indem ich die Arrays in den Schleifen einzeln ausgewählt und eine Polylinie und ein Polygon gezeichnet habe.
for (int i = 0; i < (int)plX.Size(); i++) plX[i] *= point; for (int i = 0; i < (int)plY.Size(); i++) plY[i] *= point; canvas.Polyline(plX, plY, color_); for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.Polygon(pgX, pgY, color_);
Der Code für den Aufruf der primitiven Zeichenmethoden ist gelb hervorgehoben. Die übrigen Primitive werden auf folgende Weise angezeigt.
canvas.Polygon(pgX, pgY, color_); canvas.Rectangle(point * 2, point * 5, point * 7, point, color_); canvas.Triangle(point * 2, point * 11, point * 2, point * 6, point * 7, point * 6, color_); canvas.Circle(point * 10, point * 3, point * 2, color_); canvas.Ellipse(point * 8, point * 9, point * 12, point * 6, color_); canvas.Arc(point * 15, point * 2, point * 2, point, 45.0 * M_PI / 180, 180.0 * M_PI / 180, color_); canvas.Pie(point * 16, point * 3, point * 2, point, 180.0 * M_PI / 180, 402.5 * M_PI / 180, color_, fillColor);
Wie wir im Programmcode sehen können, werden alle Koordinaten mit point multipliziert, um sie in Pixel umzuwandeln. Betrachten wir nun das Ergebnis des Skripts.
Wir sehen die Primitive mit dem einfachen Linienzeichnungsstil (STYLE_SOLID), der nicht geändert werden kann.
Zeichnen von Primitiven mit Glättung und veränderbarem Linienstil
Damit der Linienstil geändert werden kann, verwenden Sie die Methoden mit dem Sortieralgorithmus, der Antialiasing (AA) anwendet. Erstellen Sie das Skript DrawPrimitivesAA.mq5 und kopieren Sie den Code aus dem vorherigen Beispiel hinein. Alle in der CCanvas-Klasse vorhandenen Methoden mit dem Präfix AA (LineAA, PolylineAA, PolygonAA, TriangleAA, CircleAA und EllipseAA) werden vollständig konform gemacht. Andere Methoden werden entfernt. Da wir nun im Vergleich zum vorherigen Beispiel weniger Primitive haben, können wir ihre Position ändern.
void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9}; int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {7, 5, 3, 3, 5, 7}; ENUM_LINE_STYLE lineStyle = STYLE_SOLID; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.LineStyleSet(lineStyle); canvas.LineAA(point * 2, point * 12, point * 8, point * 8, color_); for (int i = 0; i < (int)plX.Size(); i++) plX[i] *= point; for (int i = 0; i < (int)plY.Size(); i++) plY[i] *= point; canvas.PolylineAA(plX, plY, color_); for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.PolygonAA(pgX, pgY, color_); canvas.TriangleAA(point * 2, point * 9, point * 2, point * 4, point * 7, point * 4, color_); canvas.CircleAA(point * 16, point * 11, point * 2, color_); canvas.EllipseAA(point * 8, point * 4, point * 12, point * 7, color_); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Die geänderten Zeichenfolgen sind gelb hervorgehoben. Starten wir nun das Skript und schauen wir uns das Ergebnis an.
Das Bild zeigt die Ergebnisse der Methoden mit Antialiasing. Die Linien sehen im Vergleich zum vorherigen Beispiel mit einfachen Primitiven glatter aus.
Allerdings ist der Linienstil hier noch STYLE_SOLID. Wir beheben dies, indem wir das Skript DrawPrimitivesAA-2.mq5 erstellen und dort den Code des vorherigen Beispiels einfügen. Wir legen sleep als Eingabeparameter fest, der die Verzögerung nach der Änderung des Linienstils und der Anzeige der Primitive bestimmt.
#property script_show_inputs //--- input parameters input int sleep = 1000;
Alle Zeichenmethoden werden im Makro festgelegt.
#define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255)); \ canvas.LineAA(point * 2, point * 12, point * 8, point * 8, color_); \ canvas.PolylineAA(plX, plY, color_); \ canvas.PolygonAA(pgX, pgY, color_); \ canvas.TriangleAA(point * 2, point * 9, point * 2, point * 4, point * 7, point * 4, color_); \ canvas.CircleAA(point * 16, point * 11, point * 2, color_); \ canvas.EllipseAA(point * 8, point * 4, point * 12, point * 7, color_); \ canvas.Update(true); \ Sleep(sleep);
Als Nächstes ändern wir einzeln den Linienstil, indem wir die Methode LineStyleSet und die Anzeige von Primitiven verwenden. Schauen wir uns das Beispiel an.
#property script_show_inputs //--- input parameters input int sleep = 1000; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include <Canvas\Canvas.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255)); \ canvas.LineAA(point * 2, point * 12, point * 8, point * 8, color_); \ canvas.PolylineAA(plX, plY, color_); \ canvas.PolygonAA(pgX, pgY, color_); \ canvas.TriangleAA(point * 2, point * 9, point * 2, point * 4, point * 7, point * 4, color_); \ canvas.CircleAA(point * 16, point * 11, point * 2, color_); \ canvas.EllipseAA(point * 8, point * 4, point * 12, point * 7, color_); \ canvas.Update(true); \ Sleep(sleep); //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9}; int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {7, 5, 3, 3, 5, 7}; //ENUM_LINE_STYLE lineStyle; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); for (int i = 0; i < (int)plX.Size(); i++) plX[i] *= point; for (int i = 0; i < (int)plY.Size(); i++) plY[i] *= point; for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.LineStyleSet(STYLE_SOLID); drawPrimitives canvas.LineStyleSet(STYLE_DOT); drawPrimitives canvas.LineStyleSet(STYLE_DASH); drawPrimitives canvas.LineStyleSet(STYLE_DASHDOTDOT); drawPrimitives Sleep(6000); canvas.Destroy(); }
Das hervorgehobene Codefragment zeigt, wie der Stil geändert wird und die Zeichenmethoden aufgerufen werden. Schauen wir uns das Ergebnis der Skriptoperation an.
Die GIF-Animation zeigt die Änderung des primitiven Linienstils mit dem angegebenen sleep-Intervall.
Nun schlage ich vor, ein Beispiel für das Zeichnen von Primitiven unter Verwendung des Wu-Algorithmus zu erstellen. Erstellen wir das Skript DrawPrimitivesWu.mq5 auf der Grundlage des vorherigen Beispiels. Wir ersetzen die AA-Symbolkombination durch Wu und kommentieren die Zeilen wie im Listing gezeigt aus.
#property script_show_inputs //--- input parameters input int sleep = 1000; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include <Canvas\Canvas.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255)); \ canvas.LineWu(point * 2, point * 12, point * 8, point * 8, color_); \ canvas.PolylineWu(plX, plY, color_); \ canvas.PolygonWu(pgX, pgY, color_); \ canvas.TriangleWu(point * 2, point * 9, point * 2, point * 4, point * 7, point * 4, color_); \ canvas.CircleWu(point * 16, point * 11, point * 2, color_); \ canvas.EllipseWu(point * 8, point * 4, point * 12, point * 7, color_); \ canvas.Update(true); \ Sleep(sleep); //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9}; int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {7, 5, 3, 3, 5, 7}; //ENUM_LINE_STYLE lineStyle; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); for (int i = 0; i < (int)plX.Size(); i++) plX[i] *= point; for (int i = 0; i < (int)plY.Size(); i++) plY[i] *= point; for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.LineStyleSet(STYLE_SOLID); drawPrimitives //canvas.LineStyleSet(STYLE_DOT); //drawPrimitives //canvas.LineStyleSet(STYLE_DASH); //drawPrimitives //canvas.LineStyleSet(STYLE_DASHDOTDOT); //drawPrimitives Sleep(6000); canvas.Destroy(); }
Alle hinzugefügten Methoden sind gelb hervorgehoben. Wir führen das Beispiel aus, um das Ergebnis zu sehen.
Wir können sehen, dass sich die Qualität der Zeichnung dank der Glättung mit dem Wu-Algorithmus erneut verbessert hat. De-kommentieren Sie nun die Zeilen im Skript und starten Sie es erneut.
Der Linienstil ändert sich genauso wie im vorherigen Beispiel, aber die Qualität der geglätteten primitiven Bilder ist höher.
Zeichnen von Primitiven mit veränderbarer Linienbreite
Wir erstellen das Skript auf der Grundlage des vorherigen Beispiels und nennen es DrawPrimitivesThick.mq5. Dann ersetzen wir die vorhandenen Methoden zum Zeichnen von Primitiven durch Methoden mit dem Präfix "Thick" und entfernen die Methoden, die keine Entsprechung haben, wie in der Auflistung gezeigt. Nun kommentieren wir die unnötigen Zeichenfolgen wie im vorherigen Beispiel aus.
#property script_show_inputs //--- input parameters input int sleep = 1000; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include <Canvas\Canvas.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255)); \ canvas.LineThickVertical(point, point, h - point, color_, size, lineStyle, endStyle); \ canvas.LineThickHorizontal(point, w - point, h - point, color_, size, lineStyle, endStyle); \ canvas.LineThick(point * 2, point * 12, point * 8, point * 8, color_, size, lineStyle, endStyle); \ canvas.PolylineThick(plX, plY, color_, size, lineStyle, endStyle); \ canvas.PolygonThick(pgX, pgY, color_, size, lineStyle, endStyle); \ canvas.Update(true); \ Sleep(sleep); //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9}; int pgX[] = {17, 18, 17, 15, 14, 15, 17}, pgY[] = {7, 5, 3, 3, 5, 7, 7}; ENUM_LINE_STYLE lineStyle = STYLE_SOLID; int size = 3; ENUM_LINE_END endStyle = LINE_END_ROUND; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); for (int i = 0; i < (int)plX.Size(); i++) plX[i] *= point; for (int i = 0; i < (int)plY.Size(); i++) plY[i] *= point; for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.LineStyleSet(STYLE_SOLID); drawPrimitives //canvas.LineStyleSet(STYLE_DOT); //drawPrimitives //canvas.LineStyleSet(STYLE_DASH); //drawPrimitives //canvas.LineStyleSet(STYLE_DASHDOTDOT); drawPrimitives Sleep(6000); canvas.Destroy(); }
Die hinzugefügten Methoden sind gelb hervorgehoben. Wie Sie vielleicht schon bemerkt haben, verfügen die von uns betrachteten Methoden über zwei zusätzliche Parameter: size, die Zeilenbreite, und end_style, der Stil für das Zeilenende. Führen Sie das Skript aus und sehen Sie sich das Ergebnis an.
Das Bild zeigt die Primitive mit dicken Linien an, deren Breite wie oben beschrieben geändert werden kann. Erstellen wir nun das Skript, das auf dem vorherigen basiert, und nennen es DrawPrimitivesThick-2.mq5. Damit können wir alle möglichen Kombinationen von Linienstärken, Linienstilen und Linienabschlussstilen sehen. Um dies zu erreichen, entfernen wir die zuvor auskommentierten Zeichenfolgen und fügen dem Makro Methode1 hinzu, in dem wir den Stil für den Linienabschluss ändern und das Makro Methode0 nach jeder Änderung aufrufen. Wir rufen die primitiven Zeichenmethoden im Makro Methode0 auf. Im Makro drawPrimitives ändern wir den Linienstil und rufen method1 nach jeder Änderung des Linienstils auf. Das DrawPrimitivesMakro wird in der Schleife aufgerufen, in der die Linienbreite in einem bestimmten Bereich geändert wird.
#property script_show_inputs //--- input parameters input int sleep = 1000; input int beginSize = 1; input int endSize = 4; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include <Canvas\Canvas.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define drawPrimitives lineStyle = STYLE_SOLID; \ method1 \ lineStyle = STYLE_DOT; \ method1 \ lineStyle = STYLE_DASH; \ method1 \ lineStyle = STYLE_DASHDOTDOT; \ method1 #define method1 endStyle = LINE_END_ROUND; \ method0 \ endStyle = LINE_END_BUTT; \ method0 \ endStyle = LINE_END_SQUARE; \ method0 #define method0 canvas.Erase(ColorToARGB(clrWhite, 255)); \ canvas.LineThickVertical(point, point, h - point, color_, size, lineStyle, endStyle); \ canvas.LineThickHorizontal(point, w - point, h - point, color_, size, lineStyle, endStyle); \ canvas.LineThick(point * 2, point * 12, point * 8, point * 8, color_, size, lineStyle, endStyle); \ canvas.PolylineThick(plX, plY, color_, size, lineStyle, endStyle); \ canvas.PolygonThick(pgX, pgY, color_, size, lineStyle, endStyle); \ canvas.TextOut(point * 2, point, "Size: " + (string)size + "; Style: " + EnumToString(lineStyle) + "; End Style: " + EnumToString(endStyle) + ";", color_); \ canvas.Update(true); \ Sleep(sleep); //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9}; int pgX[] = {17, 18, 17, 15, 14, 15, 17}, pgY[] = {7, 5, 3, 3, 5, 7, 7}; ENUM_LINE_STYLE lineStyle = STYLE_SOLID; int size = 3; ENUM_LINE_END endStyle = LINE_END_ROUND; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); canvas.FontSet("Calibri", -120); for (int i = 0; i < (int)plX.Size(); i++) plX[i] *= point; for (int i = 0; i < (int)plY.Size(); i++) plY[i] *= point; for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; for (int i = beginSize; i <= endSize; i++) { size = i; drawPrimitives } Sleep(6000); canvas.Destroy(); } //+------------------------------------------------------------------+
Alle Codeänderungen sind gelb hervorgehoben. Das resultierende Skript nimmt den Bereich der Zeilenbreite aus den Eingabeparametern beginSize und endSize und bewegt sich entlang aller möglichen Kombinationsmöglichkeiten von Linienstil und Abschluss mithilfe der Makros. Als Ergebnis erhalten wir eine Enumeration aller möglichen primitiven Zeilenparameter, deren Kombinationen beim Ausführen des Skripts zu sehen sind. Die folgende GIF-Animation zeigt das Ergebnis der Skriptausführung.
Die Animation zeigt die Änderungen in der Linienbreite, dem Linienstil und der Art des Linienendes. Alle diese Parameter werden auf dem Canvas angezeigt und sind auch für uns sichtbar.
Zeichnen von geglätteten Primitiven nach dem Bézier-Algorithmus mit einer veränderbaren Linienbreite
Verwenden wir eines unserer vorherigen Beispiele DrawPrimitivesThick.mq5 und erstellen ein Skript DrawPrimitivesSmooth.mq5. Wir ersetzen PolylineThick und PolygonThick durch PolylineSmooth und PolygonSmooth im Skript. Verschieben Sie die Koordinaten der Polylinie und des Polygons um zwei Quadrate nach links, sodass die Primitive ungefähr in der Mitte angezeigt werden.
void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {3, 5, 6, 8, 9, 11}, plY[] = {13, 11, 12, 10, 11, 9}; int pgX[] = {14, 15, 14, 12, 11, 12}, pgY[] = {7, 5, 3, 3, 5, 7};
Die geänderten Werte sind im Programmcode hervorgehoben. Das resultierende Skript sollte wie folgt aussehen.
#property script_show_inputs //--- input parameters input int sleep = 1000; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include <Canvas\Canvas.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255)); \ canvas.PolylineSmooth(plX, plY, color_, size, lineStyle, endStyle); \ canvas.PolygonSmooth(pgX, pgY, color_, size, lineStyle, endStyle); \ canvas.Update(true); \ Sleep(sleep); //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {3, 5, 6, 8, 9, 11}, plY[] = {13, 11, 12, 10, 11, 9}; int pgX[] = {14, 15, 14, 12, 11, 12}, pgY[] = {7, 5, 3, 3, 5, 7}; ENUM_LINE_STYLE lineStyle = STYLE_SOLID; int size = 3; ENUM_LINE_END endStyle = LINE_END_BUTT; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); for (int i = 0; i < (int)plX.Size(); i++) plX[i] *= point; for (int i = 0; i < (int)plY.Size(); i++) plY[i] *= point; for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.LineStyleSet(STYLE_SOLID); drawPrimitives Sleep(6000); canvas.Destroy(); }
Führen Sie das Beispiel aus und überprüfen Sie das Ergebnis.
Wir sehen eine Polylinie und ein Polygon, die mit Bézier-Kurven erstellt wurden. Die Methoden PolylineSmooth und PolygonSmooth verfügen über die Parameter tension, Glättung, und step, Näherungsschritt, auf denen Bezier-Kurven basieren. Erstellen wir ein Beispiel, in dem diese Parameter nach bestimmten Intervallen geändert werden und der Bildschirm die Ergebnisse dieser Änderungen anzeigt. Wir verwenden das Beispiel DrawPrimitivesThick-2.mq5 und erstellen darauf basierend das Skript DrawPrimitivesSmooth-2.mq5. Werfen wir einen Blick auf das Ergebnis.
#property script_show_inputs //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include <Canvas\Canvas.mqh> //--- input parameters input int sleep = 1000; input int lineSize = 3; input ENUM_LINE_STYLE lineStyle = STYLE_SOLID; input ENUM_LINE_END lineEndStyle = LINE_END_BUTT; input double minTension = 0.0; input double stepTension = 0.1; input double maxTension = 1.0; input double minStep = 1.0; input double stepStep = 5.0; input double maxStep = 21.0; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint color_ = ColorToARGB(clrDodgerBlue, 255); uint fillColor = ColorToARGB(clrRed, 255); int plX[] = {3, 5, 6, 8, 9, 11}, plY[] = {13, 11, 12, 10, 11, 9}; int pgX[] = {14, 15, 14, 12, 11, 12}, pgY[] = {7, 5, 3, 3, 5, 7}; ENUM_LINE_STYLE style = lineStyle; int size = lineSize; ENUM_LINE_END endStyle = lineEndStyle; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); canvas.FontSet("Calibri", -120); for (int i = 0; i < (int)plX.Size(); i++) plX[i] *= point; for (int i = 0; i < (int)plY.Size(); i++) plY[i] *= point; for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; for (double tension = minTension; tension <= maxTension; tension += stepTension) for (double step = minStep; step <= maxStep; step += stepStep) { canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.PolylineSmooth(plX, plY, color_, size, style, endStyle, tension, step); canvas.PolygonSmooth(pgX, pgY, color_, size, style, endStyle, tension, step); canvas.TextOut(point * 2, point, "Size: " + (string)size + "; Style: " + EnumToString(style) + "; End Style: " + EnumToString(endStyle) + ";", color_); canvas.TextOut(point * 2, point * 2, "Tension: " + DoubleToString(tension, 2) + ";" + " Step: " + DoubleToString(step, 2) + ";", color_); canvas.Update(true); Sleep(sleep); } canvas.Destroy(); }
Wie wir sehen können, wurde der Code fast vollständig geändert. Die folgenden Einstellungen sind unter den Eingabeparametern erschienen: lineSize, Liniengröße, lineStyle, Linienstil und lineEndStyle, Stil für das Linienende (sie nehmen jetzt nicht an der Schleife teil). Außerdem gibt es noch Eingabeparameter für die Einstellung der Zeichenparameter von Bézier-Kurven: minTension, maxTension und stepTension (tension, Bereich des Glättungsparameters und Schrittweite), sowie minStep, maxStep und stepStep (step Wertebereich und Schrittweite der Näherung). Weiterhin wirken diese Parameter in den Schleifen, die alle möglichen Parameterkombinationen von tension und step gemäß den angegebenen stepTension und stepStep entsprechend einstellen. Führen Sie das Beispiel aus und sehen Sie das Ergebnis.
Die GIF-Animation zeigt geglättete Primitive mit veränderbaren Glättungsparametern, deren Werte in der zweiten Zeile des Bildes angezeigt werden.
Zeichnet gefüllte Primitive
Bei der Entwicklung grafischer Anwendungen kann es vorkommen, dass Sie ein Primitiv ausfüllen möchten. Die Klasse CCanvas verfügt über Methoden mit dem Präfix Fill für diesen Fall. Diese Methoden malen die entsprechenden Primitive in einer einheitlichen Farbe. Wir verwenden das vorherige Beispiel DrawPrimitivesWu.mq5, um das Skript DrawPrimitivesFill.mq5 zu erstellen, das alle Koordinaten für die benötigten Primitive enthält, sodass wir nur noch die entsprechenden Methoden einfügen und die Füllfarbe festlegen müssen. Hinzufügen der Methoden FillPolygon, FillTriangle, FillCircle und FillEllipse. Die Methode Fill wird weiter unten beschrieben (wenn wir das Füllen besprechen). Werfen wir einen Blick auf den resultierenden Code.
void OnStart() { CCanvas canvas; int w, h; int minSize, point; uint fillColor = ColorToARGB(clrRed, 255); int pgX[] = {4, 5, 7, 8, 7, 5}, pgY[] = {12, 10, 10, 12, 14, 14}; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.FillPolygon(pgX, pgY, fillColor); canvas.FillTriangle(point * 4, point * 8, point * 4, point * 3, point * 9, point * 3, fillColor); canvas.FillCircle(point * 13, point * 12, point * 2, fillColor); canvas.FillEllipse(point * 11, point * 3, point * 15, point * 6, fillColor); canvas.Update(true); Sleep(6000); canvas.Destroy(); }
Alle geänderten und hinzugefügten Zeichenfolgen sind gelb hervorgehoben. Starten Sie das Skript, um die Ergebnisse zu sehen.
Das Bild zeigt die Primitive, die mit einer einheitlichen Farbe gefüllt sind. Darüber können wir normale Primitive als Rahmen zeichnen oder die Primitive mit einem editierbaren Linienstil, die wir oben betrachtet haben.
Ausfüllen
Wenn Sie schon einmal das Werkzeug für das Ausfüllen in grafischen Editoren verwendet haben, wissen Sie vielleicht schon, worüber ich sprechen werde. Es ist an der Zeit, einen Blick auf die oben erwähnte Methode Fill (ausfüllen) zu werfen. Das ist die Methode, mit der wir den Bildbereich einer bestimmten Farbe mit einer anderen Farbe ausfüllen können. Erstellen wir ein neues Beispiel als Indikator (da er im Gegensatz zum Skript die Chart-Ereignisse (OnChartEvent) verarbeitet). Sie fragen sich vielleicht, warum wir Chart-Ereignisse hier behandeln müssen? Wir werden ein Beispiel erstellen, bei dem Sie die Füllfarbe auswählen und auf einen beliebigen Bildpunkt klicken können, um ihn mit der ausgewählten Farbe zu füllen. Wir erstellen einen neuen Indikator und nennen Sie ihn Filling.mq5. Werfen wir einen Blick auf den Code des Indikators.
#property indicator_chart_window #property indicator_plots 0 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include <Canvas\Canvas.mqh> #include <ChartObjects\ChartObjectsTxtControls.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CCanvas canvas; CChartObjectButton colors[14]; CChartObjectButton * oldSelected = NULL; uint fillColor = 0; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { int w, h; int minSize, point; uint Color1 = ColorToARGB(clrDodgerBlue, 255); uint Color2 = ColorToARGB(clrRed, 255); int pgX[] = {4, 5, 7, 8, 7, 5}, pgY[] = {12, 10, 10, 12, 14, 14}; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); canvas.FontSet("Calibri", -120); for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.Polygon(pgX, pgY, Color1); canvas.FillTriangle(point * 4, point * 8, point * 4, point * 3, point * 9, point * 3, Color2); canvas.FillCircle(point * 13, point * 12, point * 2, Color2); canvas.Ellipse(point * 11, point * 3, point * 15, point * 6, Color1); canvas.Update(true); ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); for (int i = 0; i < (int)colors.Size(); i++) { colors[i].Create(0, "color-"+(string)i, 0, (int)((i + 2.8) * point), point, 21, 21); colors[i].SetInteger(OBJPROP_BGCOLOR, ColorToARGB(CCanvas::GetDefaultColor(i), 0)); } if ((oldSelected = GetPointer(colors[(int)colors.Size()-1])) == NULL) return(INIT_FAILED); oldSelected.State(1); fillColor = ColorToARGB((color)oldSelected.GetInteger(OBJPROP_BGCOLOR), 255); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { canvas.Destroy(); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { uint mouseState = (uint)sparam; int x = (int)lparam, y = (int)dparam; CChartObjectButton * colorBtn; int left, right, bottom, top; if (id == CHARTEVENT_MOUSE_MOVE) if ((mouseState & 1) == 1) { for (int i = 0; i < (int)colors.Size(); i++) { if ((colorBtn = GetPointer(colors[i])) == NULL) return; left = colorBtn.X_Distance(); top = colorBtn.Y_Distance(); right = left + colorBtn.X_Size() - 1; bottom = top + colorBtn.Y_Size() - 1; if (x >= left && x <= right && y >= top && y <= bottom) { fillColor = ColorToARGB((color)colorBtn.GetInteger(OBJPROP_BGCOLOR), 255); if (oldSelected == NULL) return; oldSelected.State(0); oldSelected = GetPointer(colorBtn); ChartRedraw(); return; } } canvas.Fill(x, y, fillColor); canvas.Update(true); } }
Wie funktioniert das Beispiel? Zunächst wurde die canvas Variable auf globaler Ebene spezifiziert, um für die gesamte Dauer der Indikatoroperation auf sie zugreifen zu können.
CCanvas canvas;
Das Array aus 14 Schaltflächen ermöglicht die Auswahl von Farben. Durch Drücken einer der Schaltflächen wird die Ausfüllfarbe festgelegt.
CChartObjectButton colors[14];
Als Nächstes wurde der oldSelected Zeiger deklariert.
CChartObjectButton * oldSelected = NULL;
Der folgende Parameter wird verwendet, um die gedrückte Schaltfläche zu speichern, sie an eine Ausgangsposition zurückzubringen oder die Ausfüllfarbe zu speichern.
uint fillColor = 0;
Als Nächstes sehen wir im OnInit-Handler den bereits bekannten Code, der Canvas erstellt und Primitive darauf zeichnet.
int OnInit() { int w, h; int minSize, point; uint Color1 = ColorToARGB(clrDodgerBlue, 255); uint Color2 = ColorToARGB(clrRed, 255); int pgX[] = {4, 5, 7, 8, 7, 5}, pgY[] = {12, 10, 10, 12, 14, 14}; w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); minSize = (int)fmin(w, h); point = minSize / 15; canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA); canvas.FontSet("Calibri", -120); for (int i = 0; i < (int)pgX.Size(); i++) pgX[i] *= point; for (int i = 0; i < (int)pgY.Size(); i++) pgY[i] *= point; canvas.Erase(ColorToARGB(clrWhite, 255)); canvas.Polygon(pgX, pgY, Color1); canvas.FillTriangle(point * 4, point * 8, point * 4, point * 3, point * 9, point * 3, Color2); canvas.FillCircle(point * 13, point * 12, point * 2, Color2); canvas.Ellipse(point * 11, point * 3, point * 15, point * 6, Color1); canvas.Update(true); ...
Die Behandlung von Mausereignissen wird anschließend aktiviert.
ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
Als Nächstes erstellen wir die Schaltflächen in verschiedenen Farben (um die Farbe des Ausfüllens zu ändern).
for (int i = 0; i < (int)colors.Size(); i++) { colors[i].Create(0, "color-"+(string)i, 0, (int)((i + 2.8) * point), point, 21, 21); colors[i].SetInteger(OBJPROP_BGCOLOR, ColorToARGB(CCanvas::GetDefaultColor(i), 0)); }
Achten Sie darauf, woher die Farben der Schaltflächen stammen. Das Codefragment ist gelb hervorgehoben. Wir können die statistische Methode CCanvas::GetDefaultColor sehen. Durch das Setzen des Parameters i, beginnend bei 0, können wir die Farbpalette erhalten.
Danach initialisieren wir den Link, um die Schaltfläche oldSelected an die Startposition zu bringen.
if ((oldSelected = GetPointer(colors[(int)colors.Size()-1])) == NULL) return(INIT_FAILED); oldSelected.State(1);
Die Farbe fillColor zum Ausfüllen wird initialisiert.
fillColor = ColorToARGB((color)oldSelected.GetInteger(OBJPROP_BGCOLOR), 255);
Danach werden die Ereignisse auf dem Chart in OnChartEvent behandelt. Darin werden die Variablen für den Empfang und die Speicherung der Mausparameter deklariert.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { uint mouseState = (uint)sparam; int x = (int)lparam, y = (int)dparam; ...
Als Nächstes wird die Variable deklariert, der Zeiger zum Speichern einer gedrückten Schaltfläche,
CChartObjectButton * colorBtn;
die dadurch definiert wird, dass der Cursor die Koordinaten der Schaltflächenseiten eingibt, wenn man mit der linken Maustaste auf die Schaltfläche klickt. Die Koordinaten der Seiten werden in den folgenden Variablen gespeichert.
int left, right, bottom, top;
Als Nächstes wird das Ereignis CHARTEVENT_MOUSE_MOVE kontrolliert, ebenso wie das Klicken der linken Maustaste.
if (id == CHARTEVENT_MOUSE_MOVE) if ((mouseState & 1) == 1) { ... }
Dies ist der Code, in dem die Farbauswahl und das Ausfüllen des Bildes durchgeführt werden. Hier durchläuft die Schleife nacheinander alle Schaltflächen im Array colors, das die Schaltfläche definiert, die ein Nutzer gedrückt hat, speichert die Farbe der Schaltfläche in der Variablen fillColor und setzt die zuvor gedrückte Schaltfläche oldSelected an die Ausgangsposition. Als Nächstes verlassen wir die Ereignisbehandlung (Return), da der Klick auf die Schaltfläche und nicht auf das auszufüllende Bild erfolgt ist. Wenn der Klick auf das Bild und nicht auf eine der Farb-Schaltflächen erfolgt, wird das Steuerelement weitergereicht und das Ausfüllen wird mit der Methode Fill und der ausgewählten Farbe fillColor mit anschließender Bildaktualisierung (Methode Update) durchgeführt.
if (id == CHARTEVENT_MOUSE_MOVE) if ((mouseState & 1) == 1) { for (int i = 0; i < (int)colors.Size(); i++) { if ((colorBtn = GetPointer(colors[i])) == NULL) return; left = colorBtn.X_Distance(); top = colorBtn.Y_Distance(); right = left + colorBtn.X_Size() - 1; bottom = top + colorBtn.Y_Size() - 1; if (x >= left && x <= right && y >= top && y <= bottom) { fillColor = ColorToARGB((color)colorBtn.GetInteger(OBJPROP_BGCOLOR), 255); if (oldSelected == NULL) return; oldSelected.State(0); oldSelected = GetPointer(colorBtn); ChartRedraw(); return; } } canvas.Fill(x, y, fillColor); canvas.Update(true); }
Führen wir das resultierende Beispiel aus und versuchen wir, das Ausfüllen durchzuführen.
Entsprechend der GIF-Animation haben wir das Ausfüllen mit dem Mitteln von CCanvas durchgeführt, das ähnlich wie das Hilfsmittel zum Ausfüllen in grafischen Editoren funktioniert.
Schlussfolgerung
In diesem Artikel wurde die Klasse CCanvas untersucht und ihre Methoden beschrieben, damit die Nutzer die Funktionsprinzipien der Klasse vollständig verstehen. Die mitgelieferten Beispiele erklären die Prinzipien der Handhabung der Klasse CCanvas und verdeutlichen gleichzeitig einige schwer verständliche theoretische Aspekte.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/10361






- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.