
DoEasy. Kontrollen (Teil 9): Neuanordnung von WinForms-Objektmethoden, Steuerung von RadioButton und Steuerungen
Inhalt
- Konzept
- Verbesserung des Bibliotheksklassen
- Das WinForms-Objekt RadioButton
- Die Schaltfläche WinForms-Objekt
- Test
- Was kommt als Nächstes?
Konzept
In diesem Artikel werde ich damit beginnen, die Namen der Methoden des WinForms-Objekts festzulegen und die Logik ihrer Konstruktion auf das für alle Bibliotheksobjekte etablierte Konzept zu übertragen — jedes Objekt hat eine Reihe von Integer-, Real- und String-Eigenschaften, die allen WinForms-Objekten innewohnen, aber für jedes spezifische Objekt ist es möglich, das Flag der Aufrechterhaltung einer solchen Eigenschaft durch das Objekt zu setzen. Wenn ein Objekt eine Eigenschaft nicht unterstützt, ist das Kennzeichen für diese Eigenschaft nicht markiert und das Objekt verwendet sie nicht.
Bisher habe ich viele Eigenschaften nur in Klassenvariablen gespeichert, aber dennoch werde ich alle Eigenschaften in den Mainstream des allgemeinen Bibliothekskonzepts verschieben. Dies vereinfacht die Entwicklung von z. B. visuellen Konstruktoren von grafischen Objekten für nutzerdefinierte bibliotheksbasierte Programme, wenn wir einfach eine Schleife durch alle Eigenschaften machen, um die Eigenschaftsnamen eines grafischen Objekts, das gerade konstruiert wird, und die Elemente zum Ändern jeder Eigenschaft anzuzeigen. Nur die vom Objekt unterstützten Eigenschaften werden in der Liste angezeigt. Mit anderen Worten, wir werden eine einzige Methode haben, um die Eigenschaften eines beliebigen Objekts anzuzeigen. Für jedes der vielen verschiedenen Objekte wird eine individuelle Liste der von einem Objekt unterstützten Eigenschaften erstellt.
Im aktuellen Artikel werde ich auch damit beginnen, noch statische WinForms-Objekte wiederzubeleben — jetzt wird die Bibliothek anfangen zu "sehen", über welchem Element sich der Cursor befindet (da das Container-Panel mehrere andere Elemente enthalten kann, die Interaktion erfordern). Später werde ich solche Interaktionen von Elementen mit der Maus behandeln und Ereignisse senden, um auf sie zu reagieren.
Außerdem werde ich zwei WinForms-Objekte erstellen — Button und RadioButton. Dies sind die Standard-WinForms-Objekte aus der Kategorie der Standard-Steuerelemente. Sie müssen nicht vorgestellt werden. Natürlich werden alle diese Elemente dann hinsichtlich ihrer Interaktivitätsfunktionen verbessert. Ich fange an, die Grundlage für verschiedene vollwertige Elemente zu schaffen. Später werden wir ihnen die Methoden für die Interaktion mit der Maus und verschiedene visuelle Effekte hinzufügen.
Verbesserung des Bibliotheksklassen
Im Falle von Steuerelementen sind bestimmte Werte bei der Erstellung standardmäßig festgelegt. Aktualisieren wir die Liste dieser Werte.
Fügen wir im Abschnitt Canvas-Parameter in \MQL5\Include\DoEasy\ Defines.mqh die Makro-Ersetzungen für die Farben des CheckBox-Elements hinzu:
#define CLR_DEF_SHADOW_OPACITY (127) // Default color non-transparency for canvas objects #define DEF_SHADOW_BLUR (4) // Default blur for canvas object shadows #define CLR_DEF_CHECK_BACK_COLOR (C'0xD9,0xEC,0xEB') // Color of control checkbox background #define CLR_DEF_CHECK_BACK_OPACITY (255) // Non-transparency of the control checkbox background color #define CLR_DEF_CHECK_BACK_MOUSE_DOWN (C'0xBA,0xEB,0xF5') // Color of control checkbox background when clicking on the control #define CLR_DEF_CHECK_BACK_MOUSE_OVER (C'0xCE,0xE0,0xE3') // Color of control checkbox background when hovering the mouse over the control #define CLR_DEF_CHECK_FORE_COLOR (C'0x2D,0x43,0x48') // Color of control checkbox frame #define CLR_DEF_CHECK_FORE_OPACITY (255) // Non-transparency of the control checkbox frame color #define CLR_DEF_CHECK_FORE_MOUSE_DOWN (C'0x06,0x0B,0xAA') // Color of control checkbox frame when clicking on the control #define CLR_DEF_CHECK_FORE_MOUSE_OVER (C'0x06,0x0B,0xAA') // Color of control checkbox frame when hovering the mouse over the control #define CLR_DEF_CHECK_FLAG_COLOR (C'0x04,0x7B,0x0D') // Color of control checkbox #define CLR_DEF_CHECK_FLAG_OPACITY (255) // Non-transparency of the control checkbox color #define CLR_DEF_CHECK_FLAG_MOUSE_DOWN (C'0x0E,0x9B,0x0B') // Color of control checkbox when clicking on the control #define CLR_DEF_CHECK_FLAG_MOUSE_OVER (C'0x0E,0xC7,0x2E') // Color of control checkbox when hovering the mouse over the control #define CLR_DEF_CONTROL_STD_BACK_COLOR (C'0xCD,0xD8,0xDA') // Standard controls background color #define CLR_DEF_CONTROL_STD_OPACITY (255) // Non-transparency of standard controls background color #define DEF_FONT ("Calibri") // Default font #define DEF_FONT_SIZE (8) // Default font size
Hinzufügen von zwei neue Elementtypen, die ich in diesem Artikel erstellen werde, zur Liste der grafischen Elementtypen hinzu:
//+------------------------------------------------------------------+ //| The list of graphical element types | //+------------------------------------------------------------------+ enum ENUM_GRAPH_ELEMENT_TYPE { GRAPH_ELEMENT_TYPE_STANDARD, // Standard graphical object GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED, // Extended standard graphical object GRAPH_ELEMENT_TYPE_SHADOW_OBJ, // Shadow object GRAPH_ELEMENT_TYPE_ELEMENT, // Element GRAPH_ELEMENT_TYPE_FORM, // Form GRAPH_ELEMENT_TYPE_WINDOW, // Window //--- WinForms GRAPH_ELEMENT_TYPE_WF_UNDERLAY, // Panel object underlay GRAPH_ELEMENT_TYPE_WF_BASE, // Windows Forms Base GRAPH_ELEMENT_TYPE_WF_CONTAINER, // Windows Forms container base object GRAPH_ELEMENT_TYPE_WF_PANEL, // Windows Forms Panel GRAPH_ELEMENT_TYPE_WF_GROUPBOX, // Windows Forms GroupBox GRAPH_ELEMENT_TYPE_WF_COMMON_BASE, // Windows Forms base standard control GRAPH_ELEMENT_TYPE_WF_LABEL, // Windows Forms Label GRAPH_ELEMENT_TYPE_WF_BUTTON, // Windows Forms Button GRAPH_ELEMENT_TYPE_WF_CHECKBOX, // Windows Forms ChackBox GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON, // Windows Forms RadioButton }; //+------------------------------------------------------------------+
Fügen wir in der Enumeration der Ganzzahl-Eigenschaften von Canvas-basierten grafischen Elementen neue Elementeigenschaften hinzu und und ändern die Gesamtzahl der Ganzzahl-Eigenschaften von 48 auf 71:
//+------------------------------------------------------------------+ //| Integer properties of the graphical element on the canvas | //+------------------------------------------------------------------+ enum ENUM_CANV_ELEMENT_PROP_INTEGER { CANV_ELEMENT_PROP_ID = 0, // Element ID CANV_ELEMENT_PROP_TYPE, // Graphical element type CANV_ELEMENT_PROP_BELONG, // Graphical element affiliation CANV_ELEMENT_PROP_NUM, // Element index in the list CANV_ELEMENT_PROP_CHART_ID, // Chart ID CANV_ELEMENT_PROP_WND_NUM, // Chart subwindow index CANV_ELEMENT_PROP_COORD_X, // Element X coordinate on the chart CANV_ELEMENT_PROP_COORD_Y, // Element Y coordinate on the chart CANV_ELEMENT_PROP_WIDTH, // Element width CANV_ELEMENT_PROP_HEIGHT, // Element height CANV_ELEMENT_PROP_RIGHT, // Element right border CANV_ELEMENT_PROP_BOTTOM, // Element bottom border CANV_ELEMENT_PROP_ACT_SHIFT_LEFT, // Active area offset from the left edge of the element CANV_ELEMENT_PROP_ACT_SHIFT_TOP, // Active area offset from the upper edge of the element CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT, // Active area offset from the right edge of the element CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM, // Active area offset from the bottom edge of the element CANV_ELEMENT_PROP_MOVABLE, // Element moveability flag CANV_ELEMENT_PROP_ACTIVE, // Element activity flag CANV_ELEMENT_PROP_INTERACTION, // Flag of interaction with the outside environment CANV_ELEMENT_PROP_COORD_ACT_X, // X coordinate of the element active area CANV_ELEMENT_PROP_COORD_ACT_Y, // Y coordinate of the element active area CANV_ELEMENT_PROP_ACT_RIGHT, // Right border of the element active area CANV_ELEMENT_PROP_ACT_BOTTOM, // Bottom border of the element active area CANV_ELEMENT_PROP_ZORDER, // Priority of a graphical object for receiving the event of clicking on a chart CANV_ELEMENT_PROP_ENABLED, // Element availability flag CANV_ELEMENT_PROP_FORE_COLOR, // Default text color for all control objects CANV_ELEMENT_PROP_FORE_COLOR_OPACITY, // Default text color opacity for all control objects CANV_ELEMENT_PROP_BACKGROUND_COLOR, // Control background color CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY, // Non-transparency of control background color CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN, // Control background color when clicking on the control CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER, // Control background color when hovering the mouse over the control CANV_ELEMENT_PROP_BOLD_TYPE, // Font width type CANV_ELEMENT_PROP_BORDER_STYLE, // Control frame style CANV_ELEMENT_PROP_BORDER_SIZE_TOP, // Control frame top size CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM, // Control frame bottom size CANV_ELEMENT_PROP_BORDER_SIZE_LEFT, // Control frame left size CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT, // Control frame right size CANV_ELEMENT_PROP_BORDER_COLOR, // Control frame color CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN, // Control frame color when clicking on the control CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER, // Control frame color when hovering the mouse over the control CANV_ELEMENT_PROP_AUTOSIZE, // Flag of the element auto resizing depending on the content CANV_ELEMENT_PROP_AUTOSIZE_MODE, // Mode of the element auto resizing depending on the content //--- ... //--- ... CANV_ELEMENT_PROP_CHECK_STATE, // Status of a control having a checkbox CANV_ELEMENT_PROP_AUTOCHECK, // Auto change flag status when it is selected CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR, // Color of control checkbox background CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY, // Non-transparency of the control checkbox background color CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN,// Color of control checkbox background when clicking on the control CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_OVER,// Color of control checkbox background when hovering the mouse over the control CANV_ELEMENT_PROP_CHECK_FORE_COLOR, // Color of control checkbox frame CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY, // Non-transparency of the control checkbox frame color CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN, // Color of control checkbox frame when clicking on the control CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_OVER, // Color of control checkbox frame when hovering the mouse over the control CANV_ELEMENT_PROP_CHECK_FLAG_COLOR, // Color of control checkbox CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY, // Non-transparency of the control checkbox color CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN, // Color of control checkbox when clicking on the control CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER, // Color of control checkbox when hovering the mouse over the control }; #define CANV_ELEMENT_PROP_INTEGER_TOTAL (71) // Total number of integer properties #define CANV_ELEMENT_PROP_INTEGER_SKIP (0) // Number of integer properties not used in sorting
Hinzufügen neuer Kriterien, die den neu hinzugefügten Eigenschaften entsprechen, zur Liste der möglichen Kriterien für die Sortierung von grafischen Elementen auf der Leinwand:
//+------------------------------------------------------------------+ //| Possible sorting criteria of graphical elements on the canvas | //+------------------------------------------------------------------+ #define FIRST_CANV_ELEMENT_DBL_PROP (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP) #define FIRST_CANV_ELEMENT_STR_PROP (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP+CANV_ELEMENT_PROP_DOUBLE_TOTAL-CANV_ELEMENT_PROP_DOUBLE_SKIP) enum ENUM_SORT_CANV_ELEMENT_MODE { //--- Sort by integer properties SORT_BY_CANV_ELEMENT_ID = 0, // Sort by element ID SORT_BY_CANV_ELEMENT_TYPE, // Sort by graphical element type //--- ... SORT_BY_CANV_ELEMENT_FORE_COLOR, // Sort by default text color for all control objects SORT_BY_CANV_ELEMENT_FORE_COLOR_OPACITY, // Sort by default text color opacity for all control objects SORT_BY_CANV_ELEMENT_BACKGROUND_COLOR, // Sort by control background text color SORT_BY_CANV_ELEMENT_BACKGROUND_COLOR_OPACITY, // Sort by control background color non-transparency SORT_BY_CANV_ELEMENT_BACKGROUND_COLOR_MOUSE_DOWN, // Sort by control background text color when clicking on the control SORT_BY_CANV_ELEMENT_BACKGROUND_COLOR_MOUSE_OVER, // Sort by control background text color when hovering the mouse over the control SORT_BY_CANV_ELEMENT_BOLD_TYPE, // Sort by font width type SORT_BY_CANV_ELEMENT_BORDER_STYLE, // Sort by control frame style SORT_BY_CANV_ELEMENT_BORDER_SIZE_TOP, // Sort by control frame top size SORT_BY_CANV_ELEMENT_BORDER_SIZE_BOTTOM, // Sort by control frame bottom size SORT_BY_CANV_ELEMENT_BORDER_SIZE_LEFT, // Sort by control frame left size SORT_BY_CANV_ELEMENT_BORDER_SIZE_RIGHT, // Sort by control frame right size SORT_BY_CANV_ELEMENT_BORDER_COLOR, // Sort by control frame color SORT_BY_CANV_ELEMENT_BORDER_COLOR_MOUSE_DOWN, // Sort by control frame color when clicking on the control SORT_BY_CANV_ELEMENT_BORDER_COLOR_MOUSE_OVER, // Sort by control frame color when hovering the mouse over the control SORT_BY_CANV_ELEMENT_AUTOSIZE, // Sort by the flag of the control auto resizing depending on the content SORT_BY_CANV_ELEMENT_AUTOSIZE_MODE, // Sort by the mode of the control auto resizing depending on the content //--- ... SORT_BY_CANV_ELEMENT_CHECK_STATE, // Sort by status of a control having a checkbox SORT_BY_CANV_ELEMENT_AUTOCHECK, // Sort by auto change flag status when it is selected SORT_BY_CANV_ELEMENT_CHECK_BACKGROUND_COLOR, // Sort by color of control checkbox background SORT_BY_CANV_ELEMENT_CHECK_BACKGROUND_COLOR_OPACITY, // Sort by non-transparency of control checkbox background color SORT_BY_CANV_ELEMENT_CHECK_BACKGROUND_COLOR_MOUSE_DOWN,// Sort by color of control checkbox background when clicking on the control SORT_BY_CANV_ELEMENT_CHECK_BACKGROUND_COLOR_MOUSE_OVER,// Sort by color of control checkbox background when hovering the mouse over the control SORT_BY_CANV_ELEMENT_CHECK_FORE_COLOR, // Sort by color of control checkbox frame SORT_BY_CANV_ELEMENT_CHECK_FORE_COLOR_OPACITY, // Sort by non-transparency of control checkbox frame color SORT_BY_CANV_ELEMENT_CHECK_FORE_COLOR_MOUSE_DOWN, // Sort by color of control checkbox frame when clicking on the control SORT_BY_CANV_ELEMENT_CHECK_FORE_COLOR_MOUSE_OVER, // Sort by color of control checkbox frame when hovering the mouse over the control SORT_BY_CANV_ELEMENT_CHECK_FLAG_COLOR, // Sort by color of control checkbox SORT_BY_CANV_ELEMENT_CHECK_FLAG_COLOR_OPACITY, // Sort by non-transparency of control checkbox color SORT_BY_CANV_ELEMENT_CHECK_FLAG_COLOR_MOUSE_DOWN, // Sort by color of control checkbox when clicking on the control SORT_BY_CANV_ELEMENT_CHECK_FLAG_COLOR_MOUSE_OVER, // Sort by color of control checkbox when hovering the mouse over the control //--- Sort by real properties //--- Sort by string properties SORT_BY_CANV_ELEMENT_NAME_OBJ = FIRST_CANV_ELEMENT_STR_PROP,// Sort by an element object name SORT_BY_CANV_ELEMENT_NAME_RES, // Sort by the graphical resource name SORT_BY_CANV_ELEMENT_TEXT, // Sort by graphical element text }; //+------------------------------------------------------------------+
Jetzt können wir alle grafischen Elemente nach neuen Eigenschaften auswählen und sortieren.
In \MQL5\Include\DoEasy\Data.mqh wurden neuen Nachrichtenindizes hinzugefügt:
MSG_LIB_TEXT_NOVEMBER, // November MSG_LIB_TEXT_DECEMBER, // December MSG_LIB_TEXT_FONT_STYLE_ITALIC, // Italic MSG_LIB_TEXT_FONT_STYLE_UNDERLINE, // Underline MSG_LIB_TEXT_FONT_STYLE_STRIKEOUT, // Strikeout MSG_LIB_TEXT_FONT_STYLE_NORMAL, // Normal MSG_LIB_TEXT_FRAME_STYLE_NONE, // None MSG_LIB_TEXT_FRAME_STYLE_SIMPLE, // Simple MSG_LIB_TEXT_FRAME_STYLE_FLAT, // Flat MSG_LIB_TEXT_FRAME_STYLE_BEVEL, // Embossed convex MSG_LIB_TEXT_FRAME_STYLE_STAMP, // Embossed concave MSG_LIB_TEXT_ALIGN_LEFT, // Left alignment MSG_LIB_TEXT_ALIGN_CENTER, // Center alignment
...
MSG_LIB_TEXT_BORDER_RAISED, // Raised MSG_LIB_TEXT_BORDER_SUNKEN, // Sunken MSG_LIB_TEXT_AUTO_SIZE_MODE_GROW, // Increase only MSG_LIB_TEXT_AUTO_SIZE_MODE_GROW_SHRINK, // Increase and decrease MSG_LIB_TEXT_DOCK_MODE_NONE, // Attached to the specified coordinates, size does not change MSG_LIB_TEXT_DOCK_MODE_TOP, // Attaching to the top and stretching along the container width MSG_LIB_TEXT_DOCK_MODE_BOTTOM, // Attaching to the bottom and stretching along the container width MSG_LIB_TEXT_DOCK_MODE_LEFT, // Attaching to the left and stretching along the container height MSG_LIB_TEXT_DOCK_MODE_RIGHT, // Attaching to the right and stretching along the container height MSG_LIB_TEXT_DOCK_MODE_FILL, // Stretching along the entire container width and height MSG_LIB_TEXT_CHEK_STATE_UNCHECKED, // Unchecked MSG_LIB_TEXT_CHEK_STATE_CHECKED, // Checked MSG_LIB_TEXT_CHEK_STATE_INDETERMINATE, // Undefined MSG_LIB_TEXT_SUNDAY, // Sunday MSG_LIB_TEXT_MONDAY, // Monday
...
MSG_GRAPH_ELEMENT_TYPE_WF_UNDERLAY, // Underlay of the Panel WinForms control object MSG_GRAPH_ELEMENT_TYPE_WF_BASE, // WinForms base control //--- WinForms containers MSG_GRAPH_ELEMENT_TYPE_WF_CONTAINER, // WinForms container base control MSG_GRAPH_ELEMENT_TYPE_WF_GROUPBOX, // GroupBox control MSG_GRAPH_ELEMENT_TYPE_WF_PANEL, // Panel control //--- WinForms standard MSG_GRAPH_ELEMENT_TYPE_WF_COMMON_BASE, // WinForms base standard control MSG_GRAPH_ELEMENT_TYPE_WF_LABEL, // Label control MSG_GRAPH_ELEMENT_TYPE_WF_CHECKBOX, // CheckBox control MSG_GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON, // RadioButton control MSG_GRAPH_ELEMENT_TYPE_WF_BUTTON, // Button control MSG_GRAPH_OBJ_BELONG_PROGRAM, // Graphical object belongs to a program MSG_GRAPH_OBJ_BELONG_NO_PROGRAM, // Graphical object does not belong to a program
...
//--- CPanel MSG_PANEL_OBJECT_ERR_FAILED_CREATE_UNDERLAY_OBJ, // Failed to create the underlay object MSG_PANEL_OBJECT_ERR_OBJ_MUST_BE_WFBASE, // Error. The created object should be of WinForms Base type or be derived from it //--- Integer properties of graphical elements MSG_CANV_ELEMENT_PROP_ID, // Element ID MSG_CANV_ELEMENT_PROP_TYPE, // Graphical element type MSG_CANV_ELEMENT_PROP_BELONG, // Graphical element affiliation MSG_CANV_ELEMENT_PROP_NUM, // Element index in the list MSG_CANV_ELEMENT_PROP_COORD_X, // Element X coordinate on the chart MSG_CANV_ELEMENT_PROP_COORD_Y, // Element Y coordinate on the chart MSG_CANV_ELEMENT_PROP_WIDTH, // Element width MSG_CANV_ELEMENT_PROP_HEIGHT, // Element height MSG_CANV_ELEMENT_PROP_RIGHT, // Element right border MSG_CANV_ELEMENT_PROP_BOTTOM, // Element bottom border MSG_CANV_ELEMENT_PROP_ACT_SHIFT_LEFT, // Active area offset from the left edge of the element MSG_CANV_ELEMENT_PROP_ACT_SHIFT_TOP, // Active area offset from the upper edge of the element MSG_CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT, // Active area offset from the right edge of the element MSG_CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM, // Active area offset from the bottom edge of the element MSG_CANV_ELEMENT_PROP_MOVABLE, // Element moveability flag MSG_CANV_ELEMENT_PROP_IS_MOVABLE, // Movable element MSG_CANV_ELEMENT_PROP_ACTIVE, // Element activity flag MSG_CANV_ELEMENT_PROP_IS_ACTIVE, // Element active MSG_CANV_ELEMENT_PROP_INTERACTION, // Flag of interaction with the outside environment MSG_CANV_ELEMENT_PROP_COORD_ACT_X, // X coordinate of the element active area MSG_CANV_ELEMENT_PROP_COORD_ACT_Y, // Y coordinate of the element active area MSG_CANV_ELEMENT_PROP_ACT_RIGHT, // Right border of the element active area MSG_CANV_ELEMENT_PROP_ACT_BOTTOM, // Bottom border of the element active area MSG_CANV_ELEMENT_PROP_ENABLED, // Element availability flag MSG_CANV_ELEMENT_PROP_FORE_COLOR, // Default text color for all control objects MSG_CANV_ELEMENT_PROP_FORE_COLOR_OPACITY, // Default text color opacity for all control objects MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR, // Control background color MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY, // Non-transparency of control background color MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN, // Control background color when clicking on the control MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER, // Control background color when hovering the mouse over the control MSG_CANV_ELEMENT_PROP_BOLD_TYPE, // Font width type MSG_CANV_ELEMENT_PROP_BORDER_STYLE, // Control frame style MSG_CANV_ELEMENT_PROP_BORDER_SIZE_TOP, // Control frame top size MSG_CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM, // Control frame bottom size MSG_CANV_ELEMENT_PROP_BORDER_SIZE_LEFT, // Control frame left size MSG_CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT, // Control frame right size MSG_CANV_ELEMENT_PROP_BORDER_COLOR, // Control frame color MSG_CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN, // Control frame color when clicking on the control MSG_CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER, // Control frame color when hovering the mouse over the control MSG_CANV_ELEMENT_PROP_AUTOSIZE, // Flag of the element auto resizing depending on the content MSG_CANV_ELEMENT_PROP_IS_AUTOSIZE, // The element automatically resizes to fit the content MSG_CANV_ELEMENT_PROP_AUTOSIZE_MODE, // Mode of the element auto resizing depending on the content MSG_CANV_ELEMENT_PROP_AUTOSCROLL, // Auto scrollbar flag MSG_CANV_ELEMENT_PROP_IS_AUTOSCROLL, // Scrollbar appears automatically MSG_CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W, // Width of the field inside the element during auto scrolling MSG_CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H, // Height of the field inside the element during auto scrolling MSG_CANV_ELEMENT_PROP_DOCK_MODE, // Mode of binding control borders to the container MSG_CANV_ELEMENT_PROP_MARGIN_TOP, // Top margin between the fields of this and another control MSG_CANV_ELEMENT_PROP_MARGIN_BOTTOM, // Bottom margin between the fields of this and another control MSG_CANV_ELEMENT_PROP_MARGIN_LEFT, // Left margin between the fields of this and another control MSG_CANV_ELEMENT_PROP_MARGIN_RIGHT, // Right margin between the fields of this and another control MSG_CANV_ELEMENT_PROP_PADDING_TOP, // Top margin inside the control MSG_CANV_ELEMENT_PROP_PADDING_BOTTOM, // Bottom margin inside the control MSG_CANV_ELEMENT_PROP_PADDING_LEFT, // Left margin inside the control MSG_CANV_ELEMENT_PROP_PADDING_RIGHT, // Right margin inside the control MSG_CANV_ELEMENT_PROP_TEXT_ALIGN, // Text position within text label boundaries MSG_CANV_ELEMENT_PROP_CHECK_ALIGN, // Position of the checkbox within control borders MSG_CANV_ELEMENT_PROP_CHECKED, // Control checkbox status MSG_CANV_ELEMENT_PROP_CHECK_STATE, // Status of a control having a checkbox MSG_CANV_ELEMENT_PROP_AUTOCHECK, // Auto change flag status when it is selected //--- Real properties of graphical elements //--- String properties of graphical elements MSG_CANV_ELEMENT_PROP_NAME_OBJ, // Graphical element object name MSG_CANV_ELEMENT_PROP_NAME_RES, // Graphical resource name MSG_CANV_ELEMENT_PROP_TEXT, // Graphical element text }; //+------------------------------------------------------------------+
und die Textnachrichten, die den neu hinzugefügten Indizes entsprechen:
{"Ноябрь","November"}, {"Декабрь","December"}, {"Курсив","Italic"}, {"Подчёркивание","Underline"}, {"Перечёркивание","Strikeout"}, {"Обычный","Normal"}, {"Отсутствует","Enpty"}, {"Простая","Simple"}, {"Плоская","Flat"}, {"Рельефная выпуклая","Bevel"}, {"Рельефная вдавленная","Stamp"}, {"Выравнивание по левой границе","Left alignment"}, {"Выравнивание по центру","Centered"},
...
{"Выпуклый вид","Prominent form"}, {"Вогнутый вид","Concave form"}, {"Только увеличение","Grow"}, {"Увеличение и уменьшение","Grow and Shrink"}, {"Прикреплён к указанным координатам, размеры не меняются","Attached to specified coordinates, size does not change"}, {"Присоединение сверху и растягивание на ширину контейнера","Attached to the top and stretched to the container width"}, {"Присоединение снизу и растягивание на ширину контейнера","Attached to the bottom and stretch to the width of the container"}, {"Присоединение слева и растягивание на высоту контейнера","Attached to the left and stretched to the height of the container"}, {"Присоединение справа и растягивание на высоту контейнера","Attached to the right and stretched to the height of the container"}, {"Растягивание на ширину и высоту всего контейнера","Stretching to the width and height of the entire container"}, {"Не установлен","Unchecked"}, {"Установлен","Checked"}, {"Неопределённый","Indeterminate"}, {"Воскресение","Sunday"}, {"Понедельник","Monday"},
...
{"Подложка объекта-элемента управления WinForms \"Панель\"","Underlay object-control WinForms \"Panel\""}, {"Базовый элемент управления WinForms","Base WinForms control"}, //--- WinForms containers {"Базовый элемент управления WinForms-контейнер","Basic Control WinForms Container"}, {"Элемент управления GroupBox","Control element \"GroupBox\""}, {"Элемент управления \"Panel\"","Control element \"Panel\""}, //--- WinForms standard {"Базовый стандартный элемент управления WinForms","Basic Standard WinForms Control"}, {"Элемент управления \"Label\"","Control element \"Label\""}, {"Элемент управления \"CheckBox\"","Control element \"CheckBox\""}, {"Элемент управления \"RadioButton\"","Control element \"RadioButton\""}, {"Элемент управления \"Button\"","Control element \"Button\""}, {"Графический объект принадлежит программе","The graphic object belongs to the program"}, {"Графический объект не принадлежит программе","The graphic object does not belong to the program"},
...
//--- CPanel {"Не удалось создать объект-подложку","Failed to create underlay object"}, {"Ошибка. Создаваемый объект должен иметь тип WinForms Base или быть его наследником","Error. The object being created must be of type WinForms Base or be derived from it"}, //--- Integer properties of graphical elements {"Идентификатор элемента","Element ID"}, {"Тип графического элемента","Graphic element type"}, {"Принадлежность графического элемента","Graphic element belong"}, {"Номер элемента в списке","The number of the element in the list"}, {"X-координата элемента на графике","X-coordinate of the element on the chart"}, {"Y-координата элемента на графике","Y-coordinate of the element on the chart"}, {"Ширина элемента","Element Width"}, {"Высота элемента","Element Height"}, {"Правая граница элемента","Element's right border"}, {"Нижняя граница элемента","Element's bottom border"}, {"Отступ активной зоны от левого края элемента","Active area indent from the left edge of the element"}, {"Отступ активной зоны от верхнего края элемента","Active area indent from the top edge of the element"}, {"Отступ активной зоны от правого края элемента","Active area indent from the right edge of the element"}, {"Отступ активной зоны от нижнего края элемента","Active area indent from the bottom edge of the element"}, {"Флаг перемещаемости элемента","Element mobility flag"}, {"Элемент перемещаемый","Element can be moved"}, {"Флаг активности элемента","Element activity flag"}, {"Элемент активен","Element active"}, {"Флаг взаимодействия элемента со внешней средой","Flag of the interaction of the element with the external environment"}, {"X-координата активной зоны элемента","X-coordinate of the element's active area"}, {"Y-координата активной зоны элемента","Y-coordinate of the element's active area"}, {"Правая граница активной зоны элемента","Right border of the element's active area"}, {"Нижняя граница активной зоны элемента","Bottom border of the element's active area"}, {"Флаг доступности элемента","Element Availability Flag"}, {"Цвет текста по умолчанию для всех объектов элемента управления","Default text color for all objects in the control"}, {"Непрозрачность цвета текста по умолчанию для всех объектов элемента управления","Default text color opacity for all objects in the control"}, {"Цвет фона элемента управления","Background color of the control"}, {"Непрозрачность цвета фона элемента управления","Opacity of the control's background color"}, {"Цвет фона элемента управления при нажатии мышки на элемент управления","Background color of the control when the mouse is clicked on the control"}, {"Цвет фона элемента управления при наведении мышки на элемент управления","Background color of the control when hovering the mouse over the control"}, {"Тип толщины шрифта","Font weight type"}, {"Стиль рамки элемента управления","Control's border style"}, {"Размер рамки элемента управления сверху","Control's border size on the top"}, {"Размер рамки элемента управления снизу","Control's border size on the bottom"}, {"Размер рамки элемента управления слева","Control's border size on the left"}, {"Размер рамки элемента управления справа","Control's border size on the right"}, {"Цвет рамки элемента управления","Control's border color"}, {"Цвет рамки элемента управления при нажатии мышки на элемент управления","Border color of the control when the mouse is clicked on the control"}, {"Цвет рамки элемента управления при наведении мышки на элемент управления","Border color of the control when hovering the mouse over the control"}, {"Флаг автоматического изменения размера элемента управления под содержимое","Automatically resize a control to fit its content"}, {"Элемент автоматически измененяет размер под содержимое","Element automatically resizes to fit the content"}, {"Режим автоматического изменения размера элемента управления под содержимое","Mode for automatically resizing a control to fit its content"}, {"Флаг автоматического появления полосы прокрутки","Scrollbar auto-appear flag"}, {"Полоса прокрутки автоматически появляется","Scroll bar automatically appears"}, {"Ширина поля вокруг элемента при автоматической прокрутке","Margin width around element when auto scrolling"}, {"Высота поля вокруг элемента при автоматической прокрутке","Height of margin around element when auto scrolling"}, {"Режим привязки границ элемента управления к контейнеру","Binding mode of the control's borders to the container"}, {"Промежуток сверху между полями данного и другого элемента управления","Top spacing between the margins of this control and another control"}, {"Промежуток снизу между полями данного и другого элемента управления","Bottom spacing between the margins of this control and another control"}, {"Промежуток слева между полями данного и другого элемента управления","Left spacing between the margins of this control and another control"}, {"Промежуток справа между полями данного и другого элемента управления","Right spacing between the margins of this control and another control"}, {"Промежуток сверху внутри элемента управления","Top spacing inside a control"}, {"Промежуток снизу внутри элемента управления","Bottom spacing inside a control"}, {"Промежуток слева внутри элемента управления","Left spacing inside a control"}, {"Промежуток справа внутри элемента управления","Right spacing inside a control"}, {"Положение текста в границах текстовой метки","Text position within text label bounds"}, {"Положение флажка проверки в границах элемента управления","The position of the checkbox within the control's bounds"}, {"Состояние флажка проверки элемента управления","Checkbox state of the control"}, {"Состояние элемента управления, имеющего флажок проверки","The state of a control that has a checkbox"}, {"Автоматическое изменение состояния флажка при его выборе","Automatically change the state of the checkbox when it is selected"}, //--- String properties of graphical elements {"Имя объекта-графического элемента","The name of the graphic element object"}, {"Имя графического ресурса","Image resource name"}, {"Текст графического элемента","Text of the graphic element"}, }; //+---------------------------------------------------------------------+
Wir werden alle diese Meldungen später benötigen, um die Beschreibungen der Eigenschaften der grafischen Steuerelemente anzuzeigen.
Die Beschreibungen der Kontrolltypen sind in der Methode implementiert, die die Beschreibung des Typs des grafischen Elements, der Klasse des grafischen Basisobjekts der Bibliothek in \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh zurückgibt. Ergänzen wir sie durch Zeichenketten, die die Beschreibungen der neuen Typen zurückgeben:
//+------------------------------------------------------------------+ //| Return the description of the graphical element type | //+------------------------------------------------------------------+ string CGBaseObj::TypeElementDescription(void) { return ( this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_STANDARD ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_ELEMENT ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_ELEMENT) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_SHADOW_OBJ ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_FORM ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_FORM) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WINDOW ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WINDOW) : //--- this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_UNDERLAY) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_BASE ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BASE) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_CONTAINER ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CONTAINER) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_GROUPBOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_GROUPBOX) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_PANEL ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_PANEL) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_COMMON_BASE ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_COMMON_BASE) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_LABEL ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LABEL) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_CHECKBOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CHECKBOX) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_BUTTON ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BUTTON) : "Unknown" ); } //+------------------------------------------------------------------+
Je nach Typ des grafischen Elements gibt die Methode die Zeichenkette mit der Typbeschreibung zurück.
Wir haben hässliche Inkonsistenzen in den Namen von Methoden, die eine Farbe setzen oder zurückgeben. Die Methode ForeColor() gibt zum Beispiel die Textfarbe zurück. Gleichzeitig wird die Methode, die die Hintergrundfarbe zurückgibt, ColorBackground() genannt. Um die Namen miteinander in Einklang zu bringen, benennen wir die Methode ColorBackground() und ähnliche Methoden in BackgroundColor() um. Darüber hinaus habe ich die neuen Eigenschaften von grafischen Elementen eingeführt, die Farbeigenschaften aufweisen, wenn der Mauszeiger über einem Objekt schwebt und darauf geklickt wird. Wir sollten auch die Methoden zum Setzen und Zurückgeben dieser und aller anderen neuen Eigenschaften hinzufügen.
Verbessern wir noch die Objektklasse der grafischen Elemente in \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh.
Da wir einen Farbverlauf als Hintergrundfarbe haben können, werden wir das Farbfeld verwenden, um alle Farbverläufe zu speichern. Wir müssen zwei weitere solcher Arrays hinzufügen — für die Speicherung der Hintergrundfarbverläufe, wenn der Mauszeiger über dem Objekt schwebt und es anklickt.
Im „protected“ Abschnit der Klasse deklarieren wir zwei solcher Arrays:
//+------------------------------------------------------------------+ //| Class of the graphical element object | //+------------------------------------------------------------------+ class CGCnvElement : public CGBaseObj { protected: CGCnvElement *m_element_main; // Pointer to the initial parent element within all the groups of bound objects CGCnvElement *m_element_base; // Pointer to the parent element within related objects of the current group CCanvas m_canvas; // CCanvas class object CPause m_pause; // Pause class object bool m_shadow; // Shadow presence color m_chart_color_bg; // Chart background color uint m_duplicate_res[]; // Array for storing resource data copy color m_array_colors_bg[]; // Array of element background colors color m_array_colors_bg_dwn[]; // Array of control background colors when clicking on the control color m_array_colors_bg_ovr[]; // Array of control background colors when hovering the mouse over the control bool m_gradient_v; // Vertical gradient filling flag bool m_gradient_c; // Cyclic gradient filling flag int m_init_relative_x; // Initial relative X coordinate int m_init_relative_y; // Initial relative Y coordinate //--- Create (1) the object structure and (2) the object from the structure virtual bool ObjectToStruct(void); virtual void StructToObject(void); private:
Wir haben eine Objektstruktur, die alle Eigenschaften eines erstellten grafischen Elements aufnimmt, um die Eigenschaften des Objekts anschließend auf dem Datenträger zu speichern und von dort zu lesen, um das Objekt beim Neustart des Terminals und des Programms wiederherzustellen.
Hinzufügen der Struktur alle neuen Eigenschaften:
private: int m_shift_coord_x; // Offset of the X coordinate relative to the base object int m_shift_coord_y; // Offset of the Y coordinate relative to the base object struct SData { //--- Object integer properties int id; // Element ID int type; // Graphical element type int belong; // Graphical element affiliation int number; // Element index in the list long chart_id; // Chart ID int subwindow; // Chart subwindow index int coord_x; // Element X coordinate on the chart int coord_y; // Element Y coordinate on the chart int width; // Element width int height; // Element height int edge_right; // Element right border int edge_bottom; // Element bottom border int act_shift_left; // Active area offset from the left edge of the element int act_shift_top; // Active area offset from the top edge of the element int act_shift_right; // Active area offset from the right edge of the element int act_shift_bottom; // Active area offset from the bottom edge of the element bool movable; // Element moveability flag bool active; // Element activity flag bool interaction; // Flag of interaction with the outside environment int coord_act_x; // X coordinate of the element active area int coord_act_y; // Y coordinate of the element active area int coord_act_right; // Right border of the element active area int coord_act_bottom; // Bottom border of the element active area long zorder; // Priority of a graphical object for receiving the event of clicking on a chart bool enabled; // Element availability flag color fore_color; // Default text color for all control objects uchar fore_color_opacity; // Default text color opacity for all control objects color background_color; // Control background color uchar background_color_opacity; // Non-transparency of control background color color background_color_mouse_down; // Control background color when clicking on the control color background_color_mouse_over; // Control background color when hovering the mouse over the control int bold_type; // Font width type int border_style; // Control frame style int border_size_top; // Control frame top size int border_size_bottom; // Control frame bottom size int border_size_left; // Control frame left size int border_size_right; // Control frame right size color border_color; // Control frame color color border_color_mouse_down; // Control frame color when clicking on the control color border_color_mouse_over; // Control frame color when hovering the mouse over the control bool autosize; // Flag of the element auto resizing depending on the content int autosize_mode; // Mode of the element auto resizing depending on the content bool autoscroll; // Auto scrollbar flag int autoscroll_margin_w; // Width of the field inside the element during auto scrolling int autoscroll_margin_h; // Height of the field inside the element during auto scrolling int dock_mode; // Mode of binding control borders to the container int margin_top; // Top margin between the fields of this and another control int margin_bottom; // Bottom margin between the fields of this and another control int margin_left; // Left margin between the fields of this and another control int margin_right; // Right margin between the fields of this and another control int padding_top; // Top margin inside the control int padding_bottom; // Bottom margin inside the control int padding_left; // Left margin inside the control int padding_right; // Right margin inside the control int text_align; // Text position within text label boundaries int check_align; // Position of the checkbox within control borders bool checked; // Control checkbox status int check_state; // Status of a control having a checkbox bool autocheck; // Auto change flag status when it is selected color check_background_color; // Color of control checkbox background color check_background_color_opacity; // Non-transparency of the control checkbox background color color check_background_color_mouse_down; // Color of control checkbox background when clicking on the control color check_background_color_mouse_over; // Color of control checkbox background when hovering the mouse over the control color check_fore_color; // Color of control checkbox frame color check_fore_color_opacity; // Non-transparency of the control checkbox frame color color check_fore_color_mouse_down; // Color of control checkbox frame when clicking on the control color check_fore_color_mouse_over; // Color of control checkbox frame when hovering the mouse over the control color check_flag_color; // Color of control checkbox color check_flag_color_opacity; // Non-transparency of the control checkbox color color check_flag_color_mouse_down; // Color of control checkbox when clicking on the control color check_flag_color_mouse_over; // Color of control checkbox when hovering the mouse over the control //--- Object real properties //--- Object string properties uchar name_obj[64]; // Graphical element object name uchar name_res[64]; // Graphical resource name uchar text[256]; // Graphical element text }; SData m_struct_obj; // Object structure uchar m_uchar_array[]; // uchar array of the object structure
Jetzt haben wir alle notwendigen Eigenschaftsfelder in der Struktur, um ein Objekt aus der Struktur ordnungsgemäß zu speichern und wiederherzustellen. Das Schreiben von Objekteigenschaften in Dateien wird erst viel später implementiert werden.
Aus dem „private“ Teile der Klasse entfernen wir die beiden Variablen für die Speicherung der Hintergrundfarbe und der Nicht-Transparenz, da die Werte dieser Variablen jetzt direkt in den Objekteigenschaften gespeichert werden:
ENUM_FRAME_ANCHOR m_text_anchor; // Current text alignment int m_text_x; // Text last X coordinate int m_text_y; // Text last Y coordinate color m_color_bg; // Element background color uchar m_opacity; // Element opacity //--- Return the index of the array the order's (1) double and (2) string properties are located at
Zuvor gab es eine SaveColorsBG-Methode zum Speichern einer Farbe in einem Array von Hintergrundfarben. Jetzt haben wir mehrere verschiedene Farbverläufe. Ihre Farben sind in Arrays zu speichern. Daher deklarieren wir die Methode, die das Farbarray in das angegebene Array der Hintergrundfarben kopiert und fügen zwei weitere Methoden zum Speichern von Hintergrundfarben mit Farbverläufen hinzu:
//--- Return the index of the array the order's (1) double and (2) string properties are located at int IndexProp(ENUM_CANV_ELEMENT_PROP_DOUBLE property) const { return(int)property-CANV_ELEMENT_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_CANV_ELEMENT_PROP_STRING property) const { return(int)property-CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_DOUBLE_TOTAL; } //--- Copy the color array to the specified background color array void CopyArraysColors(color &array_dst[],const color &array_src[],const string source); //--- Save the colors to the background color array void SaveColorsBG(color &colors[]) { this.CopyArraysColors(this.m_array_colors_bg,colors,DFUN); } void SaveColorsBGMouseDown(color &colors[]) { this.CopyArraysColors(this.m_array_colors_bg_dwn,colors,DFUN); } void SaveColorsBGMouseOver(color &colors[]) { this.CopyArraysColors(this.m_array_colors_bg_ovr,colors,DFUN); } public:
Die erste Methode kopiert die Farben aus dem Array, das an die Methode übergeben wurde, in das Array, das in den Methodenparametern angegeben ist, während die beiden anderen das an die Methoden übergebene Farbarray kopieren, und zwar in die entsprechenden Arrays der oben deklarierten Farbverläufe.
Im „public“ Abschnitt der Klasse aus der Methode, die ein grafisches Element erstellt, entfernen wir zwei Variablen aus den Eingaben, da sie in der Methode nicht verwendet werden:
bool Create(const long chart_id, const int wnd_num, const string name, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool redraw=false);
Wir fügen zwei Methoden hinzu, die die Flags zurückgeben, die anzeigen, ob das Objekt das Haupt- (main) und/ oder das Basisobjekt (base) ist:
//--- (1) Set and (2) return the pointer to the parent element within all groups of related objects void SetMain(CGCnvElement *element) { this.m_element_main=element; } CGCnvElement *GetMain(void) { return this.m_element_main; } //--- Return the flag indicating that the object is (1) main, (2) base bool IsMain(void) { return this.GetMain()==NULL; } bool IsBase(void) { return this.GetBase()==NULL; } //--- Return the pointer to a canvas object CCanvas *GetCanvasObj(void) { return &this.m_canvas; }
Die Methoden prüfen einfach, ob die Zeiger auf die Haupt- und Basisobjekte NULL sind.
Mit diesem Zeigerwert ist es entweder das Haupt- oder das Basisobjekt, denn wenn das Objekt an ein anderes gebunden ist, wird der Zeiger auf das Haupt- und das Basisobjekt in den Variablen gesetzt, die von den Methoden GetMain() und GetBase() zurückgegeben werden. Wenn also der Zeiger gleich NULL ist, ist das Objekt an kein anderes Objekt gebunden und kann entweder das Hauptobjekt für andere Objekte in der Hierarchie sein (das allererste in der Hierarchie der verwandten Objekte) oder das Basisobjekt (andere Objekte sind mit ihm verbunden, aber es ist nicht das Hauptobjekt selbst, da es wiederum mit einem anderen Objekt in der gemeinsamen Kette der gesamten Hierarchie verbunden ist).
Wir benennen die Methode, die die Hintergrundfarbe festlegt, um und fügen die Methoden für das Klicken oder das Bewegen des Mauszeigers über ein Objekt hinzu:
//--- (5) all shifts of the active area edges relative to the element, (6) opacity void SetActiveAreaLeftShift(const int value) { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,fabs(value)); } void SetActiveAreaRightShift(const int value) { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,fabs(value)); } void SetActiveAreaTopShift(const int value) { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,fabs(value)); } void SetActiveAreaBottomShift(const int value) { this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,fabs(value)); } void SetActiveAreaShift(const int left_shift,const int bottom_shift,const int right_shift,const int top_shift); void SetOpacity(const uchar value,const bool redraw=false); //--- Set the main background color void SetBackgroundColor(const color colour) { this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR,colour); color arr[1]; arr[0]=colour; this.SaveColorsBG(arr); } void SetBackgroundColors(color &colors[]) { this.SaveColorsBG(colors); this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR,this.m_array_colors_bg[0]); } //--- Set the background color when clicking on the control void SetBackgroundColorMouseDown(const color colour) { this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN,colour); color arr[1]; arr[0]=colour; this.SaveColorsBGMouseDown(arr); } void SetBackgroundColorsMouseDown(color &colors[]) { this.SaveColorsBGMouseDown(colors); this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN,this.m_array_colors_bg_dwn[0]); } //--- Set the background color when hovering the mouse over control void SetBackgroundColorMouseOver(const color colour) { this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER,colour); color arr[1]; arr[0]=colour; this.SaveColorsBGMouseOver(arr); } void SetBackgroundColorsMouseOver(color &colors[]) { this.SaveColorsBGMouseOver(colors); this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER,this.m_array_colors_bg_ovr[0]); } //--- Set (1) object movability, (2) activity, (3) interaction,
Anstatt Werte in gelöschte Variablen zu schreiben, schreiben wir jetzt Werte in Objekteigenschaften. Wir haben diese Methoden in früheren Artikeln behandelt. Es hat keinen Sinn, sie hier zu beschreiben.
In ähnlicher Weise ändern wir den Namen der Methoden, die die Werte der Hintergrundfarben zurückgeben und schreiben neue Methoden für die Rückgabe der Werte zusätzlicher Hintergrundfarben:
//--- Return the number of colors set for the gradient filling of the (1) main background, when clicking (2), (3) when hovering the mouse over the control uint BackgroundColorsTotal(void) const { return this.m_array_colors_bg.Size(); } uint BackgroundColorsMouseDownTotal(void)const { return this.m_array_colors_bg_dwn.Size(); } uint BackgroundColorsMouseOverTotal(void)const { return this.m_array_colors_bg_ovr.Size(); } //--- Return the main background color color BackgroundColor(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR); } color BackgroundColor(const uint index) const { uint total=this.m_array_colors_bg.Size(); if(total==0) return this.BackgroundColor(); return(index>total-1 ? this.m_array_colors_bg[total-1] : this.m_array_colors_bg[index]); } //--- Return the background color when clicking on the control color BackgroundColorMouseDown(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN); } color BackgroundColorMouseDown(const uint index) const { uint total=this.m_array_colors_bg_dwn.Size(); if(total==0) return this.BackgroundColorMouseDown(); return(index>total-1 ? this.m_array_colors_bg_dwn[total-1] : this.m_array_colors_bg_dwn[index]); } //--- Return the background color when hovering the mouse over the control color BackgroundColorMouseOver(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER); } color BackgroundColorMouseOver(const uint index) const { uint total=this.m_array_colors_bg_ovr.Size(); if(total==0) return this.BackgroundColorMouseOver(); return(index>total-1 ? this.m_array_colors_bg_ovr[total-1] : this.m_array_colors_bg_ovr[index]); } //--- Return (1) the opacity, coordinate (2) of the right and (3) bottom element edge uchar Opacity(void) const { return (uchar)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY); } int RightEdge(void) const { return this.CoordX()+this.m_canvas.Width(); } int BottomEdge(void) const { return this.CoordY()+this.m_canvas.Height(); }
Auch hier werden die in den Objekteigenschaften eingestellten Werte zurückgegeben und nicht die bereits entfernten Variablen. Ich habe diese Methoden bereits früher erörtert, sodass es keinen Sinn macht, sie hier zu wiederholen.
Die Methode ChartColorBackground() wird ebenfalls umbenannt (ebenso wie alle anderen, die Farbparameter zurückgeben und deren Namen nicht dem allgemeinen Prinzip der Konstruktion von Methodennamen folgen, die mit Farbe arbeiten):
//--- Return (1) the element ID, (2) element index in the list, (3) flag of the form shadow presence and (4) the chart background color int ID(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ID); } int Number(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_NUM); } bool IsShadow(void) const { return this.m_shadow; } color ChartBackgroundColor(void) const { return this.m_chart_color_bg; } //--- Set the object above all
Im parametrischen Konstruktor der Klasse ersetzen wir das Schreiben von Werten in Variablen durch den Aufruf der entsprechenden Methoden, fügen das Speichern der Hintergrundfarbe zu den Arrays mit den zusätzlichen Hintergrundfarben hinzu (wenn man auf das Objekt klickt und mit dem Mauszeiger darüber fährt) und initialisieren alle neuen Eigenschaften der grafischen Elemente mit den Standardwerten:
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, const int element_id, const int element_num, const long chart_id, const int wnd_num, const string name, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable=true, const bool activity=true, const bool redraw=false) : m_shadow(false) { this.m_type=OBJECT_DE_TYPE_GELEMENT; this.m_element_main=NULL; this.m_element_base=NULL; this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND); this.m_name=(::StringFind(name,this.m_name_prefix)<0 ? this.m_name_prefix : "")+name; this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id); this.m_subwindow=wnd_num; this.m_type_element=element_type; this.SetFont(DEF_FONT,DEF_FONT_SIZE); this.m_text_anchor=0; this.m_text_x=0; this.m_text_y=0; this.SetBackgroundColor(colour); this.SetOpacity(opacity); this.m_shift_coord_x=0; this.m_shift_coord_y=0; if(::ArrayResize(this.m_array_colors_bg,1)==1) this.m_array_colors_bg[0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1) this.m_array_colors_bg_dwn[0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1) this.m_array_colors_bg_ovr[0]=this.BackgroundColor(); if(this.Create(chart_id,wnd_num,this.m_name,x,y,w,h,redraw)) { this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,this.m_canvas.ResourceName()); // Graphical resource name this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,CGBaseObj::ChartID()); // Chart ID this.SetProperty(CANV_ELEMENT_PROP_WND_NUM,CGBaseObj::SubWindow()); // Chart subwindow index this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,CGBaseObj::Name()); // Element object name this.SetProperty(CANV_ELEMENT_PROP_TYPE,element_type); // Graphical element type this.SetProperty(CANV_ELEMENT_PROP_ID,element_id); // Element ID this.SetProperty(CANV_ELEMENT_PROP_NUM,element_num); // Element index in the list this.SetProperty(CANV_ELEMENT_PROP_COORD_X,x); // Element's X coordinate on the chart this.SetProperty(CANV_ELEMENT_PROP_COORD_Y,y); // Element's Y coordinate on the chart this.SetProperty(CANV_ELEMENT_PROP_WIDTH,w); // Element width this.SetProperty(CANV_ELEMENT_PROP_HEIGHT,h); // Element height this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,0); // Active area offset from the left edge of the element this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,0); // Active area offset from the upper edge of the element this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,0); // Active area offset from the right edge of the element this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,0); // Active area offset from the bottom edge of the element this.SetProperty(CANV_ELEMENT_PROP_MOVABLE,movable); // Element moveability flag this.SetProperty(CANV_ELEMENT_PROP_ACTIVE,activity); // Element activity flag this.SetProperty(CANV_ELEMENT_PROP_INTERACTION,false); // Flag of interaction with the outside environment this.SetProperty(CANV_ELEMENT_PROP_ENABLED,true); // Element availability flag this.SetProperty(CANV_ELEMENT_PROP_RIGHT,this.RightEdge()); // Element right border this.SetProperty(CANV_ELEMENT_PROP_BOTTOM,this.BottomEdge()); // Element bottom border this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_X,this.ActiveAreaLeft()); // X coordinate of the element active area this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y,this.ActiveAreaTop()); // Y coordinate of the element active area this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.ActiveAreaRight()); // Right border of the element active area this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.ActiveAreaBottom()); // Bottom border of the element active area //--- this.SetProperty(CANV_ELEMENT_PROP_BELONG,ENUM_GRAPH_OBJ_BELONG::GRAPH_OBJ_BELONG_PROGRAM); // Graphical element affiliation this.SetProperty(CANV_ELEMENT_PROP_ZORDER,0); // Priority of a graphical object for receiving the event of clicking on a chart this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN,this.BackgroundColor()); // Control background color when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER,this.BackgroundColor()); // Control background color when hovering the mouse over the control this.SetProperty(CANV_ELEMENT_PROP_BOLD_TYPE,FW_NORMAL); // Font width type this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,FRAME_STYLE_NONE); // Control frame style this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP,0); // Control frame top size this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM,0); // Control frame bottom size this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT,0); // Control frame left size this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT,0); // Control frame right size this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR,this.BackgroundColor()); // Control frame color this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN,this.BackgroundColor()); // Control frame color when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER,this.BackgroundColor()); // Control frame color when hovering the mouse over the control this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE,false); // Flag of the element auto resizing depending on the content this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE,CANV_ELEMENT_AUTO_SIZE_MODE_GROW); // Mode of the element auto resizing depending on the content this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL,false); // Auto scrollbar flag this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W,0); // Width of the field inside the element during auto scrolling this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H,0); // Height of the field inside the element during auto scrolling this.SetProperty(CANV_ELEMENT_PROP_DOCK_MODE,CANV_ELEMENT_DOCK_MODE_NONE); // Mode of binding control borders to the container this.SetProperty(CANV_ELEMENT_PROP_MARGIN_TOP,0); // Top margin between the fields of this and another control this.SetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM,0); // Bottom margin between the fields of this and another control this.SetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT,0); // Left margin between the fields of this and another control this.SetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT,0); // Right margin between the fields of this and another control this.SetProperty(CANV_ELEMENT_PROP_PADDING_TOP,0); // Top margin inside the control this.SetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM,0); // Bottom margin inside the control this.SetProperty(CANV_ELEMENT_PROP_PADDING_LEFT,0); // Left margin inside the control this.SetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT,0); // Right margin inside the control this.SetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN,ANCHOR_LEFT_UPPER); // Text position within text label boundaries this.SetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN,ANCHOR_LEFT_UPPER); // Position of the checkbox within control borders this.SetProperty(CANV_ELEMENT_PROP_CHECKED,false); // Control checkbox status this.SetProperty(CANV_ELEMENT_PROP_CHECK_STATE,CANV_ELEMENT_CHEK_STATE_UNCHECKED); // Status of a control having a checkbox this.SetProperty(CANV_ELEMENT_PROP_AUTOCHECK,true); // Auto change flag status when it is selected //--- this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR,CLR_DEF_CHECK_BACK_COLOR); // Color of control checkbox background this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY,CLR_DEF_CHECK_BACK_OPACITY); // Opacity of the control checkbox background color this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_BACK_MOUSE_DOWN);// Color of control checkbox background when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_OVER,CLR_DEF_CHECK_BACK_MOUSE_OVER);// Color of control checkbox background when hovering the mouse over the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR,CLR_DEF_CHECK_FORE_COLOR); // Color of control checkbox frame this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY,CLR_DEF_CHECK_FORE_OPACITY); // Opacity of the control checkbox frame color this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_FORE_MOUSE_DOWN); // Color of control checkbox frame when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_OVER,CLR_DEF_CHECK_FORE_MOUSE_OVER); // Color of control checkbox frame when hovering the mouse over the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR,CLR_DEF_CHECK_FLAG_COLOR); // Color of control checkbox this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY,CLR_DEF_CHECK_FLAG_OPACITY); // Opacity of the control checkbox color this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_FLAG_MOUSE_DOWN); // Color of control checkbox when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER,CLR_DEF_CHECK_FLAG_MOUSE_OVER); // Color of control checkbox when hovering the mouse over the control } else { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",this.m_name); } } //+------------------------------------------------------------------+
In den „protected“ Konstruktor schreiben wir alles auf dieselbe Weise. Die Änderungen sind fast dieselben wie in dem oben betrachteten Konstruktor, daher werde ich sie hier nicht berücksichtigen. Sie finden sie in den Dateien im Anhang zu diesem Artikel.
Die Methode zur Erstellung der Objektstruktur wurde ebenfalls verbessert, um die Werte neuer Objekteigenschaften in die Felder der Struktur zu schreiben (betrachten wir sie in ihrer Gesamtheit):
//+------------------------------------------------------------------+ //| Create the object structure | //+------------------------------------------------------------------+ bool CGCnvElement::ObjectToStruct(void) { //--- Save integer properties this.m_struct_obj.id=(int)this.GetProperty(CANV_ELEMENT_PROP_ID); // Element ID this.m_struct_obj.type=(int)this.GetProperty(CANV_ELEMENT_PROP_TYPE); // Graphical element type this.m_struct_obj.belong=(int)this.GetProperty(CANV_ELEMENT_PROP_BELONG); // Graphical element affiliation this.m_struct_obj.number=(int)this.GetProperty(CANV_ELEMENT_PROP_NUM); // Element ID in the list this.m_struct_obj.chart_id=this.GetProperty(CANV_ELEMENT_PROP_CHART_ID); // Chart ID this.m_struct_obj.subwindow=(int)this.GetProperty(CANV_ELEMENT_PROP_WND_NUM); // Chart subwindow index this.m_struct_obj.coord_x=(int)this.GetProperty(CANV_ELEMENT_PROP_COORD_X); // Form's X coordinate on the chart this.m_struct_obj.coord_y=(int)this.GetProperty(CANV_ELEMENT_PROP_COORD_Y); // Form's Y coordinate on the chart this.m_struct_obj.width=(int)this.GetProperty(CANV_ELEMENT_PROP_WIDTH); // Element width this.m_struct_obj.height=(int)this.GetProperty(CANV_ELEMENT_PROP_HEIGHT); // Element height this.m_struct_obj.edge_right=(int)this.GetProperty(CANV_ELEMENT_PROP_RIGHT); // Element right edge this.m_struct_obj.edge_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_BOTTOM); // Element bottom edge this.m_struct_obj.act_shift_left=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT); // Active area offset from the left edge of the element this.m_struct_obj.act_shift_top=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP); // Active area offset from the top edge of the element this.m_struct_obj.act_shift_right=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT); // Active area offset from the right edge of the element this.m_struct_obj.act_shift_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM); // Active area offset from the bottom edge of the element this.m_struct_obj.movable=(bool)this.GetProperty(CANV_ELEMENT_PROP_MOVABLE); // Element moveability flag this.m_struct_obj.active=(bool)this.GetProperty(CANV_ELEMENT_PROP_ACTIVE); // Element activity flag this.m_struct_obj.interaction=(bool)this.GetProperty(CANV_ELEMENT_PROP_INTERACTION); // Flag of interaction with the outside environment this.m_struct_obj.coord_act_x=(int)this.GetProperty(CANV_ELEMENT_PROP_COORD_ACT_X); // X coordinate of the element active area this.m_struct_obj.coord_act_y=(int)this.GetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y); // Y coordinate of the element active area this.m_struct_obj.coord_act_right=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_RIGHT); // Right border of the element active area this.m_struct_obj.coord_act_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM); // Bottom border of the element active area this.m_struct_obj.zorder=this.GetProperty(CANV_ELEMENT_PROP_ZORDER); // Priority of a graphical object for receiving the on-chart mouse click event this.m_struct_obj.enabled=(bool)this.GetProperty(CANV_ELEMENT_PROP_ENABLED); // Element availability flag this.m_struct_obj.fore_color=(color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR); // Default text color for all control objects this.m_struct_obj.fore_color_opacity=(uchar)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY); // Opacity of the default text color for all control objects this.m_struct_obj.background_color=(color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR); // Element background color this.m_struct_obj.background_color_opacity=(uchar)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY); // Element opacity this.m_struct_obj.background_color_mouse_down=(color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN);// Control background color when clicking on the control this.m_struct_obj.background_color_mouse_over=(color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER);// Control background color when hovering the mouse over the control this.m_struct_obj.bold_type=(int)this.GetProperty(CANV_ELEMENT_PROP_BOLD_TYPE); // Font width type this.m_struct_obj.border_style=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_STYLE); // Control frame style this.m_struct_obj.border_size_top=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP); // Control frame top size this.m_struct_obj.border_size_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM);// Control frame bottom size this.m_struct_obj.border_size_left=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT); // Control frame left size this.m_struct_obj.border_size_right=(int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT); // Control frame right size this.m_struct_obj.border_color=(color)this.GetProperty(CANV_ELEMENT_PROP_BORDER_COLOR); // Control frame color this.m_struct_obj.border_color_mouse_down=(color)this.GetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN);// Control frame color when clicking on the control this.m_struct_obj.border_color_mouse_over=(color)this.GetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER);// Control frame color when hovering the mouse over the control this.m_struct_obj.autosize=this.GetProperty(CANV_ELEMENT_PROP_AUTOSIZE); // Flag of the element auto resizing depending on the content this.m_struct_obj.autosize_mode=(int)this.GetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE); // Mode of the control auto resizing depending on the content this.m_struct_obj.autoscroll=this.GetProperty(CANV_ELEMENT_PROP_AUTOSCROLL); // Auto scrollbar flag this.m_struct_obj.autoscroll_margin_w=(int)this.GetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W); // Width of the field inside the element during auto scrolling this.m_struct_obj.autoscroll_margin_h=(int)this.GetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H); // Height of the field inside the element during auto scrolling this.m_struct_obj.dock_mode=(int)this.GetProperty(CANV_ELEMENT_PROP_DOCK_MODE); // Mode of binding control borders to the container this.m_struct_obj.margin_top=(int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_TOP); // Top margin between the fields of this and another control this.m_struct_obj.margin_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM); // Bottom margin between the fields of this and another control this.m_struct_obj.margin_left=(int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT); // Left margin between the fields of this and another control this.m_struct_obj.margin_right=(int)this.GetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT); // Right margin between the fields of this and another control this.m_struct_obj.padding_top=(int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_TOP); // Top margin inside the control this.m_struct_obj.padding_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM); // Bottom margin inside the control this.m_struct_obj.padding_left=(int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_LEFT); // Left margin inside the control this.m_struct_obj.padding_right=(int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT); // Right margin inside the control this.m_struct_obj.text_align=(int)this.GetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN); // Text position within text label boundaries this.m_struct_obj.check_align=(int)this.GetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN); // Position of the checkbox within control borders this.m_struct_obj.checked=(int)this.GetProperty(CANV_ELEMENT_PROP_CHECKED); // Control checkbox status this.m_struct_obj.check_state=(int)this.GetProperty(CANV_ELEMENT_PROP_CHECK_STATE); // Status of a control having a checkbox this.m_struct_obj.autocheck=(int)this.GetProperty(CANV_ELEMENT_PROP_AUTOCHECK); // Auto change flag status when it is selected this.m_struct_obj.check_background_color=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR); // Control checkbox background color this.m_struct_obj.check_background_color_opacity=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY); // Control checkbox background color opacity this.m_struct_obj.check_background_color_mouse_down=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN);// Control checkbox background color when clicking on the control this.m_struct_obj.check_background_color_mouse_over=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_OVER);// Control checkbox background color when hovering the mouse over the control this.m_struct_obj.check_fore_color=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR); // Control checkbox frame color this.m_struct_obj.check_fore_color_opacity=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY); // Control checkbox frame color opacity this.m_struct_obj.check_fore_color_mouse_down=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN); // Control checkbox frame color when clicking on the control this.m_struct_obj.check_fore_color_mouse_over=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_OVER); // Control checkbox frame color when hovering the mouse over the control this.m_struct_obj.check_flag_color=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR); // Control checkbox color this.m_struct_obj.check_flag_color_opacity=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY); // Control checkbox color opacity this.m_struct_obj.check_flag_color_mouse_down=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN); // Control checkbox color when clicking on the control this.m_struct_obj.check_flag_color_mouse_over=(color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER); // Control checkbox color when hovering the mouse over the control //--- Save real properties //--- Save string properties ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_OBJ),this.m_struct_obj.name_obj); // Graphical element object name ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_RES),this.m_struct_obj.name_res); // Graphical resource name ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TEXT),this.m_struct_obj.text); // Graphical element text //--- Save the structure to the uchar array ::ResetLastError(); if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY,true); return false; } return true; } //+------------------------------------------------------------------+
und ebenso wurde die Methode, die ein Objekt aus der Struktur erzeugt, abgeschlossen:
//+------------------------------------------------------------------+ //| Create the object from the structure | //+------------------------------------------------------------------+ void CGCnvElement::StructToObject(void) { //--- Save integer properties this.SetProperty(CANV_ELEMENT_PROP_ID,this.m_struct_obj.id); // Element ID this.SetProperty(CANV_ELEMENT_PROP_TYPE,this.m_struct_obj.type); // Graphical element type this.SetProperty(CANV_ELEMENT_PROP_BELONG,this.m_struct_obj.belong); // Graphical element affiliation this.SetProperty(CANV_ELEMENT_PROP_NUM,this.m_struct_obj.number); // Element index in the list this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,this.m_struct_obj.chart_id); // Chart ID this.SetProperty(CANV_ELEMENT_PROP_WND_NUM,this.m_struct_obj.subwindow); // Chart subwindow index this.SetProperty(CANV_ELEMENT_PROP_COORD_X,this.m_struct_obj.coord_x); // Form's X coordinate on the chart this.SetProperty(CANV_ELEMENT_PROP_COORD_Y,this.m_struct_obj.coord_y); // Form's Y coordinate on the chart this.SetProperty(CANV_ELEMENT_PROP_WIDTH,this.m_struct_obj.width); // Element width this.SetProperty(CANV_ELEMENT_PROP_HEIGHT,this.m_struct_obj.height); // Element height this.SetProperty(CANV_ELEMENT_PROP_RIGHT,this.m_struct_obj.edge_right); // Element right edge this.SetProperty(CANV_ELEMENT_PROP_BOTTOM,this.m_struct_obj.edge_bottom); // Element bottom edge this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,this.m_struct_obj.act_shift_left); // Active area offset from the left edge of the element this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,this.m_struct_obj.act_shift_top); // Active area offset from the upper edge of the element this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,this.m_struct_obj.act_shift_right); // Active area offset from the right edge of the element this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,this.m_struct_obj.act_shift_bottom); // Active area offset from the bottom edge of the element this.SetProperty(CANV_ELEMENT_PROP_MOVABLE,this.m_struct_obj.movable); // Element moveability flag this.SetProperty(CANV_ELEMENT_PROP_ACTIVE,this.m_struct_obj.active); // Element activity flag this.SetProperty(CANV_ELEMENT_PROP_INTERACTION,this.m_struct_obj.interaction); // Flag of interaction with the outside environment this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_X,this.m_struct_obj.coord_act_x); // X coordinate of the element active area this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y,this.m_struct_obj.coord_act_y); // Y coordinate of the element active area this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.m_struct_obj.coord_act_right); // Right border of the element active area this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.m_struct_obj.coord_act_bottom); // Bottom border of the element active area this.SetProperty(CANV_ELEMENT_PROP_ZORDER,this.m_struct_obj.zorder); // Priority of a graphical object for receiving the event of clicking on a chart this.SetProperty(CANV_ELEMENT_PROP_ENABLED,this.m_struct_obj.enabled); // Element availability flag this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,this.m_struct_obj.fore_color); // Default text color for all control objects this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,this.m_struct_obj.fore_color_opacity); // Opacity of the default text color for all control objects this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR,this.m_struct_obj.background_color); // Element background color this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY,this.m_struct_obj.background_color_opacity); // Element opacity this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN,this.m_struct_obj.background_color_mouse_down); // Control background color when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER,this.m_struct_obj.background_color_mouse_over); // Control background color when hovering the mouse over the control this.SetProperty(CANV_ELEMENT_PROP_BOLD_TYPE,this.m_struct_obj.bold_type); // Font width type this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,this.m_struct_obj.border_style); // Control frame style this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP,this.m_struct_obj.border_size_top); // Control frame top size this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM,this.m_struct_obj.border_size_bottom); // Control frame bottom size this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT,this.m_struct_obj.border_size_left); // Control frame left size this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT,this.m_struct_obj.border_size_right); // Control frame right size this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR,this.m_struct_obj.border_color); // Control frame color this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN,this.m_struct_obj.border_color_mouse_down);// Control frame color when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER,this.m_struct_obj.border_color_mouse_over);// Control frame color when hovering the mouse over the control this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE,this.m_struct_obj.autosize); // Flag of the element auto resizing depending on the content this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE,this.m_struct_obj.autosize_mode); // Mode of the element auto resizing depending on the content this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL,this.m_struct_obj.autoscroll); // Auto scrollbar flag this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W,this.m_struct_obj.autoscroll_margin_w); // Width of the field inside the element during auto scrolling this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H,this.m_struct_obj.autoscroll_margin_h); // Height of the field inside the element during auto scrolling this.SetProperty(CANV_ELEMENT_PROP_DOCK_MODE,this.m_struct_obj.dock_mode); // Mode of binding control borders to the container this.SetProperty(CANV_ELEMENT_PROP_MARGIN_TOP,this.m_struct_obj.margin_top); // Top margin between the fields of this and another control this.SetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM,this.m_struct_obj.margin_bottom); // Bottom margin between the fields of this and another control this.SetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT,this.m_struct_obj.margin_left); // Left margin between the fields of this and another control this.SetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT,this.m_struct_obj.margin_right); // Right margin between the fields of this and another control this.SetProperty(CANV_ELEMENT_PROP_PADDING_TOP,this.m_struct_obj.padding_top); // Top margin inside the control this.SetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM,this.m_struct_obj.padding_bottom); // Bottom margin inside the control this.SetProperty(CANV_ELEMENT_PROP_PADDING_LEFT,this.m_struct_obj.padding_left); // Left margin inside the control this.SetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT,this.m_struct_obj.padding_right); // Right margin inside the control this.SetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN,this.m_struct_obj.text_align); // Text position within text label boundaries this.SetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN,this.m_struct_obj.check_align); // Position of the checkbox within control borders this.SetProperty(CANV_ELEMENT_PROP_CHECKED,this.m_struct_obj.checked); // Control checkbox status this.SetProperty(CANV_ELEMENT_PROP_CHECK_STATE,this.m_struct_obj.check_state); // Status of a control having a checkbox this.SetProperty(CANV_ELEMENT_PROP_AUTOCHECK,this.m_struct_obj.autocheck); // Auto change flag status when it is selected this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR,this.m_struct_obj.check_background_color); // Color of control checkbox background this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY,this.m_struct_obj.check_background_color_opacity); // Opacity of the control checkbox background color this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN,this.m_struct_obj.check_background_color_mouse_down);// Color of control checkbox background when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_OVER,this.m_struct_obj.check_background_color_mouse_over);// Color of control checkbox background when hovering the mouse over the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR,this.m_struct_obj.check_fore_color); // Color of control checkbox frame this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY,this.m_struct_obj.check_fore_color_opacity); // Opacity of the control checkbox frame color this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN,this.m_struct_obj.check_fore_color_mouse_down); // Color of control checkbox frame when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_OVER,this.m_struct_obj.check_fore_color_mouse_over); // Color of control checkbox frame when hovering the mouse over the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR,this.m_struct_obj.check_flag_color); // Color of control checkbox this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY,this.m_struct_obj.check_flag_color_opacity); // Opacity of the control checkbox color this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN,this.m_struct_obj.check_flag_color_mouse_down); // Color of control checkbox when clicking on the control this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER,this.m_struct_obj.check_flag_color_mouse_over); // Color of control checkbox when hovering the mouse over the control //--- Save real properties //--- Save string properties this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,::CharArrayToString(this.m_struct_obj.name_obj)); // Graphical element object name this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,::CharArrayToString(this.m_struct_obj.name_res)); // Graphical resource name this.SetProperty(CANV_ELEMENT_PROP_TEXT,::CharArrayToString(this.m_struct_obj.text)); // Graphical element text } //+------------------------------------------------------------------+
Beide Methoden sind identisch, aber entgegengesetzt zueinander. Während bei der ersten Methode die entsprechenden Objekteigenschaften in den Strukturfeldern gesetzt werden, werden bei der zweiten Methode die Werte aus den entsprechenden Strukturfeldern in den Objekteigenschaften gesetzt.
Entfernen wir noch unbenutzte Variablen in der Implementierung der Methode, die ein grafisches Elementobjekt erzeugt:
//+------------------------------------------------------------------+ //| Create the graphical element object | //+------------------------------------------------------------------+ bool CGCnvElement::Create(const long chart_id, // Chart ID const int wnd_num, // Chart subwindow const string name, // Element name const int x, // X coordinate const int y, // Y coordinate const int w, // Width const int h, // Height const color colour, // Background color const uchar opacity, // Opacity const bool redraw=false) // Flag indicating the need to redraw { ::ResetLastError(); if(this.m_canvas.CreateBitmapLabel((chart_id==NULL ? ::ChartID() : chart_id),wnd_num,name,x,y,w,h,COLOR_FORMAT_ARGB_NORMALIZE)) { this.Erase(CLR_CANV_NULL); this.m_canvas.Update(redraw); this.m_shift_y=(int)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_WINDOW_YDISTANCE,wnd_num); return true; } CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //+------------------------------------------------------------------+
In der Methode, die die Deckkraft des Elements festlegt, wird anstelle der Zeichenkette der Deckkraftwert in der Variablen gespeichert,
this.m_opacity=value;
und es wird dessen Speicherung der Objekteigenschaft hinzugefügt:
//+------------------------------------------------------------------+ //| Set the element opacity | //+------------------------------------------------------------------+ void CGCnvElement::SetOpacity(const uchar value,const bool redraw=false) { this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY,value); this.m_canvas.TransparentLevelSet(value); this.m_canvas.Update(redraw); } //+------------------------------------------------------------------+
Implementierung der Methode, die das Farbfeld in das angegebene Hintergrundfarbfeld kopiert:
//+------------------------------------------------------------------+ //| Copy the color array to the specified background color array | //+------------------------------------------------------------------+ void CGCnvElement::CopyArraysColors(color &array_dst[],const color &array_src[],const string source) { if(array_dst.Size()!=array_src.Size()) { ::ResetLastError(); if(::ArrayResize(array_dst,array_src.Size())!=array_src.Size()) { CMessage::ToLog(source,MSG_LIB_SYS_FAILED_COLORS_ARRAY_RESIZE); CMessage::ToLog(::GetLastError(),true); return; } } ::ArrayCopy(array_dst,array_src); } //+------------------------------------------------------------------+
Die Methode empfängt das Array, in das wir alle Daten aus dem Quell-Array. Wenn die Array-Größen nicht übereinstimmen, passt das Ziel-Array seine Größe an die Größe des Quell-Arrays an. Dann wird der gesamte Inhalt des Quellarrays in das Zielarray kopiert.
Im Konstruktor der Schattenobjektklasse in \MQL5\Include\DoEasy\Objects\Graph\ShadowObj.mqh ändern wir die Namen der aufgerufenen Methoden:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CShadowObj::CShadowObj(const long chart_id, const int subwindow, const string name, const int x, const int y, const int w, const int h) : CGCnvElement(GRAPH_ELEMENT_TYPE_SHADOW_OBJ,chart_id,subwindow,name,x,y,w,h) { this.m_type=OBJECT_DE_TYPE_GSHADOW; CGCnvElement::SetBackgroundColor(clrNONE); CGCnvElement::SetOpacity(0); CGCnvElement::SetActive(false); this.m_opacity=CLR_DEF_SHADOW_OPACITY; this.m_blur=DEF_SHADOW_BLUR; color gray=CGCnvElement::ChangeColorSaturation(this.ChartBackgroundColor(),-100); this.m_color=CGCnvElement::ChangeColorLightness(gray,-50); this.m_shadow=false; this.m_visible=true; CGCnvElement::Erase(); } //+------------------------------------------------------------------+
Das Formularobjekt ist ein Objekt, das die Funktionsweisen für die Interaktion mit der Maus implementiert. Das Basisobjekt der WinForms-Bibliotheksobjekte ist sein Abkömmling. Wir müssen mehrere Methoden in der Formularobjektklassendatei \MQL5\Include\DoEasy\Objects\Graph\Form.mqh verbessern.
Die Methoden, die Farben behandeln, werden umbenannt und neue hinzugefügt. Die Methoden, die das Objekt "frame" behandeln, werden ebenfalls umbenannt. Sie werden „Border“ statt „Frame“ genannt. Darüber hinaus können andere Objekte an das Objekt angehängt werden, z.B. können Schaltflächen oder Texte auf dem Panel erstellt werden...
Wenn sich der Mauszeiger über einem solchen Feld befindet, ermittelt die Bibliothek derzeit, ob der Mauszeiger über dem Feld schwebt. Es ist jedoch nicht in der Lage zu definieren, ob sich der Cursor über einem Objekt befindet, das mit dem Bedienfeld verbunden ist. Dementsprechend gibt es keine Möglichkeit, mit dem an der Paneel befestigten Objekt zu interagieren.
Um dieses Problem zu lösen, müssen wir die Liste aller mit dem Bedienfeld verbundenen Objekte durchgehen und das jüngste Objekt in der Hierarchie ermitteln, über dem sich der Cursor befindet. Zu diesem Zweck erstellen wir eine Liste aller Objekte, die mit dem Paneel verbunden sind. Im Gegenzug können auch andere Objekte an das bereits angehängte Objekt gebunden werden. Das heißt, wir müssen mit einer Schleife die gesamte Hierarchie solcher Objekte durchgehen.
Dafür erstellen wir die Liste, die die Zeiger auf die angehängten Objekte enthalten soll. Nennen wir sie Interaktionsobjekte, da wir nach dem Objekt suchen, mit dem die Maus interagieren soll, und nach der Methode, die der Liste alle anderen Steuerelemente hinzufügt, die mit dem Objekt verbunden sind. Wenn das angehängte Element auch seine eigenen angehängten Objekte hat, wird dieselbe Methode dafür aufgerufen, während der Zeiger auf die Liste, in die die Zeiger geschrieben werden, an die Methode übergeben wird.
So können wir die gesamte Hierarchie der angehängten Objekte in einer Schleife durchlaufen und eine Liste von Zeigern auf sie erhalten. Danach wird es einfacher. Sobald wir feststellen, dass der Mauszeiger über dem Paneel schwebt, rufen wir die Methode des Panels auf, die eine Liste aller angehängten Objekte erstellt. Dann müssen wir nur noch das allererste Objekt am Ende der Liste finden, über dem sich die Flagge des Cursors befindet. Wir übergeben den Zeiger auf das gefundene Objekt zur weiteren Bearbeitung, da die leeren Handler bereits vor langer Zeit vorbereitet worden sind.
Entfernen der unnötigen Variablen aus dem Abschnitt über die geschützte Klasse:
protected: 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 CMouseState m_mouse; // "Mouse status" class object ENUM_MOUSE_FORM_STATE m_mouse_form_state; // Mouse status relative to the form ushort m_mouse_state_flags; // Mouse status flags color m_color_frame; // Form frame color int m_offset_x; // Offset of the X coordinate relative to the cursor int m_offset_y; // Offset of the Y coordinate relative to the cursor CArrayObj m_list_tmp; // List for storing the pointers 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 int m_init_x; // Newly created form X coordinate int m_init_y; // Newly created form Y coordinate int m_init_w; // Newly created form width int m_init_h; // Newly created form height //--- Initialize the variables
Anstelle der Variablen werden nun alle Werte in den Objekteigenschaften gespeichert.
Entfernen des Zeigers aus der Methode CreateAndAddNewElement() auf das Hauptobjekt der Hierarchie aller miteinander verbundenen Objekte:
//--- Create a new bound element and add it to the list of bound objects virtual CGCnvElement *CreateAndAddNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, CGCnvElement *main, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool activity); public:
Bisher mussten wir bei der Erstellung von angehängten Objekten explizit das Hauptobjekt für das zu erstellende Objekt angeben und den Zeiger darauf in den Methodenparametern übergeben. Jetzt stellen wir sicher, dass das Haupt- oder Basisobjekt in der Hierarchie automatisch bestimmt wird, was dem Endbenutzer die unnötige Angabe eines solchen Objekts beim Erstellen eines neuen angehängten Steuerelements erspart.
Ebenfalls im geschützten Abschnitt deklarieren wir die Methode zur Erstellung der Liste aller Interaktionsobjekte und die Methode, die das Objektpräsenzflag in der Liste durch ihren Namen zurückgibt:
//--- Create a new bound element and add it to the list of bound objects virtual CGCnvElement *CreateAndAddNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool activity); //--- Create the list of all interaction objects void CreateListDepInteractObj(CArrayObj *list); //--- Return the flag indicating the presence of the pointer to an object in the list of interaction objects by name bool IsPresentInteractObj(const string name); public:
Im „public“ Abschnitt deklarieren wir eine Methode, die eine Liste aller Interaktionsobjekte erstellt (allerdings ohne den Zeiger auf die Liste in den formalen Parametern der Methode zu übergeben), sowie die Methode, die den Zeiger auf das Formularobjekt in der Liste der Interaktionsobjekte nach seinem Index zurückgibt:
public: //--- Create the list of all interaction objects int CreateListInteractObj(void); //--- Return the pointer to the form object in the list of interaction objects CForm *GetInteractForm(const int index) { return this.m_list_interact.At(index); }
Die erste Methode wird von dem Objekt aufgerufen, über dem der Mauszeiger schwebt. Die geschützte Methode für die Suche nach den übrigen Interaktionsobjekten in der Hierarchie des Hauptobjekts ist innerhalb der Methode aufzurufen. Der Zeiger auf die Liste wird an jedes nachfolgende Objekt der Hierarchie weitergegeben, sodass in einer Liste des allerersten Objekts, auf das der Cursor gesetzt wurde, eine Liste von Zeigern auf alle mit ihm verbundenen Objekte enthalten ist.
Schreiben wir die Methoden, die alle Objektrahmenabmessungen aus ihren Eigenschaften zurückgeben und setzen:
//--- (1) Set and (2) return the shift of X and Y coordinates relative to the cursor void SetOffsetX(const int value) { this.m_offset_x=value; } void SetOffsetY(const int value) { this.m_offset_y=value; } int OffsetX(void) const { return this.m_offset_x; } int OffsetY(void) const { return this.m_offset_y; } //--- Return the frame size (1) to the left, (2) at the top, (3) to the right, (4) at the bottom and (5) on all sides int BorderSizeLeft(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT); } int BorderSizeTop(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP); } int BorderSizeRight(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT); } int BorderSizeBottom(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM);} //--- Set the frame size (1) to the left, (2) at the top, (3) to the right, (4) at the bottom and (5) on all sides void SetBorderSizeLeft(const uint value) { this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT,value); } void SetBorderSizeTop(const uint value) { this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP,value); } void SetBorderSizeRight(const uint value) { this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT,value); } void SetBorderSizeBottom(const uint value) { this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM,value); } //--- Update the coordinates (shift the canvas)
Fügen wir die Methode hinzu , die die Liste der Interaktionsobjekte zurückgibt und die Methode, die die Anzahl der Interaktionsobjekte in der erstellten Liste zurückgibt:
//--- Return (1) itself, the list of (2) attached objects, (3) the list of interaction objects and (4) shadow object CForm *GetObject(void) { return &this; } CArrayObj *GetListElements(void) { return &this.m_list_elements; } CArrayObj *GetListInteractObj(void) { return &this.m_list_interact; } CShadowObj *GetShadowObj(void) { return this.m_shadow_obj; } //--- Return the pointer to (1) the animation object, the list of (2) text and (3) rectangular 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); } //--- Return the number of (1) bound elements, (2) interaction objects and (3) the bound element by the index in the list int ElementsTotal(void) const { return this.m_list_elements.Total(); } int InteractTotal(void) const { return this.m_list_interact.Total(); } CGCnvElement *GetElement(const int index) { return this.m_list_elements.At(index); }
Aus der Methode, die ein neues angehängtes Element erstellt, entfernen wir die Übergabe des Zeigers an das Hauptobjekt:
//--- Create a new attached element virtual bool CreateNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, CGCnvElement *main, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool activity, const bool redraw); //--- Add a new attached element
Wir brauchen diesen Zeiger jetzt nicht mehr, da die Bibliothek selbst definiert, welches Objekt das Hauptobjekt und welches das Basisobjekt sein soll.
Benennen wir die Methoden zum Setzen und Zurückgeben der Formularrahmenfarbe um und fügen neue Methoden zur Behandlung zusätzlicher Formularhintergrundfarben hinzu:
//+------------------------------------------------------------------+ //| Methods of simplified access to object properties | //+------------------------------------------------------------------+ //--- (1) Set and (2) return the control frame color void SetBorderColor(const color colour) { this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR,colour); } color BorderColor(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_BORDER_COLOR); } //--- (1) Set and (2) return the control frame color when clicking the control void SetBorderColorMouseDown(const color colour) { this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN,colour); } color BorderColorMouseDown(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN); } //--- (1) Set and (2) return the control frame color when hovering the mouse over the control void SetBorderColorMouseOver(const color colour) { this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER,colour); } color BorderColorMouseOver(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER); }
Jetzt arbeiten die Methoden nicht mehr mit Variablen, sondern mit den Werten, die in den Objekteigenschaften gefunden werden.
In der Variableninitialisierungsmethode leeren wir die Liste der Interaktionsobjekte und setzen das Flag für sortierte Liste. Anstatt die Abmessungen des Formularrahmens in Variablen zu schreiben, setzen wir sie mit den oben beschriebenen neuen Methoden:
//+------------------------------------------------------------------+ //| Initialize the variables | //+------------------------------------------------------------------+ void CForm::Initialize(void) { this.m_list_elements.Clear(); this.m_list_elements.Sort(); this.m_list_interact.Clear(); this.m_list_interact.Sort(); this.m_list_tmp.Clear(); this.m_list_tmp.Sort(); this.m_shadow_obj=NULL; this.m_shadow=false; this.SetBorderSizeTop(DEF_FRAME_WIDTH_SIZE); this.SetBorderSizeBottom(DEF_FRAME_WIDTH_SIZE); this.SetBorderSizeLeft(DEF_FRAME_WIDTH_SIZE); this.SetBorderSizeRight(DEF_FRAME_WIDTH_SIZE); this.m_gradient_v=true; this.m_gradient_c=false; this.m_mouse_state_flags=0; this.m_offset_x=0; this.m_offset_y=0; this.m_init_x=0; this.m_init_y=0; this.m_init_w=0; this.m_init_h=0; CGCnvElement::SetInteraction(false); this.m_animations=new CAnimations(CGCnvElement::GetObject()); this.m_list_tmp.Add(this.m_animations); } //+------------------------------------------------------------------+
Zuvor haben wir für jedes erstellte Objekt nicht nur die tatsächlichen Koordinaten (im Koordinatensystem des Charts), sondern auch die relativen Koordinaten angegeben, d. h. den Abstand in Pixeln vom Ursprung der Koordinaten des Objekts, an das das erstellte Objekt angehängt ist. Wir haben einfach den Wert des Einzugs aus dem bei der Erstellung gesetzten Objektrand angegeben.
Dies ist nicht sehr effizient und erfordert eine ständige Überwachung dieser Koordinaten, falls sie sich ändern. Jetzt werden wir sie aus den Bildschirmkoordinaten berechnen, indem wir die Bildschirmkoordinate des gebundenen Objekts von der Bildschirmkoordinate des Basisobjekts abziehen. Auf diese Weise sind die relativen Koordinaten des gebundenen Objekts immer genau bekannt, unabhängig davon, ob sich seine Koordinaten ändern.
In der Methode zur Erstellung eines neuen grafischen Objekts werden die relativen Elementkoordinaten berechnet und festgelegt:
//+------------------------------------------------------------------+ //| Create a new graphical object | //+------------------------------------------------------------------+ CGCnvElement *CForm::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int obj_num, const string obj_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) { string name=this.CreateNameDependentObject(obj_name); CGCnvElement *element=NULL; //--- Depending on the created object type, switch(type) { //--- create a graphical element object case GRAPH_ELEMENT_TYPE_ELEMENT : element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),name,x,y,w,h,colour,opacity,movable,activity); break; //--- create a form object case GRAPH_ELEMENT_TYPE_FORM : element=new CForm(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; default: break; } if(element==NULL) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",name); element.SetMovable(movable); element.SetCoordXRelative(element.CoordX()-this.CoordX()); element.SetCoordYRelative(element.CoordY()-this.CoordY()); return element; } //+------------------------------------------------------------------+
In der Methode, die ein neues angehängtes Element erstellt und zur Liste der angehängten Objekte hinzufügt, ändern wir den Namen der Methode zur Einstellung des Objekthintergrunds, definieren und schreiben den Zeiger auf das Hauptobjekt der Hierarchie der angehängten Objekte und berechnen und setzen die relativen Koordinaten des erstellten angehängten Steuerelements:
//+------------------------------------------------------------------+ //| Create a new attached element | //| and add it to the list of bound objects | //+------------------------------------------------------------------+ CGCnvElement *CForm::CreateAndAddNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool activity) { //--- If the type of a created graphical element is less than the "element", inform of that and return 'false' if(element_type<GRAPH_ELEMENT_TYPE_ELEMENT) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_NOT_INTENDED),::StringSubstr(::EnumToString(element_type),19)); return NULL; } //--- Specify the element index in the list int num=this.m_list_elements.Total(); //--- Create a graphical element name string ns=(::StringLen((string)num)<2 ? ::IntegerToString(num,2,'0') : (string)num); string name="Elm"+ns; //--- Get the screen coordinates of the object relative to the coordinate system of the base object int elm_x=x; int elm_y=y; this.GetCoords(elm_x,elm_y); //--- Create a new graphical element CGCnvElement *obj=this.CreateNewGObject(element_type,num,name,elm_x,elm_y,w,h,colour,opacity,false,activity); if(obj==NULL) return NULL; //--- and add it to the list of bound graphical elements if(!this.AddNewElement(obj,elm_x,elm_y)) { delete obj; return NULL; } //--- Set the minimum properties for a bound graphical element obj.SetBackgroundColor(colour); obj.SetOpacity(opacity); obj.SetActive(activity); obj.SetMain(this.GetMain()==NULL ? this.GetObject() : this.GetMain()); obj.SetBase(this.GetObject()); obj.SetID(this.ID()); obj.SetNumber(num); obj.SetCoordXRelative(obj.CoordX()-this.CoordX()); obj.SetCoordYRelative(obj.CoordY()-this.CoordY()); obj.SetZorder(this.Zorder(),false); obj.SetCoordXRelativeInit(obj.CoordXRelative()); obj.SetCoordYRelativeInit(obj.CoordYRelative()); return obj; } //+------------------------------------------------------------------+
Wie definieren wir das Hauptobjekt der Hierarchie? Es ist ganz einfach: Wenn das Objekt mit keinem anderen verbunden ist, ist der Zeiger auf das Hauptobjekt zunächst gleich NULL. Wird aus einem solchen Objekt ein anderes, mit ihm verbundenes Steuerelement erstellt, so wird der Wert des Zeigers auf das Hauptobjekt daraufhin überprüft. Ist der Zeiger NULL, so ist das Steuerelement das Hauptobjekt. Andernfalls hat dieses Objekt bereits den Zeiger auf das Hauptobjekt der gesamten Hierarchie — schreiben wir ihn in das neu erstellte Steuerelement. Es wird also immer ein Hauptobjekt in der gesamten Hierarchie geben — das allererste, von dem die Erstellung der Hierarchie der angehängten Objekte ausging.
In der Methode zur Erstellung eines neuen angehängten Elements entfernen wir die Übergabe des Zeigers auf das Hauptobjekt und entfernen dementsprechend einen übermäßigen Wert, der an die Methode CreateAndAddNewElement() übergeben wurde:
//+------------------------------------------------------------------+ //| Create a new attached element | //+------------------------------------------------------------------+ bool CForm::CreateNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, CGCnvElement *main, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool activity, const bool redraw) { //--- Create a new graphical element CGCnvElement *obj=this.CreateAndAddNewElement(element_type,main,x,y,w,h,colour,opacity,activity); //--- If the object has been created, draw the added object and return 'true' if(obj==NULL) return false; obj.Erase(colour,opacity,redraw); return true; } //+------------------------------------------------------------------+
Da wir nun die Methoden haben, die die Breite des Objektrahmens zurückgeben, und diese Werte nicht in Variablen, sondern in den Objekteigenschaften gespeichert werden, ersetzen wir in der Methode, die die Anfangskoordinaten des gebundenen Objekts zurückgibt, den Zugriff auf die Variablen durch den Erhalt von Werten aus den neuen Methoden:
//+------------------------------------------------------------------+ //| Return the initial coordinates of a bound object | //+------------------------------------------------------------------+ void CForm::GetCoords(int &x,int &y) { x=this.CoordX()+this.BorderSizeLeft()+x; y=this.CoordY()+this.BorderSizeTop()+y; } //+------------------------------------------------------------------+
Wir ändern den Namen der aufgerufenen Methoden und ersetzen die Handhabung der Variablen durch die Handhabung der Objekteigenschaften:
//+------------------------------------------------------------------+ //| Set the color scheme | //+------------------------------------------------------------------+ void CForm::SetColorTheme(const ENUM_COLOR_THEMES theme,const uchar opacity) { if(this.m_shadow && this.m_shadow_obj!=NULL) this.SetColorShadow(array_color_themes[theme][COLOR_THEME_COLOR_FORM_SHADOW]); this.SetOpacity(opacity); this.SetBackgroundColor(array_color_themes[theme][COLOR_THEME_COLOR_FORM_BG]); this.SetBorderColor(array_color_themes[theme][COLOR_THEME_COLOR_FORM_FRAME]); } //+------------------------------------------------------------------+ //| Set the form style | //+------------------------------------------------------------------+ void CForm::SetFormStyle(const ENUM_FORM_STYLE style, const ENUM_COLOR_THEMES theme, const uchar opacity, const bool shadow=false, const bool use_bg_color=true, const bool redraw=false) { //--- Set opacity parameters and the size of the form frame side this.m_shadow=shadow; this.SetBorderSizeTop(array_form_style[style][FORM_STYLE_FRAME_WIDTH_TOP]); this.SetBorderSizeBottom(array_form_style[style][FORM_STYLE_FRAME_WIDTH_BOTTOM]); this.SetBorderSizeLeft(array_form_style[style][FORM_STYLE_FRAME_WIDTH_LEFT]); this.SetBorderSizeRight(array_form_style[style][FORM_STYLE_FRAME_WIDTH_RIGHT]); this.m_gradient_v=array_form_style[style][FORM_STYLE_GRADIENT_V]; this.m_gradient_c=array_form_style[style][FORM_STYLE_GRADIENT_C]; //--- Create the shadow object this.CreateShadowObj(clrNONE,(uchar)array_form_style[style][FORM_STYLE_FRAME_SHADOW_OPACITY]); //--- Set a color scheme this.SetColorTheme(theme,opacity); //--- Calculate a shadow color with color darkening color clr=array_color_themes[theme][COLOR_THEME_COLOR_FORM_SHADOW]; color gray=CGCnvElement::ChangeColorSaturation(this.ChartBackgroundColor(),-100); color color_shadow=CGCnvElement::ChangeColorLightness((use_bg_color ? gray : clr),-fabs(array_form_style[style][FORM_STYLE_DARKENING_COLOR_FOR_SHADOW])); this.SetColorShadow(color_shadow); //--- Draw a rectangular shadow int shift_x=array_form_style[style][FORM_STYLE_FRAME_SHADOW_X_SHIFT]; int shift_y=array_form_style[style][FORM_STYLE_FRAME_SHADOW_Y_SHIFT]; this.DrawShadow(shift_x,shift_y,color_shadow,this.OpacityShadow(),(uchar)array_form_style[style][FORM_STYLE_FRAME_SHADOW_BLUR]); //--- Fill in the form background with color and opacity this.Erase(this.m_array_colors_bg,this.Opacity(),this.m_gradient_v,this.m_gradient_c); //--- Depending on the selected form style, draw the corresponding form frame and the outer bounding frame switch(style) { case FORM_STYLE_BEVEL : this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),FRAME_STYLE_BEVEL); break; //---FORM_STYLE_FLAT default: this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),FRAME_STYLE_FLAT); break; } this.DrawRectangle(0,0,this.Width()-1,this.Height()-1,array_color_themes[theme][COLOR_THEME_COLOR_FORM_RECT_OUTER],this.Opacity()); } //+------------------------------------------------------------------+
Die Methode, die das Flag zurückgibt, das das Vorhandensein des Zeigers auf ein Objekt in der Liste der Interaktionsobjekte nach Namen anzeigt:
//+----------------------------------------------------------------------+ //| Return the flag indicating the presence of the pointer to an object | //| in the list of interaction objects by name | //+----------------------------------------------------------------------+ bool CForm::IsPresentInteractObj(const string name) { for(int i=0;i<this.InteractTotal();i++) { CForm *obj=this.GetInteractForm(i); if(obj==NULL) continue; if(obj.Name()==name) return true; } return false; } //+------------------------------------------------------------------+
In der Schleife durch die Liste der Interaktionsobjekte erhalten wir das nächste Formularobjekt. Wenn sein Name mit dem der Methode übergebenen Namen übereinstimmt, wird true zurückgegeben — das Objekt mit demselben Namen ist bereits in der Liste enthalten. Nach Beendigung der Schleife wird false zurückgegeben — das Objekt mit dem angegebenen Namen wurde nicht gefunden.
Die „protected“ Methode, die die Liste aller Interaktionsobjekte erstellt:
//+------------------------------------------------------------------+ //| Create the list of all interaction objects | //+------------------------------------------------------------------+ void CForm::CreateListDepInteractObj(CArrayObj *list) { for(int i=0;i<this.ElementsTotal();i++) { CForm *form=this.GetElement(i); if(form==NULL || form.TypeGraphElement()<GRAPH_ELEMENT_TYPE_FORM) continue; if(this.IsPresentInteractObj(form.Name())) continue; if(list.Add(form)) form.CreateListDepInteractObj(list); } } //+------------------------------------------------------------------+
In der Schleife über alle angehängten Objekte, holen wir uns das nächste Formularobjekt.
Wurde das Objekt nicht empfangen oder ist sein Typ kleiner als der des Formularobjekts, gehen wir zum nächsten Objekt über.
Wenn das Objekt mit demselben Namen bereits in der Liste vorhanden ist, gehen wir zum nächsten Objekt.
Wenn das Objekt erfolgreich in der Liste der Interaktionsobjekte platziert wurde, rufen wir die gleiche Methode für das Objekt auf, um nach Interaktionsobjekten zu suchen, die mit ihm verbunden sind.
Gleichzeitig erhält die Methode die in den Eingaben der Methode angegebene Liste.
Auf diese Weise werden die Zeiger auf alle Interaktionsobjekte der gesamten Hierarchie der angeschlossenen Objekte in einer Liste zusammengefasst.
Wir übergeben die Liste, die sich im Hauptobjekt befindet, und geben sie in der „public“ Methode an, die die Liste aller Interaktionsobjekte erstellt:
//+------------------------------------------------------------------+ //| Create the list of all interaction objects | //+------------------------------------------------------------------+ int CForm::CreateListInteractObj(void) { this.CreateListDepInteractObj(this.GetListInteractObj()); return this.m_list_interact.Total(); } //+------------------------------------------------------------------+
Hier ist alles ganz einfach: Wir rufen die obige Methode auf, um die Liste der Interaktionsobjekte zu erstellen, und übergeben ihr den Zeiger auf die Liste des aktuellen Objekts. Die Methode gibt die Anzahl der Zeiger auf die Interaktionsobjekte zurück, die der Liste hinzugefügt wurden.
Verbesserungen in \MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqh der Basisobjektklasse der WinForms-Objekte der Bibliothek.
Da wir die Variablen entfernt haben, die die Breite des Formularrahmens speichern, und sie durch Methoden in der Klassendatei des Formularobjekts ersetzt haben, müssen wir nun die jetzt unnötigen Methoden zum Setzen und Zurückgeben der Rahmenbreite in der Datei entfernen:
virtual void SetPadding(const int left,const int top,const int right,const int bottom) { this.SetPaddingLeft(left); this.SetPaddingTop(top); this.SetPaddingRight(right); this.SetPaddingBottom(bottom); } //--- Set the width of the element frame (1) to the left, (2) at the top, (3) to the right and (4) at the bottom virtual void SetFrameWidthLeft(const uint value) { this.m_frame_width_left=(int)value; } virtual void SetFrameWidthTop(const uint value) { this.m_frame_width_top=(int)value; } virtual void SetFrameWidthRight(const uint value) { this.m_frame_width_right=(int)value; } virtual void SetFrameWidthBottom(const uint value) { this.m_frame_width_bottom=(int)value; } virtual void SetFrameWidthAll(const uint value) { this.SetFrameWidthLeft(value); this.SetFrameWidthTop(value); this.SetFrameWidthRight(value); this.SetFrameWidthBottom(value); } virtual void SetFrameWidth(const uint left,const uint top,const uint right,const uint bottom) { this.SetFrameWidthLeft(left); this.SetFrameWidthTop(top); this.SetFrameWidthRight(right); this.SetFrameWidthBottom(bottom); } //--- Return the width of the element frame (1) to the left, (2) at the top, (3) to the right and (4) at the bottom int FrameWidthLeft(void) const { return this.m_frame_width_left; } int FrameWidthTop(void) const { return this.m_frame_width_top; } int FrameWidthRight(void) const { return this.m_frame_width_right; } int FrameWidthBottom(void) const { return this.m_frame_width_bottom; } //--- Return the gap (1) to the left, (2) at the top, (3) to the right and (4) at the bottom between the fields inside the control int PaddingLeft(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_LEFT); } int PaddingTop(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_TOP); } int PaddingRight(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT); } int PaddingBottom(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM); }
In den Methoden, die die Größe des Einzugs festlegen, ersetzen wir den Zugriff auf die Variablen durch das Abrufen der von den Methoden zurückgegebenen Werte:
//--- Set the gap (1) to the left, (2) at the top, (3) to the right, (4) at the bottom and (5) on all sides inside the control virtual void SetPaddingLeft(const uint value) { int padding=((int)value<this.BorderSizeLeft() ? this.BorderSizeLeft() : (int)value); this.SetProperty(CANV_ELEMENT_PROP_PADDING_LEFT,padding); } virtual void SetPaddingTop(const uint value) { int padding=((int)value<this.BorderSizeTop() ? this.BorderSizeTop() : (int)value); this.SetProperty(CANV_ELEMENT_PROP_PADDING_TOP,padding); } virtual void SetPaddingRight(const uint value) { int padding=((int)value<this.BorderSizeRight() ? this.BorderSizeRight() : (int)value); this.SetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT,padding); } virtual void SetPaddingBottom(const uint value) { int padding=((int)value<this.BorderSizeBottom() ? this.BorderSizeBottom() : (int)value); this.SetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM,padding); }
Wir ersetzen den Aufruf der alten Methoden FrameWidth durch die neuen Methoden BorderSize:
virtual void SetPadding(const int left,const int top,const int right,const int bottom) { this.SetPaddingLeft(left); this.SetPaddingTop(top); this.SetPaddingRight(right); this.SetPaddingBottom(bottom); } //--- Set the width of all sides of the element frame virtual void SetBorderSizeAll(const uint value) { this.SetBorderSizeLeft(value); this.SetBorderSizeTop(value); this.SetBorderSizeRight(value); this.SetBorderSizeBottom(value); } virtual void SetBorderSize(const uint left,const uint top,const uint right,const uint bottom) { this.SetBorderSizeLeft(left); this.SetBorderSizeTop(top); this.SetBorderSizeRight(right); this.SetBorderSizeBottom(bottom); } //--- Return the gap (1) to the left, (2) at the top, (3) to the right and (4) at the bottom between the fields inside the control
...
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //+------------------------------------------------------------------+ void CWinFormBase::Erase(const color colour,const uchar opacity,const bool redraw=false) { //--- Fill the element having the specified color and the redrawing flag CGCnvElement::Erase(colour,opacity,redraw); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE && redraw) this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),this.BorderStyle()); //--- Update the element having the specified redrawing flag this.Update(redraw); } //+------------------------------------------------------------------+ //| Clear the element with a gradient fill | //+------------------------------------------------------------------+ void CWinFormBase::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { //--- Fill the element having the specified color array and the redrawing flag CGCnvElement::Erase(colors,opacity,vgradient,cycle,redraw); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE && redraw) this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),this.BorderStyle()); //--- Update the element having the specified redrawing flag this.Update(redraw); } //+------------------------------------------------------------------+
Deklarieren wir die Methoden, die die Beschreibungen der Steuereigenschaften zurückgeben:
//--- Return the gap (1) to the left, (2) at the top, (3) to the right and (4) at the bottom between the fields inside the control int PaddingLeft(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_LEFT); } int PaddingTop(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_TOP); } int PaddingRight(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT); } int PaddingBottom(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM); } //--- Get description of an order's (1) integer, (2) real and (3) string property string GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_INTEGER property,bool only_prop=false); string GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_DOUBLE property,bool only_prop=false); string GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_STRING property,bool only_prop=false); //--- Return the description (1) of the control auto resizing depending on the content, //--- (2) mode of binding the control borders to the container, //--- (3) status of a control having a checkbox, //--- (4) font style, (5) font width type and (6) control frame style string AutoSizeModeDescription(void); string DockModeDescription(void); string CheckStateDescription(void); string FontStyleDescription(void); string FontBoldTypeDescription(void); string BorderStyleDescription(void); }; //+------------------------------------------------------------------+
Im Klassenkonstruktor ersetzen wir die Zuweisung von Werten an Variablen durch das Setzen von Eigenschaftswerten mit einer neuen Methode:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CWinFormBase::CWinFormBase(const long chart_id, const int subwindow, const string name, const int x, const int y, const int w, const int h) : CForm(chart_id,subwindow,name,x,y,w,h) { //--- Set the graphical element and library object types as a base WinForms object CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_BASE); CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_BASE); this.m_type=OBJECT_DE_TYPE_GWF_BASE; //--- Initialize all variables this.SetText(""); this.SetForeColor(CLR_DEF_FORE_COLOR); this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY); this.SetFontBoldType(FW_TYPE_NORMAL); this.SetMarginAll(0); this.SetPaddingAll(0); this.SetBorderSizeAll(0); this.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false); this.SetBorderStyle(FRAME_STYLE_NONE); this.SetAutoSize(false,false); CForm::SetCoordXInit(x); CForm::SetCoordYInit(y); CForm::SetWidthInit(w); CForm::SetHeightInit(h); this.m_shadow=false; this.m_gradient_v=true; this.m_gradient_c=false; } //+------------------------------------------------------------------+
Die Methode, die die Beschreibung des Schriftstils zurückgibt:
//+------------------------------------------------------------------+ //| Return the font style description | //+------------------------------------------------------------------+ string CWinFormBase::FontStyleDescription(void) { return ( this.FontDrawStyle()==FONT_STYLE_ITALIC ? CMessage::Text(MSG_LIB_TEXT_FONT_STYLE_ITALIC) : this.FontDrawStyle()==FONT_STYLE_UNDERLINE ? CMessage::Text(MSG_LIB_TEXT_FONT_STYLE_UNDERLINE) : this.FontDrawStyle()==FONT_STYLE_STRIKEOUT ? CMessage::Text(MSG_LIB_TEXT_FONT_STYLE_STRIKEOUT) : CMessage::Text(MSG_LIB_TEXT_FONT_STYLE_NORMAL) ); } //+------------------------------------------------------------------+
Je nach der angegebenen Schriftart wird die entsprechende Textmeldung zurückgegeben.
Die Methode, die die Breite des Schrifttyps zurückgibt:
//+------------------------------------------------------------------+ //| Return the font width type description | //+------------------------------------------------------------------+ string CWinFormBase::FontBoldTypeDescription(void) { uchar array[]; int total=StringToCharArray(EnumToString((ENUM_FW_TYPE)this.GetProperty(CANV_ELEMENT_PROP_BOLD_TYPE)),array,8); for(int i=1;i<total;i++) array[i]+=0x20; return CharArrayToString(array); } //+------------------------------------------------------------------+
Die Enumeration ENUM_FW_TYPE umfasst die folgenden Konstanten:
//+------------------------------------------------------------------+ //| FOnt width type list | //+------------------------------------------------------------------+ enum ENUM_FW_TYPE { FW_TYPE_DONTCARE=FW_DONTCARE, FW_TYPE_THIN=FW_THIN, FW_TYPE_EXTRALIGHT=FW_EXTRALIGHT, FW_TYPE_ULTRALIGHT=FW_ULTRALIGHT, FW_TYPE_LIGHT=FW_LIGHT, FW_TYPE_NORMAL=FW_NORMAL, FW_TYPE_REGULAR=FW_REGULAR, FW_TYPE_MEDIUM=FW_MEDIUM, FW_TYPE_SEMIBOLD=FW_SEMIBOLD, FW_TYPE_DEMIBOLD=FW_DEMIBOLD, FW_TYPE_BOLD=FW_BOLD, FW_TYPE_EXTRABOLD=FW_EXTRABOLD, FW_TYPE_ULTRABOLD=FW_ULTRABOLD, FW_TYPE_HEAVY=FW_HEAVY, FW_TYPE_BLACK=FW_BLACK }; //+------------------------------------------------------------------+
Im Falle des Breitentyps Regular müssen wir zum Beispiel eine Teilzeichenkette aus der Konstante FW_TYPE_REGULAR ab Position 8 nehmen. Nach dem Extrahieren der Teilzeichenkette aus dem Namen der Konstante erhalten wir die Zeichenfolge "REGULAR". Hier werden alle Zeichen in Großbuchstaben geschrieben. Jetzt müssen wir alle Zeichen klein schreiben, außer dem ersten Zeichen.
Dazu müssen wir nur den Offset von 32 (0x20) zum Symbolcode hinzufügen, da sich die Codes für Kleinbuchstaben von denen für Großbuchstaben um genau 32 unterscheiden. Die extrahierte Teilzeichenkette, die aus Großbuchstaben besteht, wird in das Array uchar eingetragen. Dann in der Schleife durch alle Zeichen im Array (für jeden Buchstaben), addieren wir 32 auf den Zeichenwert. Da das erste Zeichen (in Zelle 0 des Arrays) nicht geändert werden muss, beginnen wir die Schleife ab Zelle 1 des Arrays (ab dem zweiten Zeichen). Als Ergebnis wird das geänderte uchar-Array zurückgegeben, das in eine Zeichenkette zurückgewandelt wurde.
Die Methode liefert die Beschreibung des Kontrollrahmenstils:
//+------------------------------------------------------------------+ //| Return the description of the control frame style | //+------------------------------------------------------------------+ string CWinFormBase::BorderStyleDescription(void) { ENUM_FRAME_STYLE property=(ENUM_FRAME_STYLE)this.GetProperty(CANV_ELEMENT_PROP_BORDER_STYLE); return ( property==FRAME_STYLE_SIMPLE ? CMessage::Text(MSG_LIB_TEXT_FRAME_STYLE_SIMPLE) : property==FRAME_STYLE_FLAT ? CMessage::Text(MSG_LIB_TEXT_FRAME_STYLE_FLAT) : property==FRAME_STYLE_BEVEL ? CMessage::Text(MSG_LIB_TEXT_FRAME_STYLE_BEVEL) : property==FRAME_STYLE_STAMP ? CMessage::Text(MSG_LIB_TEXT_FRAME_STYLE_STAMP) : CMessage::Text(MSG_LIB_TEXT_FRAME_STYLE_NONE) ); } //+------------------------------------------------------------------+
Die zurückgegebene Textnachricht hängt von dem für das Objekt eingestellten Rahmenstil ab.
Die Methode liefert die Beschreibung der Integer-Eigenschaft des Steuerelements:
//+------------------------------------------------------------------+ //| Return the description of the control integer property | //+------------------------------------------------------------------+ string CWinFormBase::GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_INTEGER property,bool only_prop=false) { return ( property==CANV_ELEMENT_PROP_ID ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ID)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_TYPE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_TYPE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.TypeElementDescription() ) : property==CANV_ELEMENT_PROP_BELONG ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BELONG)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.BelongDescription() ) : property==CANV_ELEMENT_PROP_NUM ? CMessage::Text(MSG_CANV_ELEMENT_PROP_NUM)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_CHART_ID ? CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_ID)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_WND_NUM ? CMessage::Text(MSG_GRAPH_OBJ_PROP_WND_NUM)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_COORD_X ? CMessage::Text(MSG_CANV_ELEMENT_PROP_COORD_X)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_COORD_Y ? CMessage::Text(MSG_CANV_ELEMENT_PROP_COORD_Y)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_WIDTH ? CMessage::Text(MSG_CANV_ELEMENT_PROP_WIDTH)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_HEIGHT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_HEIGHT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_RIGHT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_RIGHT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_BOTTOM ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BOTTOM)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ACT_SHIFT_LEFT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ACT_SHIFT_LEFT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ACT_SHIFT_TOP ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ACT_SHIFT_TOP)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_MOVABLE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_MOVABLE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)(bool)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ACTIVE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ACTIVE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)(bool)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_INTERACTION ? CMessage::Text(MSG_CANV_ELEMENT_PROP_INTERACTION)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)(bool)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_COORD_ACT_X ? CMessage::Text(MSG_CANV_ELEMENT_PROP_COORD_ACT_X)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_COORD_ACT_Y ? CMessage::Text(MSG_CANV_ELEMENT_PROP_COORD_ACT_Y)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ACT_RIGHT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ACT_RIGHT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ACT_BOTTOM ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ACT_BOTTOM)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ZORDER ? CMessage::Text(MSG_GRAPH_OBJ_PROP_ZORDER)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ENABLED ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ENABLED)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)(bool)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_FORE_COLOR ? CMessage::Text(MSG_CANV_ELEMENT_PROP_FORE_COLOR)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+ColorToString((color)this.GetProperty(property),true) ) : property==CANV_ELEMENT_PROP_FORE_COLOR_OPACITY ? CMessage::Text(MSG_CANV_ELEMENT_PROP_FORE_COLOR_OPACITY)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_BACKGROUND_COLOR ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+ColorToString((color)this.GetProperty(property),true) ) : property==CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_DOWN)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+ColorToString((color)this.GetProperty(property),true) ) : property==CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+ColorToString((color)this.GetProperty(property),true) ) : property==CANV_ELEMENT_PROP_BOLD_TYPE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BOLD_TYPE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+FontBoldTypeDescription() ) : property==CANV_ELEMENT_PROP_BORDER_STYLE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BORDER_STYLE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+BorderStyleDescription() ) : property==CANV_ELEMENT_PROP_BORDER_SIZE_TOP ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BORDER_SIZE_TOP)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_BORDER_SIZE_LEFT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BORDER_SIZE_LEFT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_BORDER_COLOR ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BORDER_COLOR)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+ColorToString((color)this.GetProperty(property),true) ) : property==CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+ColorToString((color)this.GetProperty(property),true) ) : property==CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER ? CMessage::Text(MSG_CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+ColorToString((color)this.GetProperty(property),true) ) : property==CANV_ELEMENT_PROP_AUTOSIZE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_AUTOSIZE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)(bool)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_AUTOSIZE_MODE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_AUTOSIZE_MODE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.AutoSizeModeDescription() ) : property==CANV_ELEMENT_PROP_AUTOSCROLL ? CMessage::Text(MSG_CANV_ELEMENT_PROP_AUTOSCROLL)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)(bool)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W ? CMessage::Text(MSG_CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H ? CMessage::Text(MSG_CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_DOCK_MODE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_DOCK_MODE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.DockModeDescription() ) : property==CANV_ELEMENT_PROP_MARGIN_TOP ? CMessage::Text(MSG_CANV_ELEMENT_PROP_MARGIN_TOP)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_MARGIN_BOTTOM ? CMessage::Text(MSG_CANV_ELEMENT_PROP_MARGIN_BOTTOM)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_MARGIN_LEFT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_MARGIN_LEFT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_MARGIN_RIGHT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_MARGIN_RIGHT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_PADDING_TOP ? CMessage::Text(MSG_CANV_ELEMENT_PROP_PADDING_TOP)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_PADDING_BOTTOM ? CMessage::Text(MSG_CANV_ELEMENT_PROP_PADDING_BOTTOM)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_PADDING_LEFT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_PADDING_LEFT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_PADDING_RIGHT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_PADDING_RIGHT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_TEXT_ALIGN ? CMessage::Text(MSG_CANV_ELEMENT_PROP_TEXT_ALIGN)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+AnchorForGraphicsObjDescription((ENUM_ANCHOR_POINT)this.GetProperty(property)) ) : property==CANV_ELEMENT_PROP_CHECK_ALIGN ? CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_ALIGN)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+AnchorForGraphicsObjDescription((ENUM_ANCHOR_POINT)this.GetProperty(property)) ) : property==CANV_ELEMENT_PROP_CHECKED ? CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECKED)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)(bool)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_CHECK_STATE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_STATE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.CheckStateDescription() ) : property==CANV_ELEMENT_PROP_AUTOCHECK ? CMessage::Text(MSG_CANV_ELEMENT_PROP_AUTOCHECK)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)(bool)this.GetProperty(property) ) : "" ); } //+------------------------------------------------------------------+
Die Eigenschaft des Objekts Integer wird an die Methode übergeben. Die Zeichenkette, die von der Methode zurückgegeben wird, hängt von der Eigenschaft ab, die der Methode übergeben wird, sowie von dem Flag, das angibt, dass das Objekt die Eigenschaft beibehält. Ähnliche Methoden gibt es in fast jedem Objekt der Bibliothek, und es macht keinen Sinn, sie hier noch einmal zu besprechen. Bislang unterstützt jedes grafische Element alle Eigenschaften von grafischen Elementen. Ich werde die Methoden hinzufügen, die die Flags für die Aufrechterhaltung einer bestimmten Eigenschaft der grafischen Elemente zu WinForms-Objekte, während es möglich ist, die visuelle Kontrolle über die Werte dieser Eigenschaften und Werkzeuge für die Änderung von ihnen über die Maus oder Tastatur, nach der Erstellung der meisten der WinForms-Objekte und ihre Interaktivität Funktionalität.
Die Methode, die die Beschreibung der Real-Eigenschaft des Steuerelements zurückgibt:
//+------------------------------------------------------------------+ //| Return the description of the control real property | //+------------------------------------------------------------------+ string CWinFormBase::GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_DOUBLE property,bool only_prop=false) { return(""); } //+------------------------------------------------------------------+
Da wir noch keine echten Eigenschaften für grafische Elemente haben, gibt die Methode eine leere Zeichenkette zurück.
Die Methode, die die Beschreibung einer String-Eigenschaft eines Elements zurückgibt:
//+------------------------------------------------------------------+ //| Return the description of the control string property | //+------------------------------------------------------------------+ string CWinFormBase::GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_STRING property,bool only_prop=false) { return ( property==CANV_ELEMENT_PROP_NAME_OBJ ? CMessage::Text(MSG_CANV_ELEMENT_PROP_NAME_OBJ)+": \""+this.GetProperty(property)+"\"" : property==CANV_ELEMENT_PROP_NAME_RES ? CMessage::Text(MSG_CANV_ELEMENT_PROP_NAME_RES)+": \""+this.GetProperty(property)+"\"" : property==CANV_ELEMENT_PROP_TEXT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_TEXT)+": \""+this.GetProperty(property)+"\"" : "" ); } //+------------------------------------------------------------------+
Eine String-Eigenschaft des Objekts wird an die Methode übergeben. Je nach der an die Methode übergebenen Eigenschaft wird die von der Methode zurückgegebene Zeichenkette konstruiert.
Die Methode liefert die Beschreibung der automatischen Größenänderung des Steuerelements in Abhängigkeit vom Inhalt:
//+------------------------------------------------------------------+ //| Return the description of the mode for auto | //| resizing the control to fit the content | //+------------------------------------------------------------------+ string CWinFormBase::AutoSizeModeDescription(void) { return ( this.GetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE)==CANV_ELEMENT_AUTO_SIZE_MODE_GROW ? CMessage::Text(MSG_LIB_TEXT_AUTO_SIZE_MODE_GROW) : CMessage::Text(MSG_LIB_TEXT_AUTO_SIZE_MODE_GROW_SHRINK) ); } //+------------------------------------------------------------------+
Je nach Modus der automatischen Größenänderung des Steuerelements wird die entsprechende Textmeldung zurückgegeben.
Die Methode gibt die Beschreibung des Modus für die Bindung der Elementränder an den Container zurück:
//+-------------------------------------------------------------------------------------+ //| Return the description of the mode for binding the element borders to the container | //+-------------------------------------------------------------------------------------+ string CWinFormBase::DockModeDescription(void) { return ( this.GetProperty(CANV_ELEMENT_PROP_DOCK_MODE)==CANV_ELEMENT_DOCK_MODE_TOP ? CMessage::Text(MSG_LIB_TEXT_DOCK_MODE_TOP) : this.GetProperty(CANV_ELEMENT_PROP_DOCK_MODE)==CANV_ELEMENT_DOCK_MODE_BOTTOM ? CMessage::Text(MSG_LIB_TEXT_DOCK_MODE_BOTTOM) : this.GetProperty(CANV_ELEMENT_PROP_DOCK_MODE)==CANV_ELEMENT_DOCK_MODE_LEFT ? CMessage::Text(MSG_LIB_TEXT_DOCK_MODE_LEFT) : this.GetProperty(CANV_ELEMENT_PROP_DOCK_MODE)==CANV_ELEMENT_DOCK_MODE_RIGHT ? CMessage::Text(MSG_LIB_TEXT_DOCK_MODE_RIGHT) : this.GetProperty(CANV_ELEMENT_PROP_DOCK_MODE)==CANV_ELEMENT_DOCK_MODE_FILL ? CMessage::Text(MSG_LIB_TEXT_DOCK_MODE_FILL) : CMessage::Text(MSG_LIB_TEXT_DOCK_MODE_NONE) ); } //+------------------------------------------------------------------+
Je nach dem Modus der Rahmenbindung wird die entsprechende Textmeldung zurückgegeben.
Die Methode liefert die Beschreibung des Zustands eines Steuerelements mit einem Kontrollkästchen:
//+------------------------------------------------------------------+ //| Return the status description | //| of a control featuring the checkbox | //+------------------------------------------------------------------+ string CWinFormBase::CheckStateDescription(void) { return ( this.GetProperty(CANV_ELEMENT_PROP_CHECK_STATE)==CANV_ELEMENT_CHEK_STATE_CHECKED ? CMessage::Text(MSG_LIB_TEXT_CHEK_STATE_CHECKED) : this.GetProperty(CANV_ELEMENT_PROP_CHECK_STATE)==CANV_ELEMENT_CHEK_STATE_INDETERMINATE ? CMessage::Text(MSG_LIB_TEXT_CHEK_STATE_INDETERMINATE) : CMessage::Text(MSG_LIB_TEXT_CHEK_STATE_UNCHECKED) ); } //+------------------------------------------------------------------+
Je nach Status des Kontrollkästchens wird die entsprechende Textnachricht zurückgegeben.
Kleinere Verbesserungen in \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\CommonBase.mqh der Basisobjektklasse der Standardsteuerungen von WinForms-Objekten.
Wir ändern den Typ der Methode, die automatisch die Breite und Höhe eines Steuerelements festlegt, von void auf bool. Für jedes abgeleitete Objekt kann die Implementierung der Methode unterschiedlich sein. Wenn es also notwendig ist, die Logik dieser Methode zu ändern, wird sie in verschiedenen Klassen auf ihre eigene Weise neu definiert. Aber sie sollte in der Lage sein, das Ergebnis ihrer Arbeit zurückzugeben. Wenn das Objekt seine Größe nicht ändert, muss die Methode in der Klasse nicht neu definiert werden. Hier gibt sie einfach true zurück, ohne etwas zu tun:
//+------------------------------------------------------------------+ //| Class of the base WForms standard control object | //+------------------------------------------------------------------+ class CCommonBase : public CWinFormBase { private: protected: //--- Set the element width and height automatically virtual bool AutoSetWH(void) { return true; } //--- Initialize the variables virtual void Initialize(void); public:
In der Variableninitialisierungsmethode ersetzen wir das Setzen von Werten für die Rahmenbreite auf Variablen durch das Setzen der Werte mit der Methode und benennen die Methode zum Setzen der Hintergrundfarbe um:
//+------------------------------------------------------------------+ //| Initialize the variables | //+------------------------------------------------------------------+ void CCommonBase::Initialize(void) { //--- Clear all object lists and set sorted list flags for them this.m_list_elements.Clear(); this.m_list_elements.Sort(); this.m_list_tmp.Clear(); this.m_list_tmp.Sort(); //--- Standard control has no shadow object this.m_shadow_obj=NULL; this.m_shadow=false; //--- The width of the object frame on each side is 1 pixel by default this.SetBorderSizeAll(1); //--- The object does not have a gradient filling (neither vertical, nor horizontal) this.m_gradient_v=false; this.m_gradient_c=false; //--- Reset all "working" flags and variables this.m_mouse_state_flags=0; this.m_offset_x=0; this.m_offset_y=0; CGCnvElement::SetInteraction(false); //--- Create an animation object and add it to the list for storing such objects this.m_animations=new CAnimations(CGCnvElement::GetObject()); this.m_list_tmp.Add(this.m_animations); //--- Set the transparent color for the object background this.SetBackgroundColor(CLR_CANV_NULL); this.SetOpacity(0); //--- Set the default color and text opacity, as well as the absence of the object frame this.SetForeColor(CLR_DEF_FORE_COLOR); this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY); this.SetBorderStyle(FRAME_STYLE_NONE); //--- Set the default text parameters this.SetFont(DEF_FONT,DEF_FONT_SIZE); this.SetText(""); this.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP); this.SetTextAlign(ANCHOR_LEFT_UPPER); //--- Set the default object parameters this.SetAutoSize(false,false); this.SetMarginAll(3); this.SetPaddingAll(0); this.SetEnabled(true); this.SetVisible(true,false); } //+------------------------------------------------------------------+
Umbenennen der Methoden, die die Werte für die Rahmenbreite zurückgeben:
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //+------------------------------------------------------------------+ void CCommonBase::Erase(const color colour,const uchar opacity,const bool redraw=false) { //--- Fill the element having the specified color and the redrawing flag CGCnvElement::Erase(colour,opacity,redraw); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE && redraw) this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),255,this.BorderStyle()); //--- Update the element having the specified redrawing flag this.Update(redraw); } //+------------------------------------------------------------------+ //| Clear the element with a gradient fill | //+------------------------------------------------------------------+ void CCommonBase::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { //--- Fill the element having the specified color array and the redrawing flag CGCnvElement::Erase(colors,opacity,vgradient,cycle,redraw); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE && redraw) this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),255,this.BorderStyle()); //--- Update the element having the specified redrawing flag this.Update(redraw); } //+------------------------------------------------------------------+
Die Objektklasse der Textetiketten \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\Label.mqh enthält die Methode zur Berechnung der Etikettenkoordinaten in Abhängigkeit vom Textankerpunkt und der Ausrichtung. All dies wird in der Methode zum Neuzeichnen von Objekten durchgeführt. Dies ist nicht optimal, da viele Objekte, die von dieser Klasse geerbt werden, auch die Positionierung der Beschriftung benötigen können. Daher werden wir die Berechnung der Textkoordinaten aus der Methode zum Neuzeichnen von Textbeschriftungen in eine neue Methode übertragen und diese bei Bedarf aufrufen, und zwar nicht nur in der Objektklasse Textbeschriftung, sondern auch in ihren Nachfolgern.
Im „protected“ Teile der Klasse ändern wir den Typ der Methode zur automatischen Größenanpassung des Steuerelements und deklarieren die Methode, die die Koordinaten und den Textankerpunkt in Abhängigkeit vom Ausrichtungsmodus setzt, während wir im „puiblic“ Abschnitt der Klasse die Methode deklarieren, die das Flag zur automatischen Größenanpassung des Steuerelements in Abhängigkeit vom Inhalt setzt:
//+------------------------------------------------------------------+ //| Label object class of WForms controls | //+------------------------------------------------------------------+ class CLabel : public CCommonBase { private: protected: //--- Set the element width and height automatically virtual bool AutoSetWH(void); //--- Set the text coordinates and anchor point depending on its alignment mode void SetTextParamsByAlign(int &x,int &y); public: //--- Redraw the object virtual void Redraw(bool redraw); //--- Set the element text virtual void SetText(const string text) { CWinFormBase::SetText(text); if(this.AutoSize()) this.AutoSetWH(); } //--- Set the flag of the element auto resizing depending on the content virtual void SetAutoSize(const bool flag,const bool redraw); //--- Constructor
Da die Methode zur Berechnung der Textkoordinaten nun in eine separate Methode ausgelagert wurde, ist die Methode zum Neuzeichnen von Objekten kürzer geworden:
//+------------------------------------------------------------------+ //| Redraw the object | //+------------------------------------------------------------------+ void CLabel::Redraw(bool redraw) { //--- Fill the object with the background color having full transparency this.Erase(this.BackgroundColor(),0,true); //--- Declare the variables for X and Y coordinates and set their values depending on the text alignment int x=0,y=0; this.SetTextParamsByAlign(x,y); //--- Draw the text within the set coordinates of the object and the binding point of the text, and update the object this.Text(x,y,this.Text(),this.ForeColor(),this.ForeColorOpacity(),this.TextAnchor()); this.Update(redraw); } //+------------------------------------------------------------------+
Die Methode setzt die Textkoordinaten und den Ankerpunkt je nach Ausrichtungsmodus:
//+------------------------------------------------------------------+ //| Set the text coordinates and anchor point | //| depending on its alignment mode | //+------------------------------------------------------------------+ void CLabel::SetTextParamsByAlign(int &x,int &y) { //--- Depending on the element text alignment type switch(this.TextAlign()) { //--- The text is displayed in the upper left corner of the object case ANCHOR_LEFT_UPPER : //--- Set the text binding point coordinate x=this.BorderSizeLeft(); y=this.BorderSizeTop(); //--- Set the text binding point at the top left this.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP); break; //--- The text is drawn vertically from the left side of the object in the center case ANCHOR_LEFT : //--- Set the text binding point coordinate x=this.BorderSizeLeft(); y=this.Height()/2; //--- Set the text binding point at the center left this.SetTextAnchor(FRAME_ANCHOR_LEFT_CENTER); break; //--- The text is displayed in the lower left corner of the object case ANCHOR_LEFT_LOWER : //--- Set the text binding point coordinate x=this.BorderSizeLeft(); y=this.Height()-this.BorderSizeBottom(); //--- Set the text binding point at the bottom left this.SetTextAnchor(FRAME_ANCHOR_LEFT_BOTTOM); break; //--- The text is drawn at the center of the bottom edge of the object case ANCHOR_LOWER : //--- Set the text binding point coordinate x=this.Width()/2; y=this.Height()-this.BorderSizeBottom(); //--- Set the text anchor point at the bottom center this.SetTextAnchor(FRAME_ANCHOR_CENTER_BOTTOM); break; //--- The text is displayed in the lower right corner of the object case ANCHOR_RIGHT_LOWER : //--- Set the text binding point coordinate x=this.Width()-this.BorderSizeRight(); y=this.Height()-this.BorderSizeBottom(); //--- Set the text binding point at the bottom right this.SetTextAnchor(FRAME_ANCHOR_RIGHT_BOTTOM); break; //--- The text is drawn vertically from the right side of the object in the center case ANCHOR_RIGHT : //--- Set the text binding point coordinate x=this.Width()-this.BorderSizeRight(); y=this.Height()/2; //--- Set the text binding point at the center right this.SetTextAnchor(FRAME_ANCHOR_RIGHT_CENTER); break; //--- The text is displayed in the upper right corner of the object case ANCHOR_RIGHT_UPPER : //--- Set the text binding point coordinate x=this.Width()-this.BorderSizeRight(); y=this.BorderSizeTop(); //--- Set the text binding point at the top right this.SetTextAnchor(FRAME_ANCHOR_RIGHT_TOP); break; //--- The text is drawn at the center of the upper edge of the object case ANCHOR_UPPER : //--- Set the text binding point coordinate x=this.Width()/2; y=this.BorderSizeTop(); //--- Set the text binding point at the center top this.SetTextAnchor(FRAME_ANCHOR_CENTER_TOP); break; //--- The text is drawn at the object center //---ANCHOR_CENTER default: //--- Set the text binding point coordinate x=this.Width()/2; y=this.Height()/2; //--- Set the text binding point at the center this.SetTextAnchor(FRAME_ANCHOR_CENTER); break; } } //+------------------------------------------------------------------+
Die Zeichenketten zur Berechnung der Textkoordinaten werden hier von der Objektmethode zum Neuzeichnen übergeben. Die zuvor umbenannten Methoden werden nun hier verwendet.
Da die virtuelle Methode, die automatisch die Elementbreite und -höhe festlegt, jetzt ein Ergebnis zurückgeben sollte, schreibt die Methode das Ergebnis der Größenänderung des Objekts in die zurückgegebene Variable, anstatt einfach eine neue Breite und Höhe in den Objekteigenschaften festzulegen:
//+------------------------------------------------------------------+ //| Set the element width and height automatically | //+------------------------------------------------------------------+ bool CLabel::AutoSetWH(void) { //--- Define the variables for receiving the label width and height int w=0, h=0; //--- Get the width and height depending on the object text CGCnvElement::TextSize(this.Text()!="" && this.Text()!=NULL ? this.Text() : " ",w,h); //--- Add the Margin values of the object on the left and right to the resulting width w+=(this.MarginLeft()+this.MarginRight()); //--- If failed to get the width, set it to three pixels if(w==0) w=3; //--- Add the Margin values of the object on the top and bottom to the resulting height h+=(this.MarginTop()+this.MarginBottom()); //--- If failed to get the height, set it as "font size" * ratio if(h==0) h=(int)ceil(FontSize()*1.625); //--- Set the object width and height from the received values and write the result to res bool res=true; res &=this.SetWidth(w); res &=this.SetHeight(h); //--- Return the result of changing the width and height return res; } //+------------------------------------------------------------------+
Die Methode setzt das Flag für die automatische Größenänderung des Elements in Abhängigkeit vom Inhalt:
//+------------------------------------------------------------------+ //| Set the flag of the control auto resizing | //| depending on the content | //+------------------------------------------------------------------+ void CLabel::SetAutoSize(const bool flag,const bool redraw) { if(flag && this.AutoSetWH()) CWinFormBase::SetAutoSize(flag,redraw); } //+------------------------------------------------------------------+
Wenn das an die Methode übergebene Flag gesetzt ist und wenn es möglich ist, die Größe des Objekts zu ändern, wird der Wert des Flags in die Eigenschaften eingetragen.
In diesem Artikel werde ich die WinForms-Objektklasse RadioButton implementieren. In seinem internen Inhalt ähnelt das Objekt dem in \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\CheckBox.mqh implementierten CheckBox-Steuerelement. Im Gegensatz zum letzten Objekt hat das RadioButton-Objekt jedoch ein rundes Feld mit der Möglichkeit, es auszuwählen, anstatt eines quadratischen Feldes mit einem Häkchen. Daher wäre es für uns von Vorteil, von der CheckBox-Objektklasse zu erben und die Methoden zum Zeichnen des Auswahlfeldes neu zu definieren. Entfernen wir die Methode SetTextCoords(), da sie die übergeordnete Objektmethode SetTextParamsByAlign() vollständig wiederholt. Damit alle Variablen des CheckBox-Objekts in seinen Nachkommen verfügbar bleiben, verschieben wir sie aus dem privaten Bereich in den geschützten Bereich:
//+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Label.mqh" //+------------------------------------------------------------------+ //| CheckBox object class of the WForms controls | //+------------------------------------------------------------------+ class CCheckBox : public CLabel { private: //--- Set X and Y checkbox coordinates void SetCheckFlagCoords(int &x,int &y); void SetTextCoords(int &x,int &y); //--- Set the corrected text coordinates depending on the text alignment and checkbox void SetCorrectTextCoords(void); protected: int m_text_x; // Text X coordinate int m_text_y; // Text Y coordinate int m_check_x; // Checkbox X coordinate int m_check_y; // Checkbox Y coordinate int m_check_w; // Checkbox width int m_check_h; // Checkbox height //--- Set the element width and height automatically virtual bool AutoSetWH(void);
Die virtuelle Methode, die automatisch die Breite und Höhe des Steuerelements festlegt, sollte jetzt vom Typ bool sein.
Im öffentlichen Abschnitt der Klasse ändern wir die Methoden, die den Zustand des Kontrollkästchens und des Steuerelements festlegen. Jetzt wird vor dem Setzen der Zustände zuerst der aktuelle Status geprüft, da das Setzen der Zustände dazu führen sollte, dass die Flags und das Objekt neu gezeichnet werden, anstatt einfach den Wert für die Objekteigenschaften zu setzen. Wir schreiben die Methoden, die die Flags und die Hintergrundfarben der Objekte setzen:
public: //--- Set the element (1) width and (2) height, virtual bool SetWidth(const int width) { return CGCnvElement::SetWidth(width>this.m_check_w ? width : this.m_check_w); } virtual bool SetHeight(const int height) { return CGCnvElement::SetHeight(height>this.m_check_h ? height : this.m_check_h); } //--- (1) Set and (2) return the element checkbox location angle (alignment type) void SetCheckAlign(const ENUM_ANCHOR_POINT anchor) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN,anchor); } ENUM_ANCHOR_POINT CheckAlign(void) const { return (ENUM_ANCHOR_POINT)this.GetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN); } //--- (1) Set and (2) return the checkbox status void SetChecked(const bool flag) { this.SetProperty(CANV_ELEMENT_PROP_CHECKED,flag); if((bool)this.CheckState()!=flag) this.SetCheckState((ENUM_CANV_ELEMENT_CHEK_STATE)flag); } bool Checked(void) const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_CHECKED); } //--- (1) Set and (2) return the control status void SetCheckState(const ENUM_CANV_ELEMENT_CHEK_STATE state) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_STATE,state); if((bool)state!=this.Checked()) this.SetChecked((bool)state); } ENUM_CANV_ELEMENT_CHEK_STATE CheckState(void) const { return (ENUM_CANV_ELEMENT_CHEK_STATE)this.GetProperty(CANV_ELEMENT_PROP_CHECK_STATE);} //--- (1) Set and (2) return the flag of the checkbox auto change when it is selected void SetAutoCheck(const bool flag) { this.SetProperty(CANV_ELEMENT_PROP_AUTOCHECK,flag); } bool AutoCheck(void) const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_AUTOCHECK); } //--- (1) Set and (2) return the control checkbox background color void SetCheckBackgroundColor(const color clr) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR,clr); } color CheckBackgroundColor(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR); } //--- (1) Set and (2) return the control checkbox background color opacity void SetCheckBackgroundColorOpacity(const uchar value) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY,value); } uchar CheckBackgroundColorOpacity(void) const { return (uchar)this.GetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY); } //--- (1) Set and (2) return the color of control checkbox background when clicking on the control void SetCheckBackgroundColorMouseDown(const color clr) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN,clr); } color CheckBackgroundColorMouseDown(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN);} //--- (1) Set and (2) return the color of control checkbox background when hovering the mouse over the control void SetCheckBackgroundColorMouseOver(const color clr) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_OVER,clr); } color CheckBackgroundColorMouseOver(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_OVER);} //--- (1) Set and (2) return the control checkbox frame color void SetCheckBorderColor(const color clr) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR,clr); } color CheckBorderColor(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR); } //--- (1) Set and (2) return the control checkbox frame color opacity void SetCheckBorderColorOpacity(const uchar value) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY,value); } uchar CheckBorderColorOpacity(void) const { return (uchar)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY); } //--- (1) Set and (2) return the color of control checkbox frame color when clicking on the control void SetCheckBorderColorMouseDown(const color clr) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN,clr); } color CheckBorderColorMouseDown(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN); } //--- (1) Set and (2) return the color of the control checkbox frame color when hovering the mouse over the control void SetCheckBorderColorMouseOver(const color clr) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_OVER,clr); } color CheckBorderColorMouseOver(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_OVER); } //--- (1) Set and (2) return the control checkbox color void SetCheckFlagColor(const color clr) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR,clr); } color CheckFlagColor(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR); } //--- (1) Set and (2) return the control checkbox color opacity void SetCheckFlagColorOpacity(const uchar value) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY,value); } uchar CheckFlagColorOpacity(void) const { return (uchar)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY); } //--- (1) Set and (2) return the color of control checkbox when clicking on the control void SetCheckFlagColorMouseDown(const color clr) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN,clr); } color CheckFlagColorMouseDown(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN); } //--- (1) Set and (2) return the color of the control checkbox when hovering the mouse over the control void SetCheckFlagColorMouseOver(const color clr) { this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER,clr); } color CheckFlagColorMouseOver(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER); } //--- Redraw the object virtual void Redraw(bool redraw); //--- Constructor
In der Methode zum Neuzeichnen von Objekten ändern wir den Namen der Methode zum Einstellen der Hintergrundfarbe:
//+------------------------------------------------------------------+ //| Redraw the object | //+------------------------------------------------------------------+ void CCheckBox::Redraw(bool redraw) { //--- Fill the object with the background color having full transparency this.Erase(this.BackgroundColor(),0,true); //--- Set corrected text coordinates relative to the checkbox this.SetCorrectTextCoords(); //--- Draw the text and checkbox within the set coordinates of the object and the binding point, and update the object this.Text(this.m_text_x,this.m_text_y,this.Text(),this.ForeColor(),this.ForeColorOpacity(),this.TextAnchor()); this.ShowControlFlag(this.CheckState()); this.Update(redraw); } //+------------------------------------------------------------------+
In der Methode SetCorrectTextCoords() rufen wir statt der gelöschten Methode SetTextCoords die übergeordnete Methode SetTextParamsByAlign auf:
//+------------------------------------------------------------------+ //| Set valid text coordinates depending on | //| text alignment and checkbox | //+------------------------------------------------------------------+ void CCheckBox::SetCorrectTextCoords(void) { //--- Set checkbox and text coordinates depending on their alignment method this.SetCheckFlagCoords(this.m_check_x,this.m_check_y); this.SetTextParamsByAlign(this.m_text_x,this.m_text_y); //--- Get the text size int text_w=0, text_h=0; this.TextSize(this.Text(),text_w,text_h); //--- Depending on the checkbox location within the object boundaries //--- ... //--- ...
Wir ändern die Methode zum Zeichnen des Auswahlkontrollkästchens. Das Kontrollkästchen soll nicht wie bisher auf einem transparenten Hintergrund gezeichnet werden, sondern vor dem Hintergrund eines gefüllten und umrahmten Rechtecks. Das in diesem Feld gezeichnete Häkchen ist ziemlich dünn, also werde ich nicht eine, sondern drei Linien zeichnen, von denen jede in der Mitte ein Pixel höher liegt als die vorherige. Natürlich ist dies vom Standpunkt der Skalierbarkeit des Auswahlkästchens aus gesehen falsch, aber ich werde die relative Berechnung der Koordinaten der Polylinie, die das Kontrollkästchen zeichnet, später vornehmen:
//+------------------------------------------------------------------+ //| Display the checkbox for the specified state | //+------------------------------------------------------------------+ void CCheckBox::ShowControlFlag(const ENUM_CANV_ELEMENT_CHEK_STATE state) { //--- Draw a filled rectangle of the selection checkbox area this.DrawRectangleFill(this.m_check_x,this.m_check_y,this.m_check_x+this.CheckWidth(),this.m_check_y+this.CheckHeight(),this.CheckBackgroundColor(),this.CheckBackgroundColorOpacity()); //--- Draw the rectangle of checkbox boundaries this.DrawRectangle(this.m_check_x,this.m_check_y,this.m_check_x+this.CheckWidth(),this.m_check_y+this.CheckHeight(),this.CheckBorderColor(),this.CheckBorderColorOpacity()); //--- Create X and Y coordinate arrays for drawing a polyline int array_x[]={m_check_x+2,m_check_x+m_check_w/2-1,m_check_x+m_check_w-2}; int array_y[]={m_check_y+m_check_h/2,m_check_y+m_check_h-3,m_check_y+3}; //--- Depending on the checkbox status passed to the method switch(state) { //--- Checked box case CANV_ELEMENT_CHEK_STATE_CHECKED : //--- Draw a polyline in the form of a checkmark inside the checkbox boundaries this.DrawPolylineAA(array_x,array_y,this.CheckFlagColor(),this.CheckFlagColorOpacity()); array_y[1]=array_y[1]-1; this.DrawPolylineAA(array_x,array_y,this.CheckFlagColor(),this.CheckFlagColorOpacity()); array_y[1]=array_y[1]-1; this.DrawPolylineAA(array_x,array_y,this.CheckFlagColor(),this.CheckFlagColorOpacity()); break; //--- Undefined state case CANV_ELEMENT_CHEK_STATE_INDETERMINATE : //--- Draw a filled rectangle inside the checkbox boundaries this.DrawRectangleFill(this.m_check_x+3,this.m_check_y+3,this.m_check_x+this.m_check_w-3,this.m_check_y+this.m_check_h-3,this.CheckFlagColor(),this.CheckFlagColorOpacity()); break; //--- Unchecked checkbox default: break; } } //+------------------------------------------------------------------+
Die Methode, die automatisch die Breite und Höhe des Steuerelements festlegt, hat jetzt den Typ bool und gibt das Ergebnis zurück:
//+------------------------------------------------------------------+ //| Set the element width and height automatically | //+------------------------------------------------------------------+ bool CCheckBox::AutoSetWH(void) { //--- Define the variables for receiving the label width and height int w=0, h=0; //--- Get the width and height depending on the object text CGCnvElement::TextSize(this.Text()!="" && this.Text()!=NULL ? this.Text() : " ",w,h); //--- Add the Margin values of the object on the left and right to the resulting width, as well as the checkbox size w+=(this.MarginLeft()+this.MarginRight()+this.CheckWidth()); //--- If the width is equal to the size of the checkbox, set it to three pixels + checkbox size if(w==this.CheckWidth()) w=this.CheckWidth()+3; //--- Add the Margin values of the object on the top and bottom to the resulting height h+=(this.MarginTop()+this.MarginBottom()); //--- If failed to get the height, set it as "font size" * ratio if(h==0) h=(int)ceil(FontSize()*1.625); //--- If the height is ultimately less than the size of the checkbox, set the height equal to the height of the checkbox if(h<this.CheckHeight()) h=this.CheckHeight(); //--- Set the object width and height from the received values and write the result to res bool res=true; res &=this.SetWidth(w); res &=this.SetHeight(h); //--- Return the result of changing the width and height return res; } //+------------------------------------------------------------------+
Hier ist alles ähnlich wie bei der oben betrachteten Methode der Textlabel-Objektklasse. Deklarieren wir die Variable, weisen ihr das Ergebnis der Größenänderung zu und geben das Ergebnis zurück.
Das WinForms-Objekt RadioButton
Das Objekt wird ein Nachkomme der CheckBox WinForms-Objekte sein, da es deren Funktionsweise und interne Organisation fast vollständig wiederholt.
Wir erstellen im Ordner der Bibliothek \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ die neue Datei RadioButton.mqh für die Klasse CRadioButton.
Die Klasse sollte von der Klasse CCheckBox abgeleitet sein, und ihre Datei sollte in die eingebunden Klassendatei aufgenommen werden:
//+------------------------------------------------------------------+ //| RadioButton.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "CheckBox.mqh" //+------------------------------------------------------------------+ //| CheckBox object class of the WForms controls | //+------------------------------------------------------------------+ class CRadioButton : public CCheckBox { }
Im geschützten Teil der Klasse deklarieren wir die virtuelle Methode, die das Kontrollkästchen anzeigt, während wir im öffentlichen Teil den parametrischen Konstruktor deklarieren:
//+------------------------------------------------------------------+ //| CheckBox object class of the WForms controls | //+------------------------------------------------------------------+ class CRadioButton : public CCheckBox { private: protected: //--- Displays the checkbox for the specified state virtual void ShowControlFlag(const ENUM_CANV_ELEMENT_CHEK_STATE state); public: //--- Constructor CRadioButton(const long chart_id, const int subwindow, const string name, const int x, const int y, const int w, const int h); }; //+------------------------------------------------------------------+
Die Methode, die das Kontrollkästchen anzeigt, definiert die Methode der übergeordneten Klasse neu, da das Kontrollkästchen hier rund ist, im Gegensatz zu dem quadratischen des CheckBox-Objekts.
Wenden wir uns dieser Methoden zu.
Der parametrische Konstrukteur:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CRadioButton::CRadioButton(const long chart_id, const int subwindow, const string name, const int x, const int y, const int w, const int h) : CCheckBox(chart_id,subwindow,name,x,y,w,h) { CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON); CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON); this.Redraw(false); } //+------------------------------------------------------------------+
Hier wird nur der WinForms-Objekttyp definiert und das Objekt neu gezeichnet. Alles andere wird im Konstruktor der übergeordneten Klasse erstellt und festgelegt.
Die Methode, die das Ankreuzfeld für den angegebenen Zustand anzeigt:
//+------------------------------------------------------------------+ //| Display the checkbox for the specified state | //+------------------------------------------------------------------+ void CRadioButton::ShowControlFlag(const ENUM_CANV_ELEMENT_CHEK_STATE state) { //--- Draw the filled circle of the selection checkbox area this.DrawEllipseFill(this.m_check_x,this.m_check_y,this.m_check_x+this.CheckWidth(),this.m_check_y+this.CheckHeight(),this.CheckBackgroundColor(),this.CheckBackgroundColorOpacity()); //--- Draw the circle within the checkbox borders DrawEllipseAA(this.m_check_x,this.m_check_y,this.m_check_x+this.CheckWidth(),this.m_check_y+this.CheckHeight(),this.CheckBorderColor(),this.CheckBorderColorOpacity()); //--- Depending on the checkbox status passed to the method switch(state) { //--- Checked box case CANV_ELEMENT_CHEK_STATE_CHECKED : //--- Draw a filled rectangle inside the checkbox borders DrawEllipseFill(this.m_check_x+3,this.m_check_y+3,this.m_check_x+this.CheckWidth()-3,this.m_check_y+this.CheckHeight()-3,this.CheckFlagColor(),this.CheckFlagColorOpacity()); break; //--- Undefined state //--- Unchecked checkbox default: break; } } //+------------------------------------------------------------------+
Ähnlich wie bei der übergeordneten Klasse wird hier zunächst ein mit der Hintergrundfarbe gefüllter Kreis gezeichnet. Dann zeichnen wir seinen Rand. Je nach dem Zustand, der der Flag-Methode oder innerhalb des gezeichneten Kreises übergeben wird, wird ein weiterer Kreis gezeichnet (mit kleinerem Durchmesser) oder es wird nichts gezeichnet.
Dies sind alle Dinge, die für die Erstellung des Objekts erforderlich sind. Alles andere wird in den übergeordneten Klassen implementiert.
Die Schaltfläche WinForms-Objekt
Das Schaltflächenobjekt ist in Wirklichkeit eine Textbeschriftung. Die Textbeschriftung ist in der Lage, Objektgrenzen zu zeichnen. Außerdem besteht die Möglichkeit, den Text innerhalb der Steuerelementgrenzen zu positionieren. Die Beschriftung wird nur auf einem transparenten Hintergrund gezeichnet, während die Schaltfläche auf einem gefüllten Hintergrund gezeichnet wird. Daher wird das Button-Objekt vom Text-Label-Objekt geerbt.
Wir erstellen in \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ eine neue Datei Label.mqh mit der Klasse CLabel.
Die Klasse sollte von der Klasse CLabel abgeleitet werden, und ihre Datei sollte in die erstellte Klasse aufgenommen werden:
//+------------------------------------------------------------------+ //| Button.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Label.mqh" //+------------------------------------------------------------------+ //| Label object class of WForms controls | //+------------------------------------------------------------------+ class CButton : public CLabel { }
Im privaten Teil der Klasse deklarieren wir die Variablen für die Speicherung der Koordinaten der Schaltflächenbeschriftung, während wir im geschützten Teil die virtuelle Methode zur automatischen Einstellung der Größe des Steuerelements deklarieren:
class CButton : public CLabel { private: int m_text_x; // Text X coordinate int m_text_y; // Text Y coordinate protected: //--- Set the element width and height automatically virtual bool AutoSetWH(void); public:
Im öffentlichen Abschnitt deklarieren wir die virtuelle Methode zum Neuzeichnen eines Objekts und schreiben die Methoden zum Setzen und Zurückgeben des Modus der automatischen Größenanpassung des Objekts an die Etikettengröße:
public: //--- Redraw the object virtual void Redraw(bool redraw); //--- (1) Set and (2) return the mode of the element auto resizing depending on the content void SetAutoSizeMode(const ENUM_CANV_ELEMENT_AUTO_SIZE_MODE mode,const bool redraw) { ENUM_CANV_ELEMENT_AUTO_SIZE_MODE prev=this.AutoSizeMode(); if(prev==mode) return; this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE,mode); } ENUM_CANV_ELEMENT_AUTO_SIZE_MODE AutoSizeMode(void) const { return (ENUM_CANV_ELEMENT_AUTO_SIZE_MODE)this.GetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE); } //--- Constructor CButton(const long chart_id, const int subwindow, const string name, const int x, const int y, const int w, const int h); }; //+------------------------------------------------------------------+
Im parametrischen Konstruktor setzen wir den Kontrolltyp und die Standardwerte der Objekteigenschaften und rufen die Methode zum Neuzeichnen auf:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CButton::CButton(const long chart_id, const int subwindow, const string name, const int x, const int y, const int w, const int h) : CLabel(chart_id,subwindow,name,x,y,w,h) { CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_BUTTON); CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_BUTTON); this.m_type=OBJECT_DE_TYPE_GWF_COMMON; this.SetCoordX(x); this.SetCoordY(y); this.SetWidth(w); this.SetHeight(h); this.Initialize(); this.SetTextAlign(ANCHOR_CENTER); this.SetMarginAll(3); this.SetWidthInit(this.Width()); this.SetHeightInit(this.Height()); this.SetCoordXInit(x); this.SetCoordYInit(y); this.Redraw(false); } //+------------------------------------------------------------------+
Die Methode zum Neuzeichnen eines Objekts:
//+------------------------------------------------------------------+ //| Redraw the object | //+------------------------------------------------------------------+ void CButton::Redraw(bool redraw) { //--- Fill the object with the background color featuring the default transparency this.Erase(this.BackgroundColor(),CLR_DEF_CONTROL_STD_OPACITY,true); //--- Declare the variables for X and Y coordinates and set their values depending on the text alignment int x=0,y=0; CLabel::SetTextParamsByAlign(x,y); //--- Draw the text within the set coordinates of the object and the binding point of the text, and update the object this.Text(x,y,this.Text(),this.ForeColor(),this.ForeColorOpacity(),this.TextAnchor()); this.Update(redraw); } //+------------------------------------------------------------------+
Zunächst werden die Objektränder mit der Hintergrundfarbe gefüllt. Die Beschriftung wird dann unter Verwendung der berechneten Koordinaten in Abhängigkeit von der Textausrichtung gezeichnet und das Objekt wird aktualisiert.
Die Methode legt automatisch die Breite und Höhe des Elements fest:
//+------------------------------------------------------------------+ //| Set the element width and height automatically | //+------------------------------------------------------------------+ bool CButton::AutoSetWH(void) { //--- Define the variables for receiving the label width and height int w=0, h=0; //--- Get the width and height depending on the object text CGCnvElement::TextSize(this.Text()!="" && this.Text()!=NULL ? this.Text() : " ",w,h); //--- Add the Margin values of the object on the left and right to the resulting width w+=(this.MarginLeft()+this.MarginRight()); //--- If failed to get the width, set it to three pixels if(w==0) w=3; //--- Add the Margin values of the object on the top and bottom to the resulting height h+=(this.MarginTop()+this.MarginBottom()); //--- If failed to get the height, set it as "font size" * ratio if(h==0) h=(int)ceil(FontSize()*1.625); //--- Set the object width and height from the received values and write the result to res bool res=true; //--- In case of the auto resize mode, increase only if(this.AutoSizeMode()==CANV_ELEMENT_AUTO_SIZE_MODE_GROW) { if(w>this.Width()) res &=this.SetWidth(w); if(h>this.Height()) res &=this.SetHeight(h); } //--- In case of the auto resize mode, increase and decrease else { if(w!=this.Width()) res &=this.SetWidth(w); if(h!=this.Height()) res &=this.SetHeight(h); } //--- Return the result of changing the width and height return res; } //+------------------------------------------------------------------+
Die Methode ist fast identisch mit den oben beschriebenen Methoden der Elternklasse. Es ist jedoch zu beachten, dass sich die Größe je nach dem angegebenen Größenänderungsmodus ändert. Mit anderen Worten: Im Modus „Nur Vergrößerung“ wird das Objekt nur vergrößert, wenn der Text darüber hinausgeht. Im Modus Vergrößern und Verkleinern wird das gesamte Objekt an die Größe des darin enthaltenen Textes angepasst.
Natürlich soll die Funktionsweise des Schaltflächenobjekts viel mehr Elemente enthalten, aber alles andere wird in späteren Artikeln bei der Entwicklung anderer WinForms-Objekte hinzugefügt.
Um gebundene Objekte zu erstellen, sollten die Containerobjekte von der Existenz der neu erstellten Steuerelemente wissen. Dazu müssen wir die Datei mit den neuen Klassen in die Klassendateien der Containerobjekte aufnehmen.
Die übergeordnete Klasse für alle Containerobjekte ist eine Klasse des Basis-Containerobjekts, das in \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Container.mqh implementiert ist.
Einbinden der Dateien der neuen Steuerelemente. Anstelle von CheckBox.mqh binden wir die Objektdatei RadioButton ein, da sie ein Abkömmling des Elements CheckBox ist. Daher werden beide in der Klasse sichtbar sein:
//+------------------------------------------------------------------+ //| Container.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\..\WForms\WinFormBase.mqh" #include "..\..\WForms\Common Controls\RadioButton.mqh" #include "..\..\WForms\Common Controls\Button.mqh" //+------------------------------------------------------------------+
Da die Methode zur Erstellung eines neuen grafischen Objekts für jede geerbte Klasse unterschiedlich ist, wird hier nur die virtuelle Methode deklariert und ihre Implementierung entfernt. Die Methode gibt NULL zurück:
//+------------------------------------------------------------------+ //| Class of the base container object of WForms controls | //+------------------------------------------------------------------+ class CContainer : public CWinFormBase { private: //--- Create a new graphical object virtual 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) { return NULL; } //--- Calculate Dock objects' binding coordinates
Wir benennen die öffentlichen Methoden FrameWidth in die Methoden BorderSize um:
public: //--- Return the size and coordinates of the working area int GetWidthWorkspace(void) const { return this.Width()-::fmax(this.BorderSizeLeft(),this.PaddingLeft())-::fmax(this.BorderSizeRight(),this.PaddingRight()); } int GetHeightWorkspace(void) const { return this.Height()-::fmax(this.BorderSizeTop(),this.PaddingTop())-::fmax(this.BorderSizeBottom(),this.PaddingBottom()); } int GetCoordXWorkspace(void) const { return this.CoordX()+::fmax(this.BorderSizeLeft(),this.PaddingLeft()); } int GetCoordYWorkspace(void) const { return this.CoordY()+::fmax(this.BorderSizeTop(),this.PaddingTop()); } int GetRightEdgeWorkspace(void) const { return this.RightEdge()-::fmax(this.BorderSizeRight(),this.PaddingRight()); } int GetBottomEdgeWorkspace(void) const { return this.BottomEdge()-::fmax(this.BorderSizeBottom(),this.PaddingBottom()); } //--- Return the list of bound WinForms objects with (1) any and (2) specified WinForms object type (from the base one and higher)
...
//--- Set the width of the form frame (1) to the left, (2) at the top, (3) to the right, (4) at the bottom and (5) on all sides of the control virtual void SetFrameWidthLeft(const uint value) { this.SetBorderSizeLeft(value); if(this.PaddingLeft()<this.BorderSizeLeft()) this.SetPaddingLeft(this.BorderSizeLeft()); } virtual void SetFrameWidthTop(const uint value) { this.SetBorderSizeTop(value); if(this.PaddingTop()<this.BorderSizeTop()) this.SetPaddingTop(this.BorderSizeTop()); } virtual void SetFrameWidthRight(const uint value) { this.SetBorderSizeRight(value); if(this.PaddingRight()<this.BorderSizeRight()) this.SetPaddingRight(this.BorderSizeRight()); } virtual void SetFrameWidthBottom(const uint value) { this.SetBorderSizeBottom(value); if(this.PaddingBottom()<this.BorderSizeBottom()) this.SetPaddingBottom(this.BorderSizeBottom()); } virtual void SetFrameWidthAll(const uint value) { this.SetBorderSizeLeft(value); this.SetBorderSizeTop(value); this.SetBorderSizeRight(value); this.SetBorderSizeBottom(value); } //--- Constructors
Entfernen der Übergabe des Zeigers auf das Hauptobjekt aus der Methode zur Erstellung eines neuen Elements:
//--- Create a new attached element virtual bool CreateNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, CGCnvElement *main, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool activity, const bool redraw);
In der Methodenimplementierung fügen wir die Erstellung aller bekannten Steuerelemente hinzu:
//+------------------------------------------------------------------+ //| Create a new attached element | //+------------------------------------------------------------------+ bool CContainer::CreateNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool activity, const bool redraw) { //--- If the object type is less than the base WinForms object if(element_type<GRAPH_ELEMENT_TYPE_WF_BASE) { //--- report the error and return 'false' CMessage::ToLog(DFUN,MSG_PANEL_OBJECT_ERR_OBJ_MUST_BE_WFBASE); return false; } //--- If failed to create a new graphical element, return 'false' CWinFormBase *obj=CForm::CreateAndAddNewElement(element_type,x,y,w,h,colour,opacity,activity); if(obj==NULL) return false; //--- Set the text color of the created object as that of the base panel obj.SetForeColor(this.ForeColor()); //--- Depending on the created object type, switch(obj.TypeGraphElement()) { //--- For the Container, Panel and GroupBox WinForms objects case GRAPH_ELEMENT_TYPE_WF_CONTAINER : case GRAPH_ELEMENT_TYPE_WF_PANEL : case GRAPH_ELEMENT_TYPE_WF_GROUPBOX : //--- set the frame color equal to the background color obj.SetBorderColor(obj.BackgroundColor()); break; //--- For the Text Label, CheckBox and RadioButton WinForms objects case GRAPH_ELEMENT_TYPE_WF_LABEL : case GRAPH_ELEMENT_TYPE_WF_CHECKBOX : case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON : //--- set the object text color depending on the one passed to the method: //--- either the container text color, or the one passed to the method. //--- The frame color is set equal to the text color obj.SetForeColor(colour==clrNONE ? this.ForeColor() : colour); obj.SetBorderColor(obj.ForeColor()); break; //--- For the Button WinForms object case GRAPH_ELEMENT_TYPE_WF_BUTTON : //--- set the object text color as a container text color depending on the one passed to the method: //--- set the background color depending on the one passed to the method: //--- either the default standard control background color, or the one passed to the method. //--- The frame color is set equal to the text color obj.SetForeColor(this.ForeColor()); obj.SetBackgroundColor(colour==clrNONE ? CLR_DEF_CONTROL_STD_BACK_COLOR : colour); obj.SetBorderColor(obj.ForeColor()); obj.SetBorderStyle(FRAME_STYLE_SIMPLE); break; default: break; } //--- If the panel has auto resize enabled and features bound objects, call the resize method if(this.AutoSize() && this.ElementsTotal()>0) this.AutoSizeProcess(redraw); //--- Redraw the panel and all added objects, and return 'true' this.Redraw(redraw); return true; } //+------------------------------------------------------------------+
Die Methode, die die Größe des Elements an seinen internen Inhalt anpasst, wurde zwar konvertiert, funktioniert aber immer noch nicht richtig, sodass wir hier nur die aktuelle Implementierung ohne jegliche Erklärung anhängen, mit Ausnahme der Kommentare, die bereits im Code der Methode enthalten sind:
//+------------------------------------------------------------------+ //| Adjust the element size to fit its content | //+------------------------------------------------------------------+ bool CContainer::AutoSizeProcess(const bool redraw) { //--- Get the list of bound objects with WinForms type basic and higher CArrayObj *list=this.GetListWinFormsObj(); int maxcX=0; int maxcY=0; //--- Calculate the maximum coordinate of the right and bottom edge from all bound objects for(int i=0;i<list.Total();i++) { CWinFormBase *obj=list.At(i); if(obj==NULL) continue; if(obj.RightEdge()>maxcX) maxcX=obj.RightEdge(); if(obj.BottomEdge()>maxcY) maxcY=obj.BottomEdge(); } //--- Calculate the required width and height of the panel after adjusting its size to the content int w=maxcX-this.CoordX(); int h=maxcY-this.CoordY(); //--- Calculate the number of pixels, by which we need to resize the container in width and height int excess_x=w-this.GetWidthWorkspace()-this.BorderSizeRight()-1; int excess_y=h-this.GetHeightWorkspace()-this.BorderSizeBottom()-1; //--- If failed to change the container size, return 'true' if(excess_x==0 && excess_y==0) return true; //--- Return the result of resizing the container return ( //--- In case of size increase only this.AutoSizeMode()==CANV_ELEMENT_AUTO_SIZE_MODE_GROW ? this.Resize(this.Width()+(excess_x>0 ? excess_x : 0),this.Height()+(excess_y>0 ? excess_y : 0),redraw) : //--- if both increase and decrease this.Resize(this.Width()+(excess_x!=0 ? excess_x : 0),this.Height()+(excess_y!=0 ? excess_y : 0),redraw) ); } //+------------------------------------------------------------------+
Andere geringfügige Änderungen in der Klasse, die das Ergebnis von Experimenten sind und nichts mit dem Thema dieses Artikels zu tun haben, werden hier nicht berücksichtigt. Ich werde mich melden, wenn alles richtig funktioniert.
Die Container-Objektklasse GroupBox in \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\GroupBox.mqh wurde ebenfalls leicht verbessert.
Die Aufrufe der umbenannten Methoden wurden korrigiert:
//--- Set a frame style virtual void SetBorderStyle(const ENUM_FRAME_STYLE style) { if((this.BorderSizeTop()<2 || this.BorderSizeBottom()<2 || this.BorderSizeLeft()<2 || this.BorderSizeRight()<2) && style>FRAME_STYLE_FLAT) this.SetBorderSizeAll(2); this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,style); } //--- Constructors
...
//+------------------------------------------------------------------+ //| Initialize the variables | //+------------------------------------------------------------------+ void CGroupBox::Initialize(void) { //--- Clear all object lists and set sorted list flags for them this.m_list_elements.Clear(); this.m_list_elements.Sort(); this.m_list_tmp.Clear(); this.m_list_tmp.Sort(); //--- GroupBox has no shadow object this.m_shadow_obj=NULL; this.m_shadow=false; //--- The width of the object frame on each side is 1 pixel by default this.SetBorderSize(1,1,1,1); //--- The object does not have a gradient filling (neither vertical, nor horizontal) this.m_gradient_v=false; this.m_gradient_c=false; //--- Reset all "working" flags and variables this.m_mouse_state_flags=0; this.m_offset_x=0; this.m_offset_y=0; CGCnvElement::SetInteraction(false); //--- Create an animation object and add it to the list for storing such objects this.m_animations=new CAnimations(CGCnvElement::GetObject()); this.m_list_tmp.Add(this.m_animations); //--- Set a transparent background for the object background and the default color for the frame this.SetBackgroundColor(CLR_CANV_NULL); this.SetOpacity(0); this.SetBorderColor(CLR_DEF_FRAME_GBOX_COLOR); //--- Set the default color and text opacity, as well as the absence of the object frame this.SetForeColor(CLR_DEF_FORE_COLOR); this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY); this.SetBorderStyle(FRAME_STYLE_SIMPLE); //--- Set the default text parameters this.SetFont(DEF_FONT,DEF_FONT_SIZE); this.SetText("GroupBox"); this.SetTextAnchor(FRAME_ANCHOR_LEFT_TOP); this.SetTextAlign(ANCHOR_LEFT_UPPER); //--- Set the default object parameters this.SetAutoSize(false,false); this.SetMarginAll(3); this.SetPaddingAll(3); this.SetEnabled(true); this.SetVisible(true,false); } //+------------------------------------------------------------------+
...
//+------------------------------------------------------------------+ //| Draw the frame | //+------------------------------------------------------------------+ void CGroupBox::DrawFrame(void) { //--- Get half of the text height int w=0; int h=0; this.TextSize(Text(),w,h); int height=this.Height()-h/2; //--- Depending on the frame style, draw its necessary type switch(this.BorderStyle()) { case FRAME_STYLE_FLAT : this.DrawFrameFlat(0,h/2,this.Width(),height,this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.ForeColorOpacity()); break; case FRAME_STYLE_BEVEL : this.DrawFrameBevel(0,h/2,this.Width(),height,this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.ForeColorOpacity()); break; case FRAME_STYLE_STAMP : this.DrawFrameStamp(0,h/2,this.Width(),height,this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.ForeColorOpacity()); break; //--- FRAME_STYLE_SIMPLE default: this.DrawFrameSimple(0,h/2,this.Width(),height,this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.ForeColorOpacity()); break; } //--- If the text set for an object is not an empty string, erase the frame area where a text should be located using the transparent color if(this.Text()!="") this.DrawRectangleFill(5,h/2-1,w+7,h/2+this.BorderSizeTop()+1,CLR_CANV_NULL,0); } //+------------------------------------------------------------------+
Die virtuelle Methode zur Erstellung eines neuen grafischen Objekts umfasst die Erstellung aller derzeit bekannten Elemente:
//+------------------------------------------------------------------+ //| Create a new graphical object | //+------------------------------------------------------------------+ CGCnvElement *CGroupBox::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int obj_num, const string obj_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) { string name=this.CreateNameDependentObject(obj_name); CGCnvElement *element=NULL; switch(type) { case GRAPH_ELEMENT_TYPE_ELEMENT : element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),name,x,y,w,h,colour,opacity,movable,activity); break; case GRAPH_ELEMENT_TYPE_FORM : element=new CForm(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CONTAINER : element=new CContainer(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_GROUPBOX : element=new CGroupBox(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_PANEL : element=new CPanel(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LABEL : element=new CLabel(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKBOX : element=new CCheckBox(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON : element=new CRadioButton(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON : element=new CButton(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; default: break; } if(element==NULL) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",name); return element; } //+------------------------------------------------------------------+
Wir sollten auch einige Verbesserungen an der Container-Klasse des Panel-Objekts in \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Panel.mqh vornehmen.
Bei den Abstandsmethoden müssen wir den Versatz der Unterlage berechnen und einstellen, nachdem wir ihre Koordinaten und Größe festgelegt haben:
//--- Set the gap (1) to the left, (2) at the top, (3) to the right, (4) at the bottom and (5) on all sides inside the control virtual void SetPaddingLeft(const uint value) { CWinFormBase::SetPaddingLeft(value); if(this.m_underlay!=NULL) { //--- Set the X coordinate and the underlay width this.SetCoordXUnderlay(this.CoordX()+this.PaddingLeft()); this.SetWidthUnderlay(this.Width()-this.PaddingLeft()-this.PaddingRight()); //--- Set the underlay shift along the X axis this.m_underlay.SetCoordXRelative(this.m_underlay.CoordX()-this.CoordX()); } } virtual void SetPaddingTop(const uint value) { CWinFormBase::SetPaddingTop(value); if(this.m_underlay!=NULL) { //--- Set the Y coordinate and underlay height this.SetCoordYUnderlay(this.CoordY()+this.PaddingTop()); this.SetHeightUnderlay(this.Height()-this.PaddingTop()-this.PaddingBottom()); //--- Set the underlay shift along the Y axis this.m_underlay.SetCoordYRelative(this.m_underlay.CoordY()-this.CoordY()); } }
Zuvor wurde der Versatz vor der Berechnung der Koordinaten und der Größe berechnet. Dies führte zu einem Fehler bei der Berechnung des Versatzes, nachdem Änderungen vorgenommen wurden.
Bei der Methode zur Erstellung eines neuen grafischen Objekts fügen wir die Erstellung aller bekannten Elemente hinzu:
//+------------------------------------------------------------------+ //| Create a new graphical object | //+------------------------------------------------------------------+ CGCnvElement *CPanel::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int obj_num, const string obj_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) { string name=this.CreateNameDependentObject(obj_name); CGCnvElement *element=NULL; switch(type) { case GRAPH_ELEMENT_TYPE_ELEMENT : element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),name,x,y,w,h,colour,opacity,movable,activity); break; case GRAPH_ELEMENT_TYPE_FORM : element=new CForm(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CONTAINER : element=new CContainer(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_GROUPBOX : element=new CGroupBox(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_PANEL : element=new CPanel(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LABEL : element=new CLabel(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKBOX : element=new CCheckBox(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON : element=new CRadioButton(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON : element=new CButton(this.ChartID(),this.SubWindow(),name,x,y,w,h); break; default: break; } if(element==NULL) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",name); return element; } //+------------------------------------------------------------------+
In der Methode zur Erstellung aller Unterlegparameter auch verschieben wir die Abstandsberechnung unter die Koordinatenberechnung:
//+------------------------------------------------------------------+ //| Set all underlay parameters | //+------------------------------------------------------------------+ bool CPanel::SetUnderlayParams(void) { //--- Set the object type this.m_underlay.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_UNDERLAY); //--- Set the underlay coordinates and size bool res=true; res &=this.SetCoordXUnderlay(this.CoordX()+this.PaddingLeft()); res &=this.SetCoordYUnderlay(this.CoordY()+this.PaddingTop()); res &=this.SetWidthUnderlay(this.Width()-this.PaddingLeft()-this.PaddingRight()); res &=this.SetHeightUnderlay(this.Height()-this.PaddingTop()-this.PaddingBottom()); //--- Set the underlay shift values to the variables by X and Y axes this.m_underlay.SetCoordXRelative(this.m_underlay.CoordX()-this.CoordX()); this.m_underlay.SetCoordYRelative(this.m_underlay.CoordY()-this.CoordY()); return res; } //+------------------------------------------------------------------+
In der Methode Verschieben ändern wir die Berechnung der Objektversatzwerte:
//--- Shift all bound objects if(!this.MoveDependentObj(x+this.GetCoordXUnderlayRelative(),y+this.GetCoordYUnderlayRelative(),false)) return false;
Hier ist jetzt alles einfacher:
//+------------------------------------------------------------------+ //| Update the coordinate elements | //+------------------------------------------------------------------+ bool CPanel::Move(const int x,const int y,const bool redraw=false) { //--- Get the pointers to the base and main objects in the bound objects hierarchy, as well as the shadow object CGCnvElement *base=this.GetBase(); CGCnvElement *main=this.GetMain(); CShadowObj *shadow=this.GetShadowObj(); //--- If the element is not movable and is a base object, leave if(!this.Movable() && main==NULL) return false; //--- If the object has a shadow and we failed to set new coordinate values to the properties of the shadow object, return 'false' if(this.m_shadow && shadow!=NULL) { if(!shadow.Move(x-OUTER_AREA_SIZE+shadow.CoordXRelative(),y-OUTER_AREA_SIZE+shadow.CoordYRelative(),false)) return false; } //--- If failed to set new values into graphical object properties, return 'false' if(!this.SetCoordX(x) || !this.SetCoordY(y)) return false; //--- If failed to move the underlay, return 'false' if(this.m_underlay!=NULL && !this.m_underlay.Move(x+this.GetCoordXUnderlayRelative(),y+this.GetCoordYUnderlayRelative())) return false; //--- Shift all bound objects if(!this.MoveDependentObj(x,y,false)) return false; //--- If the update flag is set and this is the hierarchy main object, redraw the chart. if(redraw && main==NULL) ::ChartRedraw(this.ChartID()); //--- Return 'true' return true; } //+------------------------------------------------------------------+
Da nun die relativen Koordinaten aller Objekte berechnet werden und die ursprünglich eingestellten nicht verwendet werden, muss hier nichts mehr angepasst werden. Wir ersetzen einfach die X- und Y-Werte,die an die Methode für die Bewegung übergeben werden.
Ich habe mehrere Verbesserungen in der Kollektionsklasse für grafische Elemente in \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh vorgenommen, da ich einige Methoden, auf die in der Klasse aktiv zugegriffen wird, umbenannt habe. Ich denke, es macht keinen Sinn, hier alle einfachen Fälle von Umbenennung zu beschreiben. Ich habe alle ähnlichen Änderungen, die heute vorgenommen werden, in diesem Artikel berücksichtigt. Sie finden sie in den unten angehängten Dateien.
Worauf ich mich konzentrieren muss, ist die Suche nach den Objekten, die mit dem Panel verbunden sind, und die Erstellung einer Liste von Interaktionsobjekten, mit denen wir bestimmen können, mit welchem Objekt die Maus interagieren soll.
In der Methode, die einen Zeiger auf das Formular unter dem Cursor zurückgibt, müssen wir zwei Codeblöcke hinzufügen (sie sind ähnlich, und ich werde sie wahrscheinlich in eine separate Methode nach den Tests verschieben). In diesen Blöcken wird die Liste aller an das Panel angehängten Objekte erstellt, d. h. ihre Hierarchie, und das jüngste von ihnen wird als das Objekt zurückgegeben, mit dem interagiert werden soll:
//+------------------------------------------------------------------+ //| Return the pointer to the form located under the cursor | //+------------------------------------------------------------------+ CForm *CGraphElementsCollection::GetFormUnderCursor(const int id, const long &lparam, const double &dparam, const string &sparam, ENUM_MOUSE_FORM_STATE &mouse_state, long &obj_ext_id, int &form_index) { //--- Set the ID of the extended standard graphical object to -1 //--- and the index of the anchor point managed by the form to -1 obj_ext_id=WRONG_VALUE; form_index=WRONG_VALUE; //--- Initialize the mouse status relative to the form mouse_state=MOUSE_FORM_STATE_NONE; //--- Declare the pointers to graphical element collection class objects CGCnvElement *elm=NULL; CForm *form=NULL; //--- Get the list of objects the interaction flag is set for (there should be only one object) CArrayObj *list=CSelect::ByGraphCanvElementProperty(GetListCanvElm(),CANV_ELEMENT_PROP_INTERACTION,true,EQUAL); //--- If managed to obtain the list and it is not empty, if(list!=NULL && list.Total()>0) { //--- Get the only graphical element there elm=list.At(0); //--- If the element is a form object or its descendants if(elm.TypeGraphElement()>=GRAPH_ELEMENT_TYPE_WF_BASE) { //--- Assign the pointer to the element for the form object pointer form=elm; //--- Get the mouse status relative to the form mouse_state=form.MouseFormState(id,lparam,dparam,sparam); //--- If the cursor is inside the form, if(mouse_state>MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL) { //--- Create the list of interaction objects int count=form.CreateListInteractObj(); //--- If the list has objects if(count>0) { //--- In the loop by the created list for(int j=count-1;j>WRONG_VALUE;j--) { //--- get the next form object CForm *obj=form.GetInteractForm(j); if(obj==NULL) continue; //--- if the mouse cursor is located above the object, write it to the pointer and break the loop if(obj.MouseFormState(id,lparam,dparam,sparam)>MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL) { form=obj; break; } } } //--- Return the found form object return form; } } } //--- If there is no a single form object with a specified interaction flag, //--- in the loop by all graphical element collection class objects int total=this.m_list_all_canv_elm_obj.Total(); for(int i=0;i<total;i++) { //--- get the next element elm=this.m_list_all_canv_elm_obj.At(i); if(elm==NULL) continue; //--- if the obtained element is a form object or its descendants if(elm.TypeGraphElement()>=GRAPH_ELEMENT_TYPE_WF_BASE) { //--- Assign the pointer to the element for the form object pointer form=elm; //--- Get the mouse status relative to the form mouse_state=form.MouseFormState(id,lparam,dparam,sparam); //--- If the cursor is within the form, return the pointer to the form if(mouse_state>MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL) { //--- Create the list of interaction objects int count=form.CreateListInteractObj(); //--- If the list has objects if(count>0) { //--- In the loop by the created list for(int j=count-1;j>WRONG_VALUE;j--) { //--- get the next form object CForm *obj=form.GetInteractForm(j); if(obj==NULL) continue; //--- if the mouse cursor is located above the object, write it to the pointer and break the loop if(obj.MouseFormState(id,lparam,dparam,sparam)>MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL) { form=obj; break; } } } //--- Return the found form object return form; } } } //--- If there is no a single form object from the collection list //--- Get the list of extended standard graphical objects list=this.GetListStdGraphObjectExt(); if(list!=NULL) { //--- in the loop by all extended standard graphical objects for(int i=0;i<list.Total();i++) { //--- get the next graphical object, CGStdGraphObj *obj_ext=list.At(i); if(obj_ext==NULL) continue; //--- get the object of its toolkit, CGStdGraphObjExtToolkit *toolkit=obj_ext.GetExtToolkit(); if(toolkit==NULL) continue; //--- handle the event of changing the chart for the current graphical object obj_ext.OnChartEvent(CHARTEVENT_CHART_CHANGE,lparam,dparam,sparam); //--- Get the total number of form objects created for the current graphical object total=toolkit.GetNumControlPointForms(); //--- In the loop by all form objects for(int j=0;j<total;j++) { //--- get the next form object, form=toolkit.GetControlPointForm(j); if(form==NULL) continue; //--- get the mouse status relative to the form mouse_state=form.MouseFormState(id,lparam,dparam,sparam); //--- If the cursor is inside the form, if(mouse_state>MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL) { //--- set the object ID and form index //--- and return the pointer to the form obj_ext_id=obj_ext.ObjectID(); form_index=j; return form; } } } } //--- Nothing is found - return NULL return NULL; } //+------------------------------------------------------------------+
Die gesamte Logik ist in den Code-Kommentaren ausreichend detailliert beschrieben. Ich hoffe, dass hier alles klar ist. Wenn Sie Fragen haben, können Sie diese gerne im Kommentarteil stellen.
In der Klasse der Ereignisbehandlung CGraphElementsCollection::OnChartEvent(), und zwar im Block der Ereignisbehandlung von "Der Cursor befindet sich im aktiven Bereich, das Mausrad wird gescrollt", wird die Anzeige des Typs und des Namens eines grafischen Elements, über dem sich der Cursor befindet, zum Journal hinzugefügt. Auf diese Weise ist es möglich, die Interaktion der Maus mit dem Objekt, über dem sich der Cursor befindet, zu steuern. Wenn wir mit der Maus über das Element fahren und das Mausrad drehen, werden die Objektdaten im Journal angezeigt:
//--- 'The cursor is inside the active area, the mouse wheel is being scrolled' event handler workpiece if(mouse_state==MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL) { Print(DFUN,"Mouse scroll: ",form.TypeElementDescription()," ",form.Name()); }
Test
Um den Test durchzuführen, verwende ich den EA aus dem vorherigen Artikel und speichere ihn in \MQL5\Experts\TestDoEasy\Part109\ als TstDE109.mq5.
Fügen wir neue Parameter zu den EA-Eingaben hinzu, die es ermöglichen, das Auswahlkästchen und die Textausrichtung sowie die Parameter für Schaltflächenobjekte einzustellen:
//--- input parameters sinput bool InpMovable = true; // Panel Movable flag sinput ENUM_INPUT_YES_NO InpAutoSize = INPUT_YES; // Panel Autosize sinput ENUM_AUTO_SIZE_MODE InpAutoSizeMode = AUTO_SIZE_MODE_GROW; // Panel Autosize mode sinput ENUM_BORDER_STYLE InpFrameStyle = BORDER_STYLE_NONE; // Label border style sinput ENUM_ANCHOR_POINT InpTextAlign = ANCHOR_LEFT_UPPER; // Label text align sinput ENUM_INPUT_YES_NO InpTextAutoSize = INPUT_YES; // Label autosize sinput ENUM_ANCHOR_POINT InpCheckAlign = ANCHOR_LEFT_UPPER; // Check flag align sinput ENUM_ANCHOR_POINT InpCheckTextAlign = ANCHOR_LEFT_UPPER; // Check label text align sinput ENUM_CHEK_STATE InpCheckState = CHEK_STATE_UNCHECKED; // Check flag state sinput ENUM_INPUT_YES_NO InpCheckAutoSize = INPUT_YES; // CheckBox autosize sinput ENUM_BORDER_STYLE InpCheckFrameStyle = BORDER_STYLE_NONE; // CheckBox border style sinput ENUM_ANCHOR_POINT InpButtonTextAlign = ANCHOR_LEFT_UPPER; // Button text align sinput ENUM_INPUT_YES_NO InpButtonAutoSize = INPUT_YES; // Button autosize sinput ENUM_AUTO_SIZE_MODE InpButtonAutoSizeMode= AUTO_SIZE_MODE_GROW; // Button Autosize mode sinput ENUM_BORDER_STYLE InpButtonFrameStyle = BORDER_STYLE_NONE; // Button border style //--- global variables
In OnInit() erstellen wir alle erforderlichen Objekte auf dem Paneel und im Container GroupBox:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Set EA global variables ArrayResize(array_clr,2); // Array of gradient filling colors array_clr[0]=C'26,100,128'; // Original ≈Dark-azure color array_clr[1]=C'35,133,169'; // Lightened original color //--- Create the array with the current symbol and set it to be used in the library string array[1]={Symbol()}; engine.SetUsedSymbols(array); //--- Create the timeseries object for the current symbol and period, and show its description in the journal engine.SeriesCreate(Symbol(),Period()); engine.GetTimeSeriesCollection().PrintShort(false); // Short descriptions //--- Create WinForms Panel object CPanel *pnl=NULL; pnl=engine.CreateWFPanel("WFPanel",50,50,230,150,array_clr,200,true,true,false,-1,FRAME_STYLE_BEVEL,true,false); if(pnl!=NULL) { //--- Set Padding to 4 pnl.SetPaddingAll(4); //--- Set the flags of relocation, auto resizing and auto changing mode from the inputs pnl.SetMovable(InpMovable); pnl.SetAutoSize(InpAutoSize,false); pnl.SetAutoSizeMode((ENUM_CANV_ELEMENT_AUTO_SIZE_MODE)InpAutoSizeMode,false); //--- In the loop, create 2 bound panel objects CPanel *obj=NULL; for(int i=0;i<2;i++) { //--- create the panel object with calculated coordinates, width of 90 and height of 40 CPanel *prev=pnl.GetElement(i-1); int xb=0, yb=0; int x=(prev==NULL ? xb : xb+prev.Width()+20); int y=0; if(pnl.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_PANEL,x,y,90,40,C'0xCD,0xDA,0xD7',200,true,false)) { obj=pnl.GetElement(i); if(obj==NULL) continue; obj.SetFrameWidthAll(3); obj.SetBorderStyle(FRAME_STYLE_BEVEL); obj.SetBackgroundColor(obj.ChangeColorLightness(obj.BackgroundColor(),4*i)); obj.SetForeColor(clrRed); //--- Calculate the width and height of the future text label object int w=obj.Width()-obj.BorderSizeLeft()-obj.BorderSizeRight(); int h=obj.Height()-obj.BorderSizeTop()-obj.BorderSizeBottom(); //--- Create a text label object obj.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_LABEL,pnl.BorderSizeLeft(),pnl.BorderSizeTop(),w,h,clrNONE,255,false,false); //--- Get the pointer to a newly created object CLabel *lbl=obj.GetElement(0); if(lbl!=NULL) { //--- If the object has an even or zero index in the list, set the default text color for it if(i % 2==0) lbl.SetForeColor(CLR_DEF_FORE_COLOR); //--- If the object index in the list is odd, set the object opacity to 127 else lbl.SetForeColorOpacity(127); //--- Set the font Black width type and //--- specify the text alignment from the EA settings lbl.SetFontBoldType(FW_TYPE_BLACK); lbl.SetTextAlign(InpTextAlign); lbl.SetAutoSize((bool)InpTextAutoSize,false); //--- For an object with an even or zero index, specify the Bid price for the text, otherwise - the Ask price of the symbol lbl.SetText(GetPrice(i % 2==0 ? SYMBOL_BID : SYMBOL_ASK)); //--- Set the frame width, type and color for a text label and update the modified object lbl.SetBorderSizeAll(1); lbl.SetBorderStyle((ENUM_FRAME_STYLE)InpFrameStyle); lbl.SetBorderColor(CLR_DEF_FRAME_COLOR); lbl.Update(true); } } } //--- Create the 'GroupBox' WinForms object CGroupBox *gbox=NULL; //--- Indent from attached panels by 6 pixels is a Y coordinate for GroupBox int w=pnl.GetUnderlay().Width(); int y=obj.BottomEdgeRelative()+6; //--- If the attached GroupBox object is created if(pnl.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_GROUPBOX,0,y,210,110,C'0x91,0xAA,0xAE',0,true,false)) { //--- get the pointer to the GroupBox object by its index in the list of bound objects gbox=pnl.GetElement(2); if(gbox!=NULL) { //--- set the "indented frame" type, the frame color matches the main panel background color, //--- while the text color is the background color of the last attached panel darkened by 1 gbox.SetBorderStyle(FRAME_STYLE_STAMP); gbox.SetBorderColor(pnl.BackgroundColor()); gbox.SetForeColor(gbox.ChangeColorLightness(obj.BackgroundColor(),-1)); //--- Create the CheckBox object gbox.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_CHECKBOX,2,10,50,20,clrNONE,255,true,false); CCheckBox *cbox=gbox.GetElement(0); //--- If CheckBox is created and the pointer to it is received if(cbox!=NULL) { //--- Set the CheckBox parameters from the EA inputs cbox.SetAutoSize((bool)InpCheckAutoSize,false); cbox.SetCheckAlign(InpCheckAlign); cbox.SetTextAlign(InpCheckTextAlign); //--- Set the displayed text, frame style and color, as well as checkbox status cbox.SetText("CheckBox"); cbox.SetBorderStyle((ENUM_FRAME_STYLE)InpCheckFrameStyle); cbox.SetBorderColor(CLR_DEF_FRAME_COLOR); cbox.SetChecked(true); cbox.SetCheckState((ENUM_CANV_ELEMENT_CHEK_STATE)InpCheckState); } //--- Create the RadioButton object gbox.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON,2,cbox.BottomEdgeRelative(),50,20,clrNONE,255,true,false); CRadioButton *rbtn=gbox.GetElement(1); //--- If RadioButton is created and the pointer to it is received if(rbtn!=NULL) { //--- Set the RadioButton parameters from the EA inputs rbtn.SetAutoSize((bool)InpCheckAutoSize,false); rbtn.SetCheckAlign(InpCheckAlign); rbtn.SetTextAlign(InpCheckTextAlign); //--- Set the displayed text, frame style and color, as well as checkbox status rbtn.SetText("RadioButton"); rbtn.SetBorderStyle((ENUM_FRAME_STYLE)InpCheckFrameStyle); rbtn.SetBorderColor(CLR_DEF_FRAME_COLOR); rbtn.SetChecked(true); } //--- Create the Button object gbox.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_BUTTON,(int)fmax(rbtn.RightEdgeRelative(),cbox.RightEdgeRelative())+10,10,30,30,clrNONE,255,true,false); CButton *butt=gbox.GetElement(2); //--- If Button is created and the pointer to it is received if(butt!=NULL) { //--- Set the RadioButton parameters from the EA inputs butt.SetAutoSize((bool)InpButtonAutoSize,false); butt.SetAutoSizeMode((ENUM_CANV_ELEMENT_AUTO_SIZE_MODE)InpButtonAutoSizeMode,false); butt.SetTextAlign(InpButtonTextAlign); //--- Set the displayed text, frame style and color, as well as checkbox status butt.SetText("Button"); butt.SetForeColor(butt.ChangeColorLightness(CLR_DEF_FORE_COLOR,2)); butt.SetBorderStyle((ENUM_FRAME_STYLE)InpButtonFrameStyle); butt.SetBorderColor(butt.ChangeColorLightness(butt.BackgroundColor(),-10)); butt.SetBorderColor(CLR_DEF_FRAME_COLOR); } } } //--- Redraw all objects according to their hierarchy pnl.Redraw(true); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Die Logik des Codeblocks für die Erstellung von drei Steuerelementen, die an GroupBox angehängt sind, ist im Code kommentiert. Ich glaube, da ist alles klar.
Die Schaltfläche (WinForm-Objekt Button) ist absichtlich größer als der Text und kleiner als die Breite. In diesem Fall, im Modus der automatischen Größenanpassung, können wir sehen, wie die Schaltfläche ihre Größe an den Text anpasst.
Kompilieren Sie den EA und starten Sie ihn auf dem Chart:
Es ist zu erkennen, dass die Schaltfläche ihre Größe je nach dem Modus der automatischen Größenanpassung korrekt an den Text anpasst. CheckBox und RadioButton haben normale, helle Checkbox-Felder, während CheckBox selbst jetzt eine gewisse Dicke hat.
Ich habe mit dem Mausrad einen Bildlauf durchgeführt, während ich mit der Maus über einige Steuerelemente gefahren bin. Die folgenden Einträge wurden im Journal angezeigt:
CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "Button" TstDE109_WFPanel_Elm02_Elm02 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "Button" TstDE109_WFPanel_Elm02_Elm02 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "Button" TstDE109_WFPanel_Elm02_Elm02 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "Button" TstDE109_WFPanel_Elm02_Elm02 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "Label" TstDE109_WFPanel_Elm01_Elm00 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "Label" TstDE109_WFPanel_Elm01_Elm00 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "Label" TstDE109_WFPanel_Elm00_Elm00
...
CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "CheckBox" TstDE109_WFPanel_Elm02_Elm00 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "CheckBox" TstDE109_WFPanel_Elm02_Elm00 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "RadioButton" TstDE109_WFPanel_Elm02_Elm01 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "RadioButton" TstDE109_WFPanel_Elm02_Elm01 CGraphElementsCollection::OnChartEvent: Mouse scroll: Control element "GroupBox" TstDE109_WFPanel_Elm02
Diese Einträge zeigen die richtige Wahl des aktiven Objekts für die Interaktion mit der Maus an.
Was kommt als Nächstes?
Im nächsten Artikel werde ich die Entwicklung neuer WinForms-Objekte fortsetzen und die Funktionsweise der bereits vorhandenen Objekte verbessern.
*Vorherige Artikel in dieser Reihe:
DoEasy. Steuerung (Teil 1): Erste Schritte
DoEasy. Steuerung (Teil 2): Arbeiten an der Klasse CPanel
DoEasy. Steuerung (Teil 3): Erstellen gebundener Steuerelemente
DoEasy. Steuerung (Teil 4): Paneel-Steuerung, Parameter für Padding und Dock
DoEasy. Steuerung (Teil 5): Basisobjekt von WinForms, Paneel-Steuerelement, Parameter AutoSize
DoEasy. Steuerung (Teil 6): Paneel-Steuerung, automatische Größenanpassung des Containers an den inneren Inhalt
DoEasy. Steuerung (Teil 7): Steuerung der Text Label
DoEasy. Steuerung (Teil 8): Objektkategorien von Basis-WinForms zur Steuerung von GroupBox- und CheckBox
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/11121





- 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.