English Русский Español Deutsch 日本語 Português
preview
DoEasy. 控件 (第 10 部分): WinForms 对象 — 动画界面

DoEasy. 控件 (第 10 部分): WinForms 对象 — 动画界面

MetaTrader 5示例 | 12 十月 2022, 10:23
1 038 0
Artyom Trishkin
Artyom Trishkin

内容


概述

事实上,所有以前创建的 WinForms 对象都是静态图像,您只能在屏幕上拖动它。 现在是时候实现动画图形界面功能,方便用户与对象的交互了。

我们已经创建的 WinForms 对象既是构建图形界面的独立单元,也是构建更复杂对象的组件。 为了让更复杂的对象能正确工作,还需要新功能。 在本文中,我将开始实现所有这些东西。 此外,我将为与鼠标交互的对象创建一个可视化组件。 在后续文章中,我将实现这些对象的事件功能,并继续创建新的 WinForms 函数库对象。

每个能够与鼠标交互,并具有可用性标志的活动 GUI 对象都应该通知用户其可与鼠标交互。 例如,我们看一个简单的按钮。 当鼠标悬停在按钮上时,按钮会略微改变颜色,通知用户它处于活动状态,并准备好进行交互。 按下时,它会再次变换颜色,但尚未触发。 当在交互对象范围内释放鼠标按钮时,就会触发。 如果在对象上按下鼠标按钮,但不释放鼠标,将光标移离对象,然后释放鼠标按钮,则不应触发对象 — 它将返回到按下鼠标按钮之前的状态。 这是 Windows 操作系统中所有对象的行为方式。 在此,我们为 WinForms 对象实现了相同的行为。

完成可视化组件后,我将开始创建 WinForms 对象的事件功能,这令我们能够依据简单对象创建更复杂的对象。 由简单对象组成的复杂对象的事件将交由对象本身进行分析和处理。 它的外观也会相应地改变,因此,对象会将此对象中发生的事件发送到控制程序所处图表。

由于对象现在需要为同一状态提供更多颜色(基准颜色、鼠标光标悬停时的颜色、按下对象上的按钮时的颜色),我们来为对象所有这些可能的不同属性添加对应的新颜色。 如果对象属性中存在新颜色,那么稍后我们就可以更容易为这些对象创建可视化编辑器 — 所有属性都可以显示在面板上并进行处理。 如果没有在对象属性中设置新的附加颜色,我们将不得不为每个对象手动设置,以便显示它们。 这不是最优雅的解决方案。


改进库类

在 \MQL5\Include\DoEasy\Defines.mqh 里,添加新的宏替换,作为各种 WinForms 对象状态的默认颜色:

//--- Canvas parameters
#define PAUSE_FOR_CANV_UPDATE          (16)                       // Canvas update frequency
#define CLR_CANV_NULL                  (0x00FFFFFF)               // Zero for the canvas with the alpha channel
#define CLR_DEF_FORE_COLOR             (C'0x2D,0x43,0x48')        // Default color for texts of objects on canvas
#define CLR_DEF_FORE_COLOR_MOUSE_DOWN  (C'0x0E,0x11,0x98')        // Default color for texts of objects on canvas when clicking the mouse on the control
#define CLR_DEF_FORE_COLOR_MOUSE_OVER  (C'0x14,0x67,0xF1')        // Default color for texts of objects on canvas when hovering the mouse over the control
#define CLR_DEF_FORE_COLOR_OPACITY     (255)                      // Default color non-transparency for canvas object texts
#define CLR_DEF_BORDER_COLOR           (C'0x2D,0x43,0x48')        // Default color for object frames on canvas
#define CLR_DEF_BORDER_MOUSE_DOWN      (C'0x61,0x88,0xC9')        // Default color for object frames on canvas when clicking the mouse on the control
#define CLR_DEF_BORDER_MOUSE_OVER      (C'0x93,0xAD,0xC8')        // Default color for object frames on canvas when hovering the mouse over the control
#define CLR_DEF_BORDER_COLOR_OPACITY   (255)                      // Default color non-transparency for canvas object frames
#define CLR_DEF_BORDER_COLOR_DARKNESS  (-2.0)                     // Default color opacity for canvas object frames (when using the background color)
#define CLR_DEF_FRAME_GBOX_COLOR       (C'0xDC,0xDC,0xDC')        // Default color for GroupBox object frames on canvas
#define CLR_DEF_OPACITY                (200)                      // Default color non-transparency for canvas objects
#define CLR_DEF_SHADOW_COLOR           (C'0x6B,0x6B,0x6B')        // Default color for canvas object shadows
#define CLR_DEF_SHADOW_OPACITY         (127)                      // Default color opacity for canvas objects
#define DEF_SHADOW_BLUR                (4)                        // Default blur for canvas object shadows

#define CLR_DEF_CHECK_BACK_COLOR       (C'0xFF,0xFF,0xFF')        // Color of control checkbox background
#define CLR_DEF_CHECK_BACK_OPACITY     (255)                      // Opacity of the control checkbox background color
#define CLR_DEF_CHECK_BACK_MOUSE_DOWN  (C'0xC0,0xDC,0xF3')        // Color of control checkbox background when clicking on the control
#define CLR_DEF_CHECK_BACK_MOUSE_OVER  (C'0xD8,0xE6,0xF2')        // Color of control checkbox background when hovering the mouse over the control
#define CLR_DEF_CHECK_BORDER_COLOR     (C'0x2D,0x43,0x48')        // Color of control checkbox frame
#define CLR_DEF_CHECK_BORDER_OPACITY   (255)                      // Opacity of the control checkbox frame color
#define CLR_DEF_CHECK_BORDER_MOUSE_DOWN (C'0x00,0x54,0x99')       // Color of control checkbox frame when clicking on the control
#define CLR_DEF_CHECK_BORDER_MOUSE_OVER (C'0x00,0x78,0xD7')       // 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)                      // Opacity of the control checkbox color
#define CLR_DEF_CHECK_FLAG_MOUSE_DOWN  (C'0x00,0x54,0x99')        // Color of control checkbox when clicking on the control
#define CLR_DEF_CHECK_FLAG_MOUSE_OVER  (C'0x00,0x78,0xD7')        // Color of control checkbox when hovering the mouse over the control

#define CLR_DEF_CONTROL_STD_BACK_COLOR (C'0xF0,0xF0,0xF0')        // Standard controls background color
#define CLR_DEF_CONTROL_STD_MOUSE_DOWN (C'0xC0,0xDC,0xF3')        // Color of standard control background when clicking on the control
#define CLR_DEF_CONTROL_STD_MOUSE_OVER (C'0xD8,0xE6,0xF2')        // Color of standard controls background when hovering the mouse over the control
#define CLR_DEF_CONTROL_STD_OPACITY    (255)                      // Opacity of standard controls background color

#define CLR_DEF_CONTROL_STD_BACK_COLOR_ON (C'0xC9,0xDE,0xD0')     // Background color of standard controls which are on
#define CLR_DEF_CONTROL_STD_BACK_DOWN_ON (C'0xA6,0xC8,0xB0')      // Color of standard control background when clicking on the control when it is on
#define CLR_DEF_CONTROL_STD_BACK_OVER_ON (C'0xB8,0xD3,0xC0')      // Color of standard control background when hovering the mouse over the control when it is on

#define DEF_FONT                       ("Calibri")                // Default font
#define DEF_FONT_SIZE                  (8)                        // Default font size
#define DEF_CHECK_SIZE                 (12)                       // Verification flag default size
#define OUTER_AREA_SIZE                (16)                       // Size of one side of the outer area around the form workspace
#define DEF_FRAME_WIDTH_SIZE           (3)                        // Default form/panel/window frame width
//--- Graphical object parameters

复选框不需要 ForeColor。 所以我们用 BorderColor 替代它 — 复选框边框颜色。 当与鼠标交互时,它将随背景颜色而变化。 复选框颜色在此处用作 ForeColor。

与窗体相关的另一个鼠标状态会由函数库跟踪,即光标位于活动区域,鼠标按钮在单击后再释放。 将新状态添加到与窗体相关的可能鼠标状态列表中:

//+------------------------------------------------------------------+
//| The list of possible mouse states relative to the form           |
//+------------------------------------------------------------------+
enum ENUM_MOUSE_FORM_STATE
  {
   MOUSE_FORM_STATE_NONE = 0,                         // Undefined state
//--- Outside the form
   MOUSE_FORM_STATE_OUTSIDE_FORM_NOT_PRESSED,         // The cursor is outside the form, the mouse buttons are not clicked
   MOUSE_FORM_STATE_OUTSIDE_FORM_PRESSED,             // The cursor is outside the form, the mouse button (any) is clicked
   MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL,               // The cursor is outside the form, the mouse wheel is being scrolled
//--- Within the form
   MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED,          // The cursor is inside the form, no mouse buttons are clicked
   MOUSE_FORM_STATE_INSIDE_FORM_PRESSED,              // The cursor is inside the form, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_FORM_WHEEL,                // The cursor is inside the form, the mouse wheel is being scrolled
//--- Within the window header area
   MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED,   // The cursor is inside the active area, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED,       // The cursor is inside the active area,  any mouse button is clicked
   MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL,         // The cursor is inside the active area, the mouse wheel is being scrolled
   MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED,      // The cursor is inside the active area, left mouse button is released
//--- Within the window scrolling area
   MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_NOT_PRESSED,   // The cursor is within the window scrolling area, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_PRESSED,       // The cursor is within the window scrolling area, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_WHEEL,         // The cursor is within the window scrolling area, the mouse wheel is being scrolled
  };
//+------------------------------------------------------------------+

通过跟踪此状态,我们可以判定释放鼠标按钮的时刻。 这一时刻将是更改图形对象状态的关键。

为了针对鼠标的交互做出反应,我们需要知道发生了哪些鼠标事件。 随后,基于所处理的事件,我们将其发送到程序,从而函数库用户可以在其程序中处理此事件。

创建一个新的枚举内含鼠标事件列表:

//+------------------------------------------------------------------+
//| List of possible mouse events                                    |
//+------------------------------------------------------------------+
enum ENUM_MOUSE_EVENT
  {
   MOUSE_EVENT_NO_EVENT = CHART_OBJ_EVENTS_NEXT_CODE, // No event
//---
   MOUSE_EVENT_OUTSIDE_FORM_NOT_PRESSED,              // The cursor is outside the form, the mouse buttons are not clicked
   MOUSE_EVENT_OUTSIDE_FORM_PRESSED,                  // The cursor is outside the form, the mouse button (any) is clicked
   MOUSE_EVENT_OUTSIDE_FORM_WHEEL,                    // The cursor is outside the form, the mouse wheel is being scrolled
//--- Within the form
   MOUSE_EVENT_INSIDE_FORM_NOT_PRESSED,               // The cursor is inside the form, no mouse buttons are clicked
   MOUSE_EVENT_INSIDE_FORM_PRESSED,                   // The cursor is inside the form, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_FORM_WHEEL,                     // The cursor is inside the form, the mouse wheel is being scrolled
//--- Within the window header area
   MOUSE_EVENT_INSIDE_ACTIVE_AREA_NOT_PRESSED,        // The cursor is inside the active area, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_ACTIVE_AREA_PRESSED,            // The cursor is inside the active area, any mouse button is clicked
   MOUSE_EVENT_INSIDE_ACTIVE_AREA_WHEEL,              // The cursor is inside the active area, the mouse wheel is being scrolled
   MOUSE_EVENT_INSIDE_ACTIVE_AREA_RELEASED,           // The cursor is inside the active area, left mouse button is released
//--- Within the window scrolling area
   MOUSE_EVENT_INSIDE_SCROLL_AREA_NOT_PRESSED,        // The cursor is within the window scrolling area, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_SCROLL_AREA_PRESSED,            // The cursor is within the window scrolling area, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_SCROLL_AREA_WHEEL,              // The cursor is within the window scrolling area, the mouse wheel is being scrolled
  };
#define ENUM_MOUSE_EVENT_NEXT_CODE  (MOUSE_EVENT_INSIDE_SCROLL_AREA_WHEEL+1)  // The code of the next event after the last chart event code
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Data for handling graphical elements                             |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of possible graphical object events                         |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_EVENT
  {
   GRAPH_OBJ_EVENT_NO_EVENT = ENUM_MOUSE_EVENT_NEXT_CODE,// No event
   GRAPH_OBJ_EVENT_CREATE,                            // "Creating a new graphical object" event
   GRAPH_OBJ_EVENT_CHANGE,                            // "Changing graphical object properties" event
   GRAPH_OBJ_EVENT_RENAME,                            // "Renaming graphical object" event
   GRAPH_OBJ_EVENT_DELETE,                            // "Removing graphical object" event
   GRAPH_OBJ_EVENT_DEL_CHART,                         // "Removing a graphical object together with the chart window" event
  };
#define GRAPH_OBJ_EVENTS_NEXT_CODE  (GRAPH_OBJ_EVENT_DEL_CHART+1) // The code of the next event after the last graphical object event code
//+------------------------------------------------------------------+

由于我已添加了一个新的事件枚举,它是在图表事件列表和图表对象事件列表之间“挤进”的,图形对象的第一个事件的初始值现在将计算为最后一个鼠标事件+1

将新属性添加到图形元素的整数型属性列表当中:

//+------------------------------------------------------------------+
//| 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_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_FORE_COLOR_MOUSE_DOWN,           // Default control text color when clicking on the control
   CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_OVER,           // Default control text color when hovering the mouse over the control
   CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE,               // Text color of the control which is on
   CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_DOWN,    // Default control text color when clicking on the control which is on
   CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_OVER,    // Default control text color when hovering the mouse over the control which is on
   CANV_ELEMENT_PROP_BACKGROUND_COLOR,                // Control background color
   CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY,        // Opacity 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_BACKGROUND_COLOR_TOGGLE,           // Background color of the control which is on
   CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN,// Control background color when clicking on the control which is on
   CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_OVER,// Control background color hovering the mouse over control which is on
   CANV_ELEMENT_PROP_BOLD_TYPE,                       // Font width type
   CANV_ELEMENT_PROP_BORDER_STYLE,                    // Control frame style
   //---...
   //---...
   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_BUTTON_TOGGLE,                   // Toggle flag of the control featuring a button
   CANV_ELEMENT_PROP_BUTTON_STATE,                    // Status of the Toggle control featuring a button
   CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR,          // Color of control checkbox background
   CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY,  // Opacity of the control checkbox background 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 (81)          // Total number of integer properties
#define CANV_ELEMENT_PROP_INTEGER_SKIP  (0)           // Number of integer properties not used in sorting
//+------------------------------------------------------------------+

增加整数型属性的总数从 71 到 81

将新属性添加到画布上图形元素的可能排序准则列表中:

//+------------------------------------------------------------------+
//| 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_FORE_COLOR_MOUSE_DOWN,        // Sort by control text color when clicking on the control
   SORT_BY_CANV_ELEMENT_FORE_COLOR_MOUSE_OVER,        // Sort by control text color when hovering the mouse over the control
   SORT_BY_CANV_ELEMENT_FORE_COLOR_TOGGLE,            // Sort by control text color when the control is on
   SORT_BY_CANV_ELEMENT_FORE_COLOR_TOGGLE_MOUSE_DOWN, // Sort by the default control text color when clicking on the control while it is on
   SORT_BY_CANV_ELEMENT_FORE_COLOR_TOGGLE_MOUSE_OVER, // Sort by the default control text color when hovering the mouse over the control while it is on
   SORT_BY_CANV_ELEMENT_BACKGROUND_COLOR,             // Sort by control background text color
   SORT_BY_CANV_ELEMENT_BACKGROUND_COLOR_OPACITY,     // Sort by control background color opacity
   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_BACKGROUND_COLOR_TOGGLE,           // Sort by control background color when the control is on
   SORT_BY_CANV_ELEMENT_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN,// Sort by control background color when clicking on the control while it is on
   SORT_BY_CANV_ELEMENT_BACKGROUND_COLOR_TOGGLE_MOUSE_OVER,// Sort by control background color when hovering the mouse over the control while it is on
   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_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_BUTTON_TOGGLE,                // Sort by the Toggle flag of the control featuring a button
   SORT_BY_CANV_ELEMENT_BUTTON_STATE,                 // Sort by the status of the Toggle control featuring a button  
   SORT_BY_CANV_ELEMENT_CHECK_BACKGROUND_COLOR,       // Sort by color of control checkbox background
   SORT_BY_CANV_ELEMENT_CHECK_BACKGROUND_COLOR_OPACITY,   // Sort by opacity of control checkbox background 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_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_FORE_COLOR_MOUSE_DOWN,       // Default control text color when clicking on the control
   MSG_CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_OVER,       // Default control text color when hovering the mouse over the control
   MSG_CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE,           // Text color of the control which is on
   MSG_CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_DOWN,// Default control text color when clicking on the control which is on
   MSG_CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_OVER,// Default control text color when hovering the mouse over the control which is on
   MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR,            // Control background color
   MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_OPACITY,    // Opacity 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_BACKGROUND_COLOR_TOGGLE,           // Background color of the control which is on
   MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN,// Control background color when clicking on the control which is on
   MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_OVER,// Control background color when hovering the mouse over control which is on
   MSG_CANV_ELEMENT_PROP_BOLD_TYPE,                   // Font width type
   MSG_CANV_ELEMENT_PROP_BORDER_STYLE,                // Control frame style

...

   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
   MSG_CANV_ELEMENT_PROP_BUTTON_TOGGLE,               // Toggle flag of the control featuring a button
   MSG_CANV_ELEMENT_PROP_BUTTON_STATE,                // Status of the Toggle control featuring a button
   MSG_CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR,      // Color of control checkbox background
   MSG_CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY,// Opacity of the control checkbox background color
   MSG_CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN,// Color of control checkbox background when clicking on the control
   MSG_CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_OVER,// Color of control checkbox background when hovering the mouse over the control
   MSG_CANV_ELEMENT_PROP_CHECK_FORE_COLOR,            // Color of control checkbox frame
   MSG_CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY,    // Opacity of the control checkbox frame color
   MSG_CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN, // Color of control checkbox frame when clicking on the control
   MSG_CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_OVER, // Color of control checkbox frame when hovering the mouse over the control
   MSG_CANV_ELEMENT_PROP_CHECK_FLAG_COLOR,            // Color of control checkbox
   MSG_CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY,    // Opacity of the control checkbox color
   MSG_CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN, // Color of control checkbox when clicking on the control
   MSG_CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER, // Color of control checkbox when hovering the mouse over the control
   
//--- 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


以及与新添加的索引对应的消息文本

   {"Цвет текста по умолчанию для всех объектов элемента управления","Default text color for all objects in the control"},
   {"Непрозрачность цвета текста по умолчанию для всех объектов элемента управления","Default text color opacity for all objects in the control"},
   {"Цвет текста элемента по умолчанию при нажатии мышки на элемент управления","The default text color of an element when the mouse is pressed on the control"},
   {"Цвет текста элемента по умолчанию при наведении мышки на элемент управления","The default text color of an element when hovering over the control"},
   {"Цвет текста элемента управления в состоянии \"включено\"","The text color of a control in the enabled state"},
   {"Цвет текста элемента управления по умолчанию в состоянии \"включено\" при нажатии мышки на элемент управления","The default text color of the control in the \"On\" state when the mouse is pressed on the control"},
   {"Цвет текста элемента управления по умолчанию в состоянии \"включено\" при наведении мышки на элемент управления","The default text color of a control in the \"On\" state when hovering the mouse over 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"},
   {"Цвет фона элемента управления в состоянии \"включено\"","Background color of the control in the enabled state"},
   {"Цвет фона элемента управления в состоянии \"включено\" при нажатии мышки на элемент управления","The background color of the control in the \"On\" state when the mouse is pressed on the control"},
   {"Цвет фона элемента управления в состоянии \"включено\" при наведении мышки на элемент управления","The background color of a control in the \"On\" state when the mouse is over the control"},
   {"Тип толщины шрифта","Font weight type"},
   {"Стиль рамки элемента управления","Control's border style"},

...

   {"Состояние элемента управления, имеющего флажок проверки","The state of a control that has a checkbox"},
   {"Автоматическое изменение состояния флажка при его выборе","Automatically change the state of the checkbox when it is selected"},
   {"Флаг \"Переключатель\" элемента управления, имеющего кнопку","\"Button-toggle\" flag of a control"},
   {"Состояние элемента управления \"Переключатель\", имеющего кнопку","The \"Toggle-button\" control state"},
   {"Цвет фона флажка проверки элемента управления","The background color of the control's validation checkbox"},
   {"Непрозрачность цвета фона флажка проверки элемента управления","Opacity of the backgroung color of the checkbox control"},
   {"Цвет фона флажка проверки элемента управления при нажатии мышки на элемент управления","The background color of the control's checkbox when the control is pressed with the mouse"},
   {"Цвет фона флажка проверки элемента управления при наведении мышки на элемент управления","The background color of the control's validation checkbox when hovering the mouse over the control"},
   {"Цвет рамки флажка проверки элемента управления","Border color of the checkbox control"},
   {"Непрозрачность цвета рамки флажка проверки элемента управления","Border color opacity of the checkbox control"},
   {"Цвет рамки флажка проверки элемента управления при нажатии мышки на элемент управления","Border color of the checkbox control when the mouse is pressed on the control"},
   {"Цвет рамки флажка проверки элемента управления при наведении мышки на элемент управления","Border color of the checkbox control when hovering the mouse over the control"},
   {"Цвет флажка проверки элемента управления","Control Checkbox Color"},
   {"Непрозрачность цвета флажка проверки элемента управления","Opacity of control's checkbox color"},
   {"Цвет флажка проверки элемента управления при нажатии мышки на элемент управления","Control Checkbox Colorl when the mouse is pressed on the control"},
   {"Цвет флажка проверки элемента управления при наведении мышки на элемент управления","Control Checkbox Colorl when hovering the mouse over the control"},

//--- 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\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
   color             m_array_colors_bg_init[];                 // Array of element background colors (initial color)

//--- Create (1) the object structure and (2) the object from the structure
   virtual bool      ObjectToStruct(void);
   virtual void      StructToObject(void);
//--- Copy the color array to the specified background color array
   void              CopyArraysColors(color &array_dst[],const color &array_src[],const string source);
   
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
      //---...
      //---...
      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 clicking on the control
      color          fore_color_mouse_down;                    // Default control text color when clicking on the control
      color          fore_color_mouse_over;                    // Default control text color when hovering the mouse over the control
      color          fore_color_toggle;                        // Text color of the control which is on
      color          fore_color_toggle_mouse_down;             // Default control text color when clicking on the control which is on
      color          fore_color_toggle_mouse_over;             // Default control text color when hovering the mouse over the control which is on
      color          background_color_toggle;                  // Background color of the control which is on
      color          background_color_toggle_mouse_down;       // Control background color when clicking on the control which is on
      color          background_color_toggle_mouse_over;       // Control background color when hovering the mouse over the control which is on
      bool           button_toggle;                            // Toggle flag of the control featuring a button
      bool           button_state;                             // Status of the Toggle control featuring a button
      //--- 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

在将来,这是把对象正确保存到媒体,并从中读取所必需的。


我们添加另一种保存渐变色数组的方法,来记住原始背景色:

//--- 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);  }
   void              SaveColorsBGInit(color &colors[])                     { this.CopyArraysColors(this.m_array_colors_bg_init,colors,DFUN); }
   
public:

该方法在设置背景色的方法中调用。 为了达此目的,我将引入标志,指定在设置对象背景颜色后需要将初始背景颜色保存到其形式变量之中。 因此,我们有一个选择 — 要么设置一个对象背景色并在数组中记住它的初始颜色;要么只设置一个新的背景色,然后就可以从数组中先前设置的整个背景渐变色集恢复它。 针对所有在与鼠标交互时颜色应该改变的对象,我都会执行此操作:

//--- Set the main background color
   void              SetBackgroundColor(const color colour,const bool set_init_color)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR,colour);
                        color arr[1];
                        arr[0]=colour;
                        this.SaveColorsBG(arr);
                        if(set_init_color)
                           this.SetBackgroundColorInit(this.BackgroundColor());
                       }
   void              SetBackgroundColors(color &colors[],const bool set_init_colors)
                       {
                        this.SaveColorsBG(colors);
                        this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR,this.m_array_colors_bg[0]);
                        if(set_init_colors)
                           this.SetBackgroundColorsInit(colors);
                       }


我们添加类似的方法来设置初始背景颜色

   void              SetBackgroundColorsMouseOver(color &colors[])
                       {
                        this.SaveColorsBGMouseOver(colors);
                        this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_MOUSE_OVER,this.m_array_colors_bg_ovr[0]);
                       }
//--- Set the initial main background color
   void              SetBackgroundColorInit(const color colour)
                       {
                        color arr[1];
                        arr[0]=colour;
                        this.SaveColorsBGInit(arr);
                       }
   void              SetBackgroundColorsInit(color &colors[])
                       {
                        this.SaveColorsBGInit(colors);
                       }
                       
//--- Set (1) object movability, (2) activity, (3) interaction,

在此,除了指示需要保存初始颜色的标志(通过调用这些方法来保存)外,所有设置主背景颜色的方法都是雷同的。

编写返回初始背景颜色的方法

//--- 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 the initial color of the main background
   color             BackgroundColorInit(void)           const { return (color)this.m_array_colors_bg_init[0];    }
   color             BackgroundColorInit(const uint index)const
                       {
                        uint total=this.m_array_colors_bg_init.Size();
                        if(total==0)
                           return this.BackgroundColor();
                        return(index>total-1 ? this.m_array_colors_bg_init[total-1] : this.m_array_colors_bg_init[index]);
                       }
   
//--- Return (1) the opacity, coordinate (2) of the right and (3) bottom element edge

这些方法要么返回唯一的背景色,要么返回与传递给该方法的索引对应的渐变色集合中的颜色。


在这两个类构造函数中,设置新属性的初始化,并传递保存初始背景色的标志

//+------------------------------------------------------------------+
//| 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,true);
   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_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_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_BORDER_COLOR);                // Color of control checkbox frame
      this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY,CLR_DEF_CHECK_BORDER_OPACITY);      // Opacity of the control checkbox frame color
      this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_BORDER_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_BORDER_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);                  // Control checkbox color
      this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY,CLR_DEF_CHECK_FLAG_OPACITY);        // Control checkbox color opacity
      this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN,CLR_DEF_CHECK_FLAG_MOUSE_DOWN);  // Control checkbox color when clicking on the control
      this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER,CLR_DEF_CHECK_FLAG_MOUSE_OVER);  // Control checkbox color when hovering the mouse over the control
      this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,CLR_DEF_FORE_COLOR);                              // Default text color for all control objects
      this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,CLR_DEF_FORE_COLOR_OPACITY);              // Opacity of the default text color for all control objects
      this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_DOWN,CLR_DEF_FORE_COLOR_MOUSE_DOWN);        // Default control text color when clicking on the control
      this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_OVER,CLR_DEF_FORE_COLOR_MOUSE_OVER);        // Default control text color when hovering the mouse over the control
      this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE,CLR_DEF_FORE_COLOR);                       // Text color of the control which is on
      this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_DOWN,CLR_DEF_FORE_COLOR_MOUSE_DOWN); // Default control text color when clicking on the control which is on
      this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_OVER,CLR_DEF_FORE_COLOR_MOUSE_OVER); // Default control text color when hovering the mouse over the control which is on
      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_BACKGROUND_COLOR_TOGGLE,CLR_DEF_CONTROL_STD_BACK_COLOR_ON);  // Background color of the control which is on
      this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN,CLR_DEF_CONTROL_STD_BACK_DOWN_ON); // Control background color when clicking on the control which is on
      this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_OVER,CLR_DEF_CONTROL_STD_BACK_OVER_ON); // Control background color when clicking on the control which is on
      this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_DOWN,CLR_DEF_BORDER_MOUSE_DOWN);          // Control frame color when clicking on the control
      this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR_MOUSE_OVER,CLR_DEF_BORDER_MOUSE_OVER);          // Control frame color when hovering the mouse over the control
      this.SetProperty(CANV_ELEMENT_PROP_BUTTON_TOGGLE,false);                                        // Toggle flag of the control featuring a button
      this.SetProperty(CANV_ELEMENT_PROP_BUTTON_STATE,false);                                         // Status of the Toggle control featuring a button
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),": ",this.m_name);
     }
  }
//+------------------------------------------------------------------+

BorderColor 值现在设置给复选框 ForceColor 属性,因为复选框有自己的颜色。

第二个构造函数类似。 在这里啰嗦没有意义。


在创建对象结构的方法中,在结构字段中添加保存新对象属性

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

   this.m_struct_obj.fore_color_mouse_down=(color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_DOWN);            // Default control text color when clicking on the control
   this.m_struct_obj.fore_color_mouse_over=(color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_OVER);            // Default control text color when hovering the mouse over the control
   this.m_struct_obj.fore_color_toggle=(color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE);                    // Text color of the control which is on
   this.m_struct_obj.fore_color_toggle_mouse_down=(color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_DOWN);// Default control text color when clicking on the control which is on
   this.m_struct_obj.fore_color_toggle_mouse_over=(color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_OVER);// Default control text color when hovering the mouse over the control which is on
   this.m_struct_obj.background_color_toggle=(color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE);        // Background color of the control which is on
   this.m_struct_obj.background_color_toggle_mouse_down=(color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN);// Control background color when clicking on the control which is on
   this.m_struct_obj.background_color_toggle_mouse_over=(color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_OVER);// Control background color when hovering the mouse over the control which is on
   this.m_struct_obj.button_toggle=(bool)this.GetProperty(CANV_ELEMENT_PROP_BUTTON_TOGGLE);                             // Toggle flag of the control featuring a button
   this.m_struct_obj.button_state=(bool)this.GetProperty(CANV_ELEMENT_PROP_BUTTON_STATE);                               // Status of the Toggle control featuring a button
//--- 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_CHECK_FLAG_COLOR_MOUSE_OVER,this.m_struct_obj.check_flag_color_mouse_over); // Control checkbox color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_DOWN,this.m_struct_obj.fore_color_mouse_down);             // Default control text color when clicking on the control
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_OVER,this.m_struct_obj.fore_color_mouse_over);             // Default control text color when hovering the mouse over the control
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE,this.m_struct_obj.fore_color_toggle);                     // Text color of the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_DOWN,this.m_struct_obj.fore_color_toggle_mouse_down);// Default control text color when clicking on the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_OVER,this.m_struct_obj.fore_color_toggle_mouse_over);// Default control text color when hovering the mouse over the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE,this.m_struct_obj.background_color_toggle);         // Background color of the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN,this.m_struct_obj.background_color_toggle_mouse_down);// Control background color when clicking on the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_OVER,this.m_struct_obj.background_color_toggle_mouse_over);// Control background color when clicking on the control which is on
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_TOGGLE,this.m_struct_obj.button_toggle);                             // Toggle flag of the control featuring a button
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_STATE,this.m_struct_obj.button_state);                               // Status of the Toggle control featuring a button
//--- 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
  }
//+------------------------------------------------------------------+


在 \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,true);
   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 窗体对象文件的类受保护部分,声明两个变量 — 存储最后一个鼠标事件(最后一个事件处理程序需要),和存储初始窗体边框颜色(因为它在与鼠标交互时可以更改颜色,故有必要恢复原始颜色)。 此外,声明每个鼠标事件的虚拟处理程序

protected:
   CArrayObj         m_list_elements;                          // List of attached elements
   CArrayObj         m_list_interact;                          // List of interaction 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
   ENUM_MOUSE_EVENT  m_mouse_event_last;                       // Last mouse event
   ushort            m_mouse_state_flags;                      // Mouse status flags
   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_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
   color             m_border_color_init;                      // Initial color of the control frame
   
//--- Initialize the variables
   virtual void      Initialize(void);
   void              Deinitialize(void);
//--- Create a shadow object
   void              CreateShadowObj(const color colour,const uchar opacity);
//--- Return the name of the dependent object
   string            CreateNameDependentObject(const string base_name)  const
                       { return ::StringSubstr(this.NameObj(),::StringLen(::MQLInfoString(MQL_PROGRAM_NAME))+1)+"_"+base_name;   }
//--- Update coordinates of bound objects
   virtual bool      MoveDependentObj(const int x,const int y,const bool redraw=false);
//--- 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);
   
//--- 'The cursor is outside the form, no mouse buttons are clicked' event handler
   virtual void      MouseOutsideNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is outside the form, a mouse button is clicked (any)' event handler
   virtual void      MouseOutsidePressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is outside the form, the mouse wheel is being scrolled' event handler
   virtual void      MouseOutsideWhellHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the form, no mouse buttons are clicked' event handler
   virtual void      MouseInsideNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the form, a mouse button is clicked (any)' event handler
   virtual void      MouseInsidePressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the form, the mouse wheel is being scrolled' event handler
   virtual void      MouseInsideWhellHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the active area, the mouse buttons are not clicked' event handler
   virtual void      MouseActiveAreaNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the active area, a mouse button is clicked (any)' event handler
   virtual void      MouseActiveAreaPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the active area, the mouse wheel is being scrolled' event handler
   virtual void      MouseActiveAreaWhellHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the active area, the left mouse button is clicked' event handler
   virtual void      MouseActiveAreaReleasedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the window scrolling area, no mouse buttons are clicked' event handler
   virtual void      MouseScrollAreaNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the window scrolling area, a mouse button is clicked (any)' event handler
   virtual void      MouseScrollAreaPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the window scrolling area, the mouse wheel is being scrolled' event handler
   virtual void      MouseScrollAreaWhellHandler(const int id,const long& lparam,const double& dparam,const string& sparam);

public:


在类的公开部分,声明重绘对象的虚拟方法,编写返回存储鼠标状态变量的方法,以及
返回最后一个鼠标事件的方法
在每一侧设置边框大小的方法是虚拟的
。 此外,我们声明虚拟的鼠标事件处理程序,及其最后一个事件处理程序

public:
//--- Redraw the object
   virtual void      Redraw(bool redraw) { return; }
//--- 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);  }
//--- Return the initial (1) X and (2) Y coordinate, (3) form width and (4) height
   int               GetCoordXInit(void)                 const { return this.m_init_x;             }
   int               GetCoordYInit(void)                 const { return this.m_init_y;             }
   int               GetWidthInit(void)                  const { return this.m_init_w;             }
   int               GetHeightInit(void)                 const { return this.m_init_h;             }
//--- Set the initial (1) X and (2) Y coordinate, (3) form width and (4) height
   void              SetCoordXInit(const int value)            { this.m_init_x=value;              }
   void              SetCoordYInit(const int value)            { this.m_init_y=value;              }
   void              SetWidthInit(const int value)             { this.m_init_w=value;              }
   void              SetHeightInit(const int value)            { this.m_init_h=value;              }
//--- (1) Get and (2) return the mouse status relative to the form, as well as cursor (3) X, (4) Y coordinates and (4) the last mouse event
   ENUM_MOUSE_FORM_STATE MouseFormState(const int id,const long lparam,const double dparam,const string sparam);
   ENUM_MOUSE_FORM_STATE GetMouseState(void)             const { return this.m_mouse_form_state;   }
   int               MouseCursorX(void)                  const { return this.m_mouse.CoordX();     }
   int               MouseCursorY(void)                  const { return this.m_mouse.CoordY();     }
   ENUM_MOUSE_EVENT  MouseEventLast(void)                const { return this.m_mouse_event_last;   }
//--- Set the flags of mouse scrolling, context menu and the crosshairs tool for the chart
   void              SetChartTools(const bool flag);
//--- (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
   virtual void      SetBorderSizeLeft(const uint value)       { this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT,value);        }
   virtual void      SetBorderSizeTop(const uint value)        { this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP,value);         }
   virtual void      SetBorderSizeRight(const uint value)      { this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT,value);       }
   virtual void      SetBorderSizeBottom(const uint value)     { this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM,value);      }

//--- Update the coordinates (shift the canvas)
   virtual bool      Move(const int x,const int y,const bool redraw=false);
//--- Set the priority of a graphical object for receiving the event of clicking on a chart
   virtual bool      SetZorder(const long value,const bool only_prop);
//--- Set the object above all
   virtual void      BringToTop(void);
   
//--- Event handler
   virtual void      OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- Mouse event handler
   virtual void      OnMouseEvent(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- Last mouse event handler
   virtual void      OnMouseEventPostProcessing(void);

//--- Constructors


修改设置对象边框颜色的方法,如此标志状态指示必须保存初始帧颜色,并编写设置和返回初始对象边框颜色的方法

//+------------------------------------------------------------------+
//| Methods of simplified access to object properties                |
//+------------------------------------------------------------------+
//--- (1) Set and (2) return the control frame color
   void              SetBorderColor(const color colour,const bool set_init_color)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR,colour);
                        if(set_init_color)
                           this.SetBorderColorInit(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);  }
//--- (1) Set and (2) get the initial color of the control frame
   void              SetBorderColorInit(const color colour)             { this.m_border_color_init=colour;                                            }
   color             BorderColorInit(void)                        const { return (color)this.m_border_color_init;                                     }

//--- (1) Set and (2) return the form shadow color


在对象初始化方法中保存初始边框颜色,方法是在设置其颜色的方法中指定必要的标志,并在鼠标光标悬停在对象上,和单击对象时设置边框颜色的默认颜色初始化最后的鼠标事件:

//+------------------------------------------------------------------+
//| 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.SetBorderColor(CLR_DEF_BORDER_COLOR,true);
   this.SetBorderColorMouseDown(CLR_DEF_BORDER_MOUSE_DOWN);
   this.SetBorderColorMouseOver(CLR_DEF_BORDER_MOUSE_OVER);
   this.m_gradient_v=true;
   this.m_gradient_c=false;
   this.m_mouse_state_flags=0;
   this.m_mouse_event_last=MOUSE_EVENT_NO_EVENT;
   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);
  }
//+------------------------------------------------------------------+


在所有需要背景色的对象创建方法中设置标志。 在 CreateAndAddNewElement() 方法里:

obj.SetBackgroundColor(colour,true);

在设置配色方案的方法中:

//+------------------------------------------------------------------+
//| 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],true);
   this.SetBorderColor(array_color_themes[theme][COLOR_THEME_COLOR_FORM_FRAME],true);
  }
//+------------------------------------------------------------------+

控件的原始背景色现在将在各种情况下都予以保留。


在设置并返回鼠标相对于窗体的状态的方法中,我们之前声明了一个局部变量,在该变量中我们写入了鼠标的状态,并返回该变量值。 现在我们在类中已有一个这样的变量来存储这个值。
我们将值写入它,并从方法返回
:

//+------------------------------------------------------------------+
//| Set and get the mouse status relative to the form                |
//+------------------------------------------------------------------+
ENUM_MOUSE_FORM_STATE CForm::MouseFormState(const int id,const long lparam,const double dparam,const string sparam)
  {
//--- Get the mouse status relative to the form, as well as the states of mouse buttons and Shift/Ctrl keys
   this.m_mouse_form_state=MOUSE_FORM_STATE_OUTSIDE_FORM_NOT_PRESSED;
   ENUM_MOUSE_BUTT_KEY_STATE state=this.m_mouse.ButtonKeyState(id,lparam,dparam,sparam);
//--- Get the mouse status flags from the CMouseState class object and save them in the variable
   this.m_mouse_state_flags=this.m_mouse.GetMouseFlags();
//--- If the cursor is inside the form
   if(CGCnvElement::CursorInsideElement(m_mouse.CoordX(),m_mouse.CoordY()))
     {
      //--- Set bit 8 responsible for the "cursor inside the form" flag
      this.m_mouse_state_flags |= (0x0001<<8);
      //--- If the cursor is inside the active area, set bit 9 "cursor inside the active area"
      if(CGCnvElement::CursorInsideActiveArea(m_mouse.CoordX(),m_mouse.CoordY()))
         this.m_mouse_state_flags |= (0x0001<<9);
      //--- otherwise, release the bit "cursor inside the active area"
      else this.m_mouse_state_flags &=0xFDFF;
      //--- If one of the mouse buttons is clicked, check the cursor location in the active area and
      //--- return the appropriate value of the pressed key (in the active area or the form area)
      if((this.m_mouse_state_flags & 0x0001)!=0 || (this.m_mouse_state_flags & 0x0002)!=0 || (this.m_mouse_state_flags & 0x0010)!=0)
         this.m_mouse_form_state=((this.m_mouse_state_flags & 0x0200)!=0 ? MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED : MOUSE_FORM_STATE_INSIDE_FORM_PRESSED);
      //--- otherwise, if not a single mouse button is pressed
      else
        {
         //--- if the mouse wheel is scrolled, return the appropriate wheel scrolling value (in the active area or the form area)
         if((this.m_mouse_state_flags & 0x0080)!=0)
            this.m_mouse_form_state=((this.m_mouse_state_flags & 0x0200)!=0 ? MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL : MOUSE_FORM_STATE_INSIDE_FORM_WHEEL);
         //--- otherwise, return the appropriate value of the unpressed key (in the active area or the form area)
         else
            this.m_mouse_form_state=((this.m_mouse_state_flags & 0x0200)!=0 ? MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED : MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED);
        } 
     }
//--- If the cursor is outside the form
   else
     {
      //--- return the appropriate button value in an inactive area
      this.m_mouse_form_state=
        (
         ((this.m_mouse_state_flags & 0x0001)!=0 || (this.m_mouse_state_flags & 0x0002)!=0 || (this.m_mouse_state_flags & 0x0010)!=0) ? 
          MOUSE_FORM_STATE_OUTSIDE_FORM_PRESSED : MOUSE_FORM_STATE_OUTSIDE_FORM_NOT_PRESSED
        );
     }
   return this.m_mouse_form_state;
  }
//+------------------------------------------------------------------+


鼠标事件处理程序:

//+------------------------------------------------------------------+
//| Mouse event handler                                              |
//+------------------------------------------------------------------+
void CForm::OnMouseEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   switch(id)
     {
      //--- The cursor is outside the form, the mouse buttons are not clicked
      //--- The cursor is outside the form, any mouse button is clicked
      //--- The cursor is outside the form, the mouse wheel is being scrolled
      case MOUSE_EVENT_OUTSIDE_FORM_NOT_PRESSED :
      case MOUSE_EVENT_OUTSIDE_FORM_PRESSED     :
      case MOUSE_EVENT_OUTSIDE_FORM_WHEEL       :
        break;
      //--- The cursor is inside the form, the mouse buttons are not clicked
      case MOUSE_EVENT_INSIDE_FORM_NOT_PRESSED :
        this.MouseInsideNotPressedHandler(id,lparam,dparam,sparam);
        break;
      //--- The cursor is inside the form, any mouse button is clicked
      case MOUSE_EVENT_INSIDE_FORM_PRESSED :
        this.MouseInsidePressedHandler(id,lparam,dparam,sparam);
        break;
      //--- The cursor is inside the form, the mouse wheel is being scrolled
      case MOUSE_EVENT_INSIDE_FORM_WHEEL :
        this.MouseInsideWhellHandler(id,lparam,dparam,sparam);
        break;
      //--- The cursor is inside the active area, the mouse buttons are not clicked
      case MOUSE_EVENT_INSIDE_ACTIVE_AREA_NOT_PRESSED :
        this.MouseActiveAreaNotPressedHandler(id,lparam,dparam,sparam);
        break;
      //--- The cursor is inside the active area, any mouse button is clicked
      case MOUSE_EVENT_INSIDE_ACTIVE_AREA_PRESSED :
        this.MouseActiveAreaPressedHandler(id,lparam,dparam,sparam);
        break;
      //--- The cursor is inside the active area, the mouse wheel is being scrolled
      case MOUSE_EVENT_INSIDE_ACTIVE_AREA_WHEEL :
        this.MouseActiveAreaWhellHandler(id,lparam,dparam,sparam);
        break;
      //--- The cursor is inside the active area, left mouse button is released
      case MOUSE_EVENT_INSIDE_ACTIVE_AREA_RELEASED :
        this.MouseActiveAreaReleasedHandler(id,lparam,dparam,sparam);
        break;
      //--- The cursor is within the window scrolling area, the mouse buttons are not clicked
      case MOUSE_EVENT_INSIDE_SCROLL_AREA_NOT_PRESSED :
        this.MouseScrollAreaNotPressedHandler(id,lparam,dparam,sparam);
        break;
      //--- The cursor is within the window scrolling area, any mouse button is clicked
      case MOUSE_EVENT_INSIDE_SCROLL_AREA_PRESSED :
        this.MouseScrollAreaPressedHandler(id,lparam,dparam,sparam);
        break;
      //--- The cursor is within the window scrolling area, the mouse wheel is being scrolled
      case MOUSE_EVENT_INSIDE_SCROLL_AREA_WHEEL :
        this.MouseScrollAreaWhellHandler(id,lparam,dparam,sparam);
        break;
      //--- MOUSE_EVENT_NO_EVENT
      default:
        break;
     }
   this.m_mouse_event_last=(ENUM_MOUSE_EVENT)id;
  }
//+------------------------------------------------------------------+

此处,我们根据鼠标事件 ID 为每个事件调用相应的处理方法。 最终,在存储最后一个鼠标事件的变量里保存传递给方法的事件。 因此,我们首先处理事件,然后将其设置为最后处理的事件。 此处调用的所有方法都是虚拟的,应该在继承类中重新定义。

每个鼠标事件的虚拟处理程序:

//+------------------------------------------------------------------+
//| 'The cursor is outside the form,                                 |
//| no mouse buttons are clicked' event handler                      |
//+------------------------------------------------------------------+
void CForm::MouseOutsideNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is outside the form,                                 |
//| a mouse button is clicked (any)                                  |
//+------------------------------------------------------------------+
void CForm::MouseOutsidePressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is outside the form,                                 |
//| the mouse wheel is being scrolled                                |
//+------------------------------------------------------------------+
void CForm::MouseOutsideWhellHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the form,                                  |
//| no mouse buttons are clicked' event handler                      |
//+------------------------------------------------------------------+
void CForm::MouseInsideNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the form,                                  |
//| a mouse button is clicked (any)                                  |
//+------------------------------------------------------------------+
void CForm::MouseInsidePressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the form,                                  |
//| the mouse wheel is being scrolled                                |
//+------------------------------------------------------------------+
void CForm::MouseInsideWhellHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the active area,                           |
//| no mouse buttons are clicked' event handler                      |
//+------------------------------------------------------------------+
void CForm::MouseActiveAreaNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the active area,                           |
//| a mouse button is clicked (any)                                  |
//+------------------------------------------------------------------+
void CForm::MouseActiveAreaPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the active area,                           |
//| the mouse wheel is being scrolled                                |
//+------------------------------------------------------------------+
void CForm::MouseActiveAreaWhellHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the active area,                           |
//| left mouse button released                                       |
//+------------------------------------------------------------------+
void CForm::MouseActiveAreaReleasedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the window scrolling area,                 |
//| no mouse buttons are clicked' event handler                      |
//+------------------------------------------------------------------+
void CForm::MouseScrollAreaNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the window scrolling area,                 |
//| a mouse button is clicked (any)                                  |
//+------------------------------------------------------------------+
void CForm::MouseScrollAreaPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+
//| 'The cursor is inside the window scrolling area,                 |
//| the mouse wheel is being scrolled                                |
//+------------------------------------------------------------------+
void CForm::MouseScrollAreaWhellHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   return;
  }
//+------------------------------------------------------------------+

这些方法什么也不做,因为对于窗体对象的每个子对象,每个事件的整个处理都是独立的。 如有必要,应在每个继承的对象中重新定义流程。


最后一个鼠标事件的虚拟处理程序:

//+------------------------------------------------------------------+
//| Last mouse event handler                                         |
//+------------------------------------------------------------------+
void CForm::OnMouseEventPostProcessing(void)
  {
   ENUM_MOUSE_FORM_STATE state=GetMouseState();
   switch(state)
     {
      //--- The cursor is outside the form, the mouse buttons are not clicked
      //--- The cursor is outside the form, any mouse button is clicked
      //--- The cursor is outside the form, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_OUTSIDE_FORM_NOT_PRESSED :
      case MOUSE_FORM_STATE_OUTSIDE_FORM_PRESSED     :
      case MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL       :
        if(MouseEventLast()==MOUSE_EVENT_INSIDE_ACTIVE_AREA_NOT_PRESSED)
          {
           this.SetBackgroundColor(this.BackgroundColorInit(),false);
           this.SetBorderColor(this.BorderColorInit(),false);
           this.Redraw(true);
           this.m_mouse_event_last=ENUM_MOUSE_EVENT(state+MOUSE_EVENT_NO_EVENT);
          }
        break;

      //--- The cursor is inside the form, the mouse buttons are not clicked
      case MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED :
        break;
      //--- The cursor is inside the form, any mouse button is clicked
      case MOUSE_FORM_STATE_INSIDE_FORM_PRESSED :
        break;
      //--- The cursor is inside the form, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_FORM_WHEEL :
        break;
      //--- The cursor is inside the active area, the mouse buttons are not clicked
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED :
        break;
      //--- The cursor is inside the active area, any mouse button is clicked
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED :
        break;
      //--- The cursor is inside the active area, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL :
        break;
      //--- The cursor is inside the active area, left mouse button is released
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED :
        break;
      //--- The cursor is within the window scrolling area, the mouse buttons are not clicked
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_NOT_PRESSED :
        break;
      //--- The cursor is within the window scrolling area, any mouse button is clicked
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_PRESSED :
        break;
      //--- The cursor is within the window scrolling area, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_WHEEL :
        break;
      //--- MOUSE_EVENT_NO_EVENT
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

该方法也是虚拟的。 如果需要,应该在继承的类中重新定义它。
如果对象的鼠标状态定义为“光标在窗体外”(按钮和滚轮的状态不重要),则检查对象的最后一个鼠标事件。 如果“光标位于活动区域内且无单击鼠标按钮”,则认为光标已从对象中移除。 如此,我们要处理相应的事件 — 设置初始背景色、初始对象边框颜色,重新绘制对象,并将当前鼠标事件写入存储最后一个鼠标事件的变量之中
考虑到 ENUM_MOUSE_EVENT 枚举中的所有常量值都与 ENUM_MOOSE_FORM_STATE 枚举中的常量值不同(前提是它们具有相同的组成和顺序),因为 ENUM_MOUSE_EVENT_NO_EVENT 枚举的 MOUSE_EVENT 常量值不同,我们需要将 MOUSE_EVENT_NO_EVENT 常量值添加到鼠标事件值当中,在 ENUM_MOUSE_FORM_STATE 状态变量中接收,来获取正确的值

位于窗体上的文本,例如按钮文本,也可以在鼠标悬停或单击对象时更改其颜色,尽管不是在所有情况下,也不是在所有对象中(仅在必要时)。 处理 WinForms 对象文本的方法位于 \MQL5\Include\DoEasy\objects\Graph\WForms\WinFormBase.mqh 中的基准 WinForm 对象类之中。

在类的受保护部分,声明存储初始对象文本颜色的变量。 在公开部分中,声明按类型返回绑定对象列表、按类型绑定控件数量、以及按类型返回指向绑定对象指针的方法
编写设置和获取其它对象文本颜色的方法

//+------------------------------------------------------------------+
//| Form object class                                                |
//+------------------------------------------------------------------+
class CWinFormBase : public CForm
  {
protected:
   color             m_fore_color_init;                        // Initial color of the control text

private:
//--- Return the font flags
   uint              GetFontFlags(void);

public:
//--- Return by type the (1) list, (2) the number of bound controls, (3) the bound control by index in the list
   CArrayObj        *GetListElementsByType(const ENUM_GRAPH_ELEMENT_TYPE type);
   int               ElementsTotalByType(const ENUM_GRAPH_ELEMENT_TYPE type);
   CGCnvElement     *GetElementByType(const ENUM_GRAPH_ELEMENT_TYPE type,const int index);
//--- Clear the element filling it with color and opacity
   virtual void      Erase(const color colour,const uchar opacity,const bool redraw=false);
//--- Clear the element with a gradient fill
   virtual void      Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false);
//--- Clear the element completely
   virtual void      Erase(const bool redraw=false);
//--- Redraw the object
   virtual void      Redraw(bool redraw);
//--- Set the new size for the (1) current object and (2) the object specified by index
   virtual bool      Resize(const int w,const int h,const bool redraw);
   virtual bool      Resize(const int index,const int w,const int h,const bool redraw);

//--- Constructors
                     CWinFormBase(const long chart_id,
                                  const int subwindow,
                                  const string name,
                                  const int x,
                                  const int y,
                                  const int w,
                                  const int h);
                     CWinFormBase(const string name) : CForm(::ChartID(),0,name,0,0,0,0)
                       {
                        this.m_type=OBJECT_DE_TYPE_GWF_BASE; 
                       }
                       
//--- (1) Set and (2) return the default text color of all panel objects
   void              SetForeColor(const color clr,const bool set_init_color)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,clr);
                        if(set_init_color)
                           this.SetForeColorInit(clr);
                       }
   color             ForeColor(void)                           const { return (color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR);                     }
//--- (1) Set and (2) return the initial default text color of all panel objects
   void              SetForeColorInit(const color clr)               { this.m_fore_color_init=clr;                                                       }
   color             ForeColorInit(void)                       const { return (color)this.m_fore_color_init;                                             }
//--- (1) Set and (2) return the default text color opacity of all panel objects
   void              SetForeColorOpacity(const uchar value)          { this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,value);                     }
   uchar             ForeColorOpacity(void)                    const { return (uchar)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY);             }
//--- (1) Set and (2) return the control text color when clicking the control
   void              SetForeColorMouseDown(const color clr)          { this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_DOWN,clr);                    }
   color             ForeColorMouseDown(void)                  const { return (color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_DOWN);          }
//--- (1) Set and (2) return the control text color when hovering the mouse over the control
   void              SetForeColorMouseOver(const color clr)          { this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_OVER,clr);                    }
   color             ForeColorMouseOver(void)                  const { return (color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_MOUSE_OVER);          }
   
//--- (1) Set and (2) return the element text
   virtual void      SetText(const string text)                      { this.SetProperty(CANV_ELEMENT_PROP_TEXT,text);                                    }
   string            Text(void)                                const { return this.GetProperty(CANV_ELEMENT_PROP_TEXT);                                  }


在类构造函数中,当设置文本颜色时指定保存初始文本颜色的必要性

//+------------------------------------------------------------------+
//| 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,true);
   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;
  }
//+------------------------------------------------------------------+


在返回元素整数型属性的定义中,添加返回新 WinForms 对象属性描述的代码模块

      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_FORE_COLOR_MOUSE_DOWN        ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_FORE_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_FORE_COLOR_MOUSE_OVER        ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_FORE_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_FORE_COLOR_TOGGLE            ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_DOWN ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_DOWN)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_OVER ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_FORE_COLOR_TOGGLE_MOUSE_OVER)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+ColorToString((color)this.GetProperty(property),true)
         )  :
      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_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_BACKGROUND_COLOR_TOGGLE      ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_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_TOGGLE_MOUSE_OVER ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_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_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)
         )  :
      property==CANV_ELEMENT_PROP_BUTTON_TOGGLE                ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_BUTTON_TOGGLE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)(bool)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_BUTTON_STATE                 ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_BUTTON_STATE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)(bool)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR       ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY  ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_MOUSE_DOWN  ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_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_CHECK_BACKGROUND_COLOR_MOUSE_OVER  ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_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_CHECK_FORE_COLOR             ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_FORE_COLOR)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY     ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_FORE_COLOR_OPACITY)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_CHECK_FORE_COLOR_MOUSE_DOWN  ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_FORE_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_CHECK_FORE_COLOR_MOUSE_OVER  ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_FORE_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_CHECK_FLAG_COLOR             ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_FLAG_COLOR)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY     ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_OPACITY)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_DOWN  ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_FLAG_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_CHECK_FLAG_COLOR_MOUSE_OVER  ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_CHECK_FLAG_COLOR_MOUSE_OVER)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return the description of the control real property              |
//+------------------------------------------------------------------+


按类型返回绑定控件列表的方法:

//+------------------------------------------------------------------+
// Return the list of bound controls by type                         |
//+------------------------------------------------------------------+
CArrayObj *CWinFormBase::GetListElementsByType(const ENUM_GRAPH_ELEMENT_TYPE type)
  {
   return CSelect::ByGraphCanvElementProperty(this.GetListElements(),CANV_ELEMENT_PROP_TYPE,type,EQUAL);
  }
//+------------------------------------------------------------------+

在此,我们只返回从绑定对象列表中按指定类型选择的图形元素列表


该方法依据在列表中的索引返回(按类型)绑定元素:

//+------------------------------------------------------------------+
//| Get (by type) the bound element by index in the list             |
//+------------------------------------------------------------------+
CGCnvElement *CWinFormBase::GetElementByType(const ENUM_GRAPH_ELEMENT_TYPE type,const int index)
  {
   CArrayObj *list=this.GetListElementsByType(type);
   return list.At(index);
  }
//+------------------------------------------------------------------+

此处,我们通过上面所研究的依据指定类型获得对象列表,并从所获列表里,依据指定索引返回对象的指针。 如果未获得列表,或超出列表大小,则该方法将返回 NULL


按类型返回绑定元素列表的方法:

//+------------------------------------------------------------------+
//| Get the list of bound elements by type                           |
//+------------------------------------------------------------------+
int CWinFormBase::ElementsTotalByType(const ENUM_GRAPH_ELEMENT_TYPE type)
  {
   CArrayObj *list=this.GetListElementsByType(type);
   return(list!=NULL ? list.Total() : 0);
  }
//+------------------------------------------------------------------+

按指定类型获取绑定对象列表返回列表中对象的指针数量如果获取列表失败,则该方法将返回零

在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\container.mqh 中的基准 WinForms 容器对象类中,重命名设置边框宽度的方法。 以前,我在名称曾用过 “Frame”。 现在我要改名为 “Border”:

//--- 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      SetBorderSizeLeft(const uint value)
                       {
                        CForm::SetBorderSizeLeft(value);
                        if(this.PaddingLeft()<this.BorderSizeLeft())
                           this.SetPaddingLeft(this.BorderSizeLeft());
                       }
   virtual void      SetBorderSizeTop(const uint value)
                       {
                        CForm::SetBorderSizeTop(value);
                        if(this.PaddingTop()<this.BorderSizeTop())
                           this.SetPaddingTop(this.BorderSizeTop());
                       }
   virtual void      SetBorderSizeRight(const uint value)
                       {
                        CForm::SetBorderSizeRight(value);
                        if(this.PaddingRight()<this.BorderSizeRight())
                           this.SetPaddingRight(this.BorderSizeRight());
                       }
   virtual void      SetBorderSizeBottom(const uint value)
                       {
                        CForm::SetBorderSizeBottom(value);
                        if(this.PaddingBottom()<this.BorderSizeBottom())
                           this.SetPaddingBottom(this.BorderSizeBottom());
                       }

请记住,该方法现在递归地调用自身,而以前这些方法拥有不同的名称,并且调用父类方法来设置边框宽度,如此不会导致问题。 因此,在此我们显式指定上下文,调用必要的来自父类的同名方法

在类构造函数中,当保存文本颜色时,指示保存元素标签的初始颜色的必要性

//--- Constructors
                     CContainer(const long chart_id,
                                const int subwindow,
                                const string name,
                                const int x,
                                const int y,
                                const int w,
                                const int h);
                     CContainer(const string name) : CWinFormBase(::ChartID(),0,name,0,0,0,0)
                       {
                        CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_CONTAINER);
                        CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_CONTAINER);
                        this.m_type=OBJECT_DE_TYPE_GWF_CONTAINER; 
                        this.SetForeColor(CLR_DEF_FORE_COLOR,true);
                        this.SetFontBoldType(FW_TYPE_NORMAL);
                        this.SetMarginAll(3);
                        this.SetPaddingAll(0);
                        this.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false);
                        this.SetBorderStyle(FRAME_STYLE_NONE);
                        this.SetAutoScroll(false,false);
                        this.SetAutoScrollMarginAll(0);
                        this.SetAutoSize(false,false);
                        this.SetAutoSizeMode(CANV_ELEMENT_AUTO_SIZE_MODE_GROW,false);
                        this.Initialize();
                       }
//--- Destructor
                    ~CContainer();
  };
//+------------------------------------------------------------------+
//| Constructor indicating the chart and subwindow ID                |
//+------------------------------------------------------------------+
CContainer::CContainer(const long chart_id,
                       const int subwindow,
                       const string name,
                       const int x,
                       const int y,
                       const int w,
                       const int h) : CWinFormBase(chart_id,subwindow,name,x,y,w,h)
  {
   CGBaseObj::SetTypeElement(GRAPH_ELEMENT_TYPE_WF_CONTAINER);
   CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_CONTAINER);
   this.m_type=OBJECT_DE_TYPE_GWF_CONTAINER;
   this.SetForeColor(CLR_DEF_FORE_COLOR,true);
   this.SetFontBoldType(FW_TYPE_NORMAL);
   this.SetMarginAll(3);
   this.SetPaddingAll(0);
   this.SetDockMode(CANV_ELEMENT_DOCK_MODE_NONE,false);
   this.SetBorderStyle(FRAME_STYLE_NONE);
   this.SetAutoScroll(false,false);
   this.SetAutoScrollMarginAll(0);
   this.SetAutoSize(false,false);
   this.SetAutoSizeMode(CANV_ELEMENT_AUTO_SIZE_MODE_GROW,false);
   this.Initialize();
   this.SetCoordXInit(x);
   this.SetCoordYInit(y);
   this.SetWidthInit(w);
   this.SetHeightInit(h);
  }
//+------------------------------------------------------------------+


在创建新绑定元素的方法中,指示需要保存所有地方的原始颜色

//+------------------------------------------------------------------+
//| 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(),true);

//--- 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(),true);
        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,true);
        obj.SetBorderColor(obj.ForeColor(),true);
        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(),true);
        obj.SetBackgroundColor(colour==clrNONE ? CLR_DEF_CONTROL_STD_BACK_COLOR : colour,true);
        obj.SetBorderColor(obj.ForeColor(),true);
        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;
  }
//+------------------------------------------------------------------+


在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\GroupBox.mqh 中的 GroupBox WinForms 对象类文件里,即在其初始化方法中,在设置默认颜色时,指示保存初始颜色的必要性:

//--- 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,true);
   this.SetOpacity(0);
   this.SetBorderColor(CLR_DEF_FRAME_GBOX_COLOR,true);
//--- Set the default color and text opacity, as well as the absence of the object frame
   this.SetForeColor(CLR_DEF_FORE_COLOR,true);
   this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY);
   this.SetBorderStyle(FRAME_STYLE_SIMPLE);
//--- Set the default text parameters


在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\CommonBasemqh 基准标准 WinForms 对象的文件中,即在其 Initialize() 初始化方法中,当设置默认颜色时指示保存初始颜色的必要性

//--- 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,true);
   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,true);
   this.SetForeColorOpacity(CLR_DEF_FORE_COLOR_OPACITY);
   this.SetBorderStyle(FRAME_STYLE_NONE);
//--- Set the default text parameters


CheckBox WinForms 对象是由带复选框的字段和文本组成。 当鼠标光标悬停其上,并单击按钮时,字段的颜色、边框和复选框都会变化。 因此,我们需要为所有组件创建变量,来存储其初始颜色,以及设置与鼠标事件对应的颜色的方法。

在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\CheckBoxmqh 中类的受保护部分,声明存储初始颜色的变量,和处理鼠标事件的虚拟方法

//+------------------------------------------------------------------+
//| CheckBox object class of the WForms controls                     |
//+------------------------------------------------------------------+
class CCheckBox : public CLabel
  {
private:
//--- Set X and Y checkbox coordinates
   void              SetCheckFlagCoords(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
   color             m_check_back_color_init;                        // Initial color of the checkbox background
   color             m_check_border_color_init;                      // Initial color of the checkbox background frame
   color             m_check_flag_color_init;                        // Initial color of the checkbox
//--- Set the element width and height automatically
   virtual bool      AutoSetWH(void);
//--- Displays the checkbox for the specified state
   virtual void      ShowControlFlag(const ENUM_CANV_ELEMENT_CHEK_STATE state);
   
//--- (1) Set and (2) return the checkbox size on the element
   void              SetCheckWidth(const int width)                  { this.m_check_w=(width<5  ? 5 : width);  }
   void              SetCheckHeight(const int height)                { this.m_check_h=(height<5 ? 5 : height); }
   int               CheckWidth(void)                          const { return this.m_check_w;                  }
   int               CheckHeight(void)                         const { return this.m_check_h;                  }

//--- 'The cursor is inside the active area, the mouse buttons are not clicked' event handler
   virtual void      MouseActiveAreaNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the active area, a mouse button is clicked (any)' event handler
   virtual void      MouseActiveAreaPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the active area, the left mouse button is clicked' event handler
   virtual void      MouseActiveAreaReleasedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);

public:


修改设置复选框背景色、字段边框和复选框本身的方法,从而可依据标记值保持原始字段颜色添加设置和获取初始颜色的方法,以及声明最后一个鼠标事件的处理程序

//--- (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 verification checkbox background color
   void              SetCheckBackgroundColor(const color clr,const bool set_init_color)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR,clr);
                        if(set_init_color)
                           this.SetCheckBackgroundColorInit(clr);
                       }
   color             CheckBackgroundColor(void)                   const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR);         }
//--- (1) Set and (2) return the control verification 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 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 initial color of the control verification checkbox background
   void              SetCheckBackgroundColorInit(const color clr)       { this.m_check_back_color_init=clr;                                                 }
   color             CheckBackgroundColorInit(void)               const { return (color)this.m_check_back_color_init;                                       }

//--- (1) Set and (2) return the control checkbox frame color
   void              SetCheckBorderColor(const color clr,const bool set_init_color)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_CHECK_FORE_COLOR,clr);
                        if(set_init_color)
                           this.SetCheckBorderColorInit(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 initial color of the control verification checkbox frame
   void              SetCheckBorderColorInit(const color clr)           { this.m_check_border_color_init=clr;                                               }
   color             CheckBorderColorInit(void)                   const { return (color)this.m_check_border_color_init;                                     }

//--- (1) Set and (2) return the control verification checkbox color
   void              SetCheckFlagColor(const color clr,const bool set_init_color)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR,clr);
                        if(set_init_color)
                           this.SetCheckFlagColorInit(clr);
                       }
   color             CheckFlagColor(void)                         const { return (color)this.GetProperty(CANV_ELEMENT_PROP_CHECK_FLAG_COLOR);               }
//--- (1) Set and (2) return the control verification 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);    }
//--- (1) Set and (2) return the initial color of the control verification checkbox
   void              SetCheckFlagColorInit(const color clr)             { this.m_check_flag_color_init=clr;                                                 }
   color             CheckFlagColorInit(void)                     const { return (color)this.m_check_flag_color_init;                                       }
   
//--- Last mouse event handler
   virtual void      OnMouseEventPostProcessing(void);
   
//--- Redraw the object
   virtual void      Redraw(bool redraw);

//--- Constructor


在类构造函数中,为各种事件和鼠标状态设置默认颜色

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CCheckBox::CCheckBox(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_CHECKBOX);
   CGCnvElement::SetProperty(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_WF_CHECKBOX);
   this.m_type=OBJECT_DE_TYPE_GWF_COMMON;
   this.SetCoordX(x);
   this.SetCoordY(y);
   this.SetCheckWidth(DEF_CHECK_SIZE);
   this.SetCheckHeight(DEF_CHECK_SIZE);
   this.SetWidth(w);
   this.SetHeight(h);
   this.Initialize();
   this.SetForeColorMouseDown(CLR_DEF_FORE_COLOR_MOUSE_DOWN);
   this.SetForeColorMouseOver(CLR_DEF_FORE_COLOR_MOUSE_OVER);
   this.SetCheckBackgroundColor(CLR_DEF_CHECK_BACK_COLOR,true);
   this.SetCheckBackgroundColorMouseDown(CLR_DEF_CHECK_BACK_MOUSE_DOWN);
   this.SetCheckBackgroundColorMouseOver(CLR_DEF_CHECK_BACK_MOUSE_OVER);
   this.SetCheckBorderColor(CLR_DEF_CHECK_BORDER_COLOR,true);
   this.SetCheckBorderColorMouseDown(CLR_DEF_CHECK_BORDER_MOUSE_DOWN);
   this.SetCheckBorderColorMouseOver(CLR_DEF_CHECK_BORDER_MOUSE_OVER);
   this.SetCheckFlagColor(CLR_DEF_CHECK_FLAG_COLOR,true);
   this.SetCheckFlagColorMouseDown(CLR_DEF_CHECK_FLAG_MOUSE_DOWN);
   this.SetCheckFlagColorMouseOver(CLR_DEF_CHECK_FLAG_MOUSE_OVER);
   this.SetWidthInit(this.Width());
   this.SetHeightInit(this.Height());
   this.SetCoordXInit(x);
   this.SetCoordYInit(y);
   this.SetTextAlign(ANCHOR_LEFT);
   this.m_text_x=0;
   this.m_text_y=0;
   this.m_check_x=0;
   this.m_check_y=0;
   this.Redraw(false);
  }
//+------------------------------------------------------------------+


并非所有的鼠标事件处理程序都要在这里重新定义。 我们研究一下父类的重定义方法。

“光标位于活动区域内,且无单击鼠标按钮”事件处理程序:

//+------------------------------------------------------------------+
//| 'The cursor is inside the active area,                           |
//| no mouse buttons are clicked' event handler                      |
//+------------------------------------------------------------------+
void CCheckBox::MouseActiveAreaNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   this.SetCheckBackgroundColor(this.CheckBackgroundColorMouseOver(),false);
   this.SetCheckBorderColor(this.CheckBorderColorMouseOver(),false);
   this.SetCheckFlagColor(this.CheckFlagColorMouseOver(),false);
   this.Redraw(true);
  }
//+------------------------------------------------------------------+

如果鼠标光标悬停在对象活动区域上,则为复选框、其边框和标志本身设置新的背景色(已为当前鼠标和对象状态指定),然后重新绘制对象。


“光标位于活动区域内,单击任何鼠标按钮”事件处理程序:

//+------------------------------------------------------------------+
//| 'The cursor is inside the active area,                           |
//| a mouse button is clicked (any)                                  |
//+------------------------------------------------------------------+
void CCheckBox::MouseActiveAreaPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
   this.SetCheckBackgroundColor(this.CheckBackgroundColorMouseDown(),false);
   this.SetCheckBorderColor(this.CheckBorderColorMouseDown(),false);
   this.SetCheckFlagColor(this.CheckFlagColorMouseDown(),false);
   this.Redraw(false);
  }
//+------------------------------------------------------------------+

如果鼠标光标悬停在对象活动区域上,则为复选框、其边框和标志本身设置新的背景色(已为当前鼠标和对象状态指定),然后重新绘制对象。


“光标位于活动区域内,单击鼠标左键”事件处理程序:

//+------------------------------------------------------------------+
//| 'The cursor is inside the active area,                           |
//| left mouse button released                                       |
//+------------------------------------------------------------------+
void CCheckBox::MouseActiveAreaReleasedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
//--- The mouse button released outside the element means refusal to interact with the element
   if(lparam<this.CoordX() || lparam>this.RightEdge() || dparam<this.CoordY() || dparam>this.BottomEdge())
     {
      this.SetCheckBackgroundColor(this.BackgroundColorInit(),false);
      this.SetCheckBorderColor(this.CheckBorderColorInit(),false);
      this.SetCheckFlagColor(this.CheckFlagColorInit(),false);
      //--- Send a test entry to the journal
      Print(DFUN_ERR_LINE,TextByLanguage("Отмена","Cancel"));
     }
//--- The mouse button released within the element means a  click on the control
   else
     {
      this.SetCheckBackgroundColor(this.CheckBackgroundColorMouseOver(),false);
      this.SetCheckBorderColor(this.CheckBorderColorMouseOver(),false);
      this.SetCheckFlagColor(this.CheckFlagColorInit(),false);
      this.SetChecked(!this.Checked());
      //--- Send a test entry to the journal
      Print(DFUN_ERR_LINE,TextByLanguage("Щелчок","Click"));
     }
   this.Redraw(false);
  }
//+------------------------------------------------------------------+

此处是两种状态的处理过程:

如果释放鼠标按钮,且光标位于对象活动区域,且
如果释放鼠标按钮,且光标位于对象活动区域内

如果光标处于对象外部,这意味着用户已经单击了按钮,并将光标移开,且释放了按钮。 在这种情况下,复选框不应更改其状态,因为这意味着拒绝与对象交互。 因此,我们来设置对象的初始标志和字段颜色。

如果光标位于对象内部,则用户已单击,并释放该按钮。 此刻应该更改复选框的状态。 因此,我们取光标悬停在活动区域上时的颜色,来更改字段、边框和复选框的颜色(即使释放了鼠标按钮,光标仍停留在对象上,因此颜色应与悬停在对象上时的颜色相同),且复选框状态取反
最后,重绘对象。 发送有关每个复选框状态已处理情况的测试记录项。 稍后,当该复选框被触发时,将记录项发送到日志,取代发送事件的后续处理。


最后一个鼠标事件的虚拟处理程序:

//+------------------------------------------------------------------+
//| Last mouse event handler                                         |
//+------------------------------------------------------------------+
void CCheckBox::OnMouseEventPostProcessing(void)
  {
   ENUM_MOUSE_FORM_STATE state=GetMouseState();
   switch(state)
     {
      //--- The cursor is outside the form, the mouse buttons are not clicked
      //--- The cursor is outside the form, any mouse button is clicked
      //--- The cursor is outside the form, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_OUTSIDE_FORM_NOT_PRESSED :
      case MOUSE_FORM_STATE_OUTSIDE_FORM_PRESSED     :
      case MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL       :
        if(MouseEventLast()==MOUSE_EVENT_INSIDE_ACTIVE_AREA_NOT_PRESSED)
          {
           this.SetBackgroundColor(this.BackgroundColorInit(),false);
           this.SetBorderColor(this.BorderColorInit(),false);
           this.SetCheckBackgroundColor(this.CheckBackgroundColorInit(),false);
           this.SetCheckBorderColor(this.CheckBorderColorInit(),false);
           this.SetCheckFlagColor(this.CheckFlagColorInit(),false);
           this.m_mouse_event_last=ENUM_MOUSE_EVENT(state+MOUSE_EVENT_NO_EVENT);
           this.Redraw(false);
          }
        break;

      //--- The cursor is inside the form, the mouse buttons are not clicked
      case MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED :
        break;
      //--- The cursor is inside the form, any mouse button is clicked
      case MOUSE_FORM_STATE_INSIDE_FORM_PRESSED :
        break;
      //--- The cursor is inside the form, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_FORM_WHEEL :
        break;
      //--- The cursor is inside the active area, the mouse buttons are not clicked
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED :
        break;
      //--- The cursor is inside the active area, any mouse button is clicked
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED :
        break;
      //--- The cursor is inside the active area, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL :
        break;
      //--- The cursor is inside the active area, left mouse button is released
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED :
        break;
      //--- The cursor is within the window scrolling area, the mouse buttons are not clicked
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_NOT_PRESSED :
        break;
      //--- The cursor is within the window scrolling area, any mouse button is clicked
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_PRESSED :
        break;
      //--- The cursor is within the window scrolling area, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_WHEEL :
        break;
      //--- MOUSE_EVENT_NO_EVENT
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

这里我们只处理鼠标光标在对象外部的情况,而以前的状态是“光标在活动区域内,且无单击鼠标按钮”。 在这种情况下,为所有可更改的对象颜色属性设置初始值,并将当前状态指定为最后一个鼠标事件。


在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\RadioButtonmqh 中的 WinForms 对象的 RadioButt 类,继承自新修改的 CheckBox 对象类,因此需要的修改较少。

在该对象中,标志始终处于活动状态。 它的取消选中取决于与它协同操作的另一个类似对象。 如果在单个对象中设置了复选框,则在另一个对象中取消选中,反之亦然。 在此,我们只需要重新定义父类的单个虚拟方法

//+------------------------------------------------------------------+
//| 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);

//--- 'The cursor is inside the active area, the left mouse button is clicked' event handler
   virtual void      MouseActiveAreaReleasedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);

public:


“光标位于活动区域内,单击鼠标左键”事件处理程序:

//+------------------------------------------------------------------+
//| The cursor is inside the active area,                            |
//| left mouse button released                                       |
//+------------------------------------------------------------------+
void CRadioButton::MouseActiveAreaReleasedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
//--- The mouse button released outside the element means refusal to interact with the element
   if(lparam<this.CoordX() || lparam>this.RightEdge() || dparam<this.CoordY() || dparam>this.BottomEdge())
     {
      this.SetCheckBackgroundColor(this.BackgroundColorInit(),false);
      this.SetCheckBorderColor(this.CheckBorderColorInit(),false);
      this.SetCheckFlagColor(this.CheckFlagColorInit(),false);
      Print(DFUN_ERR_LINE,TextByLanguage("Отмена","Cancel"));
     }
//--- The mouse button released within the element means a  click on the control
   else
     {
      this.SetCheckBackgroundColor(this.CheckBackgroundColorMouseOver(),false);
      this.SetCheckBorderColor(this.CheckBorderColorMouseOver(),false);
      this.SetCheckFlagColor(this.CheckFlagColorInit(),false);
      Print(DFUN_ERR_LINE,TextByLanguage("Щелчок","Click"));
     }
   this.Redraw(false);
  }
//+------------------------------------------------------------------+

该方法与 CheckBox 对象类当中研究过的方法类似,只是于此,在对象活动区域内释放按钮后,我们不需要在处理模块中将标志值取反


WinForms 按钮对象。 按钮可以有两种类型:

  1. 单击时,按钮被触发,并返回其初始状态,
  2. 单击时,按钮被触发,并保持按下状态;第二次单击会将其状态切换到相反的状态(触发器为 Toggle-Button)。

因此,我们需要定义它是哪个按钮标志,定义触发按钮的标志(按下/释放),当然,还需要另一组用于判定按钮单击时的颜色(背景色、光标悬停、和单击按钮时的颜色)。

在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\Button.mqh 里,即在类的私密部分,声明存储新按钮状态颜色的数组

//+------------------------------------------------------------------+
//| Label object class of WForms controls                            |
//+------------------------------------------------------------------+
class CButton : public CLabel
  {
private:
   int               m_text_x;                                 // Text X coordinate
   int               m_text_y;                                 // Text Y coordinate
   color             m_array_colors_bg_tgl[];                  // Array of element background colors for the 'enabled' state
   color             m_array_colors_bg_tgl_dwn[];              // Array of control background colors for the 'enabled' state when clicking on the control
   color             m_array_colors_bg_tgl_ovr[];              // Array of control background colors for the 'enabled' state when hovering the mouse over the control
   color             m_array_colors_bg_tgl_init[];             // Array of initial element background colors for the 'enabled' state
protected:


在类的受保护部分,在此处声明应该重新定义的父类鼠标事件的处理程序

protected:
//--- Set the element width and height automatically
   virtual bool      AutoSetWH(void);

//--- 'The cursor is inside the active area, the mouse buttons are not clicked' event handler
   virtual void      MouseActiveAreaNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the active area, a mouse button is clicked (any)' event handler
   virtual void      MouseActiveAreaPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);
//--- 'The cursor is inside the active area, the left mouse button is clicked' event handler
   virtual void      MouseActiveAreaReleasedHandler(const int id,const long& lparam,const double& dparam,const string& sparam);

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);   }

//--- (1) Set and (2) return the control Toggle flag
   void              SetToggleFlag(const bool flag)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_BUTTON_TOGGLE,flag);
                        if(this.Toggle())
                           this.SetColorsToggleON(CLR_DEF_CONTROL_STD_BACK_COLOR_ON,CLR_DEF_CONTROL_STD_BACK_DOWN_ON,CLR_DEF_CONTROL_STD_BACK_OVER_ON,true);
                       }
   bool              Toggle(void)                        const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_BUTTON_TOGGLE);                               }
//--- (1) Set and (2) return the Toggle control status
   void              SetState(const bool flag)                 { this.SetProperty(CANV_ELEMENT_PROP_BUTTON_STATE,flag);                                        }
   bool              State(void)                         const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_BUTTON_STATE);                                }
   
//--- (1,2) Set and (3) return the main background color for the 'enabled' status
   void              SetBackgroundColorToggleON(const color colour,const bool set_init_color)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE,colour);
                        color arr[1];
                        arr[0]=colour;
                        this.CopyArraysColors(this.m_array_colors_bg_tgl,arr,DFUN);
                        if(set_init_color)
                           this.CopyArraysColors(this.m_array_colors_bg_tgl_init,arr,DFUN);
                       }
   void              SetBackgroundColorsToggleON(color &colors[],const bool set_init_colors)
                       {
                        this.CopyArraysColors(this.m_array_colors_bg_tgl,colors,DFUN);
                        this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE,this.m_array_colors_bg_tgl[0]);
                        if(set_init_colors)
                           this.CopyArraysColors(this.m_array_colors_bg_tgl_init,colors,DFUN);
                       }
   color             BackgroundColorToggleON(void)       const { return (color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE);                    }
   
//--- (1,2) Set and (3) return the background color when clicking on the control for the 'enabled' status
   void              SetBackgroundColorToggleONMouseDown(const color colour)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN,colour);
                        color arr[1];
                        arr[0]=colour;
                        this.CopyArraysColors(this.m_array_colors_bg_tgl_dwn,arr,DFUN);
                       }
   void              SetBackgroundColorsToggleONMouseDown(color &colors[])
                       {
                        this.CopyArraysColors(this.m_array_colors_bg_tgl_dwn,colors,DFUN);
                        this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN,this.m_array_colors_bg_dwn[0]);
                       }
   color             BackgroundColorToggleONMouseDown(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_DOWN);      }
                       
//--- (1,2) Set and (3) return the background color when hovering the mouse over the control for the 'enabled' status
   void              SetBackgroundColorToggleONMouseOver(const color colour)
                       {
                        this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_OVER,colour);
                        color arr[1];
                        arr[0]=colour;
                        this.CopyArraysColors(this.m_array_colors_bg_tgl_ovr,arr,DFUN);
                       }
   void              SetBackgroundColorsToggleONMouseOver(color &colors[])
                       {
                        this.CopyArraysColors(this.m_array_colors_bg_tgl_ovr,colors,DFUN);
                        this.SetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_OVER,this.m_array_colors_bg_ovr[0]);
                       }
   color             BackgroundColorToggleONMouseOver(void) const { return (color)this.GetProperty(CANV_ELEMENT_PROP_BACKGROUND_COLOR_TOGGLE_MOUSE_OVER);      }

//--- Return the initial main background color for the 'enabled' status
   color             BackgroundColorToggleONInit(void)      const { return this.m_array_colors_bg_tgl_init[0]; }
   
//--- Set the colors for the 'enabled' status
   void              SetColorsToggleON(const color back,const color back_down,const color back_over,const bool set_init_color);
   
//--- Last mouse event handler
   virtual void      OnMouseEventPostProcessing(void);

//--- Constructor
                     CButton(const long chart_id,
                             const int subwindow,
                             const string name,
                             const int x,
                             const int y,
                             const int w,
                             const int h);
  };
//+------------------------------------------------------------------+

这些方法与设置和返回我上面研究过的其它类对象颜色的方法雷同。


在类构造函数中,设置悬停并单击按钮时对象背景、对象不透明度值和背景颜色的默认颜色设置常规按钮(不是切换钮扣)标志,和切换钮扣按钮状态设置为 false

//+------------------------------------------------------------------+
//| 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.SetBackgroundColor(CLR_DEF_CONTROL_STD_BACK_COLOR,true);
   this.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_STD_MOUSE_DOWN);
   this.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_STD_MOUSE_OVER);
   this.SetOpacity(CLR_DEF_CONTROL_STD_OPACITY);
   this.SetTextAlign(ANCHOR_CENTER);
   this.SetMarginAll(3);
   this.SetWidthInit(this.Width());
   this.SetHeightInit(this.Height());
   this.SetCoordXInit(x);
   this.SetCoordYInit(y);
   this.SetToggleFlag(false);
   this.SetState(false);
   this.Redraw(false);
  }
//+------------------------------------------------------------------+


重新定义鼠标事件处理程序。

“光标位于活动区域内,且无单击鼠标按钮”事件处理程序:

//+------------------------------------------------------------------+
//| 'The cursor is inside the active area,                           |
//| no mouse buttons are clicked' event handler                      |
//+------------------------------------------------------------------+
void CButton::MouseActiveAreaNotPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
//--- If this is a simple button, set the color for the "The cursor is over the active area, the mouse button is not clicked" status
   if(!this.Toggle())
      this.SetBackgroundColor(this.BackgroundColorMouseOver(),false);
//--- If this is the toggle button, set the color for the status depending on whether the button is pressed or not
   else
      this.SetBackgroundColor(this.State() ? this.BackgroundColorToggleONMouseOver() : this.BackgroundColorMouseOver(),false);
//--- Set the frame color for the status
   this.SetBorderColor(this.BorderColorMouseOver(),false);
//--- Redraw the object
   this.Redraw(false);
  }
//+------------------------------------------------------------------+


“光标位于活动区域内,单击任何鼠标按钮”事件处理程序:

//+------------------------------------------------------------------+
//| The cursor is inside the active area,                            |
//| a mouse button is clicked (any)                                  |
//+------------------------------------------------------------------+
void CButton::MouseActiveAreaPressedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
//--- If this is a simple button, set the color for the "The cursor is over the active area, the mouse button is clicked" status
   if(!this.Toggle())
      this.SetBackgroundColor(this.BackgroundColorMouseDown(),false);
//--- If this is the toggle button, set the color for the status depending on whether the button is pressed or not
   else
      this.SetBackgroundColor(this.State() ? this.BackgroundColorToggleONMouseDown() : this.BackgroundColorMouseDown(),false);
//--- Set the frame color for the status
   this.SetBorderColor(this.BorderColorMouseDown(),false);
//--- Redraw the object
   this.Redraw(false);
  }
//+------------------------------------------------------------------+


“光标位于活动区域内,单击鼠标左键”事件处理程序:

//+------------------------------------------------------------------+
//| The cursor is inside the active area,                            |
//| left mouse button released                                       |
//+------------------------------------------------------------------+
void CButton::MouseActiveAreaReleasedHandler(const int id,const long& lparam,const double& dparam,const string& sparam)
  {
//--- The mouse button released outside the element means refusal to interact with the element
   if(lparam<this.CoordX() || lparam>this.RightEdge() || dparam<this.CoordY() || dparam>this.BottomEdge())
     {
      //--- If this is a simple button, set the initial background color
      if(!this.Toggle())
         this.SetBackgroundColor(this.BackgroundColorInit(),false);
      //--- If this is the toggle button, set the initial color depending on whether the button is pressed or not
      else
         this.SetBackgroundColor(!this.State() ? this.BackgroundColorInit() : this.BackgroundColorToggleONInit(),false);
      //--- Set the initial frame color
      this.SetBorderColor(this.BorderColorInit(),false);
      //--- Send the test message to the journal
      Print(DFUN_ERR_LINE,TextByLanguage("Отмена","Cancel"));
     }
//--- The mouse button released within the element means a  click on the control
   else
     {
      //--- If this is a simple button, set the color for "The cursor is over the active area" status
      if(!this.Toggle())
         this.SetBackgroundColor(this.BackgroundColorMouseOver(),false);
      //--- If this is the toggle button,
      else
        {
         //--- set the button status to the opposite one
         this.SetState(!this.State());
         //--- set the background color for "The cursor is over the active area" status depending on whether the button is clicked or not
         this.SetBackgroundColor(this.State() ? this.BackgroundColorToggleONMouseOver() : this.BackgroundColorMouseOver(),false);
        }
      //--- Send the test message to the journal
      Print(DFUN_ERR_LINE,TextByLanguage("Щелчок","Click"));
      //--- Set the frame color for "The cursor is over the active area" status
      this.SetBorderColor(this.BorderColorMouseOver(),false);
     }
//--- Redraw the object
   this.Redraw(false);
  }
//+------------------------------------------------------------------+

方法逻辑在代码注释中已有详细讲述,无需赘言。


最后一个鼠标事件处理程序:

//+------------------------------------------------------------------+
//| Last mouse event handler                                         |
//+------------------------------------------------------------------+
void CButton::OnMouseEventPostProcessing(void)
  {
   ENUM_MOUSE_FORM_STATE state=GetMouseState();
   switch(state)
     {
      //--- The cursor is outside the form, the mouse buttons are not clicked
      //--- The cursor is outside the form, any mouse button is clicked
      //--- The cursor is outside the form, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_OUTSIDE_FORM_NOT_PRESSED :
      case MOUSE_FORM_STATE_OUTSIDE_FORM_PRESSED     :
      case MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL       :
        if(MouseEventLast()==MOUSE_EVENT_INSIDE_ACTIVE_AREA_NOT_PRESSED)
          {
           this.SetBackgroundColor(this.State() ? this.BackgroundColorToggleON() : this.BackgroundColorInit(),false);
           this.SetBorderColor(this.BorderColorInit(),false);
           this.m_mouse_event_last=ENUM_MOUSE_EVENT(state+MOUSE_EVENT_NO_EVENT);
           this.Redraw(false);
          }
        break;

      //--- The cursor is inside the form, the mouse buttons are not clicked
      case MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED :
        break;
      //--- The cursor is inside the form, any mouse button is clicked
      case MOUSE_FORM_STATE_INSIDE_FORM_PRESSED :
        break;
      //--- The cursor is inside the form, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_FORM_WHEEL :
        break;
      //--- The cursor is inside the active area, the mouse buttons are not clicked
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED :
        break;
      //--- The cursor is inside the active area, any mouse button is clicked
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED :
        break;
      //--- The cursor is inside the active area, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL :
        break;
      //--- The cursor is inside the active area, left mouse button is released
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED :
        break;
      //--- The cursor is within the window scrolling area, the mouse buttons are not clicked
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_NOT_PRESSED :
        break;
      //--- The cursor is within the window scrolling area, any mouse button is clicked
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_PRESSED :
        break;
      //--- The cursor is within the window scrolling area, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_WHEEL :
        break;
      //--- MOUSE_EVENT_NO_EVENT
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

在该方法中,我们只处理鼠标光标在窗体之外的情况,而最后一个鼠标事件是窗体上方的光标,且没有单击鼠标按钮。 按钮初始颜色设置为按钮背景色,具体取决于按钮是否按下(由 State() 方法返回的简单按钮值始终为 false)。

该方法设置切换钮扣按钮“已启用”状态颜色:

//+------------------------------------------------------------------+
//| Set the colors for the toggle element 'enabled' status           |
//+------------------------------------------------------------------+
void CButton::SetColorsToggleON(const color back,const color back_down,const color back_over,const bool set_init_color)
  {
   this.SetBackgroundColorToggleON(back,set_init_color);
   this.SetBackgroundColorToggleONMouseDown(back_down);
   this.SetBackgroundColorToggleONMouseOver(back_over);
  }
//+------------------------------------------------------------------+

该方法接收三个按钮状态的颜色。 它们依据相应的变量设置。 set_init_color 标志允许定义是否应保存初始按钮背景颜色。


改进 \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh 中图形元素的集合类。

在 GetFormUnderCursor() 方法中有两段雷同的代码模块,在其内包含搜索绑定在窗体,且位于光标下的对象。 将此代码模块移至单独的方法之中,从而缩短方法代码,并能更直观地表示其逻辑。

在类的私密部分中,声明方法,并声明处理光标离开窗体事件的方法

//--- Add (1) the standard graphical object and (2) the graphical element on canvas to the collection
   bool              AddGraphObjToCollection(const string source,CChartObjectsControl *obj_control);
//--- Search for interaction objects
   CForm            *SearchInteractObj(CForm *form,const int id,const long &lparam,const double &dparam,const string &sparam);
//--- Return the pointer to the form located under the cursor
   CForm            *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);
//--- Reset all interaction flags for all forms except the specified one
   void              ResetAllInteractionExeptOne(CGCnvElement *form);
//--- Post-processing of the former active form under the cursor
   void              FormPostProcessing(void);
//--- Add the element to the collection list
   bool AddCanvElmToCollection(CGCnvElement *element);


所有创建各种图形元素的方法中,在设置颜色,且包含指示保存初始颜色标志的方法中,标志已被设置(传递 true,因为创建对象时需要保存初始颜色)。 所有这些变化都已经在类中完成了,所以我们不打算在这里详细讨论。

例如,该方法在指定图表和子窗口的画布上创建图形窗体对象:

//--- Create a graphical form object on canvas on a specified chart and subwindow
   int               CreateForm(const long chart_id,
                                const int subwindow,
                                const string name,
                                const int x,
                                const int y,
                                const int w,
                                const int h,
                                const color clr,
                                const uchar opacity,
                                const bool movable,
                                const bool activity,
                                const bool shadow=false,
                                const bool redraw=false)
                       {
                        int id=this.m_list_all_canv_elm_obj.Total();
                        CForm *obj=new CForm(chart_id,subwindow,name,x,y,w,h);
                        ENUM_ADD_OBJ_RET_CODE res=this.AddOrGetCanvElmToCollection(obj,id);
                        if(res==ADD_OBJ_RET_CODE_ERROR)
                           return WRONG_VALUE;
                        obj.SetID(id);
                        obj.SetActive(activity);
                        obj.SetMovable(movable);
                        obj.SetBackgroundColor(clr,true);
                        obj.SetBorderColor(clr,true);
                        obj.SetOpacity(opacity,false);
                        obj.SetShadow(shadow);
                        obj.DrawRectangle(0,0,obj.Width()-1,obj.Height()-1,obj.BorderColor(),obj.Opacity());
                        obj.Done();
                        obj.Erase(clr,opacity,redraw);
                        return obj.ID();
                       }

针对设置颜色的所有方法,都进行了类似的修改。


搜索交互对象的方法:

//+------------------------------------------------------------------+
//| Search for interaction objects                                   |
//+------------------------------------------------------------------+
CForm *CGraphElementsCollection::SearchInteractObj(CForm *form,const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- If a non-empty pointer is passed
   if(form!=NULL)
     {
      //--- Create the list of interaction objects
      int total=form.CreateListInteractObj();
      //--- In the loop by the created list
      for(int i=total-1;i>WRONG_VALUE;i--)
        {
         //--- get the next form object
         CForm *obj=form.GetInteractForm(i);
         //--- If the object is received and the mouse cursor is located above the object, return the pointer to the found object
         if(obj!=NULL && obj.MouseFormState(id,lparam,dparam,sparam)>MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL)
            return obj;
        }
     }
//--- Return the same pointer
   return form;
  }
//+------------------------------------------------------------------+

在上一篇文章中,我们研究了方法逻辑,但代码则是在 GetFormUnderCursor() 方法中编写的。
现在,我们只需添加调用方法,取代代码模块:

//+------------------------------------------------------------------+
//| 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)
           {
            //--- Find the interaction object.
            //--- This will be either the found object or the same form
            form=this.SearchInteractObj(form,id,lparam,dparam,sparam);
            //--- Return the 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)
           {
            //--- Find the interaction object.
            //--- This will be either the found object or the same form
            form=this.SearchInteractObj(form,id,lparam,dparam,sparam);
            //--- Return the 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;
  }
//+------------------------------------------------------------------+

感谢这样的一个小小改进,方法代码变得更加可读。


该方法处理光标下前一个活动窗体的鼠标事件:

//+------------------------------------------------------------------+
//| Post-processing of the former active form under the cursor       |
//+------------------------------------------------------------------+
void CGraphElementsCollection::FormPostProcessing(void)
  {
 //--- Get all the elements of the CForm type and above
   CArrayObj *list=GetList(CANV_ELEMENT_PROP_TYPE,GRAPH_ELEMENT_TYPE_FORM,EQUAL_OR_MORE);
   if(list==NULL)
      return;
   //--- In the loop by the list of received elements
   int total=list.Total();
   for(int i=0;i<total;i++)
     {
      //--- get the pointer to the object
      CForm *obj=list.At(i);
      //--- if failed to get the pointer, move on to the next one in the list
      if(obj==NULL)
         continue;
      //--- Create the list of interaction objects and get their number
      int count=obj.CreateListInteractObj();
      //--- In the loop by the obtained list
      for(int j=0;j<count;j++)
        {
         //--- get the next object
         CForm *elm=obj.GetInteractForm(j);
         if(elm==NULL)
            continue;
         //--- and call its method of handling mouse events
         elm.OnMouseEventPostProcessing();
        }
     }
  }
//+------------------------------------------------------------------+

当我们将光标移离图表上的窗体对象时,该对象会失去焦点,光标下的另一个对象会被自动选中。 如果光标下没有其它对象,则会激活以前禁用的所有图表功能 — 滚动、上下文菜单、和其它。 但有时需要处理从对象中删除光标的操作,例如,如果需要修改对象颜色,或者在我们的示例中,恢复原始颜色。 这正是该方法应发挥的作用。 它循环遍历所有 “form” 类型及以上的图形元素,为每个元素创建绑定对象列表,并在循环中调用这些对象的上述鼠标事件处理方法。 因此,图表上每个窗体上的每个对象都将会被处理,但仅需要最后一个鼠标事件(光标位于对象上方,鼠标按钮未单击)。 在处理事件后,我们将当前状态(光标在窗体外)分配给对象的最后一个鼠标事件。 所以,一次只有一个处理对象(光标移动的最后一个对象)。


但是,当我们将光标悬停在可移动窗体对象上,并单击鼠标按钮时,图形元素集合类的事件处理程序中的窗体将启用鼠标按住和移动标志。 但是,如果我们在绑定到窗体的对象上单击按钮,则不应移动该对象,因为对其禁用了移动标志,且将焦点设置为该对象,而非窗体。 因此,在移除移动标志时,我们仍然保持该标志启用。 鼠标移动事件和移动标志会被同时处理:
      //--- If this is a mouse movement event and the movement flag is active, move the form, above which the cursor is located (if the pointer to it is valid)
      if(id==CHARTEVENT_MOUSE_MOVE && move)
        {
         if(form!=NULL)
           {
            //---...
            //---...

我们需要将它们的验证分开,以便判移动标志何时被移除,而鼠标何时移动(同时设置了保持标志)。 如果释放了鼠标按钮,则会注册 MOUSE_FORM_STATE_NONE 事件。 这个事件只在这种情况下出现,因为我还没有添加处理这种状况的功能,而这是鼠标按钮释放事件。

因此,我们需要将检查光标移动事件,和启用移动标志分开。 对于禁用移动标志的情况,我们需要定义 MOUSE_FORM_STATE_NONE 事件,并将其替换为新的事件 — MOUSE_FROM_STATE_INSIDE_ACTIVE_AREA_RELEASED。

下面是如上所述经修订的代码段。 在此,我将这两个事件分开进行单独验证

      if(id==CHARTEVENT_MOUSE_MOVE)
        {
         //--- If the cursor is above the form
         if(form!=NULL)
           {
            //--- If the move flag is set, shift the form following the cursor
            if(move)
              {
               //--- calculate the cursor movement relative to the form coordinate origin
               int x=this.m_mouse.CoordX()-form.OffsetX();
               int y=this.m_mouse.CoordY()-form.OffsetY();
               //--- get the width and height of the chart the form is located at
               int chart_width=(int)::ChartGetInteger(form.ChartID(),CHART_WIDTH_IN_PIXELS,form.SubWindow());
               int chart_height=(int)::ChartGetInteger(form.ChartID(),CHART_HEIGHT_IN_PIXELS,form.SubWindow());
               //--- If the form is not within an extended standard graphical object
               if(form_index==WRONG_VALUE)
                 {
                  //--- Adjust the calculated form coordinates if the form is out of the chart range
                  if(x<0) x=0;
                  if(x>chart_width-form.Width()) x=chart_width-form.Width();
                  if(y<0) y=0;
                  if(y>chart_height-form.Height()) y=chart_height-form.Height();
                  //--- If the one-click trading panel is not present on the chart,
                  if(!::ChartGetInteger(form.ChartID(),CHART_SHOW_ONE_CLICK))
                    {
                     //--- calculate the form coordinates so that the form does not overlap with the one-click trading panel button
                     if(y<17 && x<41)
                        y=17;
                    }
                  //--- If the one-click trading panel is on the chart,
                  else
                    {
                     //--- calculate the form coordinates so that the form does not overlap with the one-click trading panel
                     if(y<80 && x<192)
                        y=80;
                    }
                 }
               //--- If the form is included into the extended standard graphical object
               else
                 {
                  if(graph_obj_id>WRONG_VALUE)
                    {
                     //--- Get the list of objects by object ID (there should be one object)
                     CArrayObj *list_ext=CSelect::ByGraphicStdObjectProperty(GetListStdGraphObjectExt(),GRAPH_OBJ_PROP_ID,0,graph_obj_id,EQUAL);
                     //--- If managed to obtain the list and it is not empty,
                     if(list_ext!=NULL && list_ext.Total()>0)
                       {
                        //--- get the graphical object from the list
                        CGStdGraphObj *ext=list_ext.At(0);
                        //--- If the pointer to the object has been received,
                        if(ext!=NULL)
                          {
                           //--- get the object type
                           ENUM_OBJECT type=ext.GraphObjectType();
                           //--- If the object is built using screen coordinates, set the coordinates to the object
                           if(type==OBJ_LABEL || type==OBJ_BUTTON || type==OBJ_BITMAP_LABEL || type==OBJ_EDIT || type==OBJ_RECTANGLE_LABEL)
                             {
                              ext.SetXDistance(x);
                              ext.SetYDistance(y);
                             }
                           //--- otherwise, if the object is built based on time/price coordinates,
                           else
                             {
                              //--- calculate the shift from the form coordinate origin to its center
                              int shift=(int)::ceil(form.Width()/2)+1;
                              //--- If the form is located on one of the graphical object pivot points,
                              if(form_index<ext.Pivots())
                                {
                                 //--- limit the form coordinates so that they do not move beyond the chart borders
                                 if(x+shift<0)
                                    x=-shift;
                                 if(x+shift>chart_width)
                                    x=chart_width-shift;
                                 if(y+shift<0)
                                    y=-shift;
                                 if(y+shift>chart_height)
                                    y=chart_height-shift;
                                 //--- set the calculated coordinates to the object
                                 ext.ChangeCoordsExtendedObj(x+shift,y+shift,form_index);
                                }
                              //--- If the form is central for managing all pivot points of a graphical object
                              else
                                {
                                 //--- Get screen coordinates of all object pivot points and write them to the m_data_pivot_point structure
                                 if(this.GetPivotPointCoordsAll(ext,m_data_pivot_point))
                                   {
                                    //--- In the loop by the number of object pivot points,
                                    for(int i=0;i<(int)this.m_data_pivot_point.Size();i++)
                                      {
                                       //--- limit the screen coordinates of the current pivot point so that they do not move beyond the chart borders
                                       //--- By X coordinate
                                       if(x+shift-::fabs(this.m_data_pivot_point[i].ShiftX)<0)
                                          x=-shift+::fabs(m_data_pivot_point[i].ShiftX);
                                       if(x+shift+::fabs(this.m_data_pivot_point[i].ShiftX)>chart_width)
                                          x=chart_width-shift-::fabs(this.m_data_pivot_point[i].ShiftX);
                                       //--- By Y coordinate
                                       if(y+shift-::fabs(this.m_data_pivot_point[i].ShiftY)<0)
                                          y=-shift+::fabs(this.m_data_pivot_point[i].ShiftY);
                                       if(y+shift+::fabs(this.m_data_pivot_point[i].ShiftY)>chart_height)
                                          y=chart_height-shift-::fabs(this.m_data_pivot_point[i].ShiftY);
                                       //--- set the calculated coordinates to the current object pivot point
                                       ext.ChangeCoordsExtendedObj(x+shift+this.m_data_pivot_point[i].ShiftX,y+shift+this.m_data_pivot_point[i].ShiftY,i);
                                      }
                                   }
                                }
                             }
                          }
                       }
                    }
                 }
               //--- Move the form by the obtained coordinates
               if(form.IsMain())
                  form.Move(x,y,true);
              }            
            //--- If the move flag is disabled
            else
              {
               //--- The undefined mouse status in mouse_state means releasing the left button
               //--- Assign the new mouse status to the variable
               if(mouse_state==MOUSE_FORM_STATE_NONE)
                  mouse_state=MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED;
               //--- Handle moving the cursor mouse away from the graphical element
               this.FormPostProcessing();
              }
           }
        }

现在,我们可以“捕捉”一个新的鼠标事件前提是释放了移动标志,并立即处理将光标从活动窗体对象移开的事件

在同一个 OnChartEvent() 事件处理程序中,即在鼠标事件处理程序模块中,调用对象鼠标事件处理函数,同时指示先前找到的事件

      //--- If the cursor is above the form
      else
        {
         //--- If the button is still pressed and held on the chart, exit
         if(pressed_chart)
           {
            return;
           }
         
         //--- If the flag of holding the button on the form is not set yet
         if(!pressed_form)
           {
            pressed_chart=false;    // The button is not pressed on the chart
            this.SetChartTools(form.ChartID(),false);
            //+---------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the form, no mouse buttons are clicked' event handler                 |
            //+---------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_FORM_NOT_PRESSED,lparam,dparam,sparam);
               //--- If the cursor is above the form for managing the pivot point of an extended graphical object,
               if(graph_obj_id>WRONG_VALUE)
                 {
                  //--- get the object by its ID and by the chart ID
                  CGStdGraphObj *graph_obj=this.GetStdGraphObjectExt(graph_obj_id,form.ChartID());
                  if(graph_obj!=NULL)
                    {
                     //--- Get the toolkit of an extended standard graphical object
                     CGStdGraphObjExtToolkit *toolkit=graph_obj.GetExtToolkit();
                     if(toolkit!=NULL)
                       {
                        //--- Draw a point with a circle on the form and delete it on all other forms
                        toolkit.DrawOneControlPoint(form);
                       }
                    }
                 }
              }
            //+---------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the form, a mouse button is clicked (any)' event handler              |
            //+---------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_FORM_PRESSED)
              {
               this.SetChartTools(::ChartID(),false);
               //--- If the flag of holding the form is not set yet
               if(!pressed_form)
                 {
                  pressed_form=true;      // set the flag of pressing on the form
                  pressed_chart=false;    // disable the flag of pressing on the form
                 }
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_FORM_PRESSED,lparam,dparam,sparam);
              }
            //+---------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the form, the mouse wheel is being scrolled' event handler            |
            //+---------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_FORM_WHEEL)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_FORM_WHEEL,lparam,dparam,sparam);
              }
            //+---------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the active area, the mouse buttons are not clicked' event handler     |
            //+---------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED)
              {
               //--- Set the cursor shift relative to the form initial coordinates
               form.SetOffsetX(this.m_mouse.CoordX()-form.CoordX());
               form.SetOffsetY(this.m_mouse.CoordY()-form.CoordY());
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_ACTIVE_AREA_NOT_PRESSED,lparam,dparam,sparam);
               
               //--- If the cursor is above the active area of the form for managing the pivot point of an extended graphical object,
               if(graph_obj_id>WRONG_VALUE)
                 {
                  //--- get the object by its ID and by the chart ID
                  CGStdGraphObj *graph_obj=this.GetStdGraphObjectExt(graph_obj_id,form.ChartID());
                  if(graph_obj!=NULL)
                    {
                     //--- Get the toolkit of an extended standard graphical object
                     CGStdGraphObjExtToolkit *toolkit=graph_obj.GetExtToolkit();
                     if(toolkit!=NULL)
                       {
                        //--- Draw a point with a circle on the form and delete it on all other forms
                        toolkit.DrawOneControlPoint(form);
                       }
                    }
                 }
              }
            //+---------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the active area, any mouse button is clicked' event handler           |
            //+---------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED && !move)
              {
               pressed_form=true;                                       // the flag of holding the mouse button on the form
               //--- If the left mouse button is pressed
               if(this.m_mouse.IsPressedButtonLeft())
                 {
                  //--- Set flags and form parameters
                  move=true;                                            // movement flag
                  form.SetInteraction(true);                            // flag of the form interaction with the environment
                  form.BringToTop();                                    // form on the background - above all others
                  form.SetOffsetX(this.m_mouse.CoordX()-form.CoordX()); // Cursor shift relative to the X coordinate
                  form.SetOffsetY(this.m_mouse.CoordY()-form.CoordY()); // Cursor shift relative to the Y coordinate
                  this.ResetAllInteractionExeptOne(form);               // Reset interaction flags for all forms except the current one
                  
                  //--- Get the maximum ZOrder
                  long zmax=this.GetZOrderMax();
                  //--- If the maximum ZOrder has been received and the form's ZOrder is less than the maximum one or the maximum ZOrder of all forms is equal to zero
                  if(zmax>WRONG_VALUE && (form.Zorder()<zmax || zmax==0))
                    {
                     //--- If the form is not a control point for managing an extended standard graphical object,
                     //--- set the form's ZOrder above all others
                     if(form.Type()!=OBJECT_DE_TYPE_GFORM_CONTROL)
                        this.SetZOrderMAX(form);
                    }
                 }
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_ACTIVE_AREA_PRESSED,lparam,dparam,sparam);
              }
            //+---------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the active area, the mouse wheel is being scrolled' event handler     |
            //+---------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_ACTIVE_AREA_WHEEL,lparam,dparam,sparam);
              }
            //+---------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the active area, the left mouse button is clicked' event handler      |
            //+---------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_ACTIVE_AREA_RELEASED,lparam,dparam,sparam);
              }
            //+---------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the window scrolling area, no mouse buttons are clicked' event handler|
            //+---------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_NOT_PRESSED)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_SCROLL_AREA_NOT_PRESSED,lparam,dparam,sparam);
              }
            //+------------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the window scrolling area, a mouse button is clicked (any)' event handler|
            //+------------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_PRESSED)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_SCROLL_AREA_PRESSED,lparam,dparam,sparam);
              }
            //+--------------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the window scrolling area, the mouse wheel is being scrolled' event handler|
            //+--------------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_WHEEL)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_SCROLL_AREA_WHEEL,lparam,dparam,sparam);
              }
           }
        }
     }
  }

这里我们还添加了一个新的处理程序,来处理释放鼠标按钮的事件


在为指定图表设置鼠标滚动、上下文菜单和十字线标志的方法中,添加对已设置标志的检查,从而避免为之前已设置的图表不断重新设置相同状态:

//+------------------------------------------------------------------+
//| Set the flags of scrolling a chart                               |
//| context menu and crosshairs for the chart                        |
//+------------------------------------------------------------------+
void CGraphElementsCollection::SetChartTools(const long chart_id,const bool flag)
  {
   if(::ChartGetInteger(chart_id,CHART_MOUSE_SCROLL)==flag)
      return;
   ::ChartSetInteger(chart_id,CHART_MOUSE_SCROLL,flag);
   ::ChartSetInteger(chart_id,CHART_CONTEXT_MENU,flag);
   ::ChartSetInteger(chart_id,CHART_CROSSHAIR_TOOL,flag);
  }
//+------------------------------------------------------------------+


目前,这些就是函数库类的所有改进。


测试

为了执行测试,我将借用前一篇文章中的 EA,并将其保存在 \MQL5\Experts\TestDoEasy\Part110\ 中,命名为 TstDE110.mq5

我将“原样”保留以前 EA 中的所有对象。 相反,我将稍微修改按钮的大小和位置,并添加按类型获取对象指针,以便测试方法操作。

将切换按钮标志添加到 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_SIMPLE;    // Label border style
sinput   ENUM_ANCHOR_POINT             InpTextAlign         =  ANCHOR_CENTER;          // Label text align
sinput   ENUM_INPUT_YES_NO             InpTextAutoSize      =  INPUT_NO;               // Label autosize
sinput   ENUM_ANCHOR_POINT             InpCheckAlign        =  ANCHOR_LEFT;            // Check flag align
sinput   ENUM_ANCHOR_POINT             InpCheckTextAlign    =  ANCHOR_LEFT;            // 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_CENTER;          // 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
sinput   bool                          InpButtonToggle      =  false;                  // Button toggle flag
//--- global variables

OnInit() 处理程序现在将拥有以下代码:

//+------------------------------------------------------------------+
//| 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.SetBorderSizeAll(3);
            obj.SetBorderStyle(FRAME_STYLE_BEVEL);
            obj.SetBackgroundColor(obj.ChangeColorLightness(obj.BackgroundColor(),4*i),true);
            obj.SetForeColor(clrRed,true);
            //--- 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,0,0,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,true);
               //--- 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_BORDER_COLOR,true);
               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 GroupBox type objects
         gbox=pnl.GetElementByType(GRAPH_ELEMENT_TYPE_WF_GROUPBOX,0);
         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(),true);
            gbox.SetForeColor(gbox.ChangeColorLightness(obj.BackgroundColor(),-1),true);
            //--- Create the CheckBox object
            gbox.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_CHECKBOX,2,10,50,20,clrNONE,255,true,false);
            //--- get the pointer to the CheckBox object by its index in the list of bound CheckBox type objects
            CCheckBox *cbox=gbox.GetElementByType(GRAPH_ELEMENT_TYPE_WF_CHECKBOX,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_BORDER_COLOR,true);
               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()+4,50,20,clrNONE,255,true,false);
            //--- get the pointer to the RadioButton object by its index in the list of bound RadioButton type objects
            CRadioButton *rbtn=gbox.GetElementByType(GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON,0);
            //--- 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_BORDER_COLOR,true);
               rbtn.SetChecked(true);
              }
            //--- Create the Button object
            gbox.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_BUTTON,(int)fmax(rbtn.RightEdgeRelative(),cbox.RightEdgeRelative())+10,14,60,36,clrNONE,255,true,false);
            //--- get the pointer to the Button object by its index in the list of bound Button type objects
            CButton *butt=gbox.GetElementByType(GRAPH_ELEMENT_TYPE_WF_BUTTON,0);
            //--- If Button is created and the pointer to it is received
            if(butt!=NULL)
              {
               //--- Set the Button 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 text color, as well as frame style and color
               butt.SetForeColor(butt.ChangeColorLightness(CLR_DEF_FORE_COLOR,2),true);

               butt.SetBorderStyle((ENUM_FRAME_STYLE)InpButtonFrameStyle);
               butt.SetBorderColor(butt.ChangeColorLightness(butt.BackgroundColor(),-10),true);
               //--- Set the 'toggle' mode depending on the settings
               butt.SetToggleFlag(InpButtonToggle);
               //--- Set the displayed text on the button depending on the 'toggle' flag
               if(butt.Toggle())
                  butt.SetText("Toggle-Button");
               else
                  butt.SetText("Button");
              }
           }
        }
      //--- Redraw all objects according to their hierarchy
      pnl.Redraw(true);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

事实上,这里的一切都保持原样。 我已经更改了函数库中重命名的方法名称。 现在,保持初始颜色的标志(true)被传递到设置颜色的方法中,而选定的按钮模式现在以文本形式显示在相应的按钮上
您可以在文后所附文件中查看所有更改。

编译 EA,并在品种图表上启动它:


正如我们所看到的,当与鼠标交互时,对象的整个视觉组件都能正常工作。


下一步是什么?

在下一篇文章中,我将继续研究函数库 WinForms 对象的交互性。

以下是 MQL5 的当前函数库版本、测试 EA,和图表事件控制指标的所有文件,供您测试和下载。 在评论中留下您的问题、意见和建议。

返回内容目录

*该系列的前几篇文章:

DoEasy. 控件 (第 1 部分): 第一步
DoEasy. 控件 (第 2 部分): 操控 CPanel 类
DoEasy. 控件 (第 3 部分): 创建绑定控件
DoEasy. 控件 (第 4 部分): 面板控件,Padding(填充)和 Dock(驻靠)参数
DoEasy. 控件 (第 5 部分): 基准 WinForms 对象,面板控件,AutoSize 参数
DoEasy. 控件 (第 6 部分): 面板控件,自动调整容器大小来适应内部内容
DoEasy. 控件 (第 7 部分): 文本标签控件
DoEasy. 控件 (第 8 部分): 基准 WinForms 对象类别,GroupBox 和 CheckBox 控件
DoEasy. 控件 (第 9 部分): 重新编排 WinForms 对象方法、RadioButton 和 Button 控件



本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/11173

附加的文件 |
MQL5.zip (4389.02 KB)
从头开始开发智能交易系统(第 23 部分):新订单系统 (VI) 从头开始开发智能交易系统(第 23 部分):新订单系统 (VI)
我们将会令订单系统更加灵活。 在此,我们将研究代码的修改,令其更加灵活,而这也让我们能够更快地修改持仓破位价。
价格走势模型及其主要规定(第 1 部分):概率价格域演化方程与发生的可观测随机游走 价格走势模型及其主要规定(第 1 部分):概率价格域演化方程与发生的可观测随机游走
本文研究的是概率价格域演化方程,与即将到来的价格尖峰准则。 它还揭示了图表上价格数值的本质,以及这些数值随机游走的发生机制。
神经网络变得轻松(第二十部分):自动编码器 神经网络变得轻松(第二十部分):自动编码器
我们继续研究无监督学习算法。 一些读者可能对最近发表的与神经网络主题的相关性有疑问。 在这篇新文章中,我们回到了对神经网络的研究。
您应该知道的 MQL5 向导技术(第 02 部分):Kohonen 映射 您应该知道的 MQL5 向导技术(第 02 部分):Kohonen 映射
这些系列文章所提议的是,MQL5 向导应作为交易员的支柱。 为什么呢? 因为交易员不仅可以利用 MQL5 向导装配他的新想法来节省时间,还可以大大减少重复编码带来的错误;他最终可把精力投向自我交易哲学中的几个关键领域。