Grafik in der Bibliothek DoEasy (Teil 79): Die Objektklasse "Animationsrahmen" und ihre abgeleiteten Objekte
Inhalt
- Konzept
- Verbesserung der Klassenbibliothek
- Die Objektklasse "Animationsrahmen"
- Die Textklasse der Animationsrahmen
- Rechteckklasse der Animationsrahmen
- Das Formular der Animationsklasse
- Test
- Was kommt als Nächstes?
Konzept
Im vorigen Artikel habe ich die Klasse zum Speichern und anschließenden Wiederherstellen eines Teils des Hintergrunds unter einer gezeichneten Figur erstellt. Hier werde ich die Arbeit an diesem Konzept fortsetzen und mehrere darauf basierende Klassen erstellen: die Basisklasse eines einzelnen Animationsrahmens und ihre Nachkommen — die Klassen Textanimationsrahmen und Rechteckanimationsrahmen.
Die Basisklasse soll einen gemeinsamen Satz von Eigenschaften für einen einzelnen Animationsrahmen enthalten, während ihre Unterklassen ihre eigenen Methoden zum Zeichnen von Formen haben sollen. Die Text-Animationsklasse soll die Arbeit mit Texten ermöglichen, während der Rechteck-Animationsrahmen die Erstellung eines einzelnen Animationsrahmens und das Zeichnen verschiedener Formen in diesem Rahmen unter Verwendung von Zeichenmethoden, die auf Methoden der CCanvas-Klasse basieren, ermöglichen soll.
Jedes erstellte Formularobjekt soll über eine Reihe von Methoden zum Zeichnen auf einem nutzerdefinierten Hintergrund (cancas) verfügen, die es uns ermöglicht, schnell neue Bilder auf dem Formular zu erstellen und zu verwalten. Um die Zeichenwerkzeuge in jedem Formular bequem verwenden zu können, werde ich eine gemeinsame Klasse erstellen, die die Listen aller erstellten Textbilder und Figuren auf dem Formular enthält. Später werde ich neue Animationsmethoden hinzufügen, deren Listen ebenfalls in der gemeinsamen Klasse abgelegt werden. Ein solches Konzept ermöglicht es uns, neue Bilder dynamisch zu erstellen und sie in den entsprechenden Listen zu speichern. Anschließend wird es möglich sein, sie schnell aus dem Formularobjekt abzurufen und auf dessen Hintergrund anzuzeigen. In diesem Fall speichern solche Objekte automatisch den Hintergrund des darunter liegenden Formulars. Wenn die Objekte gelöscht, geändert oder verschoben werden, wird der gespeicherte Hintergrund wiederhergestellt.
In diesem Artikel werde ich die in den vorangegangenen Artikeln erstellten Zeichnungsrahmen leicht überarbeiten, die Klasse des grundlegenden Animationsrahmenobjekts entwickeln und zwei Klassen seiner Nachkommen entwickeln — die Klassen Textanimationsrahmen und Rechteckanimationsrahmen. Wir erstellen die Klasse zum Speichern der Listen dieser Rahmenobjekte und bieten die Möglichkeit, mit ihnen vom Formularobjekt aus zu arbeiten.
Verbesserung der Klassenbibliothek
Als Erstes wollen wir die zuvor erstellten Bibliotheksklassen verbessern. In der Datei \MQL5\Include\DoEasy\Defines.mqh fügen wir die Liste der Animationsrahmen und die Liste der gezeichneten Formtypen in der Rechteck-Animationsrahmenklasse hinzu:
//+------------------------------------------------------------------+ //| Data for working with graphical element animation | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| List of animation frame types | //+------------------------------------------------------------------+ enum ENUM_ANIMATION_FRAME_TYPE { ANIMATION_FRAME_TYPE_TEXT, // Text animation frame ANIMATION_FRAME_TYPE_QUAD, // Rectangle animation frame }; //+------------------------------------------------------------------+ //| List of drawn shape types | //+------------------------------------------------------------------+ enum ENUM_FIGURE_TYPE { FIGURE_TYPE_PIXEL, // Pixel FIGURE_TYPE_PIXEL_AA, // Pixel with antialiasing FIGURE_TYPE_LINE_VERTICAL, // Vertical line FIGURE_TYPE_LINE_VERTICAL_THICK, // Vertical segment of a freehand line having a specified width using antialiasing algorithm FIGURE_TYPE_LINE_HORIZONTAL, // Horizontal line FIGURE_TYPE_LINE_HORIZONTAL_THICK, // Horizontal segment of a freehand line having a specified width using antialiasing algorithm FIGURE_TYPE_LINE, // Arbitrary line FIGURE_TYPE_LINE_AA, // Line with antialiasing FIGURE_TYPE_LINE_WU, // Line with WU smoothing FIGURE_TYPE_LINE_THICK, // Segment of a freehand line having a specified width using antialiasing algorithm FIGURE_TYPE_POLYLINE, // Polyline FIGURE_TYPE_POLYLINE_AA, // Polyline with antialiasing FIGURE_TYPE_POLYLINE_WU, // Polyline with WU smoothing FIGURE_TYPE_POLYLINE_SMOOTH, // Polyline with a specified width using two smoothing algorithms FIGURE_TYPE_POLYLINE_THICK, // Polyline with a specified width using a smoothing algorithm FIGURE_TYPE_POLYGON, // Polygon FIGURE_TYPE_POLYGON_FILL, // Filled polygon FIGURE_TYPE_POLYGON_AA, // Polygon with antialiasing FIGURE_TYPE_POLYGON_WU, // Polygon with WU smoothing FIGURE_TYPE_POLYGON_SMOOTH, // Polygon with a specified width using two smoothing algorithms FIGURE_TYPE_POLYGON_THICK, // Polygon with a specified width using a smoothing algorithm FIGURE_TYPE_RECTANGLE, // Rectangle FIGURE_TYPE_RECTANGLE_FILL, // Filled rectangle FIGURE_TYPE_CIRCLE, // Circle FIGURE_TYPE_CIRCLE_FILL, // Filled circle FIGURE_TYPE_CIRCLE_AA, // Circle with antialiasing FIGURE_TYPE_CIRCLE_WU, // Circle with WU smoothing FIGURE_TYPE_TRIANGLE, // Triangle FIGURE_TYPE_TRIANGLE_FILL, // Filled triangle FIGURE_TYPE_TRIANGLE_AA, // Triangle with antialiasing FIGURE_TYPE_TRIANGLE_WU, // Triangle with WU smoothing FIGURE_TYPE_ELLIPSE, // Ellipse FIGURE_TYPE_ELLIPSE_FILL, // Filled ellipse FIGURE_TYPE_ELLIPSE_AA, // Ellipse with antialiasing FIGURE_TYPE_ELLIPSE_WU, // Ellipse with WU smoothing FIGURE_TYPE_ARC, // Ellipse arc FIGURE_TYPE_PIE, // Ellipse sector }; //+------------------------------------------------------------------+
Ich werde Animationsrahmentypen verwenden, um Animationsrahmenobjekte zu identifizieren (sei es ein Text, ein gezeichnetes Formular oder ein anderer Animationsrahmentyp), den ich in den folgenden Artikeln vorstellen werde. Die Typen gezeichneter Formen geben an, was genau in einem einzelnen Rechteck-Animationsrahmen gezeichnet wird. Diese Typen entsprechen bestehenden Zeichenmethoden in der Klasse CCanvas ("Data access", "Draws primitives", "Draws filled primitives" und der Bereiche "Draws primitives with antialiasing" in der Tabelle der Klassenmethoden).
In \MQL5\Include\DoEasy\Data.mqh fügen wir die neue Nachrichtenindizes hinzu:
//--- CForm MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT,// No shadow object. Create it using the CreateShadowObj() method MSG_FORM_OBJECT_ERR_FAILED_CREATE_SHADOW_OBJ, // Failed to create new shadow object MSG_FORM_OBJECT_ERR_FAILED_CREATE_PC_OBJ, // Failed to create new pixel copier object MSG_FORM_OBJECT_PC_OBJ_ALREADY_IN_LIST, // Pixel copier object with ID already present in the list MSG_FORM_OBJECT_PC_OBJ_NOT_EXIST_LIST, // No pixel copier object with ID in the list //--- CFrame MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME, // Failed to create a new animation frame object MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST, // Animation frame object with ID already present in the list MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST, // Animation frame object with ID not present in the list //--- CShadowObj MSG_SHADOW_OBJ_IMG_SMALL_BLUR_LARGE, // Error! Image size too small or blur too extensive
und die Nachrichtentexte, die den neu hinzugefügten Indizes entsprechen:
//--- CForm {"Отсутствует объект тени. Необходимо сначала его создать при помощи метода CreateShadowObj()","There is no shadow object. You must first create it using the CreateShadowObj () method"}, {"Не удалось создать новый объект для тени","Failed to create new object for shadow"}, {"Не удалось создать новый объект-копировщик пикселей","Failed to create new pixel copier object"}, {"В списке уже есть объект-копировщик пикселей с идентификатором ","There is already a pixel copier object in the list with ID "}, {"В списке нет объекта-копировщика пикселей с идентификатором ","No pixel copier object with ID "}, //--- CFrame {"Не удалось создать новый объект-кадр анимации","Failed to create new animation frame object"}, {"В списке уже есть объект-кадр анимации с идентификатором ","The list already contains an animation frame object with an ID "}, {"В списке нет объекта-кадра анимации с идентификатором ","No animation frame object with ID "}, //--- CShadowObj {"Ошибка! Размер изображения очень маленький или очень большое размытие","Error! Image size is very small or very large blur"},
Wir fügen der Datei der Bibliotheksdienstfunktionen \MQL5\Include\DoEasy\Services\DELib.mqh die Funktionen hinzu, die die Höchst- und Mindestwerte im Array zurückgeben:
//+------------------------------------------------------------------+ //| Return the maximum value in the array | //+------------------------------------------------------------------+ template<typename T> bool ArrayMaximumValue(const string source,const T &array[],T &max_value) { if(ArraySize(array)==0) { CMessage::ToLog(source,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY); return false; } max_value=0; int index=ArrayMaximum(array); if(index==WRONG_VALUE) return false; max_value=array[index]; return true; } //+------------------------------------------------------------------+ //| Return the minimum value in the array | //+------------------------------------------------------------------+ template<typename T> bool ArrayMinimumValue(const string source,const T &array[],T &min_value) { if(ArraySize(array)==0) { CMessage::ToLog(source,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY); return false; } min_value=0; int index=ArrayMinimum(array); if(index==WRONG_VALUE) return false; min_value=array[index]; return true; } //+------------------------------------------------------------------+
Die Funktionen geben den maximalen oder minimalen Wert zurück, der sich in dem Array befindet, das ihnen über eine Verknüpfung übergeben wurde. Sie sind vom Typ bool, da jeder von der Funktion zurückgegebene Wert in den Array-Zellen als "ungültiger" Wert vorkommen kann. Wenn z.B. -1 beim Empfang von Daten aus dem Array zurückgegeben wird (wie es in vielen Funktionen der Fall ist), kann ein solcher Wert einer der im Array gesetzten sein. Wenn ein gültiger Wert (-1) zurückgegeben wird, nimmt unser Programm an, dass dies ein Fehler ist. Dies ist jedoch falsch. Deshalb geben wir im Falle eines Fehlers false zurück, während der gefundene Maximal- oder Minimalwert im Array der Variablen zugewiesen wird, die der Funktion über eine Verknüpfung übergeben wurde. Wenn die Funktion true zurückgibt, speichert die Variable den gewünschten Wert. Die Quellvariable erhält den Namen der Methode, aus der die Funktion aufgerufen wurde. Im Falle eines Fehlers können wir so den Namen der Methode, aus der die Funktion aufgerufen wurde, sowie die Fehlermeldung sehen.
Die Variable erhält auch die Funktion, die die Beschreibung der gezeichneten Figur zurückgibt:
//+------------------------------------------------------------------+ //| Return the description of the drawn shape type | //+------------------------------------------------------------------+ string FigureTypeDescription(const ENUM_FIGURE_TYPE figure_type) { return(StringSubstr(EnumToString(figure_type),12)); } //+------------------------------------------------------------------+
Hier wird der Typ, der der Funktion Wert der Enumeration übergeben wird, in die textliche Beschreibung umgewandelt. Die Teilzeichenkette ab der Position des 12. Symbols wird aus der Textdarstellung des Typs entnommen, um einen überflüssigen Text abzuschneiden. Zum Beispiel wird der Figurentyp FIGURE_TYPE_TRIANGLE in "FIGURE_TYPE_TRIANGLE" umgewandelt, und die notwendige Teilzeichenkette ab dem 12. Symbol "FIGURE_TYPE_TRIANGLE" wird aus diesem Text abgerufen. Als Ergebnis wird die Zeichenkette "TRIANGLE" zurückgegeben.
Im vorigen Artikel habe ich bei der Erstellung der Methoden zum Kopieren eines Teils des Hintergrunds in das Array die Größe und die Koordinaten des kopierten Hintergrundrechtecks durch eine auf dem Formular angezeigte Textgröße definiert. Hier werde ich auch Bilder anzeigen. Deren Größe wird nicht mehr durch eine Textgröße definiert sein. Daher müssen wir eine Methode erstellen, die die Koordinaten und die Größe des kopierten Rechtecks des Hintergrundteils definiert.
In der Datei \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh der grafischen Elementklasse, geben wir der Methode einen neuen Namen:
//--- Return coordinate offsets relative to the text anchor point void TextGetShiftXY(const string text, // Text for calculating the size of its outlining rectangle const ENUM_TEXT_ANCHOR anchor,// Text anchor point, relative to which the offsets are calculated int &shift_x, // X coordinate of the rectangle upper left corner int &shift_y); // Y coordinate of the rectangle upper left corner
Jetzt heißt die Methode GetShiftXYbyText(). Deklarieren wir eine neue Methode, die die Koordinaten und die Größe des kopierten Teils des Bildes um die angegebene Größe relativ zum Objektankerpunkt zurückgibt:
//--- Return coordinate offsets relative to the text anchor point by text void GetShiftXYbyText(const string text, // Text for calculating the size of its outlining rectangle const ENUM_TEXT_ANCHOR anchor, // Text anchor point, relative to which the offsets are calculated int &shift_x, // X coordinate of the rectangle upper left corner int &shift_y); // Y coordinate of the rectangle upper left corner //--- Return coordinate offsets relative to the rectangle anchor point by size void GetShiftXYbySize(const int width, //Rectangle size by width const int height, //Rectangle size by height const ENUM_TEXT_ANCHOR anchor, // Rectangle anchor point, relative to which the offsets are calculated int &shift_x, // X coordinate of the rectangle upper left corner int &shift_y); // Y coordinate of the rectangle upper left corner
Implementieren wir diese am Codeende der Klasse.
Die Methode, die Koordinaten-Offsets relativ zum Rechteckankerpunkt nach Größe zurückgibt:
//+------------------------------------------------------------------+ //| Return coordinate offsets relative to the rectangle anchor point | //| by size | //+------------------------------------------------------------------+ void CGCnvElement::GetShiftXYbySize(const int width,const int height,const ENUM_TEXT_ANCHOR anchor,int &shift_x,int &shift_y) { switch(anchor) { case TEXT_ANCHOR_LEFT_TOP : shift_x=0; shift_y=0; break; case TEXT_ANCHOR_LEFT_CENTER : shift_x=0; shift_y=-height/2; break; case TEXT_ANCHOR_LEFT_BOTTOM : shift_x=0; shift_y=-height; break; case TEXT_ANCHOR_CENTER_TOP : shift_x=-width/2; shift_y=0; break; case TEXT_ANCHOR_CENTER : shift_x=-width/2; shift_y=-height/2; break; case TEXT_ANCHOR_CENTER_BOTTOM : shift_x=-width/2; shift_y=-height; break; case TEXT_ANCHOR_RIGHT_TOP : shift_x=-width; shift_y=0; break; case TEXT_ANCHOR_RIGHT_CENTER : shift_x=-width; shift_y=-height/2; break; case TEXT_ANCHOR_RIGHT_BOTTOM : shift_x=-width; shift_y=-height; break; default : shift_x=0; shift_y=0; break; } } //+------------------------------------------------------------------+
Hier werden in Abhängigkeit von der Breite und Höhe des kopierten Bereichs sowie des an die Methode übergebenen Ankerpunkts Koordinaten-Offsets relativ zum Ankerpunkt berechnet und über eine Verknüpfung in die an die Methode übergebenen Variablen geschrieben.
Die Methode gibt die Koordinatenoffsets relativ zum Textankerpunkt zurück:
//+------------------------------------------------------------------+ //| Return coordinate offsets relative to the text anchor point | //+------------------------------------------------------------------+ void CGCnvElement::GetShiftXYbyText(const string text,const ENUM_TEXT_ANCHOR anchor,int &shift_x,int &shift_y) { int tw=0,th=0; this.TextSize(text,tw,th); this.GetShiftXYbySize(tw,th,anchor,shift_x,shift_y); } //+------------------------------------------------------------------+
Hier wird zunächst die Größe des Textes festgelegt, die der Methode übergeben wird, und die oben besprochene Methode zur Festlegung des Koordinatenversatzes des gespeicherten Formular-Hintergrundbildbereichs aufgerufen.
Im vorigen Artikel habe ich die Klasse für das Kopieren eines Teils des Formularhintergrundbildes und dessen anschließende Wiederherstellung aus dem Array entwickelt. Die Klasse wurde in der Klassendatei des Formularobjekts festgelegt. Jetzt werde ich die Klasse aus der Formularobjektklassendatei entfernen und sie in die neue Datei einer neu erstellten Rahmenobjektklasse verschieben (wieder einmal stelle ich fest, dass es besser ist, Klassen in getrennten Dateien zu schreiben und zu speichern).
Lassen Sie uns also eine Basisklasse für ein einzelnes Animationsbild erstellen. Die Klasse soll die Eigenschaften enthalten, die für alle ihre Nachkommen gemeinsam sind.
Die Objektklasse "Animationsrahmen"
In \MQL5\Include\DoEasy\Objects\Graph\ erstellen wir den neuen Ordner Animations\ mit der neuen Datei Frame.mqh der Klasse CFrame.
Die Datei der Objektklasse des grafischen Elements sollte in die Klassendatei aufgenommen werden:
//+------------------------------------------------------------------+ //| Frame.mqh | //| 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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\GCnvElement.mqh" //+------------------------------------------------------------------+
Als Nächstes platzieren wir die Objektklasse des Pixelkopierers, die aus der Objektklassendatei des Formulars entfernt (und im vorherigen Artikel behandelt) wurde:
//+------------------------------------------------------------------+ //| Frame.mqh | //| 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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\GCnvElement.mqh" //+------------------------------------------------------------------+ //| Pixel copier class | //+------------------------------------------------------------------+ class CPixelCopier : public CObject { protected: CGCnvElement *m_element; // Pointer to the graphical element uint m_array[]; // Pixel array int m_id; // ID int m_x; // X coordinate of the upper left corner int m_y; // Y coordinate of the upper left corner int m_w; // Copied image width int m_h; // Copied image height int m_wr; // Calculated copied image width int m_hr; // Calculated copied image height public: //--- Compare CPixelCopier objects by a specified property (to sort the list by an object property) virtual int Compare(const CObject *node,const int mode=0) const { const CPixelCopier *obj_compared=node; return(mode==0 ? (this.ID()>obj_compared.ID() ? 1 : this.ID()<obj_compared.ID() ? -1 : 0) : WRONG_VALUE); } //--- Set the properties void SetElement(CGCnvElement *element) { this.m_element=element; } void SetID(const int id) { this.m_id=id; } void SetCoordX(const int value) { this.m_x=value; } void SetCoordY(const int value) { this.m_y=value; } void SetWidth(const int value) { this.m_w=value; } void SetHeight(const int value) { this.m_h=value; } //--- Get the properties int ID(void) const { return this.m_id; } int CoordX(void) const { return this.m_x; } int CoordY(void) const { return this.m_y; } int Width(void) const { return this.m_w; } int Height(void) const { return this.m_h; } int WidthReal(void) const { return this.m_wr; } int HeightReal(void) const { return this.m_hr; } //--- Copy the part or the entire image to the array bool CopyImgDataToArray(const uint x_coord,const uint y_coord,uint width,uint height); //--- Copy the part or the entire image from the array to the canvas bool CopyImgDataToCanvas(const int x_coord,const int y_coord); //--- Constructors CPixelCopier (void){;} CPixelCopier (const int id, const int x, const int y, const int w, const int h, CGCnvElement *element) : m_id(id), m_x(x),m_y(y),m_w(w),m_wr(w),m_h(h),m_hr(h) { this.m_element=element; } ~CPixelCopier (void){;} }; //+------------------------------------------------------------------+ //| Copy part or all of the image to the array | //+------------------------------------------------------------------+ bool CPixelCopier::CopyImgDataToArray(const uint x_coord,const uint y_coord,uint width,uint height) { //--- Assign coordinate values, passed to the method, to the variables int x1=(int)x_coord; int y1=(int)y_coord; //--- If X coordinates goes beyond the form on the right or Y coordinate goes beyond the form at the bottom, //--- there is nothing to copy, the copied area is outside the form. Return 'false' if(x1>this.m_element.Width()-1 || y1>this.m_element.Height()-1) return false; //--- Assign the width and height values of the copied area to the variables //--- If the passed width and height are equal to zero, assign the form width and height to them this.m_wr=int(width==0 ? this.m_element.Width() : width); this.m_hr=int(height==0 ? this.m_element.Height() : height); //--- If X and Y coordinates are equal to zero (the upper left corner of the form), as well as the width and height are equal to the form width and height, //--- the copied area is equal to the entire form area. Copy the entire form (returning it from the method) using the ImageCopy() method //if(x1==0 && y1==0 && this.m_wr==this.m_element.Width() && this.m_hr==this.m_element.Height()) // return this.m_element.ImageCopy(DFUN,this.m_array); //--- Calculate the right X coordinate and lower Y coordinate of the rectangle area int x2=int(x1+this.m_wr-1); int y2=int(y1+this.m_hr-1); //--- If the calculated X coordinate goes beyond the form, the right edge of the form will be used as the coordinate if(x2>=this.m_element.Width()-1) x2=this.m_element.Width()-1; //--- If the calculated Y coordinate goes beyond the form, the bottom edge of the form will be used as the coordinate if(y2>=this.m_element.Height()-1) y2=this.m_element.Height()-1; //--- Calculate the copied width and height this.m_wr=x2-x1+1; this.m_hr=y2-y1+1; //--- Define the necessary size of the array, which is to store all image pixels with calculated width and height int size=this.m_wr*this.m_hr; //--- If failed to set the array size, inform of that and return 'false' if(::ArrayResize(this.m_array,size)!=size) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE,true); return false; } //--- Set the index in the array for recording the image pixel int n=0; //--- In a loop by the calculated height of the copied area, starting from the specified Y coordinate for(int y=y1;y<y1+this.m_hr;y++) { //--- in a loop by the calculated width of the copied area, starting from the specified X coordinate for(int x=x1;x<x1+this.m_wr;x++) { //--- Copy the next image pixel to the array and increase the array index this.m_array[n]=this.m_element.GetCanvasObj().PixelGet(x,y); n++; } } //--- Successful - return 'true' return true; } //+------------------------------------------------------------------+ //| Copy the part or the entire image from the array to the canvas | //+------------------------------------------------------------------+ bool CPixelCopier::CopyImgDataToCanvas(const int x_coord,const int y_coord) { //--- If the array of saved pixels is empty, inform of that and return 'false' int size=::ArraySize(this.m_array); if(size==0) { CMessage::ToLog(DFUN,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY,true); return false; } //--- Set the index of the array for reading the image pixel int n=0; //--- In a loop by the previously calculated height of the copied area, starting from the specified Y coordinate for(int y=y_coord;y<y_coord+this.m_hr;y++) { //--- in a loop by the previously calculated width of the copied area, starting from the specified X coordinate for(int x=x_coord;x<x_coord+this.m_wr;x++) { //--- Restore the next image pixel from the array and increase the array index this.m_element.GetCanvasObj().PixelSet(x,y,this.m_array[n]); n++; } } return true; } //+------------------------------------------------------------------+
Das Einzige, was hier (vorübergehend) geändert wurde, ist die Tatsache, dass ich die Code-Zeilen auskommentiert habe, die das gesamte zuvor gespeicherte Formularbild kopieren sollen. Hier wurde der Fehler gemacht, dass der Hintergrund direkt aus der grafischen Ressource und nicht aus dem Formularobjekt-Array kopiert wird. Die grafische Ressource enthält alle Änderungen, die auf das Hintergrundbild des Formulars angewendet wurden. Um dies zu beheben, muss ich das Erscheinungsbild des Formulars in einem separaten Array speichern, das die Kopie des ursprünglichen Formularbildes enthält. Ich habe bereits ein solches Array, aber ich muss noch die Methoden zum Speichern des ursprünglichen Formularbildes direkt nach dessen Erstellung erstellen. Bis dahin habe ich diese Zeilen auskommentiert. Der Hintergrund mit der Größe des gesamten Formulars (und nicht eines Teils davon) wird in der Schleife zur Wiederherstellung des Teils des Formularhintergrunds wiederhergestellt (d. h. nicht durch Kopieren eines Arrays in ein anderes, sondern durch elementweises Füllen des Formularhintergrunds aus dem Array, in dem die gespeicherte Kopie des Teils des Formularhintergrundbilds gespeichert ist).
Als Nächstes, nach der Auflistung der Pixelkopierklasse, schreiben wir den Körper der Animationsrahmen-Objektklasse:
//+------------------------------------------------------------------+ //| Single animation frame class | //+------------------------------------------------------------------+ class CFrame : public CPixelCopier { protected: ENUM_ANIMATION_FRAME_TYPE m_frame_figure_type; // Type of the figure drawn by the frame ENUM_TEXT_ANCHOR m_anchor_last; // Last frame anchor point double m_x_last; // X coordinate of the upper left corner of the last frame double m_y_last; // Y coordinate of the upper left corner of the last frame int m_shift_x_prev; // Offset of the X coordinate of the last frame upper left corner int m_shift_y_prev; // Offset of the Y coordinate of the last frame upper left corner public: //--- Return the last (1) anchor point, (2) X and (3) Y coordinate, //--- previous offset by (4) X and (5) Y, (6) type of the figure drawn by the frame ENUM_TEXT_ANCHOR LastAnchor(void) const { return this.m_anchor_last; } double LastX(void) const { return this.m_x_last; } double LastY(void) const { return this.m_y_last; } int LastShiftX(void) const { return this.m_shift_x_prev; } int LastShiftY(void) const { return this.m_shift_y_prev; } ENUM_ANIMATION_FRAME_TYPE FrameFigureType(void) const { return this.m_frame_figure_type; } //--- Default constructor CFrame(); protected: //--- Text frame constructor CFrame(const int id, const int x, const int y, const string text, CGCnvElement *element); //--- Rectangle frame constructor CFrame(const int id, const int x, const int y, const int w, const int h, CGCnvElement *element); }; //+------------------------------------------------------------------+
Die Klasse ist von der Objektklasse Pixelkopierer abgeleitet, es ist also tatsächlich die Objektklasse Pixelkopierer.
Alle in der Klasse deklarierten Variablen und Methoden werden in den Kommentaren beschrieben. Da die Klasse die Grundlage für andere Animationsrahmenklassen ist, werden hier alle Eigenschaften und Methoden festgelegt, die den Nachfahren gemeinsam sind.
Die Variablen und Methoden, die die letzten Koordinaten, Offsets und Ankerpunkte zurückgeben, sind notwendig, damit wir in der Lage sind, die Koordinaten des zuvor gespeicherten Teils des Bildes zu definieren, wenn wir es wiederherstellen. Diese Koordinaten sind für die Platzierung des gespeicherten Hintergrunds zu verwenden, der durch das darüber gezeichnete Bild gelöscht wurde.
Die Klasse verfügt über drei Konstruktoren:
- dem standardmäßigen, 'public' Konstruktor,
- dem 'protected' Konstruktor des Text-Rahmen-Objekts,
- dem 'protected' Konstruktor für Rechteckrahmen-Objekte.
Kommrn wir nun zur Implementierung der 'protected' Konstruktoren.
Konstruktor für rechteckige Rahmen:
//+------------------------------------------------------------------+ //| Constructor of rectangle frames | //+------------------------------------------------------------------+ CFrame::CFrame(const int id,const int x,const int y,const int w,const int h,CGCnvElement *element) : CPixelCopier(id,x,y,w,h,element) { this.m_frame_figure_type=ANIMATION_FRAME_TYPE_QUAD; this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=x; this.m_y_last=y; this.m_shift_x_prev=0; this.m_shift_y_prev=0; } //+------------------------------------------------------------------+
Der Konstruktor erhält die ID des erstellten Rechteckrahmenobjekts, seine X- und Y-Koordinaten, Rahmenbreite und -höhe sowie den Zeiger auf das grafische Elementobjekt, aus dem das neue Objekt erstellt wird. Da die Klasse vom Pixelkopierobjekt abgeleitet ist, übergeben wir alle notwendigen Parameter an den Konstruktor der Basisklasse in der Initialisierungsliste des Konstruktors. Diese Parameter sind alle Eigenschaften, die als Argumente dem Konstruktor übergeben werden.
Legen wir noch die Standardparameter für alle Klassenvariablen im Klassenkörper fest.
Der Konstruktor von Textrahmen:
//+------------------------------------------------------------------+ //| The constructor of text frames | //+------------------------------------------------------------------+ CFrame::CFrame(const int id, const int x, const int y, const string text, CGCnvElement *element) { int w=0,h=0; this.m_element=element; this.m_element.GetCanvasObj().TextSize(text,w,h); this.m_anchor_last=this.m_element.TextAnchor(); this.m_frame_figure_type=ANIMATION_FRAME_TYPE_TEXT; this.m_x_last=x; this.m_y_last=y; this.m_shift_x_prev=0; this.m_shift_y_prev=0; CPixelCopier::SetID(id); CPixelCopier::SetCoordX(x); CPixelCopier::SetCoordY(y); CPixelCopier::SetWidth(w); CPixelCopier::SetHeight(h); } //+------------------------------------------------------------------+
Der Konstruktor erhält die ID des erstellten Textrahmenobjekts, seine X- und Y-Koordinaten, den Text und den Zeiger auf das grafische Elementobjekt, aus dem das neue Objekt erstellt wird.
Im Klassenkörper legen wir zunächst die Textgröße fest, setzen dann die Standardwerte der Klassenvariablen und setzen die ID des erstellten Objekts, seine Koordinaten und die Textgröße auf das übergeordnete Pixelkopierobjekt.
Erstellen wir die abgeleiteten Objektklassen der Animationsrahmen-Objektklasse.
Die Textklasse der Animationsrahmen
Erstellen wir in \MQL5\Include\DoEasy\Objects\Graph\Animations\ die neue Datei FrameText.mqh der Klasse CFrameText.
Die Datei der Animationsrahmenklasse sollte in die Datei aufgenommen werden, während die Klasse selbst von ihr abgeleitet sein sollte:
//+------------------------------------------------------------------+ //| FrameText.mqh | //| 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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Frame.mqh" //+------------------------------------------------------------------+ //| Single text animation frame class | //+------------------------------------------------------------------+ class CFrameText : public CFrame { private: public: //--- Display the text on the background while saving and restoring the background bool TextOnBG(const string text,const int x,const int y,const ENUM_TEXT_ANCHOR anchor,const color clr,const uchar opacity,bool redraw=false); //--- Constructors CFrameText() {;} CFrameText(const int id,CGCnvElement *element) : CFrame(id,0,0,"",element) {} }; //+------------------------------------------------------------------+
Hier sehen wir eine öffentliche Methode zum Zeichnen des Textes auf dem Hintergrund des Formularobjekts und zwei Konstruktoren — einen Standard- und einen parametrischen Konstruktor.
Der parametrische Konstruktor erhält die ID des erstellten Textanimationsrahmenobjekts und den Zeiger auf das grafische Element, aus dem das Objekt erstellt wird. In der Initialisierungsliste erhält die Elternklasse die in den Konstruktorargumenten übergebene ID, Standardwerte für Koordinaten und einen Text sowie den Zeiger auf das grafische Element, der ebenfalls in den Konstruktorargumenten übergeben wird.
Die Methode zeigt einen Text auf dem Hintergrund an, wobei der Hintergrund gespeichert und wiederhergestellt wird:
//+-------------------------------------------------------------------------------+ //| Display the text on the background, while saving and restoring the background | //+-------------------------------------------------------------------------------+ bool CFrameText::TextOnBG(const string text,const int x,const int y,const ENUM_TEXT_ANCHOR anchor,const color clr,const uchar opacity,bool redraw=false) { //--- Find out the width and height of the text outlining the rectangle (to be used as the size of the saved area) int w=0,h=0; this.m_element.TextSize(text,w,h); //--- Calculate coordinate offsets for the saved area depending on the text anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(w,h,anchor,shift_x,shift_y); //--- If the pixel array is not empty, the background under the text has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If a background area with calculated coordinates and size under the future text is successfully saved if(!CPixelCopier::CopyImgDataToArray(x+shift_x,y+shift_y,w,h)) return false; //--- Draw the text and update the element this.m_element.Text(x,y,text,clr,opacity,anchor); this.m_element.Update(redraw); this.m_anchor_last=anchor; this.m_x_last=x; this.m_y_last=y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Die Logik der Methode ist in den Code-Kommentaren detailliert beschrieben. Ich habe es bereits im vorherigen Artikel während des Tests erklärt (eine ähnliche Logik wurde in OnChartEvent() des Test-EA eingestellt), also ist hier, glaube ich, alles klar. Nachdem der Text auf dem Formular gezeichnet wurde, werden seine Ankerpunkte, die X- und Y-Koordinaten sowie die Offset-Werte relativ zum Ankerpunkt in den Variablen der Elternklasse gesetzt. Ihre Werte werden verwendet, um den Hintergrund des Formulars wiederherzustellen, der durch den Text überschrieben wird.
Lassen Sie uns nun die zweite, abgeleitete Klasse des Animationsrahmenobjekts erstellen.
Rechteckklasse der Animationsrahmen
In \MQL5\Include\DoEasy\Objects\Graph\Animations\ erstellen wir die neue Datei FrameQuad.mqh der Klasse CFrameQuad.
Die übergeordnete Klassendatei sollte in die Klassendatei eingebunden (und von ihr abgeleitet) werden:
//+------------------------------------------------------------------+ //| FrameQuad.mqh | //| 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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Frame.mqh" //+------------------------------------------------------------------+ //| Single sprite animation frame class | //+------------------------------------------------------------------+ class CFrameQuad : public CFrame { private: double m_quad_x; // X coordinate of the rectangle enclosing the shape double m_quad_y; // Y coordinate of the rectangle enclosing the shape uint m_quad_width; // Width of the rectangle enclosing the shape uint m_quad_height; // Height of the rectangle enclosing the shape public: //--- Constructors CFrameQuad() {;} CFrameQuad(const int id,CGCnvElement *element) : CFrame(id,0,0,0,0,element) { this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; } //+------------------------------------------------------------------+
Im privaten Abschnitt der Klasse werden die Klassenvariablen deklariert, in denen die Koordinaten und die Größe des Rechtecks gespeichert werden, das die gezeichnete Figur umschließt — dies sind die Koordinaten und die Größe des gespeicherten Bildbereichs des Hintergrundteils, der von der gezeichneten Figur überschrieben wird.
Der parametrische Konstruktor erhält die ID des erstellten Objekts und den Zeiger auf das grafische Element, aus dem das Objekt erstellt wird. Die in den Methodenargumenten übergebene ID, die Parameter für die Standardkoordinaten und die Rahmengröße sowie der Zeiger auf das grafische Element werden in der Initialisierungsliste des Konstruktors an den Konstruktor der übergeordneten Klasse übergeben. Legen Sie im Konstruktorkörper den Ankerpunkt der gezeichneten Figur als "oben links" fest. Dies ist notwendig, um den Versatz des kopierten Bereichs zu berechnen. Mit diesem Wert sind die Ankerpunkte der X- und Y-Koordinatenversätze gleich Null.
Da wir in der Klasse CCanvas über zahlreiche Zeichenmethoden verfügen, werden alle geeigneten Methoden zum Zeichnen von Figuren auf dem Hintergrund des Formularobjekts im öffentlichen Teil der Klasse deklariert, gefolgt von der Wiederherstellung des Hintergrunds:
public: //--- Constructors CFrameQuad() {;} CFrameQuad(const int id,CGCnvElement *element) : CFrame(id,0,0,0,0,element) { this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; } //+------------------------------------------------------------------+ //| Drawing primitives while saving and restoring the background | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Methods of drawing primitives without smoothing | //+------------------------------------------------------------------+ //--- Set the color of the dot with the specified coordinates bool SetPixelOnBG(const int x,const int y,const color clr,const uchar opacity=255,const bool redraw=false); //--- Draw a segment of a vertical line bool DrawLineVerticalOnBG(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 const bool redraw=false); // Chart redraw flag //--- Draw a segment of a horizontal line bool DrawLineHorizontalOnBG(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 const bool redraw=false); // Chart redraw flag //--- Draw a segment of a freehand line bool DrawLineOnBG(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 bool redraw=false); // Chart redraw flag //--- Draw a polyline bool DrawPolylineOnBG(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 bool redraw=false); // Chart redraw flag //--- Draw a polygon bool DrawPolygonOnBG(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 bool redraw=false); // Chart redraw flag //--- Draw a rectangle using two points bool DrawRectangleOnBG(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 const bool redraw=false); // Chart redraw flag //--- Draw a circle bool DrawCircleOnBG(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 const bool redraw=false); // Chart redraw flag //--- Draw a triangle bool DrawTriangleOnBG(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 bool redraw=false); // Chart redraw flag //--- Draw an ellipse using two points bool DrawEllipseOnBG(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 bool redraw=false); // Chart redraw flag //--- 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) bool DrawArcOnBG(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 const bool redraw=false); // Chart redraw flag //--- 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) bool DrawPieOnBG(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 const bool redraw=false); // Chart redraw flag //+------------------------------------------------------------------+ //| Methods of drawing filled primitives without smoothing | //+------------------------------------------------------------------+ //--- Fill in the area bool FillOnBG(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 const bool redraw=false); // Chart redraw flag //--- Draw a filled rectangle bool DrawRectangleFillOnBG(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 const bool redraw=false); // Chart redraw flag //--- Draw a filled circle bool DrawCircleFillOnBG(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 const bool redraw=false); // Chart redraw flag //--- Draw a filled triangle bool DrawTriangleFillOnBG(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 bool redraw=false); // Chart redraw flag //--- Draw a filled polygon bool DrawPolygonFillOnBG(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 bool redraw=false); // Chart redraw flag //--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates bool DrawEllipseFillOnBG(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 const bool redraw=false); // Chart redraw flag //+------------------------------------------------------------------+ //| Methods of drawing primitives using smoothing | //+------------------------------------------------------------------+ //--- Draw a point using AntiAliasing algorithm bool SetPixelAAOnBG(const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a segment of a freehand line using AntiAliasing algorithm bool DrawLineAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a segment of a freehand line using Wu algorithm bool DrawLineWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draws a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickVerticalOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickHorizontalOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draws a polyline using AntiAliasing algorithm bool DrawPolylineAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draws a polyline using Wu algorithm bool DrawPolylineWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- 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 bool DrawPolylineSmoothOnBG(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 bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration bool DrawPolylineThickOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polygon using AntiAliasing algorithm bool DrawPolygonAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a polygon using Wu algorithm bool DrawPolygonWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- 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. bool DrawPolygonSmoothOnBG(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 bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration bool DrawPolygonThickOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND); // line ends style //--- Draw a triangle using AntiAliasing algorithm bool DrawTriangleAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a triangle using Wu algorithm bool DrawTriangleWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a circle using AntiAliasing algorithm bool DrawCircleAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a circle using Wu algorithm bool DrawCircleWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw an ellipse by two points using AntiAliasing algorithm bool DrawEllipseAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw an ellipse by two points using Wu algorithm bool DrawEllipseWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value }; //+------------------------------------------------------------------+
Die Implementierung jeder dieser Methoden ist ähnlich wie die Implementierung ähnlicher Zeichenmethoden. Allerdings haben fast alle von ihnen ihre Nuancen, die in ihrer Zeichenmethode enthalten sind (die Größe des gespeicherten Bereichs zweier ähnlicher Zeichenmethoden kann aufgrund der individuellen Eigenschaften jeder von ihnen unterschiedlich sein).
Werfen wir einen Blick auf die Implementierung dieser Methoden.
Die Methode zum Einstellen der Farbe des Punktes mit den angegebenen Koordinaten:
//+------------------------------------------------------------------+ //| Set the color of the dot with the specified coordinates | //+------------------------------------------------------------------+ bool CFrameQuad::SetPixelOnBG(const int x,const int y,const color clr,const uchar opacity=255,const bool redraw=false) { //--- Set the coordinates of the outlining rectangle this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=1; this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If a background area with calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.SetPixel(x,y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Die Logik der Methode ist im Code ausführlich kommentiert. Betrachten wir das Ganze etwas genauer. Hier setzen wir zunächst die X- und Y-Koordinaten des oberen linken Randes des Hintergrundrechteckbereichs, der im Array für die spätere Wiederherstellung des Hintergrunds unter dem gezeichneten Punkt gespeichert werden soll. Da es sich nur um einen Punkt handelt (ein Pixelbild), stimmen die Koordinaten des gespeicherten Bereichs mit den Koordinaten des gezeichneten Punkts überein und die Größe entspricht der eines einzelnen Pixels, d. h. 1 x 1.
Als Nächstes wird geprüft, ob der Hintergrund zuvor gespeichert wurde (anhand der Größe des Arrays, die nicht Null ist, in dem der Hintergrund gespeichert wird). Wenn ja, wird der zuvor gespeicherte Hintergrund des Formularobjekts wiederhergestellt (die Koordinaten und die Größe des wiederhergestellten Bereichs sind bereits in den Klassenvariablen festgelegt). Nachdem der Hintergrund erfolgreich wiederhergestellt wurde, speichern wir den Formularhintergrund mit den neuen Koordinaten des Punktes und zeichnen Sie den Punkt. Speichern wir die neuen Koordinaten sowie die Größe des gespeicherten Bereichs und die Verschiebung in den Klassenvariablen für die spätere Wiederherstellung des durch den neu gezeichneten Punkt gelöschten Hintergrunds.
Die Methode, die ein Segment einer vertikalen Linie zeichnet:
//+------------------------------------------------------------------+ //| Draw a segment of a vertical line | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineVerticalOnBG(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 const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=x; this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineVertical(x,y1,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Hier unterscheidet sich die Berechnung der Koordinaten und der Größe des Rechtecks, das die Figur umrandet, von der Berechnung in der vorherigen Methode. Dies ist natürlich, da wir eine vertikale Linie mit der Breite von einem Pixel zeichnen. Die Höhe der Linie sollte als Differenz zwischen dem Maximal- und dem Minimalwert von zwei Y-Koordinaten der Linie berechnet werden. Die Y-Koordinate des gespeicherten Bereichs sollte dem Minimalwert der beiden Y-Koordinaten entsprechen (dem oberen Punkt der gezeichneten Linie).
Die Methode, die ein Segment einer horizontalen Linie zeichnet:
//+------------------------------------------------------------------+ //| Draw a segment of a horizontal line | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineHorizontalOnBG(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 const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineHorizontal(x1,x2,y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Hier ist die Berechnung der Koordinaten und der Größe des gespeicherten Bereichs ähnlich wie bei der vorherigen Methode, außer dass es sich um eine horizontale Linie handelt und die Höhe hier gleich einem Pixel ist, während die Breite und die X-Koordinate des gespeicherten Bereichs berechnet werden sollten.
Die Methode, die ein Segment einer Freihandlinie zeichnet:
//+------------------------------------------------------------------+ //| Draw a segment of a freehand line | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineOnBG(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 bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLine(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Dabei werden die Koordinaten und die Größe des gespeicherten Bereichs auf der Grundlage der Koordinaten der gezeichneten Linie errechnet.
Die Methode zeichnet eine Polylinie:
//+------------------------------------------------------------------+ //| Draw a polyline | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineOnBG(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 bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; this.m_quad_height=(max_y_value-min_y_value)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolyline(array_x,array_y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Hier ist die Idee zur der Berechnung der Koordinaten und der Größe des gespeicherten Bereichs die gleiche wie bei den oben besprochenen Methoden. Die Ausführung ist jedoch anders, da bei einer Polylinie (wie auch bei vielen anderen Figuren) die Koordinaten in Arrays und nicht in Form von Variablen übergeben werden, da es unmöglich ist, die Anzahl der Linienbögen oder die Anzahl der in den Methodenargumenten zu übergebenden Koordinaten vorher zu kennen. Deshalb sollten wir vor dem Aufruf der Methode zwei Arrays mit X-Koordinaten und den entsprechenden Y-Koordinaten jedes Linienknickpunktes füllen.
In der Methode erhalten wir die Maximal- und Minimalwerte aus den Arrays mit Hilfe der zuvor besprochenen Funktion, die den Minimal- oder Maximalwert aus dem an die Funktion übergebenen Array zurückgibt. Die erhaltenen Werte werden für die Berechnung der Koordinaten und der Größe des gespeicherten Formularhintergrundbereichs verwendet.
Die übrigen Methoden zum Zeichnen von Figuren ohne Glättung (man beachte nur die Berechnung der Koordinaten und der Größe des gespeicherten Bereichs):
//+------------------------------------------------------------------+ //| Draw the rectangle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonOnBG(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 bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; if(this.m_quad_width==0) this.m_quad_width=1; this.m_quad_height=(max_y_value-min_y_value)+1; if(this.m_quad_height==0) this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygon(array_x,array_y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a rectangle using two points | //+------------------------------------------------------------------+ bool CFrameQuad::DrawRectangleOnBG(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 const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawRectangle(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw the circle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawCircleOnBG(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 const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int rd=(r>0 ? r : 1); this.m_quad_x=x-rd; this.m_quad_y=y-rd; double x2=x+rd; double y2=y+rd; if(this.m_quad_x<0) this.m_quad_x=0; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1); this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawCircle(x,y,rd,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_CENTER; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a triangle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawTriangleOnBG(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 bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(::fmin(x1,x2),x3); this.m_quad_y=::fmin(::fmin(y1,y2),y3); int max_x=::fmax(::fmax(x1,x2),x3); int max_y=::fmax(::fmax(y1,y2),y3); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(max_x-this.m_quad_x)+1; this.m_quad_height=int(max_y-this.m_quad_y)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawTriangle(x1,y1,x2,y2,x3,y3,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw an ellipse using two points | //+------------------------------------------------------------------+ bool CFrameQuad::DrawEllipseOnBG(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 bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawEllipse(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw an arc of an ellipse inscribed in a rectangle | //| with the corners in (x1,y1) and (x2,y2). | //| The arc boundaries are cropped from the ellipse center | //| moving to two points with the coordinates of (x3,y3) and (x4,y4) | //+------------------------------------------------------------------+ bool CFrameQuad::DrawArcOnBG(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 const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-1; this.m_quad_y=::fmin(y1,y2)-1; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+2; this.m_quad_height=::fabs(y2-y1)+2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawArc(x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled sector of an ellipse inscribed in a rectangle | //| with the corners in (x1,y1) and (x2,y2). | //| The sector boundaries are cropped from the ellipse center, | //| moving to two points with the coordinates of (x3,y3) and (x4,y4) | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPieOnBG(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, // Color const color fill_clr, // Fill color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-1; this.m_quad_y=::fmin(y1,y2)-1; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+2; this.m_quad_height=::fabs(y2-y1)+2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPie(x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Betrachten wir nun die Methoden zum Zeichnen von gefüllten Primitiven ohne Glättung.
Die Methode zum Ausfüllen der Fläche:
//+------------------------------------------------------------------+ //| Fill in the area | //+------------------------------------------------------------------+ bool CFrameQuad::FillOnBG(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 const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=0; this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=0; this.m_quad_height=0; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.Fill(x,y,clr,opacity,threshould); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Da die Methode einen willkürlich eingeschlossenen Bereich ausfüllt, können wir die Größe des gespeicherten Bereichs nicht im Voraus kennen. Deshalb soll hier das gesamte Formular gespeichert werden. Um dies zu erreichen, setzen wir die Koordinaten und die Größe auf Null. Bei diesen Werten speichert die Methode, die den rechteckigen Bereich des Bildes speichert, den gesamten Formularhintergrund in dem Array.
Was die übrigen Methoden zum Zeichnen von gefüllten Primitiven betrifft, so entspricht ihre Berechnung der Koordinaten und der Größe des gespeicherten Bereichs der Berechnung von einfachen, nicht geglätteten Primitiven, die zuvor betrachtet wurde. Werfen wir einen Blick auf die Methoden, wie sie sind:
//+------------------------------------------------------------------+ //| Draw a filled rectangle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawRectangleFillOnBG(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 const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawRectangleFill(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled circle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawCircleFillOnBG(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 const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int rd=(r>0 ? r : 1); this.m_quad_x=x-rd; this.m_quad_y=y-rd; double x2=x+rd; double y2=y+rd; if(this.m_quad_x<0) this.m_quad_x=0; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1); this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawCircleFill(x,y,rd,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled triangle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawTriangleFillOnBG(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 bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(::fmin(x1,x2),x3)-1; this.m_quad_y=::fmin(::fmin(y1,y2),y3)-1; int max_x=::fmax(::fmax(x1,x2),x3)+1; int max_y=::fmax(::fmax(y1,y2),y3)+1; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(max_x-this.m_quad_x)+1; this.m_quad_height=int(max_y-this.m_quad_y)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawTriangleFill(x1,y1,x2,y2,x3,y3,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled polygon | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonFillOnBG(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 bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; this.m_quad_height=(max_y_value-min_y_value)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonFill(array_x,array_y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled ellipse inscribed in a rectangle | //| with the given coordinates | //+------------------------------------------------------------------+ bool CFrameQuad::DrawEllipseFillOnBG(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 const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawEllipseFill(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Die Methoden zum Zeichnen von Primitiven mit Glättung.
Die Methode zum Zeichnen eines Punktes mit AntiAliasing-Algorithmus:
//+------------------------------------------------------------------+ //| Draw a point using AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::SetPixelAAOnBG(const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=x-1; if(this.m_quad_x<0) this.m_quad_x=0; this.m_quad_y=y-1; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=3; this.m_quad_height=3; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If a background area with calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.SetPixelAA(x,y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Hier unterscheidet sich die Berechnung der Koordinaten und der Größe des gespeicherten Bereichs von der gleichen Berechnung bei der Punktzeichnungsmethode ohne Glättung. Ein geglätteter Punkt kann auf drei benachbarten Pixeln (insgesamt 9, d.h. 3 x 3 Pixel) platziert werden, daher sollten die Abmessungen des gespeicherten Bereichs drei Pixel hoch und drei Pixel breit sein. Die X- und Y-Koordinaten sollten jeweils ein Pixel links und ein Pixel oberhalb der Koordinaten des Punktes selbst liegen. Auf diese Weise hat das Rechteck des gespeicherten Bereichs, das den Punkt umrandet, auf allen Seiten des gezeichneten Punkts einen Rand von einem Pixel, falls dieser durch den Glättungsalgorithmus verwischt und auf mehr als einem Pixel gezeichnet wird. Auf diese Weise kann die unvollständige Wiederherstellung des Hintergrunds, der durch einen gezeichneten Punkt mit Glättung ausgelöscht wurde, beseitigt werden.
Die Methode zum Zeichnen eines Segments einer Freihandlinie unter Verwendung des AntiAliasing-Algorithmus:
//+------------------------------------------------------------------+ //| Draw a segment of a freehand line | //| using AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineAA(x1,y1,x2,y2,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Das Testen der Methode ergab, dass die Kanten der gezeichneten Linie nicht verschwommen sind, so dass die Berechnung der gespeicherten Flächengröße mit der Berechnung bei der Linienzeichnungsmethode ohne Glättung übereinstimmt.
Die Methode, die ein Segment einer Freihandlinie mit dem Algorithmus von Wu zeichnet:
//+------------------------------------------------------------------+ //| Draw a segment of a freehand line using the | //| Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineWu(x1,y1,x2,y2,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Hier ist die Berechnung aus dem gleichen Grund so ähnlich wie bei der vorherigen Methode.
Die Methode zeichnet ein Segment einer Freihandlinie mit einer bestimmten Breite unter Verwendung des Glättungsalgorithmus mit der Vorfilterung:
//+------------------------------------------------------------------+ //| Draw a segment of a freehand line having a specified width | //| using a smoothing algorithm | //| with the preliminary sorting | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineThickOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size int correct=int(::ceil((double)size/2.0))+1; //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-correct; this.m_quad_y=::fmin(y1,y2)-correct; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1+correct*2; this.m_quad_height=::fabs(y2-y1)+1+correct*2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineThick(x1,y1,x2,y2,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Bei dieser Methode unterscheidet sich die Berechnung des gespeicherten Bereichs von den oben genannten. Da eine Linie mit einem solchen Glättungsalgorithmus einen editierbaren Wert und ein Aussehen ihrer Enden aufweist, sollte die Breite des gespeicherten Bereichs die Größe (Breite) der Linie und ihrer Kanten berücksichtigen (die Kanten der Linie können abgerundet werden, daher erhöht sich die Größe (Länge) der Linie um zwei Rundungsradien, d.h. um den als Linienbreite eingestellten Wert).
Die Methode zeichnet ein vertikales Segment einer Freihandlinie mit einer bestimmten Breite unter Verwendung des Glättungsalgorithmus mit der Vorfilterung:
//+---------------------------------------------------------------------+ //| Draw a vertical segment of a freehand line having a specified width | //| using a smoothing algorithm | //| with the preliminary sorting | //+---------------------------------------------------------------------+ bool CFrameQuad::DrawLineThickVerticalOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size and the type of its ends int correct_x=(int)::ceil((double)size/2.0); int correct_y=(end_style==LINE_END_BUTT ? 0 : correct_x); //--- Set the coordinates of the outlining rectangle this.m_quad_x=x-correct_x; this.m_quad_y=::fmin(y1,y2)-correct_y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=size; this.m_quad_height=::fabs(y2-y1)+1+correct_y*2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineThickVertical(x,y1,y2,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Hier ist die Berechnung die gleiche wie bei der vorhergehenden Methode.
Die übrigen Methoden zum Zeichnen von geglätteten und anderen Primitiven:
//+-----------------------------------------------------------------------+ //| Draws a horizontal segment of a freehand line having a specified width| //| using a smoothing algorithm | //| with the preliminary sorting | //+-----------------------------------------------------------------------+ bool CFrameQuad::DrawLineThickHorizontalOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size and the type of its ends int correct_y=(int)::ceil((double)size/2.0); int correct_x=(end_style==LINE_END_BUTT ? 0 : correct_y); //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-correct_x; this.m_quad_y=y-correct_y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1+correct_x*2; this.m_quad_height=size; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineThickHorizontal(x1,x2,y,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polyline using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; this.m_quad_height=(max_y_value-min_y_value)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolylineAA(array_x,array_y,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draws a polyline using Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; this.m_quad_height=(max_y_value-min_y_value)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolylineWu(array_x,array_y,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polyline with a specified width using | //| two smoothing algorithms in series. | //| First, individual segments are smoothed | //| based on Bezier curves. | //| Then, to improve the rendering quality, | //| a raster smoothing algorithm is applied | //| made of the polyline segments | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineSmoothOnBG(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, // Chart redraw flag const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Set the coordinates of the outlining rectangle this.m_quad_x=0; this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=this.m_element.Width(); this.m_quad_height=this.m_element.Height(); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolylineSmooth(array_x,array_y,size,clr,opacity,tension,step,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polyline with a specified width using | //| a smoothing algorithm with the preliminary sorting | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineThickOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size int correct=int(::ceil((double)size/2.0))+1; //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x-correct; this.m_quad_y=y-correct; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1+correct*2; this.m_quad_height=(max_y_value-min_y_value)+1+correct*2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolylineThick(array_x,array_y,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polygon using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; if(this.m_quad_width==0) this.m_quad_width=1; this.m_quad_height=(max_y_value-min_y_value)+1; if(this.m_quad_height==0) this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonAA(array_x,array_y,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polygon using Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; if(this.m_quad_width==0) this.m_quad_width=1; this.m_quad_height=(max_y_value-min_y_value)+1; if(this.m_quad_height==0) this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonWu(array_x,array_y,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polygon with a specified width using | //| two smoothing algorithms in series. | //| First, individual segments are smoothed based on Bezier curves. | //| Then, to improve the rendering quality, | //| a raster smoothing algorithm is applied | //| made of the polyline segments. | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonSmoothOnBG(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, // Chart redraw flag const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Set the coordinates of the outlining rectangle this.m_quad_x=0; this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=this.m_element.Width(); this.m_quad_height=this.m_element.Height(); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonSmooth(array_x,array_y,size,clr,opacity,tension,step,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polygon with a specified width using | //| a smoothing algorithm with the preliminary sorting | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonThickOnBG(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 bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND) // line ends style { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size int correct=int(::ceil((double)size/2.0))+1; //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x-correct; this.m_quad_y=y-correct; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1+correct*2; this.m_quad_height=(max_y_value-min_y_value)+1+correct*2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonThick(array_x,array_y,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a triangle using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawTriangleAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(::fmin(x1,x2),x3); this.m_quad_y=::fmin(::fmin(y1,y2),y3); int max_x=::fmax(::fmax(x1,x2),x3); int max_y=::fmax(::fmax(y1,y2),y3); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(max_x-this.m_quad_x)+1; this.m_quad_height=int(max_y-this.m_quad_y)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawTriangleAA(x1,y1,x2,y2,x3,y3,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a triangle using Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawTriangleWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(::fmin(x1,x2),x3); this.m_quad_y=::fmin(::fmin(y1,y2),y3); int max_x=::fmax(::fmax(x1,x2),x3); int max_y=::fmax(::fmax(y1,y2),y3); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(max_x-this.m_quad_x)+1; this.m_quad_height=int(max_y-this.m_quad_y)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawTriangleWu(x1,y1,x2,y2,x3,y3,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a circle using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawCircleAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle double rd=(r>0 ? r : 1); this.m_quad_x=x-rd; this.m_quad_y=y-rd; double x2=x+rd; double y2=y+rd; if(this.m_quad_x<0) this.m_quad_x=0; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1); this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawCircleAA(x,y,rd,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a circle using Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawCircleWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle double rd=(r>0 ? r : 1); this.m_quad_x=x-rd; this.m_quad_y=y-rd; double x2=x+rd; double y2=y+rd; if(this.m_quad_x<0) this.m_quad_x=0; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1); this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawCircleWu(x,y,rd,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw an ellipse using two points while applying | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawEllipseAAOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-1; this.m_quad_y=::fmin(y1,y2)-1; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(::fabs(x2-x1)))+1; this.m_quad_height=int(::ceil(::fabs(y2-y1)))+1; if(this.m_quad_width<3) this.m_quad_width=3; if(this.m_quad_height<3) this.m_quad_height=3; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawEllipseAA(x1,y1,x2,y2,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw an ellipse using two points while applying | //| Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawEllipseWuOnBG(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 bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; if(this.m_quad_width<3) this.m_quad_width=3; this.m_quad_height=::fabs(y2-y1)+1; if(this.m_quad_height<3) this.m_quad_height=3; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawEllipseWu(x1,y1,x2,y2,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
Dabei sind die Algorithmen zur Berechnung der gespeicherten Hintergrundfläche bei allen Methoden annähernd identisch mit den Berechnungsalgorithmen der oben betrachteten Methoden.
Bei den Zeichenmethoden für Ellipsen (DrawEllipseAAOnBG und DrawEllipseWuOnBG) wird die Figur nicht gezeichnet, wenn das Rechteck, innerhalb dessen die Ellipse gezeichnet wird, weniger als drei Pixel ist. Daher enthalten die Berechnungen hier die Prüfung auf eine Größe von weniger als drei Pixeln. Ich habe noch nicht entschieden, ob dies mein Fehler oder ein Feature der CCanvas-Klassenmethoden ist. Ich hoffe, dies später zu klären.
Ich habe alle Klassen der Animationsrahmen-Objekte entwickelt, die ich derzeit benötige.
Nun ist es an der Zeit, eine Klasse zu erstellen, die die erstellten Animationsframe-Objekte speichert, darauf zugreift und verwaltet.
Die Klasse soll (vorerst) zwei Listen zum Speichern von erstellten Animationsrahmen-Objekten (Text und Rechteck) enthalten, sowie die Methoden zum Erstellen und Verwalten neuer Objekte. Anschließend soll die Klasse alle Animationsobjekte speichern, die zu einem Formular gehören. So soll jedes Formular über einen eigenen Satz von Animationsobjekten verfügen, die dynamisch erstellt und der Liste der Formularanimationen hinzugefügt werden können.
Das Formular der Animationsklasse
In der Datei \MQL5\Include\DoEasy\Objects\Graph\Animations\ erstellen wir die neue Datei Animations.mqh der CAnimations-Klasse.
Nur neu erstellte Nachfolgeklassendateien des Basis-Animationsframe-Objekts sollten in die Klassendatei aufgenommen werden, während die Klasse selbst von dem Basisobjekts der CObject-Standardbibliothek abgeleitet sein sollte:
//+------------------------------------------------------------------+ //| Animations.mqh | //| 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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "FrameText.mqh" #include "FrameQuad.mqh" //+------------------------------------------------------------------+ //| Pixel copier class | //+------------------------------------------------------------------+ class CAnimations : public CObject { }
Im privaten Teil der Klasse deklarieren wir den Zeiger auf das Objekt des grafischen Elements, aus dem Animationsobjekte erstellt werden sollen, zwei Listen zur Speicherung von zwei Arten von Animationsrahmenobjekten und die Methoden zur Rückgabe des Flags, das das Vorhandensein eines bestimmten Objekts in der Liste anzeigt, sowie die Methoden, die den Zeiger auf das vorhandene Animationsrahmenobjekt zurückgeben oder es vorläufig erstellen, wenn es nicht in der Liste enthalten ist:
//+------------------------------------------------------------------+ //| Pixel copier class | //+------------------------------------------------------------------+ class CAnimations : public CObject { private: CGCnvElement *m_element; // Pointer to the graphical element CArrayObj m_list_frames_text; // List of text animation frames CArrayObj m_list_frames_quad; // List of rectangle animation frames //--- Return the flag indicating the presence of the frame object with the specified ID in the list bool IsPresentFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id); //--- Return or create a new animation frame object CFrame *GetOrCreateFrame(const string soutce,const int id,const ENUM_ANIMATION_FRAME_TYPE frame_type,const bool create_new); public:
Alle Methoden werden im Folgenden beschrieben.
Deklarieren wir im öffentlichen Teil der Klasse die Methoden zum Erstellen und Arbeiten mit Objekten in den Listen und die Methoden zum Zeichnen von Primitiven, während wir den Hintergrund speichern und wiederherstellen:
public: CAnimations(CGCnvElement *element); CAnimations(){;} //--- Create a new (1) rectangle and (2) text animation frame object CFrame *CreateNewFrameText(const int id); CFrame *CreateNewFrameQuad(const int id); //--- Return the animation frame objects by ID CFrame *GetFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id); //--- Return the list of (1) text and (2) rectangle animation frames CArrayObj *GetListFramesText(void) { return &this.m_list_frames_text; } CArrayObj *GetListFramesQuad(void) { return &this.m_list_frames_quad; } //+------------------------------------------------------------------+ //| The methods of drawing, while saving and restoring the background| //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Display a text on the background | //+------------------------------------------------------------------+ bool TextOnBG(const int id, const string text, const int x, const int y, const ENUM_TEXT_ANCHOR anchor, const color clr, const uchar opacity, const bool create_new=true, const bool redraw=false); //+------------------------------------------------------------------+ //| Methods of drawing primitives without smoothing | //+------------------------------------------------------------------+ //--- Set the color of the dot with the specified coordinates bool SetPixelOnBG(const int id,const int x,const int y,const color clr,const uchar opacity=255,const bool create_new=true,const bool redraw=false); //--- Draw a segment of a vertical line bool DrawLineVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate 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 const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a segment of a horizontal line bool DrawLineHorizontalOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a segment of a freehand line bool DrawLineOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a polyline bool DrawPolylineOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a polygon bool DrawPolygonOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a rectangle using two points bool DrawRectangleOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a circle bool DrawCircleOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a triangle bool DrawTriangleOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw an ellipse using two points bool DrawEllipseOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- 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) bool DrawArcOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- 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) bool DrawPieOnBG(const int id, // Frame ID 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, // Color const color fill_clr, // Fill color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //+------------------------------------------------------------------+ //| Methods of drawing filled primitives without smoothing | //+------------------------------------------------------------------+ //--- Fill in the area bool FillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled rectangle bool DrawRectangleFillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled circle bool DrawCircleFillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled triangle bool DrawTriangleFillOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled polygon bool DrawPolygonFillOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates bool DrawEllipseFillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //+------------------------------------------------------------------+ //| Methods of drawing primitives using smoothing | //+------------------------------------------------------------------+ //--- Draw a point using AntiAliasing algorithm bool SetPixelAAOnBG(const int id, // Frame ID const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a segment of a freehand line using AntiAliasing algorithm bool DrawLineAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a segment of a freehand line using Wu algorithm bool DrawLineWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draws a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickHorizontalOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draws a polyline using AntiAliasing algorithm bool DrawPolylineAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draws a polyline using Wu algorithm bool DrawPolylineWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- 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 bool DrawPolylineSmoothOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration bool DrawPolylineThickOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polygon using AntiAliasing algorithm bool DrawPolygonAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a polygon using Wu algorithm bool DrawPolygonWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- 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. bool DrawPolygonSmoothOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration bool DrawPolygonThickOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND); // line ends style //--- Draw a triangle using AntiAliasing algorithm bool DrawTriangleAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a triangle using Wu algorithm bool DrawTriangleWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a circle using AntiAliasing algorithm bool DrawCircleAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a circle using Wu algorithm bool DrawCircleWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw an ellipse by two points using AntiAliasing algorithm bool DrawEllipseAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw an ellipse by two points using Wu algorithm bool DrawEllipseWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value }; //+------------------------------------------------------------------+
Implementieren wir jetzt die deklarierten Methoden
Der parametrische Konstruktor:
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CAnimations::CAnimations(CGCnvElement *element) { this.m_element=element; } //+------------------------------------------------------------------+
Der Wert des Zeigers auf das in den Argumenten übergebene grafische Elementobjekt wird für den Pointer m_element gesetzt.
Die Methode, die den Zeiger auf das Animationsframe-Objekt nach Typ und ID zurückgibt:
//+------------------------------------------------------------------+ //| Return the animation frame objects by type and ID | //+------------------------------------------------------------------+ CFrame *CAnimations::GetFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id) { //--- Declare the pointer to the animation frame object CFrame *frame=NULL; //--- Depending on the necessary object type, receive their number in the appropriate list int total= ( frame_type==ANIMATION_FRAME_TYPE_TEXT ? this.m_list_frames_text.Total() : frame_type==ANIMATION_FRAME_TYPE_QUAD ? this.m_list_frames_quad.Total() : 0 ); //--- Get the next object in the loop ... for(int i=0;i<total;i++) { //--- ... by the list corresponding to the animation frame type switch(frame_type) { case ANIMATION_FRAME_TYPE_TEXT : frame=this.m_list_frames_text.At(i); break; case ANIMATION_FRAME_TYPE_QUAD : frame=this.m_list_frames_quad.At(i); break; default: break; } //--- if failed to get the pointer, move on to the next one if(frame==NULL) continue; //--- If the object ID correspond to the required one, //--- return the pointer to the detected object if(frame.ID()==id) return frame; } //--- Nothing is found - return NULL return NULL; } //+------------------------------------------------------------------+
Die Logik der Methode ist in den Code-Kommentaren ausführlich beschrieben und bedarf keiner weiteren Erläuterung.
Die Methode gibt das Flag zurück, das das Vorhandensein des Rahmenobjekts mit dem angegebenen Typ und der ID in der Liste:
//+-----------------------------------------------------------------------+ //| Return the flag indicating the presence of the animation frame object | //| with the specified type and ID | //+-----------------------------------------------------------------------+ bool CAnimations::IsPresentFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id) { return(this.GetFrame(frame_type,id)!=NULL); } //+------------------------------------------------------------------+
Die Methode gibt als Wahrheitswert das Ergebnis des Aufrufs der oben besprochenen Methode GetFrame() zurück. Wenn die Methode GetFrame() ein Ergebnis ungleich NULL zurückgibt (das gewünschte Objekt ist in der Liste vorhanden), gibt die Methode true zurück, andernfalls — false.
Die Methode erstellt ein neues Textanimationsrahmenobjekt:
//+------------------------------------------------------------------+ //| Create a new text animation frame object | //+------------------------------------------------------------------+ CFrame *CAnimations::CreateNewFrameText(const int id) { //--- If the object with such an ID is already present, inform of that in the journal and return NULL if(this.IsPresentFrame(ANIMATION_FRAME_TYPE_TEXT,id)) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST),(string)id); return NULL; } //--- Create a new text animation frame object with the specified ID CFrame *frame=new CFrameText(id,this.m_element); //--- If failed to create an object, inform of that and return NULL if(frame==NULL) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME)); return NULL; } //--- If failed to add the created object to the list, inform of that, remove the object and return NULL if(!this.m_list_frames_text.Add(frame)) { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST)," ID: ",id); delete frame; return NULL; } //--- Return the pointer to a newly created object return frame; } //+------------------------------------------------------------------+
Die Logik der Methode ist in den Code-Kommentaren vollständig beschrieben.
Die Methode erstellt ein neues Rechteck-Animationsframe-Objekt:
//+------------------------------------------------------------------+ //| Create a new rectangle animation frame object | //+------------------------------------------------------------------+ CFrame *CAnimations::CreateNewFrameQuad(const int id) { //--- If the object with such an ID is already present, inform of that in the journal and return NULL if(this.IsPresentFrame(ANIMATION_FRAME_TYPE_QUAD,id)) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST),(string)id); return NULL; } //--- Create a new rectangle animation frame object with the specified ID CFrame *frame=new CFrameQuad(id,this.m_element); //--- If failed to create an object, inform of that and return NULL if(frame==NULL) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME)); return NULL; } //--- If failed to add the created object to the list, inform of that, remove the object and return NULL if(!this.m_list_frames_quad.Add(frame)) { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST)," ID: ",id); delete frame; return NULL; } //--- Return the pointer to a newly created object return frame; } //+------------------------------------------------------------------+
Die Methode ist identisch mit der oben besprochenen.
Die Methode gibt den Zeiger zurück oder erstellt ein neues Animationsframe-Objekt:
//+------------------------------------------------------------------+ //| Return or create a new animation frame object | //+------------------------------------------------------------------+ CFrame *CAnimations::GetOrCreateFrame(const string source,const int id,const ENUM_ANIMATION_FRAME_TYPE frame_type,const bool create_new) { //--- Declare null pointers to objects CFrameQuad *frame_q=NULL; CFrameText *frame_t=NULL; //--- Depending on the required object type switch(frame_type) { //--- If this is a text animation frame, case ANIMATION_FRAME_TYPE_TEXT : //--- get the pointer to an object with a specified ID frame_t=this.GetFrame(ANIMATION_FRAME_TYPE_TEXT,id); //--- If the pointer is obtained, return it if(frame_t!=NULL) return frame_t; //--- If the flag of creating a new object is not set, report an error and return NULL if(!create_new) { ::Print(source,CMessage::Text(MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST),(string)id); return NULL; } //--- Return the result of creating a new text animation frame object (pointer to the created object) return this.CreateNewFrameText(id); //--- If this is a rectangle animation frame case ANIMATION_FRAME_TYPE_QUAD : //--- get the pointer to an object with a specified ID frame_q=this.GetFrame(ANIMATION_FRAME_TYPE_QUAD,id); //--- If the pointer is obtained, return it if(frame_q!=NULL) return frame_q; //--- If the flag of creating a new object is not set, report an error and return NULL if(!create_new) { ::Print(source,CMessage::Text(MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST),(string)id); return NULL; } //--- Return the result of creating a new rectangle animation frame object (pointer to the created object) return this.CreateNewFrameQuad(id); //--- In the remaining cases, return NULL default: return NULL; } } //+------------------------------------------------------------------+
Die Logik der Methode wird in den Code-Kommentaren beschrieben. Wenn wir mit einem Animationsrahmen arbeiten müssen, können wir ihn vorher erstellen, den Zeiger darauf erhalten und das erhaltene Objekt verwalten. Wenn Objekte dynamisch erstellt werden müssen, ermöglicht es diese Methode, zunächst ein neues Objekt zu erstellen (vorausgesetzt, es gibt kein Objekt mit einer bestimmten ID) und den Zeiger darauf zurückzugeben. Auf diese Weise ist es möglich, die dynamische Erstellung eines Objekts zu veranlassen, den Zeiger auf das Objekt sofort zu erhalten und es zu verwalten.
Die Methoden zur Arbeit mit Animationsframe-Objekten.
Die Methode zeigt einen Text auf dem Hintergrund an, wobei der Hintergrund gespeichert und wiederhergestellt wird:
//+--------------------------------------------------------------------------------+ //| Display the text on the background, while saving and restoring the background | //+--------------------------------------------------------------------------------+ bool CAnimations::TextOnBG(const int id, const string text, const int x, const int y, const ENUM_TEXT_ANCHOR anchor, const color clr, const uchar opacity, const bool create_new=true, const bool redraw=false) { CFrameText *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_TEXT,create_new); if(frame==NULL) return false; return frame.TextOnBG(text,x,y,anchor,clr,opacity,redraw); } //+------------------------------------------------------------------+
Die Methode erhält die Objekt-ID, die Parameter für den angezeigten Text (den Text selbst, die X- und Y-Koordinaten, den Ankerpunkt, die Farbe und die Deckkraft), das Flag, das anzeigt, dass ein neues Objekt mit der angegebenen ID erstellt werden muss, falls das Objekt mit dieser ID nicht in der Liste vorhanden ist, und das Flag für das Neuzeichnen des Diagramms.
Als Nächstes wird der Zeiger auf das gewünschte Objekt geholt (oder das Objekt erstellt, wenn es nicht vorhanden ist). Wenn es nicht gelingt, den Zeiger zu erhalten, wird false zurückgegeben.
Wenn der Zeiger erhalten wurde, gib das Ergebnis der Methode TextOnBG() des erhaltenen Textanimationsrahmenobjekts zurück.
Die Methode zum Einstellen der Farbe des Punktes mit den angegebenen Koordinaten:
//+------------------------------------------------------------------+ //| Set the color of the dot with the specified coordinates | //+------------------------------------------------------------------+ bool CAnimations::SetPixelOnBG(const int id,const int x,const int y,const color clr,const uchar opacity=255,const bool create_new=true,const bool redraw=false) { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.SetPixelOnBG(x,y,clr,opacity,redraw); } //+------------------------------------------------------------------+
Die Logik der Methode ist identisch mit der oben besprochenen Methode. Die Methode erhält die Objekt-ID, die X- und Y-Koordinaten der gezeichneten Figur, ihre Farbe und Deckkraft, das Flag, das anzeigt, dass ein neues Objekt mit der angegebenen ID erstellt werden muss, falls das Objekt mit einer solchen ID nicht in der Liste vorhanden ist, und das Flag für das Neuzeichnen des Diagramms.
Als Nächstes wird der Zeiger auf das gewünschte Objekt geholt (oder das Objekt erstellt, wenn es nicht vorhanden ist). Wenn es nicht gelingt, den Zeiger zu erhalten, wird false zurückgegeben.
Wenn es gelingt, den Zeiger zu erhalten, wird das Ergebnis der Methode SetPixelOnBG() des erhaltenen Animationsrechteck-Rahmenobjekts zurückgegeben.
Andere Methoden zum Zeichnen von Primitiven.
Die Logik der übrigen Methoden zum Zeichnen von Figuren ist identisch mit der Logik der oben besprochenen Methoden. Werfen wir einen Blick auf deren Code:
//+------------------------------------------------------------------+ //| Draw a segment of a vertical line | //+------------------------------------------------------------------+ bool CAnimations::DrawLineVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineVerticalOnBG(x,y1,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a segment of a horizontal line | //+------------------------------------------------------------------+ bool CAnimations::DrawLineHorizontalOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineHorizontalOnBG(x1,x2,y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a segment of a freehand line | //+------------------------------------------------------------------+ bool CAnimations::DrawLineOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a polyline | //+------------------------------------------------------------------+ bool CAnimations::DrawPolylineOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineOnBG(array_x,array_y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw the rectangle | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonOnBG(array_x,array_y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a rectangle using two points | //+------------------------------------------------------------------+ bool CAnimations::DrawRectangleOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawRectangleOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw the circle | //+------------------------------------------------------------------+ bool CAnimations::DrawCircleOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawCircleOnBG(x,y,r,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a triangle | //+------------------------------------------------------------------+ bool CAnimations::DrawTriangleOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawTriangleOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw an ellipse using two points | //+------------------------------------------------------------------+ bool CAnimations::DrawEllipseOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawEllipseOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw an arc of an ellipse inscribed in a rectangle | //| with the corners in (x1,y1) and (x2,y2). | //| The arc boundaries are cropped from the ellipse center | //| moving to two points with the coordinates of (x3,y3) and (x4,y4) | //+------------------------------------------------------------------+ bool CAnimations::DrawArcOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawArcOnBG(x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled sector of an ellipse inscribed in a rectangle | //| with the corners in (x1,y1) and (x2,y2). | //| The sector boundaries are cropped from the ellipse center, | //| moving to two points with the coordinates of (x3,y3) and (x4,y4) | //+------------------------------------------------------------------+ bool CAnimations::DrawPieOnBG(const int id, // Frame ID 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, // Color const color fill_clr, // Fill color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPieOnBG(x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Fill in the area | //+------------------------------------------------------------------+ bool CAnimations::FillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.FillOnBG(x,y,clr,opacity,threshould,redraw); } //+------------------------------------------------------------------+ //| Draw a filled rectangle | //+------------------------------------------------------------------+ bool CAnimations::DrawRectangleFillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawRectangleFillOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled circle | //+------------------------------------------------------------------+ bool CAnimations::DrawCircleFillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawCircleFillOnBG(x,y,r,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled triangle | //+------------------------------------------------------------------+ bool CAnimations::DrawTriangleFillOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawTriangleFillOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled polygon | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonFillOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonFillOnBG(array_x,array_y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled ellipse inscribed in a rectangle | //| with the given coordinates | //+------------------------------------------------------------------+ bool CAnimations::DrawEllipseFillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawEllipseFillOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a point using AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::SetPixelAAOnBG(const int id, // Frame ID const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.SetPixelAAOnBG(x,y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a segment of a freehand line using the | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawLineAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineAAOnBG(x1,y1,x2,y2,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a segment of a freehand line using the | //| Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawLineWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineWuOnBG(x1,y1,x2,y2,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a segment of a freehand line having a specified width | //| using a smoothing algorithm | //| with the preliminary sorting | //+------------------------------------------------------------------+ bool CAnimations::DrawLineThickOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineThickOnBG(x1,y1,x2,y2,size,clr,opacity,redraw,style,end_style); } //+---------------------------------------------------------------------+ //| Draw a vertical segment of a freehand line having a specified width | //| using a smoothing algorithm | //| with the preliminary sorting | //+---------------------------------------------------------------------+ bool CAnimations::DrawLineThickVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineThickVerticalOnBG(x,y1,y2,size,clr,opacity,redraw,style,end_style); } //+-----------------------------------------------------------------------+ //| Draws a horizontal segment of a freehand line having a specified width| //| using a smoothing algorithm | //| with the preliminary sorting | //+-----------------------------------------------------------------------+ bool CAnimations::DrawLineThickHorizontalOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineThickHorizontalOnBG(x1,x2,y,size,clr,opacity,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a polyline using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawPolylineAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineAAOnBG(array_x,array_y,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draws a polyline using Wu algorithm | //+------------------------------------------------------------------+ //--- bool CAnimations::DrawPolylineWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineWuOnBG(array_x,array_y,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a polyline with a specified width using | //| two smoothing algorithms in series. | //| First, individual segments are smoothed | //| based on Bezier curves. | //| Then, to improve the rendering quality, | //| a raster smoothing algorithm | //| made of the polyline segments is applied | //+------------------------------------------------------------------+ bool CAnimations::DrawPolylineSmoothOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineSmoothOnBG(array_x,array_y,size,clr,opacity,tension,step,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a polyline with a specified width using | //| a smoothing algorithm with the preliminary sorting | //+------------------------------------------------------------------+ bool CAnimations::DrawPolylineThickOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineThickOnBG(array_x,array_y,size,clr,opacity,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a polygon using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonAAOnBG(array_x,array_y,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a polygon using Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonWuOnBG(array_x,array_y,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a polygon with a specified width using | //| two smoothing algorithms in series. | //| First, individual segments are smoothed based on Bezier curves. | //| Then, to improve the rendering quality, | //| a raster smoothing algorithm is applied | //| made of the polyline segments. | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonSmoothOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonSmoothOnBG(array_x,array_y,size,clr,opacity,tension,step,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a polygon with a specified width using | //| a smoothing algorithm with the preliminary sorting | //+------------------------------------------------------------------+ //--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration bool CAnimations::DrawPolygonThickOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND) // line ends style { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonThickOnBG(array_x,array_y,size,clr,opacity,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a triangle using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawTriangleAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawTriangleAAOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a triangle using Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawTriangleWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawTriangleWuOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a circle using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawCircleAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawCircleAAOnBG(x,y,r,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a circle using Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawCircleWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawCircleWuOnBG(x,y,r,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw an ellipse using two points while applying | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawEllipseAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawEllipseAAOnBG(x1,y1,x2,y2,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw an ellipse using two points | //| using Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawEllipseWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawEllipseWuOnBG(x1,y1,x2,y2,clr,opacity,redraw,style); } //+------------------------------------------------------------------+
Die neu geschaffene Klasse von Animationsobjekten sollte ein integraler Bestandteil des Formularobjekts sein. So soll jedes Formular seine eigenen Methoden zur Erstellung von Bildern haben.
Öffnen wir die Datei der Formularobjektklasse \MQL5\Include\DoEasy\Objects\Graph\Form.mqh und fügen die notwendigen Verbesserungen ein.
Binden wir noch die Datei der Animationsobjektklasse ein:
//+------------------------------------------------------------------+ //| Form.mqh | //| 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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "GCnvElement.mqh" #include "ShadowObj.mqh" #include "Animations\Animations.mqh" //+------------------------------------------------------------------+
Entfernen wir die Pixelkopier-Objektklasse aus dem Verzeichnis (ich habe sie in eine andere Datei verschoben):
//+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "GCnvElement.mqh" #include "ShadowObj.mqh" #include "Animations\Animations.mqh" //+------------------------------------------------------------------+ //| Pixel copier class | //+------------------------------------------------------------------+ class CPixelCopier : public CObject { private: ... } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Form object class | //+------------------------------------------------------------------+
Im privaten Abschnitt der Klasse, anstelle der Pixelkopierliste
CArrayObj m_list_pc_obj; // List of pixel copier objects
Deklarieren wir den Zeiger auf das Objekt der Animationsklasse:
//+------------------------------------------------------------------+ //| Form.mqh | //| 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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "GCnvElement.mqh" #include "ShadowObj.mqh" #include "Animations\Animations.mqh" //+------------------------------------------------------------------+ //| Form object class | //+------------------------------------------------------------------+ class CForm : public CGCnvElement { private: CArrayObj m_list_elements; // List of attached elements CAnimations *m_animations; // Pointer to the animation object CShadowObj *m_shadow_obj; // Pointer to the shadow object color m_color_frame; // Form frame color int m_frame_width_left; // Form frame width to the left int m_frame_width_right; // Form frame width to the right int m_frame_width_top; // Form frame width at the top int m_frame_width_bottom; // Form frame width at the bottom //--- Initialize the variables void Initialize(void); //--- Return the name of the dependent object string CreateNameDependentObject(const string base_name) const { return ::StringSubstr(this.NameObj(),::StringLen(::MQLInfoString(MQL_PROGRAM_NAME))+1)+"_"+base_name; } //--- Create a new graphical object CGCnvElement *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int element_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, const bool activity); //--- Create a shadow object void CreateShadowObj(const color colour,const uchar opacity); public:
Entfernen wir die Deklaration der bereits überflüssigen Methode IsPresentPC() aus dem privaten Teil, sowie ihre Implementierung aus dem Code:
//--- Create a shadow object void CreateShadowObj(const color colour,const uchar opacity); //--- Return the flag indicating the presence of the copier object with the specified ID in the list bool IsPresentPC(const int id); public:
Entfernen wir die bereits unnötige Methode aus dem öffentlichen Abschnitt der Klasse:
//--- Return (1) itself, the list of (2) attached objects, (3) pixel copier objects and (4) the shadow object CForm *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list_elements; } CArrayObj *GetListPC(void) { return &this.m_list_pc_obj; } CGCnvElement *GetShadowObj(void) { return this.m_shadow_obj; }
und fügen die neuen Methoden hinzu, die die Zeiger auf das Animationsobjekt und die Listen der Text- und Rechteckanimationsrahmen zurückgeben:
CGCnvElement *GetShadowObj(void) { return this.m_shadow_obj; } //--- Return the pointer to (1) the animation object, the list of (2) text and (3) rectangle animation frames CAnimations *GetAnimationsObj(void) { return this.m_animations; } CArrayObj *GetListFramesText(void) { return(this.m_animations!=NULL ? this.m_animations.GetListFramesText() : NULL); } CArrayObj *GetListFramesQuad(void) { return(this.m_animations!=NULL ? this.m_animations.GetListFramesQuad() : NULL); } //--- Set the form (1) color scheme and (2) style
Entfernen wir jetzt die Deklaration der Methode zur Erstellung eines neuen Pixelkopierobjekts:
//--- Create a new pixel copier object CPixelCopier *CreateNewPixelCopier(const int id,const int x_coord,const int y_coord,const int width,const int height); //--- Draw an object shadow
Die Implementierung der Methode, die außerhalb des Klassenkörpers geschrieben wurde, wird ebenfalls entfernt.
Wir schreiben in den Methodenblock für die Arbeit mit Bildpixeln im öffentlichen Abschnitt der Klasse die neuen Methoden für die Erstellung von Animationsrahmenobjekten, die Rückgabe von Zeigern auf erstellte Objekte und Zeichenmethoden, die den Hintergrund speichern und wiederherstellen:
//+------------------------------------------------------------------+ //| Methods of working with image pixels | //+------------------------------------------------------------------+ //--- Create a new (1) rectangle and (2) text animation frame object bool CreateNewFrameText(const int id,const int x_coord,const int y_coord,const string text) { return(this.m_animations!=NULL ? this.m_animations.CreateNewFrameText(id)!=NULL : false); } bool CreateNewFrameQuad(const int id,const int x_coord,const int y_coord,const int width,const int height) { return(this.m_animations!=NULL ? this.m_animations.CreateNewFrameQuad(id)!=NULL : false); } //--- Return the frame object of the (1) text and (2) rectangle animation by ID CFrame *GetFrameText(const int id) { return(this.m_animations!=NULL ? this.m_animations.GetFrame(ANIMATION_FRAME_TYPE_TEXT,id) : NULL); } CFrame *GetFrameQuad(const int id) { return(this.m_animations!=NULL ? this.m_animations.GetFrame(ANIMATION_FRAME_TYPE_QUAD,id) : NULL); } //--- Display the text on the background while saving and restoring the background bool TextOnBG(const int id, const string text, const int x, const int y, const ENUM_TEXT_ANCHOR anchor, const color clr, const uchar opacity=255, const bool create_new=true, const bool redraw=false) { return(this.m_animations!=NULL ? this.m_animations.TextOnBG(id,text,x,y,anchor,clr,opacity,create_new,redraw) : false); } //--- Set the color of the point with the specified coordinates while saving and restoring the background bool SetPixelOnBG(const int id,const int x,const int y,const color clr,const uchar opacity=255,const bool create_new=true,const bool redraw=false) { return(this.m_animations!=NULL ? this.m_animations.SetPixelOnBG(id,x,y,clr,opacity,create_new,redraw) : false); } //--- Draw a segment of a vertical line bool DrawLineVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawLineVerticalOnBG(id,x,y1,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a segment of a horizontal line while saving and restoring the background bool DrawLineHorizontalOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawLineHorizontalOnBG(id,x1,x2,y,clr,opacity,create_new,redraw) : false); } //--- Draw a segment of a freehand line while saving and restoring the background bool DrawLineOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawLineOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a polyline while saving and restoring the background bool DrawPolylineOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false); } //--- Draw a polygon while saving and restoring the background bool DrawPolygonOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false); } //--- Draw a rectangle by two points while saving and restoring the background bool DrawRectangleOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawRectangleOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a circle while saving and restoring the background bool DrawCircleOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawCircleOnBG(id,x,y,r,clr,opacity,create_new,redraw) : false); } //--- Draw a triangle while saving and restoring the background bool DrawTriangleOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw) : false); } //--- Draw an ellipse by two points while saving and restoring the background bool DrawEllipseOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw an arc of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2) while saving and restoring the background. //--- 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) bool DrawArcOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawArcOnBG(id,x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity,create_new,redraw) : false); } //--- Draw a filled sector of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2) while saving and restoring the background. //--- 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) bool DrawPieOnBG(const int id, // Frame ID 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, // Color const color fill_clr, // Fill color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawPieOnBG(id,x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity,create_new,redraw) : false); } //--- Fill the area while saving and restoring the background bool FillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.FillOnBG(id,x,y,clr,opacity,threshould,create_new,redraw) : false); } //--- Draw a filled rectangle while saving and restoring the background bool DrawRectangleFillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawRectangleFillOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a filled circle while saving and restoring the background bool DrawCircleFillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawCircleFillOnBG(id,x,y,r,clr,opacity,create_new,redraw) : false); } //--- Draw a filled triangle while saving and restoring the background bool DrawTriangleFillOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleFillOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw) : false); } //--- Draw a filled polygon while saving and restoring the background bool DrawPolygonFillOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonFillOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false); } //--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates while saving and restoring the background bool DrawEllipseFillOnBG(const int id, // Frame ID 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 const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseFillOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a point using AntiAliasing algorithm while saving and restoring the background bool SetPixelAAOnBG(const int id, // Frame ID const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.SetPixelAAOnBG(id,x,y,clr,opacity,create_new,redraw) : false); } //--- Draw a segment of a freehand line using AntiAliasing algorithm while saving and restoring the background bool DrawLineAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawLineAAOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false); } //--- Draw a segment of a freehand line using Wu algorithm while saving and restoring the background bool DrawLineWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawLineWuOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false); } //--- Draw a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawLineThickOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickOnBG(id,x1,y1,x2,y2,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawLineThickVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickVerticalOnBG(id,x,y1,y2,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawLineThickHorizontalOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickHorizontalOnBG(id,x1,x2,y,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a polyline using AntiAliasing algorithm while saving and restoring the background bool DrawPolylineAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineAAOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false); } //--- Draw a polyline using Wu algorithm while saving and restoring the background bool DrawPolylineWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineWuOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false); } //--- Draw a polyline with a specified width consecutively using two smoothing algorithms while saving and restoring the background. //--- 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 bool DrawPolylineSmoothOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineSmoothOnBG(id,array_x,array_y,size,clr,opacity,tension,step,create_new,redraw,style,end_style) : false); } //--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawPolylineThickOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineThickOnBG(id,array_x,array_y,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a polygon using AntiAliasing algorithm while saving and restoring the background bool DrawPolygonAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonAAOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false); } //--- Draw a polygon using Wu algorithm while saving and restoring the background bool DrawPolygonWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonWuOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false); } //--- Draw a polygon with a specified width consecutively using two smoothing algorithms while saving and restoring the background. //--- 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. bool DrawPolygonSmoothOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonSmoothOnBG(id,array_x,array_y,size,clr,opacity,tension,step,create_new,redraw,style,end_style) : false); } //--- Draw a polygon of a specified width using a smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawPolygonThickOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND) // line ends style { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonThickOnBG(id,array_x,array_y,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a triangle using AntiAliasing algorithm while saving and restoring the background bool DrawTriangleAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleAAOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw,style) : false); } //--- Draw a triangle using Wu algorithm while saving and restoring the background bool DrawTriangleWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleWuOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw,style) : false); } //--- Draw a circle using AntiAliasing algorithm while saving and restoring the background bool DrawCircleAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawCircleAAOnBG(id,x,y,r,clr,opacity,create_new,redraw,style) : false); } //--- Draw a circle using Wu algorithm while saving and restoring the background bool DrawCircleWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawCircleWuOnBG(id,x,y,r,clr,opacity,create_new,redraw,style) : false); } //--- Draw an ellipse by two points using AntiAliasing algorithm while saving and restoring the background bool DrawEllipseAAOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseAAOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false); } //--- Draw an ellipse by two points using Wu algorithm while saving and restoring the background bool DrawEllipseWuOnBG(const int id, // Frame ID 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 bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseWuOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false); } //+------------------------------------------------------------------+
Alle Methoden geben die Ergebnisse der entsprechenden Methoden aus dem oben erstellten CAnimations-Animationsobjekt zurück.
Im Destruktor der Klasse, entfernen wir das Animationsobjekt:
//+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CForm::~CForm() { if(this.m_shadow_obj!=NULL) delete this.m_shadow_obj; if(this.m_animations!=NULL) delete this.m_animations; } //+------------------------------------------------------------------+
In der Initialisierungsmethode erstellen wir ein neues Animationsobjekt:
//+------------------------------------------------------------------+ //| Initialize the variables | //+------------------------------------------------------------------+ void CForm::Initialize(void) { this.m_list_elements.Clear(); this.m_list_elements.Sort(); this.m_shadow_obj=NULL; this.m_shadow=false; this.m_frame_width_right=2; this.m_frame_width_left=2; this.m_frame_width_top=2; this.m_frame_width_bottom=2; this.m_animations=new CAnimations(CGCnvElement::GetObject()); } //+------------------------------------------------------------------+
Jetzt wird beim Erstellen eines neuen Formularobjekts automatisch ein neues Animationsobjekt erstellt. Wir können dem Animationsobjekt dynamisch neue Animationsrahmen hinzufügen oder die vordefinierten Formulare erstellen. Nach Beendigung des Programmlaufs wird das Animationsobjekt zerstört, um Speicherlecks zu vermeiden.
Wir sind bereit, die erstellten Klassen zu testen.
Wir haben eine Test-EA, der vier Formulare gezeichnet. Wenn wir auf das vierte (untere) Formular klicken, bewegt sich die Beschriftung des H-Gradienten (H - für horizontalen Richtung). Diese Beschriftung wird nun als Textanimationsrahmenobjekt erstellt und bewegt. Das dritte Formular (die vertikale Füllung) wird für die Anzeige verschiedener gezeichneter Figuren verwendet. Bevor eine Figur gezeichnet wird, zeigen wir zunächst einen Formulartext als Textanimationsrahmen an. Darüber werden Figuren gezeichnet. Das Umschalten der gezeichneten Figuren erfolgt durch Drücken der Tasten, während der Text die ausgewählte gezeichnete Figur anzeigt. Jeder Mausklick auf die Figur ändert die Koordinaten der gezeichneten Punkte der Figur.
Test
Um den Test durchzuführen, verwenden wir den EA aus dem vorherigen Artikel und speichern ihn in \MQL5\Experts\TestDoEasy\Part79\ als TestDoEasyPart79.mq5.
Im Bereich der globalen Variablen geben Sie Makrosubstitutionen zur Angabe der Anfangskoordinaten der gezeichneten Figuren ein und deklarieren wir die Variablen zur Speicherung der Koordinaten verschiedener Punkte der gezeichneten Figuren (insgesamt sollen fünf Punkte verwendet werden) und deren Änderungswerte:
//+------------------------------------------------------------------+ //| TestDoEasyPart79.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\Form.mqh> //--- defines #define FORMS_TOTAL (4) // Number of created forms #define START_X (4) // Initial X coordinate of the shape #define START_Y (4) // Initial Y coordinate of the shape //--- input parameters sinput bool InpMovable = true; // Movable forms flag sinput ENUM_INPUT_YES_NO InpUseColorBG = INPUT_YES; // Use chart background color to calculate shadow color sinput color InpColorForm3 = clrCadetBlue; // Third form shadow color (if not background color) //--- global variables CArrayObj list_forms; color array_clr[]; int nx1=0, ny1=0, nx2=0, ny2=0, nx3=0, ny3=0, nx4=0, ny4=0, nx5=0, ny5=0; int coordX1=START_X+nx1; int coordY1=START_Y+ny1; int coordX2=START_X+nx2*2; int coordY2=START_Y+ny2*2; int coordX3=START_X+nx3*3; int coordY3=START_Y+ny3*3; int coordX4=START_X+nx4*4; int coordY4=START_Y+ny4*4; int coordX5=START_X+nx5*5; int coordY5=START_Y+ny5*5; double RD=1; //+------------------------------------------------------------------+
In den Blöcken zum Erstellen der beiden letzten Formen von OnInit() wird der Text mit Hilfe von Textanimationsobjekten erstellt:
//--- If this is the third form if(i==2) { //--- Set the opacity of 200 form.SetOpacity(200); //--- The form background color is set as the first color from the color array form.SetColorBackground(array_clr[0]); //--- Form outlining frame color form.SetColorFrame(clrDarkBlue); //--- Draw the shadow drawing flag form.SetShadow(true); //--- Calculate the shadow color as the chart background color converted to the monochrome one color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100); //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units //--- Otherwise, use the color specified in the settings for drawing the shadow color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3); //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes //--- Set the shadow opacity to 200, while the blur radius is equal to 4 form.DrawShadow(3,3,clr,200,4); //--- Fill the form background with a vertical gradient form.Erase(array_clr,form.Opacity()); //--- Draw an outlining rectangle at the edges of the form form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity()); //--- Display the text describing the gradient type and update the form //--- Text parameters: the text coordinates and the anchor point in the form center //--- Create a new text animation frame with the ID of 0 and display the text on the form form.TextOnBG(0,TextByLanguage("V-Градиент","V-Gradient"),form.Width()/2,form.Height()/2,TEXT_ANCHOR_CENTER,C'211,233,149',255,true,false); } //--- If this is the fourth (bottom) form if(i==3) { //--- Set the opacity of 200 form.SetOpacity(200); //--- The form background color is set as the first color from the color array form.SetColorBackground(array_clr[0]); //--- Form outlining frame color form.SetColorFrame(clrDarkBlue); //--- Draw the shadow drawing flag form.SetShadow(true); //--- Calculate the shadow color as the chart background color converted to the monochrome one color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100); //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units //--- Otherwise, use the color specified in the settings for drawing the shadow color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3); //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes //--- Set the shadow opacity to 200, while the blur radius is equal to 4 form.DrawShadow(3,3,clr,200,4); //--- Fill the form background with a horizontal gradient form.Erase(array_clr,form.Opacity(),false); //--- Draw an outlining rectangle at the edges of the form form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity()); //--- Display the text describing the gradient type and update the form //--- Text parameters: the text coordinates and the anchor point in the form center //--- Create a new text animation frame with the ID of 0 and display the text on the form form.TextOnBG(0,TextByLanguage("H-Градиент","H-Gradient"),form.Width()/2,form.Height()/2,TEXT_ANCHOR_CENTER,C'211,233,149',255,true,true); } //--- Add objects to the list
Diese Textobjekte habe ich hier vorher erstellt. Gezeichnete Figuren sollen dynamisch erstellt werden — beim Klicken in den Formularbereich.
Um Tastendrücke zu verarbeiten, fügen wir den folgenden Codeblock in OnChartEvent() hinzu:
//--- Drawing mode depending on the pressed key static ENUM_FIGURE_TYPE figure_type_prev=WRONG_VALUE; static ENUM_FIGURE_TYPE figure_type=figure_type_prev; string figure=FigureTypeDescription(figure_type); //--- If a key is pressed if(id==CHARTEVENT_KEYDOWN) { //--- Get a drawn shape type depending on a pressed key figure_type=FigureType(lparam); //--- If the shape type has changed if(figure_type!=figure_type_prev) { //--- Get the text of the drawn shape type description figure=FigureTypeDescription(figure_type); //--- In the loop by all forms, for(int i=0;i<list_forms.Total();i++) { //--- get the pointer to the next form object CForm *form=list_forms.At(i); if(form==NULL) continue; //--- If the form ID is 2, if(form.ID()==2) { //--- Reset all coordinate shifts to zero and display the text describing the drawn shape type nx1=ny1=nx2=ny2=nx3=ny3=nx4=ny4=nx5=ny5=0; form.TextOnBG(0,figure,form.TextLastX(),form.TextLastY(),form.TextAnchor(),C'211,233,149',255,false,true); } } //--- Write the new shape type figure_type_prev=figure_type; } } //--- If clicking an object
Wir ändern den Code im Block für die Behandlung von Clicks in Formularen geringfügig — jetzt wird der Text mit Textanimationsobjekten des angeklickten Formulars angezeigt:
//--- If clicking an object if(id==CHARTEVENT_OBJECT_CLICK) { //--- If the clicked object belongs to the EA if(StringFind(sparam,MQLInfoString(MQL_PROGRAM_NAME))==0) { //--- Get the object ID from it int form_id=(int)StringToInteger(StringSubstr(sparam,StringLen(sparam)-1))-1; //--- Find this form object in the loop by all forms created in the EA for(int i=0;i<list_forms.Total();i++) { CForm *form=list_forms.At(i); if(form==NULL) continue; //--- If the clicked object has the ID of 2 and the form has the same ID if(form_id==2 && form.ID()==2) { //--- Handle clicking the form - draw the corresponding shape FigureProcessing(form,figure_type); } //--- If the clicked object has the ID of 3 and the form has the same ID if(form_id==3 && form.ID()==3) { ////--- Get the anchor point of the last drawn text ENUM_TEXT_ANCHOR anchor=form.TextAnchor(); ////--- Get the coordinates of the last drawn text int text_x=form.TextLastX(); int text_y=form.TextLastY(); //--- Set the text anchor initial point (0 = LEFT_TOP) out of nine possible ones static int n=0; //--- Depending on the n variable, set the new text anchor point switch(n) { case 0 : anchor=TEXT_ANCHOR_LEFT_TOP; text_x=1; text_y=1; break; case 1 : anchor=TEXT_ANCHOR_CENTER_TOP; text_x=form.Width()/2; text_y=1; break; case 2 : anchor=TEXT_ANCHOR_RIGHT_TOP; text_x=form.Width()-2; text_y=1; break; case 3 : anchor=TEXT_ANCHOR_LEFT_CENTER; text_x=1; text_y=form.Height()/2; break; case 4 : anchor=TEXT_ANCHOR_CENTER; text_x=form.Width()/2; text_y=form.Height()/2; break; case 5 : anchor=TEXT_ANCHOR_RIGHT_CENTER; text_x=form.Width()-2; text_y=form.Height()/2; break; case 6 : anchor=TEXT_ANCHOR_LEFT_BOTTOM; text_x=1; text_y=form.Height()-2; break; case 7 : anchor=TEXT_ANCHOR_CENTER_BOTTOM;text_x=form.Width()/2; text_y=form.Height()-2; break; case 8 : anchor=TEXT_ANCHOR_RIGHT_BOTTOM; text_x=form.Width()-2; text_y=form.Height()-2; break; default: anchor=TEXT_ANCHOR_CENTER; text_x=form.Width()/2; text_y=form.Height()/2; break; } form.TextOnBG(0,TextByLanguage("H-Градиент","H-Gradient"),text_x,text_y,anchor,C'211,233,149',255,true,true); //--- Increase the object click counter (and also the pointer to the text anchor point), //--- and if the value exceeds 8, reset the value to zero (from 0 to 8 = nine anchor points) n++; if(n>8) n=0; } } } }
Das Anklicken des dritten Formulars (mit der ID 2) wird in der Funktion FigureProcessing() behandelt. Das Anklicken des vierten Formulars (ID 3) ermöglicht es uns, den Ankerwinkel des Textes in Abhängigkeit von n zu definieren und den Text anzuzeigen. Aber der Text wird jetzt mit der Objektklasse Textanimationsrahmen angezeigt.
Die Hilfsfunktion gibt den Typ der Figur in Abhängigkeit von der gedrückten Taste zurück:
//+------------------------------------------------------------------+ //| Return the shape depending on the pressed key | //+------------------------------------------------------------------+ ENUM_FIGURE_TYPE FigureType(const long key_code) { switch((int)key_code) { //--- "1" = Dot case 49 : return FIGURE_TYPE_PIXEL; //--- "2" = Dot with AntiAlliasing case 50 : return FIGURE_TYPE_PIXEL_AA; //--- "3" = Vertical line case 51 : return FIGURE_TYPE_LINE_VERTICAL; //--- "4" = Vertical segment of a freehand line having a specified width using a smoothing algorithm case 52 : return FIGURE_TYPE_LINE_VERTICAL_THICK; //--- "5" = Horizontal line case 53 : return FIGURE_TYPE_LINE_HORIZONTAL; //--- "6" = Horizontal segment of a freehand line having a specified width using a smoothing algorithm case 54 : return FIGURE_TYPE_LINE_HORIZONTAL_THICK; //--- "7" = Freehand line case 55 : return FIGURE_TYPE_LINE; //--- "8" = Line with AntiAlliasing case 56 : return FIGURE_TYPE_LINE_AA; //--- "9" = Line with WU case 57 : return FIGURE_TYPE_LINE_WU; //--- "0" = Segment of a freehand line having a specified width using a smoothing algorithm case 48 : return FIGURE_TYPE_LINE_THICK; //--- "q" = Polyline case 81 : return FIGURE_TYPE_POLYLINE; //--- "w" = Polyline with AntiAlliasing case 87 : return FIGURE_TYPE_POLYLINE_AA; //--- "e" = Polyline with WU case 69 : return FIGURE_TYPE_POLYLINE_WU; //--- "r" = Polyline with a specified width using two smoothing algorithms case 82 : return FIGURE_TYPE_POLYLINE_SMOOTH; //--- "t" = Polyline with a specified width using a smoothing algorithm case 84 : return FIGURE_TYPE_POLYLINE_THICK; //--- "y" = Polygon case 89 : return FIGURE_TYPE_POLYGON; //--- "u" = Filled polygon case 85 : return FIGURE_TYPE_POLYGON_FILL; //--- "i" = Polygon with AntiAlliasing case 73 : return FIGURE_TYPE_POLYGON_AA; //--- "o" = Polygon with WU case 79 : return FIGURE_TYPE_POLYGON_WU; //--- "p" = Polygon with a specified width using two smoothing algorithms case 80 : return FIGURE_TYPE_POLYGON_SMOOTH; //--- "a" = Polygon with a specified width using a smoothing algorithm case 65 : return FIGURE_TYPE_POLYGON_THICK; //--- "s" = Rectangle case 83 : return FIGURE_TYPE_RECTANGLE; //--- "d" = Filled rectangle case 68 : return FIGURE_TYPE_RECTANGLE_FILL; //--- "f" = Circle case 70 : return FIGURE_TYPE_CIRCLE; //--- "g" = Filled circle case 71 : return FIGURE_TYPE_CIRCLE_FILL; //--- "h" = Circle with AntiAlliasing case 72 : return FIGURE_TYPE_CIRCLE_AA; //--- "j" = Circle with WU case 74 : return FIGURE_TYPE_CIRCLE_WU; //--- "k" = Triangle case 75 : return FIGURE_TYPE_TRIANGLE; //--- "l" = Filled triangle case 76 : return FIGURE_TYPE_TRIANGLE_FILL; //--- "z" = Triangle with AntiAlliasing case 90 : return FIGURE_TYPE_TRIANGLE_AA; //--- "x" = Triangle with WU case 88 : return FIGURE_TYPE_TRIANGLE_WU; //--- "c" = Ellipse case 67 : return FIGURE_TYPE_ELLIPSE; //--- "v" = Filled ellipse case 86 : return FIGURE_TYPE_ELLIPSE_FILL; //--- "b" = Ellipse with AntiAlliasing case 66 : return FIGURE_TYPE_ELLIPSE_AA; //--- "n" = Ellipse with WU case 78 : return FIGURE_TYPE_ELLIPSE_WU; //--- "m" = Ellipse arc case 77 : return FIGURE_TYPE_ARC; //--- "," = Ellipse sector case 188 : return FIGURE_TYPE_PIE; //--- Default = Dot default : return FIGURE_TYPE_PIXEL; } } //+------------------------------------------------------------------+
Die Funktion, die den Klick auf das Formularobjekt behandelt, ist recht umfangreich. Sie ist jedoch einfach, da sie den Operator switch enthält, der jeden gedrückten Knopf behandelt, dem das gezeichnete Formular entspricht. Die Handhabung ist einfach — man setzt die Anfangskoordinaten, prüft, ob sie außerhalb des zulässigen Wertebereichs liegen, zeichnet eine Figur mit diesen Parametern und erhöht die Verschiebungen der Parameterwerte. Wenn wir das nächste Mal auf das Formular klicken, wird die vorherige Figur durch den wiederhergestellten Hintergrund überschrieben und eine neue Figur mit den neuen Koordinaten ihrer Punkte gezeichnet.
//+------------------------------------------------------------------+ //| Handle the selected shape | //+------------------------------------------------------------------+ void FigureProcessing(CForm *form,const ENUM_FIGURE_TYPE figure_type) { int array_x[5]={0,0,0,0,0}; int array_y[5]={0,0,0,0,0}; switch(figure_type) { //--- "1" = Dot case FIGURE_TYPE_PIXEL : coordX1=START_X+nx1; coordY1=START_Y+ny1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } form.SetPixelOnBG(0,coordX1,coordY1,clrWheat); nx1++; ny1++; break; //--- "2" = Dot with AntiAlliasing case FIGURE_TYPE_PIXEL_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } form.SetPixelAAOnBG(0,coordX1,coordY1,clrWheat); nx1++; ny1++; break; //--- "3" = Vertical line case FIGURE_TYPE_LINE_VERTICAL : coordX1=START_X+nx1; coordY1=START_Y; coordY2=form.Height()-START_Y-1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } form.DrawLineVerticalOnBG(0,coordX1,coordY1,coordY2,clrWheat); nx1++; break; //--- "4" = Vertical segment of a freehand line having a specified width using a smoothing algorithm case FIGURE_TYPE_LINE_VERTICAL_THICK : coordX1=START_X+nx1; coordY1=START_Y; coordY2=form.Height()-START_Y-1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } form.DrawLineThickVerticalOnBG(0,coordX1,coordY1,coordY2,5,clrWheat,255,true,false,STYLE_SOLID,LINE_END_SQUARE); nx1++; break; //--- "5" = Horizontal line case FIGURE_TYPE_LINE_HORIZONTAL : coordX1=START_X; coordX2=form.Width()-START_X-1; coordY1=START_Y+ny1; if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } form.DrawLineHorizontalOnBG(0,coordX1,coordX2,coordY1,clrWheat); ny1++; break; //--- "6" = Horizontal segment of a freehand line having a specified width using a smoothing algorithm case FIGURE_TYPE_LINE_HORIZONTAL_THICK : coordX1=START_X; coordX2=form.Width()-START_X-1; coordY1=START_Y+ny1; if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } form.DrawLineThickHorizontalOnBG(0,coordX1,coordX2,coordY1,5,clrWheat,255,true,false,STYLE_SOLID,LINE_END_ROUND); ny1++; break; //--- "7" = Freehand line case FIGURE_TYPE_LINE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawLineOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "8" = Line with AntiAlliasing case FIGURE_TYPE_LINE_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawLineAAOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "9" = Line with WU case FIGURE_TYPE_LINE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawLineWuOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "0" = Segment of a freehand line having a specified width using a smoothing algorithm case FIGURE_TYPE_LINE_THICK : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawLineThickOnBG(0,coordX1,coordY1,coordX2,coordY2,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_SQUARE); nx1++; ny1++; nx2++; ny2++; break; //--- "q" = Polyline case FIGURE_TYPE_POLYLINE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "w" = Polyline with AntiAlliasing case FIGURE_TYPE_POLYLINE_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineAAOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "e" = Polyline with WU case FIGURE_TYPE_POLYLINE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineWuOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "r" = Polyline with a specified width using two smoothing algorithms case FIGURE_TYPE_POLYLINE_SMOOTH : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineSmoothOnBG(0,array_x,array_y,1,clrWheat,255,0.5,30.0,true,false,STYLE_SOLID,LINE_END_BUTT); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "t" = Polyline with a specified width using a smoothing algorithm case FIGURE_TYPE_POLYLINE_THICK : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineThickOnBG(0,array_x,array_y,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_BUTT); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "y" = Polygon case FIGURE_TYPE_POLYGON : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "u" = Filled polygon case FIGURE_TYPE_POLYGON_FILL : return; coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- Draw a shape form.DrawPolygonFillOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; break; //--- "i" = Polygon with AntiAlliasing case FIGURE_TYPE_POLYGON_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonAAOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "o" = Polygon with WU case FIGURE_TYPE_POLYGON_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonWuOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "p" = Polygon with a specified width using two smoothing algorithms case FIGURE_TYPE_POLYGON_SMOOTH : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonSmoothOnBG(0,array_x,array_y,3,clrWheat,255,0.5,10.0,true,false,STYLE_SOLID,LINE_END_BUTT); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "a" = Polygon with a specified width using a smoothing algorithm case FIGURE_TYPE_POLYGON_THICK : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonThickOnBG(0,array_x,array_y,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_BUTT); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "s" = Rectangle case FIGURE_TYPE_RECTANGLE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawRectangleOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "d" = Filled rectangle case FIGURE_TYPE_RECTANGLE_FILL : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawRectangleFillOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "f" = Circle case FIGURE_TYPE_CIRCLE : coordX1=START_X+nx1; coordY1=START_Y+ny1; RD=nx2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(RD>form.Height()/2) { nx2=0; RD=1; } form.DrawCircleOnBG(0,coordX1,coordY1,(int)RD,clrWheat); nx1++; ny1++; nx2++; break; //--- "g" = Filled circle case FIGURE_TYPE_CIRCLE_FILL : coordX1=START_X+nx1; coordY1=START_Y+ny1; RD=nx2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(RD>form.Height()/2) { nx2=0; RD=1; } form.DrawCircleFillOnBG(0,coordX1,coordY1,(int)RD,clrWheat); nx1++; ny1++; nx2++; break; //--- "h" = Circle with AntiAlliasing case FIGURE_TYPE_CIRCLE_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; RD=nx2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(RD>form.Height()/2) { nx2=0; RD=1; } form.DrawCircleAAOnBG(0,coordX1,coordY1,RD,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; break; //--- "j" = Circle with WU case FIGURE_TYPE_CIRCLE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; RD=nx2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(RD>form.Height()/2) { nx2=0; RD=1; } form.DrawCircleWuOnBG(0,coordX1,coordY1,RD,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; break; //--- "k" = Triangle case FIGURE_TYPE_TRIANGLE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=START_Y+ny2*2; coordX3=coordX1+nx3*2; coordY3=coordY2+ny3*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } if(coordX3>form.Width()-START_X-1) { nx3=0; coordX3=START_X; } if(coordY3>form.Height()-START_Y-1) { ny3=0; coordY3=START_Y; } form.DrawTriangleOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; break; //--- "l" = Filled triangle case FIGURE_TYPE_TRIANGLE_FILL : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=START_Y+ny2*2; coordX3=coordX1+nx3*2; coordY3=coordY2+ny3*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } if(coordX3>form.Width()-START_X-1) { nx3=0; coordX3=START_X; } if(coordY3>form.Height()-START_Y-1) { ny3=0; coordY3=START_Y; } form.DrawTriangleFillOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; break; //--- "z" = Triangle with AntiAlliasing case FIGURE_TYPE_TRIANGLE_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=START_Y+ny2*2; coordX3=coordX1+nx3*2; coordY3=coordY2+ny3*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } if(coordX3>form.Width()-START_X-1) { nx3=0; coordX3=START_X; } if(coordY3>form.Height()-START_Y-1) { ny3=0; coordY3=START_Y; } form.DrawTriangleAAOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; break; //--- "x" = Triangle with WU case FIGURE_TYPE_TRIANGLE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=START_Y+ny2*2; coordX3=coordX1+nx3*2; coordY3=coordY2+ny3*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } if(coordX3>form.Width()-START_X-1) { nx3=0; coordX3=START_X; } if(coordY3>form.Height()-START_Y-1) { ny3=0; coordY3=START_Y; } form.DrawTriangleWuOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; break; //--- "c" = Ellipse case FIGURE_TYPE_ELLIPSE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawEllipseOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "v" = Filled ellipse case FIGURE_TYPE_ELLIPSE_FILL : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawEllipseFillOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "b" = Ellipse with AntiAlliasing case FIGURE_TYPE_ELLIPSE_AA : return; coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*2; coordY2=coordY1+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawEllipseAAOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; ny2++; break; //--- "n" = Ellipse with WU case FIGURE_TYPE_ELLIPSE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*2; coordY2=coordY1+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawEllipseWuOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; ny2++; break; //--- "m" = Ellipse arc case FIGURE_TYPE_ARC : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=form.Width()-START_X-1-nx2; coordY2=form.Height()-START_Y-1-ny2; coordX3=coordX1; coordY3=coordY1; coordX4=coordX2; coordY4=coordY2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX3=coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY3=coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX4=coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY4=coordY2=START_Y; } form.DrawArcOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,coordX4,coordY4,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "," = Ellipse sector case FIGURE_TYPE_PIE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=form.Width()-START_X-1-nx2; coordY2=form.Height()-START_Y-1-ny2; coordX3=coordX1; coordY3=coordY1; coordX4=coordX2; coordY4=coordY1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX3=coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY3=coordY4=coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX4=coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawPieOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,coordX4,coordY4,clrWheat,clrLightSteelBlue); nx1++; ny1++; nx2++; ny2++; break; //--- Default = Nothing default : break; } } //+------------------------------------------------------------------+
Ich glaube, der Code der Funktion ist einfach und leicht zu verstehen. In jedem Fall können Sie gerne den Abschnitt Kommentare verwenden.
Ich habe für einen einfachen Test keine generelle Behandlung von identischen Parametern durchgeführt. Es ist viel einfacher und schneller, alles explizit in die einzelnen Fälle des Operators 'switch' zu schreiben. Die Wiederholbarkeit des Codes ist nicht wichtig. Für uns ist es wichtiger, einfach die Funktionalität der erstellten Klassen zu überprüfen.
Kompilieren Sie den EA und starten Sie ihn auf dem Chart. Nach dem Start drücken Sie einige Tasten, um sicherzustellen, dass sich der Zeichenmodus ändert und in der Beschriftung des dritten Formulars angezeigt wird. Wenn Sie auf das vierte Formular klicken, wird der Text auf die gleiche Weise verschoben wie im letzten EA aus dem vorigen Artikel. Nur wird dieser Text jetzt durch die Objektklasse Animationstextrahmen gerendert.
Wenn wir nach der Auswahl des gewünschten Zeichenmodus auf das dritte Formular klicken (auf dem das Etikett mit der Beschreibung des Zeichenmodus angezeigt wird), wird die ausgewählte Figur über dem Etikett und dem gesamten Formular gezeichnet, wobei sich die Koordinaten der Figurpunkte jedes Mal ändern.
Nicht alle Zeichenmethoden scheinen reibungslos zu funktionieren. Zum Beispiel fällt die Methode FillPolygon() der Klasse CCanvas bei den angegebenen Anfangsparametern im Objekt click einfach in eine Endlosschleife, während die Methode EllipseAA() einen Nullteilungsfehler erzeugt. Diese Methode weist potentielle Punkte auf, bei denen dies passieren kann:
//+------------------------------------------------------------------+ //| Draw ellipse with antialiasing | //+------------------------------------------------------------------+ void CCanvas::EllipseAA(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style=UINT_MAX) { double rx = (x2-x1)/2; double ry = (y2-y1)/2; //--- preliminary calculations double x=(x2>x1) ? x1+rx : x2+rx; double y=(y2>y1) ? y1+ry : y2+ry; double rx2=rx*rx; double ry2=ry*ry; //--- set the line style uint prev_style=m_style; if(style!=UINT_MAX) LineStyleSet(style); uint mask=1<<m_style_idx; //--- draw double quarter=round(rx2/sqrt(rx2+ry2)); for(double dx=0; dx<=quarter; dx++) { double dy=ry*sqrt(1-dx*dx/rx2); if((m_style&mask)==mask) PixelSet4AA(x,y,dx,dy,clr); mask<<=1; if(mask==0x1000000) mask=1; } quarter=round(ry2/sqrt(rx2+ry2)); for(double dy=0; dy<=quarter; dy++) { double dx=rx*sqrt(1-dy*dy/ry2); if((m_style&mask)==mask) PixelSet4AA(x,y,dx,dy,clr); mask<<=1; if(mask==0x1000000) mask=1; } //--- set the previous line style if(style!=UINT_MAX) m_style=prev_style; } //+------------------------------------------------------------------+
Ich habe dieses Problem im Profil-Thread gemeldet. Bis ich eine Antwort von den Entwicklern habe, werde ich versuchen, solche Fehler in späteren Artikeln zu umgehen.
Diesbezüglich werden einige Zeichenmethoden nicht im Handler für Mausklicks auf das Formularobjekt aufgerufen. Stattdessen macht die Funktion einfach einen Return. Wie auch immer, dies wird später behoben werden. Aber jetzt sehen wir, dass der Hintergrund unter den gezeichneten Figuren wiederhergestellt ist und alles wie vorgesehen angezeigt wird. Es gibt ein Problem beim Umschalten des Zeichenmodus — nach dem Umschalten wird der Hintergrund nicht wiederhergestellt. Das liegt daran, dass es keine Methode gibt, um ein Bild mit der Wiederherstellung des Hintergrunds zu entfernen. Ich werde dies in späteren Artikeln nachholen. Hier habe ich zu Testzwecken einfach den Zeitrahmen umgestellt, um den Hintergrund vollständig wiederherzustellen, bevor eine andere Figur auf dem Formular angezeigt wird.
Was kommt als Nächstes?
Im nächsten Artikel werde ich die Entwicklung der Animationsklassen fortsetzen.
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.
*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
Grafiken in der Bibliothek DoEasy (Teil 75): Methoden zur Handhabung von Primitiven und Text im grafischen Grundelement
Grafiken in der Bibliothek DoEasy (Teil 76): Das Formularobjekt und vordefinierte Farbschemata
Grafik in der Bibliothek DoEasy (Teil 77): Objektklasse der Schatten
Grafik in der Bibliothek DoEasy (Teil 78): Animationsprinzipien in der Bibliothek. Schneiden von Bildern
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/9652
- 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.