DoEasy. 控件 (第 9 部分): 重新编排 WinForms 对象方法、RadioButton 和 Button 控件
内容
概述
在本文中,我将开始修复 WinForms 对象方法的名称,并将它们的构造逻辑转换为为所有函数库对象建立的概念 — 每个对象都有一组整数型、实数型和字符串型属性,这些属性是所有 WinForm 对象固有的,但对于每个特定对象,可以为对象设置由对象自己维护属性的标志。 如果对象不支持某个属性,则清楚选中该属性的标志,且该对象不再使用该属性。
以前,我许多属性只会存储在类变量中,但无论如何,我将把所有属性都转移到函数库的常规主流概念当中。 当我们简单地循环遍历所有属性,并显示正在构造的图形对象的属性名称时,或更改每个属性的元素时,这会简化基于自定义函数库程序的图形对象的可视化构造函数开发。 只有对象支持的属性才会显示在列表之中。 换言之,我们会有单一方法来显示任何对象的属性。 将为众多不同对象的每一个构建一个由对象支持的属性的单独列表。
在当前的文章中,我还将开始复活静态 WinForms 对象的操作 — 现在函数库将开始“查看”光标所覆盖的元素(因为容器面板可能含有多个其它需要交互的元素)。 稍后,我将为这些元素的交互添加鼠标操作 ,并发送事件来响应它们。
此外,我将创建两个 WinForms 对象 — Button 和 RadioButton。 这些是标准控件类别中的 标准 WinForms 对象。 它们不需要介绍了。 当然,所有这些元素的交互功能方面都会得到改进。 我开始为各种成熟元素添加基础。 稍后,我们将添加与鼠标交互的方法和各种视觉效果。
改进库类
针对控件的情况,我们在创建时会默认设置某些值。 我们更新这些值的列表。
在 \MQL5\Include\DoEasy\Defines.mqh 中的画布参数部分,为 CheckBox 元素颜色添加宏替换:
#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
在图形元素类型列表中,加入两个新元素类型,我打算在本文创建对象时用到:
//+------------------------------------------------------------------+ //| 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 }; //+------------------------------------------------------------------+
在基于画布的图形元素的整数型属性枚举中,添加新的元素属性,并将整数型属性的总数从 48 个更改为 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
在画布上图形元素排序的可能条件列表中,添加新的条件,与新添加的属性相对应:
//+------------------------------------------------------------------+ //| 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 }; //+------------------------------------------------------------------+
现在,我们可以根据新属性选择和排序所有图形元素。
在 \MQL5\Include\DoEasy\Data.mqh 里,添加新的消息索引:
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 }; //+------------------------------------------------------------------+
以及与新添加的索引对应的消息文本 :
{"Ноябрь","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"}, }; //+---------------------------------------------------------------------+
稍后我们需要所有这些消息,来显示图形控件属性的描述。
控件类型描述在返回图形元素类型描述的方法中实现,该类型是 \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh 中基准函数库图形对象的类。 我们来补充一些代码,返回新类型的描述:
//+------------------------------------------------------------------+ //| 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" ); } //+------------------------------------------------------------------+
根据图形元素类型,该方法返回含有类型描述的字符串。
我们命名设置或返回颜色的方法存在不一致。 例如,ForeColor() 方法返回文本颜色。 与此同时,返回背景色的方法名为 ColorBackground()。 为了令命名相互一致,我们将 ColorBackground() 方法和类似方法重命名为 BackgroundColor()。 此外,我还介绍了图形元素的新属性,在鼠标光标悬停在对象上并单击时这些属性可指定颜色。 我们还应该添加一些方法,设置和返回这些以及所有其它新属性。
打开图形元素对象类的文件 \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh。
鉴于我们有渐变背景色,所以我们用颜色数组来存储所有渐变颜色。 我们需要再添加两个或更多这样的数组 — 在鼠标悬停在对象上,并单击鼠标指针所指对象时,存储其背景渐变色。
在类的受保护部分中,声明两个这样的数组:
//+------------------------------------------------------------------+ //| 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:
我们的对象结构接受所创建图形元素的所有属性,以便随后在媒体上保存对象的属性,并在终端和程序重新启动时从中读取以便恢复对象。
在结构里添加所有新属性:
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
现在,我们已在结构中拥有了所有必要的属性字段,可以从结构中正确保存和恢复对象。 将对象属性写入文件的代码将在稍后实现。
从类的私密部分,删除两个存储背景色及其非透明度的变量,因为现在这些变量的值均已直接存储在对象属性当中:
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
以前,我们有一个 SaveColorsBG 方法可将颜色保存到背景色数组当中。 现在我们有了若干不同的梯度。 它们的颜色将被存储在数组中。 因此,声明复制颜色数组到指定背景色数组的方法,然后再添加两个保存渐变背景色的方法:
//--- 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:
第一个方法从数组里复制颜色,转存到传递给方法的指定数组,而另两个方法则将传递给这些方法的颜色数组复制到上面声明的相应渐变颜色数组。
从类的公开部分中,创建图形元素的方法里,从其输入中删除两个变量,因为它们在方法中的任何地方都未用到:
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);
添加两个返回标志的方法,指示对象是主要的和(或)基准的:
//--- (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; }
这些方法只是简单地检查指向主对象和基准对象的指针是否等于 NULL。
而此指针值,对象即可以是主要的,亦或是基准的,因为若对象绑定到另一个对象,则指向主要和基准对象的指针将在 GetMain() 和 GetBase() 方法返回的变量中设置。 因此,如果指针等于 NULL,则该对象未绑定到任何其它对象,并且可以是层次结构中其它对象的主对象(相关对象层次结构中的第一个对象),或基准对象(其它对象附加于它,但它本身不是主对象,因为它又附加于整个层次结构的公共链中的另一个对象)。
重命名设置背景颜色的方法,并添加处理在对象上单击或悬停光标的方法:
//--- (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,
现在,取代将值写入删除的变量,将值写入对象属性。 我们在以前的文章中曾研究过这些方法。 因此,在这里重复讲述它们没有意义。
类似地,重命名返回背景色值的方法,编写新方法来返回其它背景颜色值:
//--- 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(); }
在此,我们还返回设置在对象属性中的值,而非已删除的变量。 我以前曾研究过这些方法,所以无需在此赘言。
ChartColorBackground() 方法也将被重命名(以及所有其它返回颜色参数,和未遵循颜色方法名称构造原则的方法):
//--- 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
在参数型类构造函数中,调用实现此操作的方法,替换将值写入变量,添加把背景色保存到附加背景色数组之中(当单击并将光标悬停在对象上时),采用默认值初始化所有新的图形元素属性:
//+------------------------------------------------------------------+ //| 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); } } //+------------------------------------------------------------------+
在受保护的构造函数中,以相同的方式编写所有内容。 这些更改与上面所研究的构造函数中的更改几乎相同,所以我在此不再啰嗦。 您可以在文后所附的函数库文件中找到它们。
创建对象结构的方法也得到了改进,可以将新对象属性的值写入结构字段(我们全盘考虑):
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
以同样方式,从结构创建对象的方法也业已完成:
//+------------------------------------------------------------------+ //| 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 } //+------------------------------------------------------------------+
这两种方法是相同的,但彼此互逆。 第一个方法,在结构字段中设置相应的对象属性,而第二个方法则在对象属性中设置相应结构字段中的值。
在创建图形元素对象的方法实现中删除未使用的变量:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
在设置元素不透明度的方法中,替换将不透明度值保存到变量的代码,
this.m_opacity=value;
加入将其保存到对象属性:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
实现将颜色数组复制到指定背景颜色数组的方法:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
该方法接收数组,我们应该在其中写入来自源数组的所有数据。 如果数组大小不匹配,目标数组将更改其大小,以便适应源数组的大小。 然后将源数组的整个内容复制到目标数组。
在 \MQL5\Include\DoEasy\Objects\Graph\ShadowObj.mqh 中的阴影对象类构造函数中,重命名所调用方法的名称:
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
窗体对象是实现与鼠标交互功能的对象。 WinForms 函数库对象的基准对象是其子对象。 我们需要改进窗体对象类 \MQL5\Include\DoEasy\Objects\Graph\Form.mqh 文件中的多个方法。
处理颜色的方法需要重命名,并添加新方法。 处理对象“边框”的方法也将被重命名。 它们将被称为 “Border”,替代了 “Frame”。 此外,还可以将其它对象附加到该对象,例如,可以在面板上创建按钮或文本…
当鼠标悬停在这样的面板上时,函数库需判定光标当前是否悬停在面板上。 不过,它无法定义光标是否位于附着于面板的对象之上。 相应地,也无法与附加于面板上的对象交互。
为了解决这个问题,我们需要查看附加于面板的所有对象的列表,并判定层次结构中光标所在处的最后那个对象。 为此,我们创建一个附加于面板上的所有对象的列表。 据此,其它对象也可以绑定到已附着的对象。 也就是说,我们需要遍历此类对象的整个层次结构。
为此,我们创建一个列表,其中包含指向所附对象的指针。 我们将它们称为交互对象,由于我们正在寻找鼠标将要与之交互的对象,以及将所有附加到该对象的其它控件添加到列表中的方法。 如果附加的元素也有自己的附加对象,那么将为它调用相同的方法,而传递给该方法的指针,需指向保存对象指针的列表。
因此,我们可以遍历附加对象的整个层次结构,并获得指向它们的指针列表。 在那之后一切都变得容易了。 一旦我们判定光标悬停在面板上,我们就调用面板的方法,创建所有附加对象的列表。 然后我们要做的就是从列表末尾找到开头的那个对象,它上面有光标悬停的标志。 传递指向所发现对象的指针,以便进一步的处理,因为处理程序早就空位以待了。
从类的受保护部分删除不必要的变量:
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
现在,所有值都存储在对象属性中,替代原来的变量中。
从 CreateAndAddNewElement() 方法中,删除指向所有相互连接的对象的层次结构的主对象的指针:
//--- 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:
以前,在创建附加对象时,我们必须在方法参数中明确指定要创建的对象的主对象,并将指针传递给它。 现在,我们要确保层次结构中的主对象或基准对象能自动判定,如此可避免最终用户在创建新的附加控件时不必要地指定此类对象。
同样在受保护的部分中,声明创建所有交互对象列表的方法,声明依据名称返回列表中对象存在标志的方法:
//--- 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:
在公开部分中,声明一个方法,创建一个所有交互对象的列表(尽管没有在方法形参中传递指向列表的指针),以及依据索引返回指向交互对象列表中窗体对象指针的方法:
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); }
第一个方法是从鼠标光标悬停处的对象里调用。 在主对象的层次结构中搜索其余交互对象的受保护方法,也会在方法内部调用。 指向列表的指针将被传递给层次结构的每个后续对象,因此光标所在处的对象,应当是所有附加对象列表里最开头的第一个对象。
我们来编写从其属性返回和设置所有对象边框维度的方法:
//--- (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)
我们添加从所创建列表中返回交互对象列表的方法,和返回交互对象数量的方法:
//--- 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); }
从创建新附加元素的方法中,删除要传递的主对象指针:
//--- 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
我们现在不需要这个指针了,因为函数库将自己定义哪个对象是主对象,哪个是基准对象。
重命名设置和返回窗体边框颜色的方法,添加处理其它窗体背景颜色的新方法:
//+------------------------------------------------------------------+ //| 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); }
现在,这些方法不用变量操作了,而是取用对象属性中的值。
在变量初始化方法中,清空交互对象列表,并为其设置排序列表标志。 替代将窗体边框的维度写入变量,用上面编写的新方法设置它们:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
以前,我们不仅为每个创建的对象指定了实际坐标(在图表坐标系中),而且还指定了一次相对坐标 — 即距创建对象所附着的对象坐标原点的距离(以像素为单位)。 我们只简单地指示了创建期间设置的对象边缘缩进值。
这并不完全有效,且需要不断监测这些坐标,以防它们发生变化。 现在,我们将计算它们在屏幕上的坐标 — 从基准对象的屏幕坐标中减去绑定对象的屏幕座标。 因此,无论绑定对象的坐标有何变化,我们都会准确地知道其相对坐标。
在创建新图形对象的方法中,计算并设置元素的相对坐标:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
在创建新附加元素,并将其加入附加对象列表的方法中,重命名设置对象背景的方法,定义并写入附加对象层次结构的主对象指针,以及计算并设置所创建附加控件的相对坐标:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
我们如何定义层次结构的主要对象? 一切都很简单:如果对象没有附加到任何其它对象,那么它指向主对象的指针初值等于 NULL。 如果创建的另一个控件附加到这样的对象,则会检查指向主对象的指针值。 如果指针为 NULL,则控件将成为主对象。 否则,该对象已经含有指向整个层次结构的主对象的指针 — 其值已写入新创建的控件。 因此,整个层次结构中总会有一个主对象,即创建附加对象层次结构的第一个对象。
从创建新附加元素的方法中,删除将指针传递给主对象的操作,相应地,把传递给 CreateAndAddNewElement() 方法的多余值删除:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
因为我们现在有了返回对象边框宽度的方法,这些值不是存储在变量中,而是存储在对象属性当中,然后在返回绑定对象初始坐标的方法中,从新方法取值来替换原先访问变量:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
重命名被调用的方法,将处理变量替换为处理对象属性,
//+------------------------------------------------------------------+ //| 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()); } //+------------------------------------------------------------------+
该方法按名称返回指示交互对象列表中对象指针存在的标志:
//+----------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
循环遍历交互对象列表,我们得到下一个窗体对象。 如果其名称等于传递给方法的名称,则返回 true — 具有相同名称的对象已在列表中。 直到循环完成后,返回 false — 未找到具有指定名称的对象。
创建所有交互对象列表的受保护方法:
//+------------------------------------------------------------------+ //| 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); } } //+------------------------------------------------------------------+
循环遍历所有附加对象,获取下一个窗体对象。
如果尚未收到对象,或其类型低于窗体对象,则转到下一个。
如果列表中已存在同名对象,则转到下一个。
如果对象成功地放置在交互对象列表中,则为该对象调用相同的方法,来搜索附加到它的交互对象。
与此同时,方法接收方法输入中指定的列表。
因此,指向整个附加对象层次结构中所有交互对象的指针将放在一个列表中。
我们传递主对象中附着的列表,并在创建所有交互对象列表的公开方法中指定它:
//+------------------------------------------------------------------+ //| Create the list of all interaction objects | //+------------------------------------------------------------------+ int CForm::CreateListInteractObj(void) { this.CreateListDepInteractObj(this.GetListInteractObj()); return this.m_list_interact.Total(); } //+------------------------------------------------------------------+
这里的一切都很简单:调用上面的方法来创建交互对象列表,同时将指向当前对象列表的指针传递给它。 从方法中,返回添加到列表中的交互对象的指针数量。
改进在 \MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqh里的 函数库 WinForms 对象的基准对象类。
由于我们删除了存储窗体边框宽度的变量,并将其替换为窗体对象类文件中的方法,现在我们需要删除文件中现已作废的设置和返回边框宽度的方法:
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); }
在设置缩进大小的方法中,把访问变量替换为读取方法返回的值:
//--- 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); }
用新的 BorderSize 方法替换调用旧的 FrameWidth 方法:
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); } //+------------------------------------------------------------------+
声明返回控件属性描述的方法:
//--- 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); }; //+------------------------------------------------------------------+
在类的构造函数中,使调用新方法设置属性值,来替换为变量赋值:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
返回字体样式描述的方法:
//+------------------------------------------------------------------+ //| 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) ); } //+------------------------------------------------------------------+
依据指定的字体样式,返回对应的文本消息。
该方法返回字体宽度类型描述:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
ENUM_FW_TYPE 枚举具有以下常量:
//+------------------------------------------------------------------+ //| 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 }; //+------------------------------------------------------------------+
例如,对于常规宽度类型,我们需要从位置 8 开始取 FW_TYPE_REGULAR 常量的一个子字符串。 从常量名中提取子字符串后,我们得到 “REGULAR” 字符串。 此处的所有字符均为大写。 现在,我们需要将除第一个字符外的所有字符都变为小写。
为此,我们只需在符号编码中加上偏移量 32(0x20),因为小写字符编码与大写字符的差异正好为 32(0x20)。 提取出来的由大写字符组成的子字符串被输入到 uchar 数组之中。 然后循环遍历数组中所有字符(对于每个字母),每个字符值加上 32。 由于第一个字符(在数组的单元格 0 中)不需要更改,因此从数组的单元格 1 开始循环(从第二个字符开始)。 结果就是,将修改后的 uchar 数组转换回字符串,并返回。
该方法返回控件边框样式的描述:
//+------------------------------------------------------------------+ //| 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) ); } //+------------------------------------------------------------------+
返回的文本消息取决于为对象设置的边框样式。
该方法返回控件整数型属性的描述:
//+------------------------------------------------------------------+ //| 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) ) : "" ); } //+------------------------------------------------------------------+
把对象整数型属性传递给方法。 从方法返回的字符串取决于传递给方法的属性,以及指示对象维护该属性的标志。 几乎在函数库的每个对象中都有类似的方法,故在此重复研究它是没有意义的。 到目前为止,每个图形元素都支持所有属性。 在创建了大多数 WinForms 对象,及其交互功能后,我将添加一些方法,可返回维护图形元素特定属性的标志,同时可以对这些属性的值进行可视化控制,并通过鼠标或键盘工具对其进行更改。
返回控件属性描述的方法:
//+------------------------------------------------------------------+ //| Return the description of the control real property | //+------------------------------------------------------------------+ string CWinFormBase::GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_DOUBLE property,bool only_prop=false) { return(""); } //+------------------------------------------------------------------+
由于我们还没有图形元素的实际属性,所以该方法返回一个空字符串。
返回控件的字符串型属性描述的方法:
//+------------------------------------------------------------------+ //| 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)+"\"" : "" ); } //+------------------------------------------------------------------+
该方法接收对象字符串属性。 根据传递给方法的属性,构造从方法返回的字符串。
该方法根据内容返回控件自动调整大小的描述:
//+------------------------------------------------------------------+ //| 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) ); } //+------------------------------------------------------------------+
根据自动调整控件大小的模式,返回相应的文本消息。
该方法返回元素边界绑定到容器模式的描述:
//+-------------------------------------------------------------------------------------+ //| 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) ); } //+------------------------------------------------------------------+
根据边框绑定模式,返回相应的文本消息。
该方法返回复选框控件的状态描述:
//+------------------------------------------------------------------+ //| 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) ); } //+------------------------------------------------------------------+
取决于控件复选框的状态,返回相应的文本消息。
在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\CommonBase.mqh 中,针对标准 WinForms 对象的标准控件的基准对象类做一些小改进。
修改自动设置控件宽度和高度的方法的类型,将其从 void 改为 bool 。 对于每个衍生对象,方法的实现可能不同,因此,如果需要修改此方法的逻辑,它应在不同的类中以自己的方式重新定义。 但它应该能够回报其操作结果。 如果对象不改变其大小,则无需在类中重新定义方法。 于此,它简单地返回 true 且无任何操作:
//+------------------------------------------------------------------+ //| 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:
在变量初始化方法中,采取调用方法设置边框宽度值来替换原先的直接设置变量数值,并重命名设置背景色的方法:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
重命名返回边框宽度值的方法:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
文本标签对象类 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\Label.mqh 提供了根据文本锚点和对齐方式计算标签坐标的方法。 所有这些都是在对象重画方法中完成的。 这不是最优的,因为从这个类继承的许多对象可能也需要定位标签。 因此,我们将把文本坐标的计算从文本标签重绘方法中转移到一个新方法,并在必要时调用它,不仅在文本标签对象类中,而且在其后代中也如此。
在受保护的类部分中,更改控件自动调整大小方法的类型,声明根据其对齐模式设置坐标和文本锚点的方法,而在类的公开部分中,声明依据内容设置控件自动调整大小标志的方法:
//+------------------------------------------------------------------+ //| 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
由于计算文本坐标的方法现在已转移到单独的方法之中,故对象重绘方法变得更简洁:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
该方法依据对齐模式设置文本坐标和锚定点:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
计算文本坐标的代码从对象重绘方法转移到这里。 之前重命名的方法如今在这里调用。
由于自动设置元素宽度和高度的虚拟方法现在应该返回一个结果,该方法将对象大小调整的结果写入返回的变量,取代了简单地在对象属性里设置新的宽度和高度:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
该方法依据内容设置元素自动调整大小的标志:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
如果传递给方法的标志设置初值,且其可以调整对象的大小,则将标志值赋值给属性。
在本文章中,我将实现 RadioButton WinForms 对象类。 在其内部内容中,该对象类似于 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\CheckBox.mqh 中实现的 CheckBox 控件。 不过,与最后一个不同,RadioButton 对象有一个圆形可选取区域,代替了复选标记的方形区域。 因此,从 CheckBox 对象类继承并重新定义可选择区域的绘制方法,对我们大有益处。 我们删除 SetTextCoords() 方法,因为它与 SetTextParamsByAlign() 父对象方法完全重复。 为了令 CheckBox 对象的所有变量在其后代中保持可用,需把它们从私密部分移动到受保护部分:
//+------------------------------------------------------------------+ //| 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);
自动设置控件宽度和高度的虚拟方法现在应该是 bool 类型。
在类的公开部分中,修改设置复选框和控件状态的方法。 现在,在设置状态之前,首先检查当前状态,因为设置状态会导致标志和对象被重新绘制,并非简单地将值设置为对象属性。 编写设置标志和对象背景颜色的方法:
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
在对象重画方法中,重命名设置背景颜色的方法:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
在 SetCorrectTextCoords() 方法中,添加调用 SetTextParamsByAlign 父类方法,替换调用已删除的 SetTextCoords 方法:
//+------------------------------------------------------------------+ //| 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 //--- ... //--- ...
我们修改绘制选择复选框的方法。 复选框不应像以前那样绘制在透明背景上,而应绘制在填充矩形和框架矩形的背景上。 在该区域中绘制的复选标记很薄,故此我不只绘制一条,而是绘制三条线,每一条线的中心比前一条线高一个像素。 当然,从选择复选框可伸缩性的角度来看,这是不正确的,但我稍后将对绘制复选框的折线坐标进行相对计算:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
自动设置控件宽度和高度的方法现在为布尔类型,并返回结果:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
这里的所有方法都类似于上面研究的文本标签对象类方法。 声明变量,将大小调整结果写入该变量,然后返回该结果。
RadioButton WinForms 对象
该对象将是 CheckBox WinForms 对象的后代,因为它几乎完全重复其功能和内部组织。
在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ 函数库文件夹里,创建 CRadioButton 类的新文件 RadioButton.mqh。
该类应派生自 CCheckBox 类,而其文件应包含在所创建的类文件当中:
//+------------------------------------------------------------------+ //| 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 { }
在类的受保护部分中,声明显示复选框的虚拟方法,而在公开部分中声明参数型构造函数:
//+------------------------------------------------------------------+ //| 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); }; //+------------------------------------------------------------------+
显示复选框的方法重新定义了父类方法,因为复选框在此处是圆形的,与 checkbox 对象的方形不同。
我们研究一下这些方法。
参数型构造函数:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
这里,我们只定义 WinForms 对象类型,并重新绘制对象。 其它一切都是在父类构造函数中创建和设置的。
该方法按照指定状态显示复选框:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
与父类相似,首先在此处绘制一个填充了背景色的圆形。 然后我们画出它的边缘。 取决于传递给方法的状态,或在已绘制圆形之内,绘制另一个(直径较小),或不绘制任何内容。
这些都是创建对象所必需的。 其它一切都在父类中实现。
Button WinForms 对象
按钮对象实际上是一个文本标签。 文本标签也能够绘制对象边框。 此外,还可以在控件边框内定位文本。 标签仅绘制在透明背景上,而按钮则绘制在已填充的背景上。 因此,按钮对象将继承自文本标签对象。
在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\ 里,创建 CButton 类的新文件 Button.mqh。
该类应继承自 CLabel 类,而其文件应包含在所创建的文件当中:
//+------------------------------------------------------------------+ //| 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 { }
在类的私密部分中,声明存储按钮标签坐标的变量,而在受保护部分中,声明自动设置控件大小的虚拟方法:
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:
在公开部分,声明重绘对象的虚拟方法,编写设置并返回自动调整对象大小模式的方法,从而适应标签大小:
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); }; //+------------------------------------------------------------------+
在参数型构造函数中,设置控件类型和对象属性的默认值,并调用重绘方法:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
该方法重绘对象:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
首先,用背景色填充对象边界。 然后依据文本对齐方式计算出的坐标绘制标签,并更新对象。
自动设置元素宽度和高度的方法:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
该方法几乎与上面研究的父类方法雷同。 但是,我们应该记住,大小会根据指定的调整大小模式而变化。 换句话说,仅递增模式下,只有当文本超出该模式时,对象大小才会增加。 在递增和递减模式下,整个对象会依据其内部文本大小调整。
当然,按钮对象的功能是包含更多的元素;伴随其它 WinForms 对象的开发,其它所有内容都将在后续文章中添加。
为了创建绑定对象,容器对象应该知道新创建的控件是否存在。 为此,我们需要将新类的文件包含到容器对象的类文件当中。
所有容器对象的父类则是基准容器对象类,其实现位于 \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Container.mqh。
将新控件的文件包含到其中。 替代 CheckBox.mqh,包含 RadioButton 对象文件,因为它是 CheckBox 元素的后代。 因此,它们在类中均可见:
//+------------------------------------------------------------------+ //| 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" //+------------------------------------------------------------------+
由于创建新图形对象的方法对于每个继承的类都是不同的,所以在此我们只声明虚拟方法,并删除具体实现。 该方法将返回 NULL:
//+------------------------------------------------------------------+ //| 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
将 FrameWidth 公开方法重命名为 BorderSize 方法:
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
从创建新元素的方法中删除指向主对象的指针:
//--- 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);
在方法实现中,添加所有已知控件的创建:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
调整元素大小调整适配其内部内容的方法已被转换,但它仍然无法正常工作,故于此,我们只附带其当前实现,且不做任何解释,除外方法代码中已存在的注释:
//+------------------------------------------------------------------+ //| 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) ); } //+------------------------------------------------------------------+
类中的其它次要修改,都是实验的结果,与本文的主题无关,在此不予研究。 当一切操作正常时,我会再回到它们。
GroupBox 容器对象类位于 \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\GroupBox.mqh,也略有改善。
调用重命名方法也已更正:
//--- 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); } //+------------------------------------------------------------------+
创建新图形对象的虚拟方法拥有创建所有当前已知元素的能力:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
我们还应该改进 \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Panel.mqh 中 Panel 对象的容器类。
在间隔方法中,我们需要在设置其坐标和大小后,计算并设置参考底图偏移:
//--- 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()); } }
以前,偏移是在计算坐标和尺寸之前计算的。 这在进行某些变化后会导致偏移计算错误。
在创建新图形对象的方法中,添加所有已知元素的创建:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
在创建所有参考底图参数的方法中,计算坐标偏移如下:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
在 Move 方法中,修改对象偏移值的计算方法:
//--- Shift all bound objects if(!this.MoveDependentObj(x+this.GetCoordXUnderlayRelative(),y+this.GetCoordYUnderlayRelative(),false)) return false;
现在,此处一切都更简单:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
由于现在是计算所有对象的相对坐标,且初始设置的坐标已废弃,因此已无需再进行任何调整。 我们简单地把传递给方法的 X 和 Y 值替换,然后移动。
鉴于我在类中重命名了一些被主动访问的方法,导致我在 \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh 中的图形元素集合类进行了多次改进。 我认为,在此讲述所有重命名的简单实例没有意义。 我已在整篇文章中考虑到了所有类似的变化。 您可在文后所附的文件中找到它们。
我需要重点关注的是找到连接到面板的对象,并创建一个交互对象列表,以便我们判定鼠标应该与哪个对象交互。
在返回光标所覆盖窗体指针的方法中,我们需要添加两个代码模块(它们很相似,很可能会在测试后将它们移动到单独的方法中)。 在这些模块中创建所有对象附着到面板的列表,即它们的层次结构,其中最后的新对象当作要交互的对象返回:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
代码注释中详细描述了整个逻辑。 我希望这里一切都清楚。 如果您有任何疑问,请随时在下面的评论中提问。
在 CGraphElementsCollection::OnChartEvent() 类事件处理程序中,即在“光标位于活动区域内,鼠标滚轮正在滚动”事件处理程序块中,将光标所在处的图形元素的类型和名称显示在日志之中。 沿此方式,就可以管理鼠标与光标所在处对象的交互。 如果将鼠标悬停在元素上并滚动鼠标滚轮,对象数据将显示在日志之中:
//--- '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()); }
测试
为了执行测试,我将取用来自以前文章的 EA,并将其保存到 \MQL5\Experts\TestDoEasy\Part109\,命名为 TstDE109.mq5。
往 EA 输入里添加新参数,允许设置选择性复选框和文本对齐,以及按钮对象参数:
//--- 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
在 OnInit()处理程序中,在面板 Container 容器中创建所有所需对象:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
创建附加到 GroupBox 的三种控件的逻辑已在代码模块里进行了注释。 我想,那里的一切都很清晰明了。
按钮(button WinForm 对象)的高度故意设置大于文本,而宽度相似。 在这种情况下,在自动调整大小模式下,我们可以看到按钮如何调整其大小来适配文本。
编译 EA,并在图表上启动它:
可以看出,按钮根据自动调整大小模式正确调整其大小以适配文本。 CheckBox 和 RadioButton 是普通亮度的复选框区域,而 CheckBox 本身现在具有一定的厚度。
我滚动鼠标滚轮,同时将鼠标悬停在一些控件上。 日志中显示了以下项目:
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
这些条目表明与鼠标交互的活动对象的正确选择。
下一步是什么?
在下一篇文章中,我将继续开发新的 WinForms 对象,并改进现有对象的功能。
*该系列的前几篇文章:
DoEasy. 控件 (第 1 部分): 第一步
DoEasy. 控件 (第 2 部分): 操控 CPanel 类
DoEasy. 控件 (第 3 部分): 创建绑定控件
DoEasy. 控件 (第 4 部分): 面板控件,Padding(填充)和 Dock(驻靠)参数
DoEasy. 控件 (第 5 部分): 基准 WinForms 对象,面板控件,AutoSize 参数
DoEasy. 控件 (第 6 部分): 面板控件,自动调整容器大小来适应内部内容
DoEasy. 控件 (第 7 部分): 文本标签控件
DoEasy. 控件 (第 8 部分): 基准 WinForms 对象类别,GroupBox 和 CheckBox 控件
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/11121