English Русский Español Deutsch 日本語 Português
preview
DoEasy. 控件(第三十部分):动画态滚动条控件

DoEasy. 控件(第三十部分):动画态滚动条控件

MetaTrader 5示例 | 2 五月 2023, 10:56
419 0
Artyom Trishkin
Artyom Trishkin

内容


概述

在上一篇文章中,我启动了滚动条(ScrollBar)辅助控件的开发。 在本文中,我将实现控件元素与鼠标的交互。 WinForms 滚动条对象的构成元素是滚动按钮和捕获区域。 对于滚动按钮,我们有单独的辅助对象类(箭头按钮),但我们会以简单按钮的形式制作捕获区域。 在此,我将实现一个基于按钮对象的单独类,用于创建捕获区域对象。 为了正确处理滚动条滑块的事件,对象应拥有自己的类型。 故此,它将派生自按钮对象 — 它将继承其属性,并成为具有唯一类型的独立对象。

对于大部分创建调整控件大小和处理鼠标与滚动条交互的功能,我会做一些准备工作。 我们来扩展鼠标状态及其事件的列表。 所有这些都将令我能够开发控件及其功能,而不会被后续文章中的日常工作分散注意力。


改进库类

在 \MQL5\Include\DoEasy\Defines.mqh 中,为滚动条对象状态添加默认颜色常量

#define CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BACK_COLOR   (C'0xF0,0xF0,0xF0')  // ScrollBar control background color
#define CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BORDER_COLOR (C'0xFF,0xFF,0xFF')  // ScrollBar control frame color
#define CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_COLOR   (C'0x60,0x60,0x60')  // ScrollBar control text color
#define CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_MOUSE_DOWN (C'0x00,0x00,0x00')// Color of ScrollBar control text when clicking on the control
#define CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_MOUSE_OVER (C'0x00,0x00,0x00')// Color of ScrollBar control text when hovering the mouse over the control

#define CLR_DEF_CONTROL_SCROLL_BAR_THUMB_COLOR        (C'0xCD,0xCD,0xCD')  // ScrollBar control capture area color
#define CLR_DEF_CONTROL_SCROLL_BAR_THUMB_BORDER_COLOR (C'0xCD,0xCD,0xCD')  // ScrollBar control capture area frame color
#define CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_DOWN   (C'0x60,0x60,0x60')  // Color of ScrollBar control capture area when clicking on the control
#define CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_OVER   (C'0xA6,0xA6,0xA6')  // Color of ScrollBar control capture area when hovering over the control
#define CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_COLOR   (C'0x60,0x60,0x60')  // ScrollBar control capture area text color
#define CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_DOWN (C'0xFF,0xFF,0xFF')// Color of ScrollBar control capture area text when clicking on the control
#define CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_OVER (C'0x00,0x00,0x00')// Color of ScrollBar control capture area text when hovering the mouse over the control

#define CLR_DEF_CONTROL_SCROLL_BAR_BUTT_COLOR         (C'0xF0,0xF0,0xF0')  // ScrollBar control button color
#define CLR_DEF_CONTROL_SCROLL_BAR_BUTT_BORDER_COLOR  (C'0xCD,0xCD,0xCD')  // ScrollBar control button frame color
#define CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_DOWN    (C'0x60,0x60,0x60')  // Color of ScrollBar control buttons when clicking on the control
#define CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_OVER    (C'0xDA,0xDA,0xDA')  // Color of ScrollBar control buttons when hovering the mouse over the control
#define CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_COLOR    (C'0x60,0x60,0x60')  // ScrollBar control button text color
#define CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_DOWN (C'0xFF,0xFF,0xFF')// Color of ScrollBar control button text when clicking on the control
#define CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_OVER (C'0x00,0x00,0x00')// Color of ScrollBar control button text when hovering the mouse over the control

#define DEF_CONTROL_SCROLL_BAR_WIDTH                  (11)                 // Default ScrollBar control width
#define DEF_CONTROL_CORNER_AREA                       (4)                  // Number of pixels defining the corner area to resize
#define DEF_CONTROL_LIST_MARGIN_X                     (1)                  // Gap between columns in ListBox controls
#define DEF_CONTROL_LIST_MARGIN_Y                     (0)                  // Gap between rows in ListBox controls

每个滚动区域都有一个宽度。 对于垂直滚动条,这是对象宽度,而在水平滚动条的情况下,这是其高度。 我们为此参数设置默认值 11。 滚动条有一个边框,当悬浮在滚动条上时,该边框将其与界面分开。 宽度值为 11 像素时,滚动条活动区域将为 9 像素(每侧边框一个像素,顶部、底部、左侧和右侧)。 由于箭头按钮和滑块要构建在滚动条上,因此 9 个像素是一个足够的奇数,箭头的三角形能均匀且美观地在上面绘制。 通常,在调整对象的大小时,在其上绘制围绕其中心轴勾勒的造型,我们应该始终尝试使用奇数个像素,以便绘图保持均匀整洁。 边角区域是窗体的一部分,其中光标被视为位于角落上。 例如,在调整对象大小时,如果光标位于四个边角之一上,我们可以一次性修改其大小的两个参数(高度和宽度)。

将新值添加到相对于造型的可能鼠标状态列表之中。 对象尺寸可以在八个方向上调整大小:

  1. 当光标位于对象的上边缘时,我们可以向上移动边缘来更改其高度,
  2. 当光标位于对象的底部边缘时,我们可以向下移动边缘来更改其高度,
  3. 当光标位于对象的左边缘时,我们可以向左移动边缘来更改其宽度,
  4. 当光标位于对象的右边缘时,我们可以向右移动边缘来更改其宽度,
  5. 当光标位于对象的左上角时,我们可以向上和向左移动来更改其高度和宽度,
  6. 当光标位于对象的右上角时,我们可以向上和向右移动来更改其高度和宽度,
  7. 当光标位于对象的左下角时,我们可以通过向下和向左移动来更改其高度和宽度,
  8. 当光标位于对象的右下角时,我们可以向下和向右移动来更改其高度和宽度,

具有可滚动内容的容器,在其右侧和底部将会有滚动条。 我们需要判定光标在哪个滚动条上 — 在右侧或底部,并把这些状态设置为鼠标状态:

//+------------------------------------------------------------------+
//| 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 to the right
   MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED,// The cursor is within the window scrolling area to the right, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_PRESSED,    // The cursor is within the window scrolling area to the right, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_WHEEL,      // The cursor is within the window scrolling area to the right, the mouse wheel is being scrolled
//--- Within the window scrolling area at the bottom
   MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED,// The cursor is within the window scrolling area at the bottom, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_PRESSED,   // The cursor is within the window scrolling area at the bottom, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_WHEEL,     // The cursor is within the window scrolling area at the bottom, the mouse wheel is being scrolled

//--- Within the window resizing area at the top
   MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_NOT_PRESSED,  // The cursor is within the window resizing area at the top, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_PRESSED,      // The cursor is within the window resizing area at the top, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_WHEEL,        // The cursor is within the window resizing area at the top, the mouse wheel is being scrolled
//--- Within the window resizing area at the bottom
   MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_NOT_PRESSED,// The cursor is within the window resizing area at the bottom, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_PRESSED,   // The cursor is within the window resizing area at the bottom, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_WHEEL,     // The cursor is within the window resizing area at the bottom, the mouse wheel is being scrolled
//--- Within the window resizing area to the left
   MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_NOT_PRESSED, // The cursor is within the window resizing area to the left, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_PRESSED,     // The cursor is within the window resizing area to the left, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_WHEEL,       // The cursor is within the window resizing area to the left, the mouse wheel is being scrolled
//--- Within the window resizing area to the right
   MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_NOT_PRESSED,// The cursor is within the window resizing area to the right, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_PRESSED,    // The cursor is within the window resizing area to the right, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_WHEEL,      // The cursor is within the window resizing area to the right, the mouse wheel is being scrolled
//--- Within the window resizing area to the top-left
   MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_NOT_PRESSED,   // The cursor is within the window resizing area at the top-left, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_PRESSED,       // The cursor is within the window resizing area at the top-left, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_WHEEL,         // The cursor is within the window resizing area at the top-left, the mouse wheel is being scrolled
//--- Within the window resizing area to the top-right
   MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_NOT_PRESSED,  // The cursor is within the window resizing area at the top-right, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_PRESSED,      // The cursor is within the window resizing area at the top-right, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_WHEEL,        // The cursor is within the window resizing area at the top-right, the mouse wheel is being scrolled
//--- Within the window resizing area at the bottom left
   MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_NOT_PRESSED,// The cursor is within the window resizing area at the bottom-left, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_PRESSED,    // The cursor is within the window resizing area at the bottom-left, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_WHEEL,      // The cursor is within the window resizing area at the bottom-left, the mouse wheel is being scrolled
//--- Within the window resizing area at the bottom-right
   MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_NOT_PRESSED,// The cursor is within the window resizing area at the bottom-right, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_PRESSED,   // The cursor is within the window resizing area at the bottom-right, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_WHEEL,     // The cursor is within the window resizing area at the bottom-right, the mouse wheel is being scrolled
   
//--- Within the control area
   MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_NOT_PRESSED,  // The cursor is within the control area, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_PRESSED,      // The cursor is within the control area, the mouse button (any) is clicked
   MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_WHEEL,        // The cursor is within the control 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 active 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 to the right
   MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED,  // The cursor is within the window scrolling area to the right, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_PRESSED,      // The cursor is within the window scrolling area to the right, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_WHEEL,        // The cursor is within the window scrolling area to the right, the mouse wheel is being scrolled
//--- Within the window scrolling area at the bottom
   MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED, // The cursor is within the window scrolling area at the bottom, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_PRESSED,     // The cursor is within the window scrolling area at the bottom, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_WHEEL,       // The cursor is within the window scrolling area at the bottom, the mouse wheel is being scrolled

//--- Within the window resizing area at the top
   MOUSE_EVENT_INSIDE_RESIZE_TOP_AREA_NOT_PRESSED,    // The cursor is within the window resizing area at the top, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_RESIZE_TOP_AREA_PRESSED,        // The cursor is within the window resizing area at the top, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_RESIZE_TOP_AREA_WHEEL,          // The cursor is within the window resizing area at the top, the mouse wheel is being scrolled
//--- Within the window resizing area at the bottom
   MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_AREA_NOT_PRESSED, // The cursor is within the window resizing area at the bottom, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_AREA_PRESSED,     // The cursor is within the window resizing area at the bottom, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_AREA_WHEEL,       // The cursor is within the window resizing area at the bottom, the mouse wheel is being scrolled
//--- Within the window resizing area to the left
   MOUSE_EVENT_INSIDE_RESIZE_LEFT_AREA_NOT_PRESSED,   // The cursor is within the window resizing area to the left, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_RESIZE_LEFT_AREA_PRESSED,       // The cursor is within the window resizing area to the left, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_RESIZE_LEFT_AREA_WHEEL,         // The cursor is within the window resizing area to the left, the mouse wheel is being scrolled
//--- Within the window resizing area to the right
   MOUSE_EVENT_INSIDE_RESIZE_RIGHT_AREA_NOT_PRESSED,  // The cursor is within the window resizing area to the right, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_RESIZE_RIGHT_AREA_PRESSED,      // The cursor is within the window resizing area to the right, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_RESIZE_RIGHT_AREA_WHEEL,        // The cursor is within the window resizing area to the right, the mouse wheel is being scrolled
//--- Within the window resizing area to the top-left
   MOUSE_EVENT_INSIDE_RESIZE_TOP_LEFT_AREA_NOT_PRESSED,// The cursor is within the window resizing area at the top-left, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_RESIZE_TOP_LEFT_AREA_PRESSED,   // The cursor is within the window resizing area at the top-left, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_RESIZE_TOP_LEFT_AREA_WHEEL,     // The cursor is within the window resizing area at the top-left, the mouse wheel is being scrolled
//--- Within the window resizing area to the top-right
   MOUSE_EVENT_INSIDE_RESIZE_TOP_RIGHT_AREA_NOT_PRESSED,// The cursor is within the window resizing area at the top-right, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_RESIZE_TOP_RIGHT_AREA_PRESSED,  // The cursor is within the window resizing area at the top-right, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_RESIZE_TOP_RIGHT_AREA_WHEEL,    // The cursor is within the window resizing area at the top-right, the mouse wheel is being scrolled
//--- Within the window resizing area at the bottom left
   MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_LEFT_AREA_NOT_PRESSED,// The cursor is within the window resizing area at the bottom-left, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_LEFT_AREA_PRESSED,// The cursor is within the window resizing area at the bottom-left, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_LEFT_AREA_WHEEL,  // The cursor is within the window resizing area at the bottom-left, the mouse wheel is being scrolled
//--- Within the window resizing area at the bottom-right
   MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_NOT_PRESSED,// The cursor is within the window resizing area at the bottom-right, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_PRESSED,// The cursor is within the window resizing area at the bottom-right, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_WHEEL, // The cursor is within the window resizing area at the bottom-right, the mouse wheel is being scrolled
//--- Within the control area
   MOUSE_EVENT_INSIDE_CONTROL_AREA_NOT_PRESSED,       // The cursor is within the control area, the mouse buttons are not clicked
   MOUSE_EVENT_INSIDE_CONTROL_AREA_PRESSED,           // The cursor is within the control area, the mouse button (any) is clicked
   MOUSE_EVENT_INSIDE_CONTROL_AREA_WHEEL,             // The cursor is within the control area, the mouse wheel is being scrolled
  };
#define MOUSE_EVENT_NEXT_CODE  (MOUSE_EVENT_INSIDE_CONTROL_AREA_WHEEL+1)   // The code of the next event after the last mouse event code
//+------------------------------------------------------------------+

新的对象类型添加到图形元素类型列表之中:

//+--------------------------------------------+
//| The list of graphical element types        |
//+--------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_STANDARD,                       // Standard graphical object
   GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED,              // Extended standard graphical object
   GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                     // Shadow object
   GRAPH_ELEMENT_TYPE_ELEMENT,                        // Element
   GRAPH_ELEMENT_TYPE_FORM,                           // Form
   GRAPH_ELEMENT_TYPE_WINDOW,                         // Window
   //--- WinForms
   GRAPH_ELEMENT_TYPE_WF_UNDERLAY,                    // Panel object underlay
   GRAPH_ELEMENT_TYPE_WF_BASE,                        // Windows Forms Base
   //--- 'Container' object types are to be set below
   GRAPH_ELEMENT_TYPE_WF_CONTAINER,                   // Windows Forms container base object
   GRAPH_ELEMENT_TYPE_WF_PANEL,                       // Windows Forms Panel
   GRAPH_ELEMENT_TYPE_WF_GROUPBOX,                    // Windows Forms GroupBox
   GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,                 // Windows Forms TabControl
   GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,             // Windows Forms SplitContainer
   //--- 'Standard control' object types are to be set below
   GRAPH_ELEMENT_TYPE_WF_COMMON_BASE,                 // Windows Forms base standard control
   GRAPH_ELEMENT_TYPE_WF_LABEL,                       // Windows Forms Label
   GRAPH_ELEMENT_TYPE_WF_BUTTON,                      // Windows Forms Button
   GRAPH_ELEMENT_TYPE_WF_CHECKBOX,                    // Windows Forms CheckBox
   GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON,                 // Windows Forms RadioButton
   GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX,           // Base list object of Windows Forms elements
   GRAPH_ELEMENT_TYPE_WF_LIST_BOX,                    // Windows Forms ListBox
   GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX,            // Windows Forms CheckedListBox
   GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX,             // Windows Forms ButtonListBox
   GRAPH_ELEMENT_TYPE_WF_TOOLTIP,                     // Windows Forms ToolTip
   GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,                // Windows Forms ProgressBar
   //--- Auxiliary elements of WinForms objects
   GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM,               // Windows Forms ListBoxItem
   GRAPH_ELEMENT_TYPE_WF_TAB_HEADER,                  // Windows Forms TabHeader
   GRAPH_ELEMENT_TYPE_WF_TAB_FIELD,                   // Windows Forms TabField
   GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER_PANEL,       // Windows Forms SplitContainerPanel
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON,                // Windows Forms ArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,             // Windows Forms UpArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,           // Windows Forms DownArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,           // Windows Forms LeftArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,          // Windows Forms RightArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX,        // Windows Forms UpDownArrowButtonsBox
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX,        // Windows Forms LeftRightArrowButtonsBox
   GRAPH_ELEMENT_TYPE_WF_SPLITTER,                    // Windows Forms Splitter
   GRAPH_ELEMENT_TYPE_WF_HINT_BASE,                   // Windows Forms HintBase
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT,              // Windows Forms HintMoveLeft
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT,             // Windows Forms HintMoveRight
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP,                // Windows Forms HintMoveUp
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN,              // Windows Forms HintMoveDown
   GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,            // Windows Forms BarProgressBar
   GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,                   // Glare object
   GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB,            // Windows Forms ScrollBarThumb
   GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR,                  // Windows Forms ScrollBar
   GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL,       // Windows Forms ScrollBarHorisontal
   GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL,         // Windows Forms ScrollBarVertical
  };
//+------------------------------------------------------------------+

这将是新的“捕获区域”助手(滚动条滑块)控件。

在图形元素的整数属性枚举中添加两个新属性,并将其总数从 138 增加到 140

//+------------------------------------------------------------------+
//| 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_ZORDER,                          // Priority of a graphical object for receiving the event of clicking on a chart
   CANV_ELEMENT_PROP_ENABLED,                         // Element availability flag
   CANV_ELEMENT_PROP_RESIZABLE,                       // Resizable element flag
   CANV_ELEMENT_PROP_FORE_COLOR,                      // Default text color for all control objects
   CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,              // Default text color opacity for all control objects

   //---...
   //---...

   CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,              // Current ProgressBar value from Min to Max
   CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED, // Progress bar animation speed in case of Marquee style
   CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,               // Size of the arrow drawn on the button
  };
#define CANV_ELEMENT_PROP_INTEGER_TOTAL (140)         // Total number of integer properties
#define CANV_ELEMENT_PROP_INTEGER_SKIP  (0)           // Number of integer properties not used in sorting
//+------------------------------------------------------------------+

每个图形元素都有一个标志,指示可由鼠标调整其大小。 在元素上绘制的箭头(例如,带有箭头的按钮)将依据此参数指定的相对大小。 例如,将从中心点绘制大小为 1 的箭头,顶点缩进为 1 像素。 将从中心点绘制大小为 2 的箭头,缩进为 2 像素,依此类推。

例如,大小为 1 的向上箭头:

⊡⊠⊡
⊠⊠⊠

大小为 2 的向上箭头:

⊡⊡⊠⊡⊡
⊡⊠⊠⊠⊡
⊠⊠⊠⊠⊠

大小为 3 的向上箭头:

⊡⊡⊡⊠⊡⊡⊡
⊡⊡⊠⊠⊠⊡⊡
⊡⊠⊠⊠⊠⊠⊡
⊠⊠⊠⊠⊠⊠⊠

如果我们以三角形底部中心的一个像素作为中心,并将像素数设置为等于形状每条边的相对大小,我们将得到三角形的三个顶点,沿着它们即可构建图形。 因此,三角形的大小是自三角形底部的中心向上、向左和向右指示每个顶点坐标的像素数。

向下、向左和向右箭头均以类似的方式构建。

在 \MQL5\Include\DoEasy\Data.mqh 里,添加新的消息索引:

   MSG_GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,            // ProgressBar control
   MSG_GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR,              // ScrollBar control
   MSG_GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB,        // ScrollBar control capture area
   MSG_GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL,     // ScrollBarVertical control
   MSG_GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL,   // ScrollBarHorisontal control

...

   MSG_CANV_ELEMENT_PROP_DISPLAY_DURATION,            // Control display duration
   MSG_CANV_ELEMENT_PROP_ENABLED,                     // Element availability flag
   MSG_CANV_ELEMENT_PROP_RESIZABLE,                   // Control size changeability flag
   MSG_CANV_ELEMENT_PROP_FORE_COLOR,                  // Default text color for all control objects
   MSG_CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,          // Default text color opacity for all control objects

...

   MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,          // Current ProgressBar value from Min to Max
   MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,// Progress bar animation speed in case of Marquee style
   MSG_CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,           // Size of the arrow drawn on the button
//--- Real properties of graphical elements

//--- String properties of graphical elements

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

   {"Элемент управления \"ProgressBar\"","Control element \"ProgressBar\""},
   {"Элемент управления \"ScrollBar\"","Control element \"ScrollBar\""},
   {"Область захвата элемента управления \"ScrollBar\"","The grip area of the \"ScrollBar\" control"},
   {"Элемент управления \"ScrollBarVertical\"","Control element \"ScrollBarVertical\""},
   {"Элемент управления \"ScrollBarHorisontal\"","Control element \"ScrollBarHorisontal\""},

...

   {"Продолжительность процесса отображения элемента управления","Duration of the process of displaying the control"},
   {"Флаг доступности элемента","Element Availability flag"},
   {"Флаг изменяемости размеров элемента","Element Resizable flag"},
   {"Цвет текста по умолчанию для всех объектов элемента управления","Default text color for all objects in the control"},
   {"Непрозрачность цвета текста по умолчанию для всех объектов элемента управления","Default text color opacity for all objects in the control"},

...

   {"Текущее начение элемента ProgressBar в диапазоне от Min до Max","Current value of the ProgressBar in the range from Min to Max"},
   {"Скорость анимации полосы прогресса при стиле Marquee","Marquee style progress bar animation speed"},
   {"Размер стрелки, рисуемой на кнопке","Size of arrow drawn on the button"},
   
//--- String properties of graphical elements


为了显示新的对象类型说明,在 \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh 中,即在其 TypeElementDescription() 方法中,添加一些代码,返回给该方法传递的对象类型说明

//+------------------------------------------------------------------+
//| Return the description of the graphical element type             |
//+------------------------------------------------------------------+
string CGBaseObj::TypeElementDescription(const ENUM_GRAPH_ELEMENT_TYPE type)
  {
   return
     (
      type==GRAPH_ELEMENT_TYPE_STANDARD                  ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD)                 :
      type==GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED         ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED)        :
      type==GRAPH_ELEMENT_TYPE_ELEMENT                   ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_ELEMENT)                  :
      type==GRAPH_ELEMENT_TYPE_SHADOW_OBJ                ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ)               :
      type==GRAPH_ELEMENT_TYPE_FORM                      ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_FORM)                     :
      type==GRAPH_ELEMENT_TYPE_WINDOW                    ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WINDOW)                   :
      //--- WinForms
      type==GRAPH_ELEMENT_TYPE_WF_UNDERLAY               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_UNDERLAY)              :
      type==GRAPH_ELEMENT_TYPE_WF_BASE                   ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BASE)                  :
      //--- Containers
      type==GRAPH_ELEMENT_TYPE_WF_CONTAINER              ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CONTAINER)             :
      type==GRAPH_ELEMENT_TYPE_WF_GROUPBOX               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_GROUPBOX)              :
      type==GRAPH_ELEMENT_TYPE_WF_PANEL                  ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_PANEL)                 :
      type==GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL            ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL)           :
      type==GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER        ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER)       :
      //--- Standard controls
      type==GRAPH_ELEMENT_TYPE_WF_COMMON_BASE            ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_COMMON_BASE)           :
      type==GRAPH_ELEMENT_TYPE_WF_LABEL                  ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LABEL)                 :
      type==GRAPH_ELEMENT_TYPE_WF_CHECKBOX               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CHECKBOX)              :
      type==GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON            ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON)           :
      type==GRAPH_ELEMENT_TYPE_WF_BUTTON                 ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BUTTON)                :
      type==GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX      ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX)     :
      type==GRAPH_ELEMENT_TYPE_WF_LIST_BOX               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LIST_BOX)              :
      type==GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM          ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM)         :
      type==GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX       ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX)      :
      type==GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX        ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX)       :
      type==GRAPH_ELEMENT_TYPE_WF_TOOLTIP                ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TOOLTIP)               :
      type==GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR           ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR)          :
      //--- Auxiliary control objects
      type==GRAPH_ELEMENT_TYPE_WF_TAB_HEADER             ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TAB_HEADER)            :
      type==GRAPH_ELEMENT_TYPE_WF_TAB_FIELD              ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TAB_FIELD)             :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON           ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON)          :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP        ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP)       :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN      ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN)     :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT      ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT)     :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT     ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT)    :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX   ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX)  :
      type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX   ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX)  :
      type==GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER_PANEL  ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER_PANEL) :
      type==GRAPH_ELEMENT_TYPE_WF_SPLITTER               ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SPLITTER)              :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_BASE              ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_BASE)             :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT         ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT)        :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT        ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT)       :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP           ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP)          :
      type==GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN         ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN)        :
      type==GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR       ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR)      :
      type==GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ              ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ)             :
      type==GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR             ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR)            :
      type==GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL    ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL)   :
      type==GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL  ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL) :
      type==GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB       ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB)      :
      "Unknown"
     );
  }  
//+------------------------------------------------------------------+

每次将新属性添加到图形元素的属性枚举中时,都应将其添加到对象结构之中。 图形对象的结构可把图形元素的属性保存到文件之中,并从文件中读取它们。 若重新启动,则这对于恢复对象是必需的 — 以便它们能复原到退出前相同的状态。 到目前为止,由于图形对象属性组合的不断变化,我们尚未实现这样的功能。 但我已经规划好在未来创建这样的结构。

在 \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh 中,往对象结构添加新的整数型字段:

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

      //---...
      //---...

      long           zorder;                                   // Priority of a graphical object for receiving the event of clicking on a chart
      bool           enabled;                                  // Element availability flag
      bool           resizable;                                // Size changeability flag
      color          fore_color;                               // Default text color for all control objects
      uchar          fore_color_opacity;                       // Default text color opacity for all control objects

      //---...
      //---...

      int            progress_bar_value;                       // Current ProgressBar value from Min to Max
      int            progress_bar_marquee_speed;               // Progress bar animation speed in case of Marquee style
      uchar          button_arrow_size;                        // Size of the arrow drawn on the button
      //---
      ulong          tooltip_initial_delay;                    // Tooltip display delay
      ulong          tooltip_auto_pop_delay;                   // Tooltip display duration
      ulong          tooltip_reshow_delay;                     // One element new tooltip display delay
      bool           tooltip_show_always;                      // Display a tooltip in inactive window
      int            tooltip_icon;                             // Icon displayed in a tooltip
      bool           tooltip_is_balloon;                       // Tooltip in the form of a "cloud"
      bool           tooltip_use_fading;                       // Fade when showing/hiding a tooltip
      //--- 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
      uchar          descript[256];                            // Graphical element description
      uchar          tooltip_title[256];                       // Element tooltip title
      uchar          tooltip_text[256];                        // Element tooltip text
     };
   SData             m_struct_obj;                             // Object structure
   uchar             m_uchar_array[];                          // uchar array of the object structure

在类的公开部分中,声明新方法,返回相对于图形元素的光标位置标志:

//--- Return the cursor position relative to the (1) entire element, (2) visible part, (3) active area and (4) element control area
   bool              CursorInsideElement(const int x,const int y);
   bool              CursorInsideVisibleArea(const int x,const int y);
   bool              CursorInsideActiveArea(const int x,const int y);
   bool              CursorInsideControlArea(const int x,const int y);
//--- Return the cursor position relative to the (1) right, (2) bottom element scroll area
   bool              CursorInsideScrollRightArea(const int x,const int y);
   bool              CursorInsideScrollBottomArea(const int x,const int y);
//--- Return the cursor position relative to the (1) upper, (2) lower, (3) left and (4) right element resize area
   bool              CursorInsideResizeTopArea(const int x,const int y);
   bool              CursorInsideResizeBottomArea(const int x,const int y);
   bool              CursorInsideResizeLeftArea(const int x,const int y);
   bool              CursorInsideResizeRightArea(const int x,const int y);
//--- Return the cursor position relative to the (1) top-left, (2) top-right,
//--- (3) bottom-left, (4) bottom-right element resize area corner
   bool              CursorInsideResizeTopLeftArea(const int x,const int y);
   bool              CursorInsideResizeTopRightArea(const int x,const int y);
   bool              CursorInsideResizeBottomLeftArea(const int x,const int y);
   bool              CursorInsideResizeBottomRightArea(const int x,const int y);

//--- Create the element
   bool              Create(const long chart_id,

在简化的对象属性访问方法模块中,设置返回新区域和图形元素区域坐标的方法,以及返回大小可变性标志的方法

//--- Set (1) object movability, (2) activity, (3) interaction,
//--- (4) element ID, (5) element index in the list, the flag of (6) availability, (7) changeable size, (8) shadow
   void              SetMovable(const bool flag)               { this.SetProperty(CANV_ELEMENT_PROP_MOVABLE,flag);                     }
   void              SetActive(const bool flag)                { this.SetProperty(CANV_ELEMENT_PROP_ACTIVE,flag);                      }
   void              SetInteraction(const bool flag)           { this.SetProperty(CANV_ELEMENT_PROP_INTERACTION,flag);                 }
   void              SetID(const int id)                       { this.SetProperty(CANV_ELEMENT_PROP_ID,id);                            }
   void              SetNumber(const int number)               { this.SetProperty(CANV_ELEMENT_PROP_NUM,number);                       }
   void              SetEnabled(const bool flag)               { this.SetProperty(CANV_ELEMENT_PROP_ENABLED,flag);                     }
   void              SetResizable(const bool flag)             { this.SetProperty(CANV_ELEMENT_PROP_RESIZABLE,flag);                   }
   void              SetShadow(const bool flag)                { this.m_shadow=flag;                                                   }
   
//--- Set the (1) X, (2) Y coordinates, (3) width and (4) height of the element control area
   void              SetControlAreaX(const int value)          { this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_X,value);             }
   void              SetControlAreaY(const int value)          { this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_Y,value);             }
   void              SetControlAreaWidth(const int value)      { this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_WIDTH,value);         }
   void              SetControlAreaHeight(const int value)     { this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_HEIGHT,value);        }
   
//--- Return the shift (1) of the left, (2) right, (3) top and (4) bottom edge of the element active area
   int               ActiveAreaLeftShift(void)           const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT);       }
   int               ActiveAreaRightShift(void)          const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT);      }
   int               ActiveAreaTopShift(void)            const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP);        }
   int               ActiveAreaBottomShift(void)         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM);     }
//--- Return the coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the element active area
   int               ActiveAreaLeft(void)                const { return int(this.CoordX()+this.ActiveAreaLeftShift());                 }
   int               ActiveAreaRight(void)               const { return int(this.RightEdge()-this.ActiveAreaRightShift());             }
   int               ActiveAreaTop(void)                 const { return int(this.CoordY()+this.ActiveAreaTopShift());                  }
   int               ActiveAreaBottom(void)              const { return int(this.BottomEdge()-this.ActiveAreaBottomShift());           }

//--- Return the shift of the (1) X, (2) Y coordinates, (3) width, (4) height of the element control area
   int               ControlAreaXShift(void)             const { return (int)this.GetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_X);       }
   int               ControlAreaYShift(void)             const { return (int)this.GetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_Y);       }
   int               ControlAreaWidth(void)              const { return (int)this.GetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_WIDTH);   }
   int               ControlAreaHeight(void)             const { return (int)this.GetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_HEIGHT);  }
//--- Return the coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the element control area
   int               ControlAreaLeft(void)               const { return this.CoordX()+this.ControlAreaXShift();                        }
   int               ControlAreaRight(void)              const { return this.ControlAreaLeft()+this.ControlAreaWidth();                }
   int               ControlAreaTop(void)                const { return this.CoordY()+this.ControlAreaYShift();                        }
   int               ControlAreaBottom(void)             const { return this.ControlAreaTop()+this.ControlAreaHeight();                }
//--- Return the relative coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the element control area
   int               ControlAreaLeftRelative(void)       const { return this.ControlAreaLeft()-this.CoordX();                          }
   int               ControlAreaRightRelative(void)      const { return this.ControlAreaRight()-this.CoordX();                         }
   int               ControlAreaTopRelative(void)        const { return this.ControlAreaTop()-this.CoordY();                           }
   int               ControlAreaBottomRelative(void)     const { return this.ControlAreaBottom()-this.CoordY();                        }
   
//--- Return the shift of the (1) X, (2) Y coordinates, (3) width, (4) height of the element scroll area to the right
   int               ScrollAreaRightXShift(void)         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_RIGHT);     }
   int               ScrollAreaRightYShift(void)         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_RIGHT);     }
   int               ScrollAreaRightWidth(void)          const { return (int)this.GetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_RIGHT); }
   int               ScrollAreaRightHeight(void)         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_RIGHT);}
//--- Return the coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the element control area
   int               ScrollAreaRightLeft(void)           const { return this.CoordX()+this.ScrollAreaRightXShift();                       }
   int               ScrollAreaRightRight(void)          const { return this.ScrollAreaRightLeft()+this.ScrollAreaRightWidth();           }
   int               ScrollAreaRightTop(void)            const { return this.CoordY()+this.ScrollAreaRightYShift();                       }
   int               ScrollAreaRightBottom(void)         const { return this.ScrollAreaRightTop()+this.ScrollAreaRightHeight();           }
//--- Return the relative coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the element control area
   int               ScrollAreaRightLeftRelative(void)   const { return this.ScrollAreaRightLeft()-this.CoordX();                         }
   int               ScrollAreaRightRightRelative(void)  const { return this.ScrollAreaRightRight()-this.CoordX();                        }
   int               ScrollAreaRightTopRelative(void)    const { return this.ScrollAreaRightTop()-this.CoordY();                          }
   int               ScrollAreaRightBottomRelative(void) const { return this.ScrollAreaRightBottom()-this.CoordY();                       }
   
//--- Return the shift of the (1) X, (2) Y coordinates, (3) width, (4) height of the element scroll area at the bottom
   int               ScrollAreaBottomXShift(void)        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_BOTTOM);    }
   int               ScrollAreaBottomYShift(void)        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_BOTTOM);    }
   int               ScrollAreaBottomWidth(void)         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_BOTTOM);}
   int               ScrollAreaBottomHeight(void)        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_BOTTOM);}
//--- Return the coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the element control area
   int               ScrollAreaBottomLeft(void)          const { return this.CoordX()+this.ScrollAreaBottomXShift();                      }
   int               ScrollAreaBottomRight(void)         const { return this.ScrollAreaBottomLeft()+this.ScrollAreaBottomWidth();         }
   int               ScrollAreaBottomTop(void)           const { return this.CoordY()+this.ScrollAreaBottomYShift();                      }
   int               ScrollAreaBottomBottom(void)        const { return this.ScrollAreaBottomTop()+this.ScrollAreaBottomHeight();         }
//--- Return the relative coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the element control area
   int               ScrollAreaBottomLeftRelative(void)  const { return this.ScrollAreaBottomLeft()-this.CoordX();                        }
   int               ScrollAreaBottomRightRelative(void) const { return this.ScrollAreaBottomRight()-this.CoordX();                       }
   int               ScrollAreaBottomTopRelative(void)   const { return this.ScrollAreaBottomTop()-this.CoordY();                         }
   int               ScrollAreaBottomBottomRelative(void)const { return this.ScrollAreaBottomBottom()-this.CoordY();                      }

//--- Return the width of the (1) left, (2) right, (3) upper and (4) lower element edge area
   int               BorderResizeAreaLeft(void)          const { return (int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_LEFT_AREA_WIDTH);     }
   int               BorderResizeAreaRight(void)         const { return (int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH);    }
   int               BorderResizeAreaTop(void)           const { return (int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH);      }
   int               BorderResizeAreaBottom(void)        const { return (int)this.GetProperty(CANV_ELEMENT_PROP_BORDER_BOTTOM_AREA_WIDTH);   }

添加返回元素大小可变性标志的方法

//--- Return the (1) element movability, (2) activity, (3) interaction, (4) availability and (5) size changeability flag
   bool              Movable(void)                       const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_MOVABLE);             }
   bool              Active(void)                        const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_ACTIVE);              }
   bool              Interaction(void)                   const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_INTERACTION);         }
   bool              Enabled(void)                       const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_ENABLED);             }
   bool              Resizable(void)                     const { return (bool)this.GetProperty(CANV_ELEMENT_PROP_RESIZABLE);           }
//--- Return (1) the object name, (2) the graphical resource name, (3) the chart ID and (4) the chart subwindow index

更改箭头绘制方法的声明

//+------------------------------------------------------------------+
//| Methods for drawing predefined standard images                   |
//+------------------------------------------------------------------+
//--- Draw the Info icon
   void              DrawIconInfo(const int coord_x,const int coord_y,const uchar opacity);
//--- Draw the Warning icon
   void              DrawIconWarning(const int coord_x,const int coord_y,const uchar opacity);
//--- Draw the Error icon
   void              DrawIconError(const int coord_x,const int coord_y,const uchar opacity);
//--- Draw the left arrow
   void              DrawArrowLeft(const int base_x,const int base_y,const int size,const color clr,const uchar opacity);
//--- Draw the right arrow
   void              DrawArrowRight(const int base_x,const int base_y,const int size,const color clr,const uchar opacity);
//--- Draw the up arrow
   void              DrawArrowUp(const int base_x,const int base_y,const int size,const color clr,const uchar opacity);
//--- Draw the down arrow
   void              DrawArrowDown(const int base_x,const int base_y,const int size,const color clr,const uchar opacity);
  };
//+------------------------------------------------------------------+

现在,这些方法将接收中心点坐标相对箭头大小

在初始化对象属性的方法中,将顶部、底部、左侧和右侧对象边缘区域的宽度的默认值设置为两个像素,据此定义鼠标光标是否位于这些区域中。 默认情况下,禁用使用鼠标光标调整对象大小的功能,而绘制箭头的大小为 3

//+--------------------------------------------+
//| Initialize the properties                  |
//+--------------------------------------------+
void CGCnvElement::Initialize(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                              const int element_id,const int element_num,
                              const int x,const int y,const int w,const int h,
                              const string descript,const bool movable,const bool activity)
  {
   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_RESIZABLE,false);                       // Element changeable size 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_VISIBLE_AREA_X,0);                      // Visibility scope X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,0);                      // Visibility scope Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,w);                  // Visibility scope width
   this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,h);                 // Visibility scope height
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAYED,true);                        // Non-hidden control display flag
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE,CANV_ELEMENT_DISPLAY_STATE_NORMAL);// Control display state
   this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION,DEF_CONTROL_PROCESS_DURATION);  // Control display duration
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_X,0);                      // Control area X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_Y,0);                      // Control area Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_WIDTH,0);                  // Control area width
   this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_HEIGHT,0);                 // Control area height
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_RIGHT,0);                 // Right scroll area X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_RIGHT,0);                 // Right scroll area Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_RIGHT,0);             // Right scroll area width
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_RIGHT,0);            // Right scroll area height
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_BOTTOM,0);                // Bottom scroll area X coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_BOTTOM,0);                // Bottom scroll area Y coordinate
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_BOTTOM,0);            // Bottom scroll area width
   this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_BOTTOM,0);           // Bottom scroll area height
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_LEFT_AREA_WIDTH,2);              // Left edge area width 
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_BOTTOM_AREA_WIDTH,2);            // Bottom edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH,2);             // Right edge area width
   this.SetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH,2);               // Top edge area width
   //---
   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_PROGRESS_BAR_VALUE,50);                 // Current ProgressBar value from Min to Max
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,10);    // Progress bar animation speed in case of Marquee style
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,3);                   // Size of the arrow drawn on the button
  }
//+------------------------------------------------------------------+

在创建对象结构的方法中,把新的对象整数型属性设置到结构字段

//+--------------------------------------------+
//| 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.zorder=this.GetProperty(CANV_ELEMENT_PROP_ZORDER);                            // Priority of a graphical object for receiving the on-chart mouse click event
   this.m_struct_obj.enabled=(bool)this.GetProperty(CANV_ELEMENT_PROP_ENABLED);                    // Element availability flag
   this.m_struct_obj.resizable=(bool)this.GetProperty(CANV_ELEMENT_PROP_RESIZABLE);                // Element size changeability flag
   this.m_struct_obj.fore_color=(color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR);             // Default text color for all control objects
   this.m_struct_obj.fore_color_opacity=(uchar)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY); // Opacity of the default text color for all control objects
   
   //---...
   //---...

   this.m_struct_obj.progress_bar_value=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE);     // Current ProgressBar value from Min to Max
   this.m_struct_obj.progress_bar_marquee_speed=(int)this.GetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED);// Progress bar animation speed in case of Marquee style
   this.m_struct_obj.button_arrow_size=(uchar)this.GetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE);     // Size of the arrow drawn on the 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
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_DESCRIPTION),this.m_struct_obj.descript);// Graphical element description
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_TITLE),this.m_struct_obj.tooltip_title);// Tooltip title for the element
   ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT),this.m_struct_obj.tooltip_text);  // Tooltip text for the element
   //--- 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_ZORDER,this.m_struct_obj.zorder);                            // Priority of a graphical object for receiving the event of clicking on a chart
   this.SetProperty(CANV_ELEMENT_PROP_ENABLED,this.m_struct_obj.enabled);                          // Element availability flag
   this.SetProperty(CANV_ELEMENT_PROP_RESIZABLE,this.m_struct_obj.resizable);                      // Element size changeability flag
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,this.m_struct_obj.fore_color);                    // Default text color for all control objects
   this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,this.m_struct_obj.fore_color_opacity);    // Opacity of the default text color for all control objects
   
   //---...
   //---...

   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_VALUE,this.m_struct_obj.progress_bar_value); // Current ProgressBar value from Min to Max
   this.SetProperty(CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED,this.m_struct_obj.progress_bar_marquee_speed);  // Progress bar animation speed in case of Marquee style
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,this.m_struct_obj.button_arrow_size);   // Size of the arrow drawn on the 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
   this.SetProperty(CANV_ELEMENT_PROP_DESCRIPTION,::CharArrayToString(this.m_struct_obj.descript));// Graphical element description
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TITLE,::CharArrayToString(this.m_struct_obj.tooltip_title));// Tooltip title for the element
   this.SetProperty(CANV_ELEMENT_PROP_TOOLTIP_TEXT,::CharArrayToString(this.m_struct_obj.tooltip_text));  // Tooltip text for the element
  }
//+------------------------------------------------------------------+

实现的方法返回相对于滚动区域的光标位置,以及调整元素大小的标志

//+------------------------------------------------------------------+
//|Return the cursor position relative to the element control area   |
//+------------------------------------------------------------------+
bool CGCnvElement::CursorInsideControlArea(const int x,const int y)
  {
   return(x>=this.ControlAreaLeft() && x<=this.ControlAreaRight() && y>=this.ControlAreaTop() && y<=this.ControlAreaBottom());
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element right scrolling area               |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideScrollRightArea(const int x,const int y)
  {
   return(x>=this.ScrollAreaRightLeft() && x<=this.ScrollAreaRightRight() && y>=this.ScrollAreaRightTop() && y<=this.ScrollAreaRightBottom());
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element bottom scrolling area              |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideScrollBottomArea(const int x,const int y)
  {
   return(x>=this.ScrollAreaBottomLeft() && x<=this.ScrollAreaBottomRight() && y>=this.ScrollAreaBottomTop() && y<=this.ScrollAreaBottomBottom());
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element resize upper area                  |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideResizeTopArea(const int x,const int y)
  {
   return(x>=this.CoordX()+DEF_CONTROL_CORNER_AREA && x<=this.RightEdge()-DEF_CONTROL_CORNER_AREA && y>=this.CoordY() && y<=this.CoordY()+this.BorderResizeAreaTop());
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element resize lower area                  |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideResizeBottomArea(const int x,const int y)
  {
   return(x>=this.CoordX()+DEF_CONTROL_CORNER_AREA && x<=this.RightEdge()-DEF_CONTROL_CORNER_AREA && y>=this.BottomEdge()-this.BorderResizeAreaBottom() && y<=this.BottomEdge());
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element resize lower area                  |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideResizeLeftArea(const int x,const int y)
  {
   return(x>=this.CoordX() && x<=this.CoordX()+this.BorderResizeAreaLeft() && y>=this.CoordY()+DEF_CONTROL_CORNER_AREA && y<=this.BottomEdge()-DEF_CONTROL_CORNER_AREA);
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element resize right area                  |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideResizeRightArea(const int x,const int y)
  {
   return(x>=this.RightEdge()-this.BorderResizeAreaRight() && x<=this.RightEdge() && y>=this.CoordY()+DEF_CONTROL_CORNER_AREA && y<=this.BottomEdge()-DEF_CONTROL_CORNER_AREA);
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element resize area upper left corner      |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideResizeTopLeftArea(const int x,const int y)
  {
   return
     (
      (x>=this.CoordX() && x<this.CoordX()+DEF_CONTROL_CORNER_AREA && y>=this.CoordY() && y<=this.CoordY()+this.BorderResizeAreaTop()) ||
      (x>=this.CoordX() && x<=this.BorderResizeAreaLeft() && y>=this.CoordY() && y<=this.CoordY()+DEF_CONTROL_CORNER_AREA)
     );
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element resize area upper right corner     |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideResizeTopRightArea(const int x,const int y)
  {
   return
     (
      (x>this.RightEdge()-DEF_CONTROL_CORNER_AREA && x<=this.RightEdge() && y>=this.CoordY() && y<=this.CoordY()+this.BorderResizeAreaTop()) ||
      (x>=this.RightEdge()-this.BorderResizeAreaRight() && x<=this.RightEdge() && y>=this.CoordY() && y<=this.CoordY()+DEF_CONTROL_CORNER_AREA)
     );
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element resize area lower left corner      |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideResizeBottomLeftArea(const int x,const int y)
  {
   return
     (
      (x>=this.CoordX() && x<this.CoordX()+DEF_CONTROL_CORNER_AREA && y>=this.BottomEdge()-this.BorderResizeAreaBottom() && y<=this.BottomEdge()) ||
      (x>=this.CoordX() && x<=this.CoordX()+this.BorderResizeAreaLeft() && y>this.BottomEdge()-DEF_CONTROL_CORNER_AREA && y<=this.BottomEdge())
     );
  }
//+--------------------------------------------+
//| Return the cursor position relative to the |
//| element resize area lower right corner     |
//+--------------------------------------------+
bool CGCnvElement::CursorInsideResizeBottomRightArea(const int x,const int y)
  {
   return
     (
      (x>this.RightEdge()-DEF_CONTROL_CORNER_AREA && x<=this.RightEdge() && y>=this.BottomEdge()-this.BorderResizeAreaBottom() && y<=this.BottomEdge()) ||
      (x>=this.RightEdge()-this.BorderResizeAreaRight() && x<=this.RightEdge() && y>this.BottomEdge()-DEF_CONTROL_CORNER_AREA && y<=this.BottomEdge())
     );
  }
//+--------------------------------------------+
//| Update the coordinate elements             |
//+--------------------------------------------+

根据光标所在的坐标,这些方法返回光标在其值所围廓区域内的标志。

绘制箭头的方法现在将根据起始坐标(三角形底心),和指定的箭头大小绘制三角形:

//+--------------------------------------------+
//| Draw the left arrow                        |
//+--------------------------------------------+
void CGCnvElement::DrawArrowLeft(const int base_x,const int base_y,const int size,const color clr,const uchar opacity)
  {
   int x=base_x;
   int y=base_y;
   int s=(size<1 ? 1 : size);
   this.DrawTriangleFill(x-s,y,x,y-s,x,y+s,clr,opacity);
   this.DrawTriangleWu(  x-s,y,x,y-s,x,y+s,clr,opacity);
  }
//+--------------------------------------------+
//| Draw the right arrow                       |
//+--------------------------------------------+
void CGCnvElement::DrawArrowRight(const int base_x,const int base_y,const int size,const color clr,const uchar opacity)
  {
   int x=base_x;
   int y=base_y;
   int s=(size<1 ? 1 : size);
   this.DrawTriangleFill(x+s,y,x,y+s,x,y-s,clr,opacity);
   this.DrawTriangleWu(  x+s,y,x,y+s,x,y-s,clr,opacity);
  }
//+--------------------------------------------+
//| Draw the up arrow                          |
//+--------------------------------------------+
void CGCnvElement::DrawArrowUp(const int base_x,const int base_y,const int size,const color clr,const uchar opacity)
  {
   int x=base_x;
   int y=base_y;
   int s=(size<1 ? 1 : size);
   this.DrawTriangleFill(x,y-s,x+s,y,x-s,y,clr,opacity);
   this.DrawTriangleWu(  x,y-s,x+s,y,x-s,y,clr,opacity);
  }
//+--------------------------------------------+
//| Draw the down arrow                        |
//+--------------------------------------------+
void CGCnvElement::DrawArrowDown(const int base_x,const int base_y,const int size,const color clr,const uchar opacity)
  {
   int x=base_x;
   int y=base_y;
   int s=(size<1 ? 1 : size);
   this.DrawTriangleFill(x,y+s,x-s,y,x+s,y,clr,opacity);
   this.DrawTriangleWu(  x,y+s,x-s,y,x+s,y,clr,opacity);
  }
//+------------------------------------------------------------------+

为了计算每个顶点的坐标,我们只需从中心点的坐标中添加或减去参数中所传递箭头的大小。
请记住,大小仅受下限(1) 的限制,但没有上限。 在此,我们需要确保箭头以正常大小绘制,因为箭头的实际大小是由两个指定大小的 + 一个中心像素得到的。 换言之,在大小为 1 的情况下,实际大小将是 1+1+1。 若大小为 2,实际大小为 2+1+2;大小为 3,其为 3+1+3;依此类推。

由于现在我们已有了相对于元素和相应事件的新鼠标状态,因此它们需要反映在最后一个鼠标事件的处理程序方法当中。

在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\Button.mqh 中,在方法中添加新事件列表:

//+--------------------------------------------+
//| Last mouse event handler                   |
//+--------------------------------------------+
void CButton::OnMouseEventPostProcessing(void)
  {
   if(!this.IsVisible() || !this.Enabled())
      return;
   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(this.MouseEventLast()==MOUSE_EVENT_INSIDE_ACTIVE_AREA_NOT_PRESSED || this.MouseEventLast()==MOUSE_EVENT_INSIDE_FORM_NOT_PRESSED)
          {
           this.SetBackgroundColor(this.State() ? this.BackgroundStateOnColor() : this.BackgroundColorInit(),false);
           this.SetForeColor(this.State() ? this.ForeStateOnColor() : this.ForeColorInit(),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
      //--- The cursor is inside the form, any mouse button is clicked
      //--- The cursor is inside the form, the mouse wheel is being scrolled
      //--- The cursor is inside the active area, the mouse buttons are not clicked
      //--- The cursor is inside the active area, any mouse button is clicked
      //--- The cursor is inside the active area, the mouse wheel is being scrolled
      //--- The cursor is inside the active area, left mouse button is released
      //--- The cursor is within the window scrolling area, the mouse buttons are not clicked
      //--- The cursor is within the window scrolling area, any mouse button is clicked
      //--- The cursor is within the window scrolling area, the mouse wheel is being scrolled
      //--- The cursor is within the window resizing area, the mouse buttons are not clicked
      //--- The cursor is within the window resizing area, the mouse button (any) is clicked
      //--- The cursor is within the window resizing area, the mouse wheel is being scrolled
      //--- The cursor is within the window resizing area, the mouse buttons are not clicked
      //--- The cursor is within the window resizing area, the mouse button (any) is clicked
      //--- The cursor is within the window separator area, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED                     :
      case MOUSE_FORM_STATE_INSIDE_FORM_PRESSED                         :
      case MOUSE_FORM_STATE_INSIDE_FORM_WHEEL                           :
//--- Within the active area
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED              :
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED                  :
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL                    :
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED                 :
//--- Within the scrolling area at the bottom
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED       :
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_PRESSED           :
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_WHEEL             :
//--- Within the scrolling area to the right
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED        :
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_PRESSED            :
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_WHEEL              :
//--- Within the window resizing area at the top
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_NOT_PRESSED          :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_PRESSED              :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_WHEEL                :
//--- Within the window resizing area at the bottom
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_NOT_PRESSED       :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_PRESSED           :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_WHEEL             :
//--- Within the window resizing area to the left
      case MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_NOT_PRESSED         :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_PRESSED             :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_WHEEL               :
//--- Within the window resizing area to the right
      case MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_NOT_PRESSED        :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_PRESSED            :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_WHEEL              :
//--- Within the window resizing area to the top-left
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_NOT_PRESSED     :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_PRESSED         :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_WHEEL           :
//--- Within the window resizing area to the top-right
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_NOT_PRESSED    :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_PRESSED        :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_WHEEL          :
//--- Within the window resizing area at the bottom left
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_NOT_PRESSED  :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_PRESSED      :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_WHEEL        :
//--- Within the window resizing area at the bottom-right
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_NOT_PRESSED :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_PRESSED     :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_WHEEL       :
//--- Within the control area
      case MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_NOT_PRESSED             :
      case MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_PRESSED                 :
      case MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_WHEEL                   :
        break;
      //--- MOUSE_EVENT_NO_EVENT
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

在此,所有这些事件都不会加以处理,但若有必要,您始终可以为每个事件添加处理。

TabHeader.mqhCheckBox.mqhSplitContainer.mqh 中均已针对该方法进行了相同的更改。

为了在箭头按钮类中指定绘制箭头的颜色,我们使用了 m_arrow_color 私密变量。 采用这个变量是多余的,因为我们可以调用 ForeColor() 方法来指定颜色,它也能够控制绘制文本的颜色。 因此,在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ArrowButton.mqh 中,删除变量及其处理方法:

//+------------------------------------------------------------------+
//| Arrow Button object class of WForms controls                     |
//+------------------------------------------------------------------+
class CArrowButton : public CButton
  {
private:
   color             m_arrow_color;                      // Arrow color
protected:
   //--- Draw the arrow
   virtual void      DrawArrow(void){return;}
//--- Protected constructor with object type, chart ID and subwindow
                     CArrowButton(const ENUM_GRAPH_ELEMENT_TYPE type,
                                  CGCnvElement *main_obj,CGCnvElement *base_obj,
                                  const long chart_id,
                                  const int subwindow,
                                  const string descript,
                                  const int x,
                                  const int y,
                                  const int w,
                                  const int h);
public:
//--- (1) Set and (2) return the arrow color
   void              SetArrowColor(const color clr)      { this.m_arrow_color=clr;     }
   color             ArrowColor(void)              const { return this.m_arrow_color;  }
//--- Constructor


此外,替换调用远程方法,处理文本颜色

//+--------------------------------------------+
//| Protected constructor with an object type, |
//| chart ID and subwindow                     |
//+--------------------------------------------+
CArrowButton::CArrowButton(const ENUM_GRAPH_ELEMENT_TYPE type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const long chart_id,
                           const int subwindow,
                           const string descript,
                           const int x,
                           const int y,
                           const int w,
                           const int h) : CButton(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and assign the library object type to the current object
   this.SetTypeElement(type);
   this.m_type=OBJECT_DE_TYPE_GWF_HELPER;
   this.SetPaddingAll(0);
   this.SetMarginAll(0);
   this.SetBorderSizeAll(1);
   this.SetForeColor(CLR_DEF_FORE_COLOR,true);
  }
//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CArrowButton::CArrowButton(CGCnvElement *main_obj,CGCnvElement *base_obj,
                           const long chart_id,
                           const int subwindow,
                           const string descript,
                           const int x,
                           const int y,
                           const int w,
                           const int h) : CButton(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON);
   this.m_type=OBJECT_DE_TYPE_GWF_HELPER;
   this.SetPaddingAll(0);
   this.SetMarginAll(0);
   this.SetBorderSizeAll(1);
   this.SetForeColor(CLR_DEF_FORE_COLOR,true);
  }
//+------------------------------------------------------------------+

在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ArrowRightButton.mqh 中,即在类构造函数中,设置绘制箭头的大小为 3:

//+--------------------------------------------+
//| Protected constructor with an object type, |
//| chart ID and subwindow                     |
//+--------------------------------------------+
CArrowRightButton::CArrowRightButton(const ENUM_GRAPH_ELEMENT_TYPE type,
                                     CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h) : CArrowButton(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and the size of the drawn arrow to 3
   this.SetTypeElement(type);
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,3);
  }
//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CArrowRightButton::CArrowRightButton(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h) : CArrowButton(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT);
   this.SetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,3);
  }
//+------------------------------------------------------------------+

在绘制箭头的方法中,当调用绘制箭头的方法时更改参数:

//+--------------------------------------------+
//| Draw the arrow                             |
//+--------------------------------------------+
void CArrowRightButton::DrawArrow(void)
  {
   CGCnvElement::DrawArrowRight(this.Width()/2-1,this.Height()/2,(int)this.GetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE),this.ForeColor(),this.Opacity());
  }
//+------------------------------------------------------------------+

作为箭头的中心点,传递对象的中心(水平向左移动一个像素),指定对象属性中绘制的箭头集的大小其文本颜色和不透明度

ArrowLeftButton.mqhArrowDownButton.mqhArrowUpButton.mqh 中的其它箭头按钮对象类中也进行了类似的更改。

为了简化滚动条区域的坐标和大小设置,在窗体对象类的 \MQL5\Include\DoEasy\Objects\Graph\Form.mqh 文件中,添加公开方法

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

//--- Set the (1) X, (2) Y coordinates, (3) width and (4) height of the element scrolling right area
   void              SetScrollAreaRightX(const int value)      { this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_RIGHT,value);     }
   void              SetScrollAreaRightY(const int value)      { this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_RIGHT,value);     }
   void              SetScrollAreaRightWidth(const int value)  { this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_RIGHT,value); }
   void              SetScrollAreaRightHeight(const int value) { this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_RIGHT,value);}
//--- Set the (1) X, (2) Y coordinates, (3) width and (4) height of the element scrolling lower area
   void              SetScrollAreaBottomX(const int value)     { this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_BOTTOM,value);    }
   void              SetScrollAreaBottomY(const int value)     { this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_BOTTOM,value);    }
   void              SetScrollAreaBottomWidth(const int value) { this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_BOTTOM,value);}
   void              SetScrollAreaBottomHeight(const int value){ this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_BOTTOM,value);}

//--- Update the coordinates (shift the canvas)
   virtual bool      Move(const int x,const int y,const bool redraw=false);

在设置和返回鼠标相对于窗体的状态的方法中,检查鼠标光标的位置,将其与窗体各个区域的坐标进行比较,并将这些状态的标志设置到变量。 进而,基于这些标志,形成鼠标光标相对于对象的一般状态。 将代码模块添加到跟踪光标相对于滚动条和边框位置的方法中,在该区域中可以用鼠标抓取对象的边框进行拖动,从而调整元素的大小:

//+------------------------------------------------------------------+
//| 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)
  {
//--- Data location in the ushort value of the button status
   //---------------------------------------------------------------------------
   //   bit    |    byte   |            state            |    dec    |   hex   |
   //---------------------------------------------------------------------------
   //    0     |     0     | left mouse button           |     1     |    1    |
   //---------------------------------------------------------------------------
   //    1     |     0     | right mouse button          |     2     |    2    |
   //---------------------------------------------------------------------------
   //    2     |     0     | SHIFT key                   |     4     |    4    |
   //---------------------------------------------------------------------------
   //    3     |     0     | CTRL key                    |     8     |    8    |
   //---------------------------------------------------------------------------
   //    4     |     0     | middle mouse button         |    16     |   10    |
   //---------------------------------------------------------------------------
   //    5     |     0     | 1 add. mouse button         |    32     |   20    |
   //---------------------------------------------------------------------------
   //    6     |     0     | 2 add. mouse button         |    64     |   40    |
   //---------------------------------------------------------------------------
   //    7     |     0     | scrolling the wheel         |    128    |   80    |
   //---------------------------------------------------------------------------
   //---------------------------------------------------------------------------
   //    0     |     1     | cursor inside the form      |    256    |   100   |
   //---------------------------------------------------------------------------
   //    1     |     1     | cursor inside active area   |    512    |   200   |
   //---------------------------------------------------------------------------
   //    2     |     1     | cursor in the control area  |   1024    |   400   |
   //---------------------------------------------------------------------------
   //    3     |     1     | cursor in the scrolling area|   2048    |   800   |
   //---------------------------------------------------------------------------
   //    4     |     1     | cursor at the left edge     |   4096    |  1000   |
   //---------------------------------------------------------------------------
   //    5     |     1     | cursor at the bottom edge   |   8192    |  2000   |
   //---------------------------------------------------------------------------
   //    6     |     1     | cursor at the right edge    |   16384   |  4000   |
   //---------------------------------------------------------------------------
   //    7     |     1     | cursor at the top edge      |   32768   |  8000   |
   //---------------------------------------------------------------------------
//--- 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(this.m_mouse.CoordX(),this.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(this.m_mouse.CoordX(),this.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 the cursor is inside the control area, set bit 10 "cursor inside the control area",
      if(CGCnvElement::CursorInsideControlArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
         this.m_mouse_state_flags |= (0x0001<<10);
      //--- otherwise, remove the "cursor inside the control area" bit
      else this.m_mouse_state_flags &=0xFBFF;
      
      //--- If the cursor is inside the scroll area, set bit 11 "cursor inside the scroll area"
      if(CGCnvElement::CursorInsideScrollRightArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()) || CGCnvElement::CursorInsideScrollBottomArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
         this.m_mouse_state_flags |= (0x0001<<11);
      //--- otherwise, remove the "cursor inside the scroll area" bit
      else this.m_mouse_state_flags &=0xF7FF;
      
      //--- If the cursor is on the upper left corner, set bit 15 "cursor on the upper side" and bit 12 "cursor on the left side"
      if(CGCnvElement::CursorInsideResizeTopLeftArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
        {
         this.m_mouse_state_flags |= (0x0001<<15);
         this.m_mouse_state_flags |= (0x0001<<12);
        }
      //--- otherwise, check "cursor on the left face" and "cursor on the top face" separately
      else
        {
         //--- If the cursor is on the left side, set bit 12 "cursor on the left face"
         if(CGCnvElement::CursorInsideResizeLeftArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
            this.m_mouse_state_flags |= (0x0001<<12);
         //--- otherwise, remove the "cursor on the left face" bit
         else this.m_mouse_state_flags &=0xEFFF;
         //--- If the cursor is on the top edge, set bit 15 "cursor on the top face"
         if(CGCnvElement::CursorInsideResizeTopArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
            this.m_mouse_state_flags |= (0x0001<<15);
         //--- otherwise, remove the "cursor on the top face" bit
         else this.m_mouse_state_flags &=0x7FFF;
        }
      
      //--- If the cursor is on the upper left corner, set bit 15 "cursor on the upper face" and bit 12 "cursor on the left face"
      if(CGCnvElement::CursorInsideResizeTopRightArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
        {
         this.m_mouse_state_flags |= (0x0001<<15);
         this.m_mouse_state_flags |= (0x0001<<14);
        }
      //--- otherwise, check "cursor on the left face" and "cursor on the top face" separately
      else
        {
         //--- If the cursor is on the left side, set bit 12 "cursor on the right face"
         if(CGCnvElement::CursorInsideResizeRightArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
            this.m_mouse_state_flags |= (0x0001<<14);
         //--- otherwise, remove the "cursor on the right face" bit
         else this.m_mouse_state_flags &=0xBFFF;
         //--- If the cursor is on the top edge, set bit 15 "cursor on the top face"
         if(CGCnvElement::CursorInsideResizeTopArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
            this.m_mouse_state_flags |= (0x0001<<15);
         //--- otherwise, remove the "cursor on the top face" bit
         else this.m_mouse_state_flags &=0x7FFF;
        }
      
      //--- If the cursor is on the lower left corner, set bit 13 "cursor on the lower face" and bit 12 "cursor on the left face"
      if(CGCnvElement::CursorInsideResizeBottomLeftArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
        {
         this.m_mouse_state_flags |= (0x0001<<13);
         this.m_mouse_state_flags |= (0x0001<<12);
        }
      //--- otherwise, check "cursor on the left face" and "cursor on the lower face" separately
      else
        {
         //--- If the cursor is on the left side, set bit 12 "cursor on the left face"
         if(CGCnvElement::CursorInsideResizeLeftArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
            this.m_mouse_state_flags |= (0x0001<<12);
         //--- otherwise, remove the "cursor on the left face" bit
         else this.m_mouse_state_flags &=0xEFFF;
         //--- If the cursor is on the lower side, set bit 13 "cursor on the lower face"
         if(CGCnvElement::CursorInsideResizeLeftArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
            this.m_mouse_state_flags |= (0x0001<<13);
         //--- otherwise, remove the "cursor on the lower face" bit
         else this.m_mouse_state_flags &=0xDFFF;
        }
      
      //--- If the cursor is on the lower right corner, set bit 13 "cursor on the lower face" and bit 14 "cursor on the right face"
      if(CGCnvElement::CursorInsideResizeBottomRightArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
        {
         this.m_mouse_state_flags |= (0x0001<<13);
         this.m_mouse_state_flags |= (0x0001<<14);
        }
      //--- otherwise, check "cursor on the right face" and "cursor on the lower face" separately
      else
        {
         //--- If the cursor is on the left side, set bit 12 "cursor on the right face"
         if(CGCnvElement::CursorInsideResizeRightArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
            this.m_mouse_state_flags |= (0x0001<<14);
         //--- otherwise, remove the "cursor on the right face" bit
         else this.m_mouse_state_flags &=0xBFFF;
         //--- If the cursor is on the lower side, set bit 13 "cursor on the lower face"
         if(CGCnvElement::CursorInsideResizeLeftArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
            this.m_mouse_state_flags |= (0x0001<<13);
         //--- otherwise, remove the "cursor on the lower face" bit
         else this.m_mouse_state_flags &=0xDFFF;
        }
      
      //--- If one of the three mouse buttons is pressed, check the location of the cursor in the form areas and
      //--- return the appropriate value of the pressed key
      if((this.m_mouse_state_flags & 0x0001)!=0 || (this.m_mouse_state_flags & 0x0002)!=0 || (this.m_mouse_state_flags & 0x0010)!=0)
        {
         //--- If the cursor is inside the form
         if((this.m_mouse_state_flags & 0x0100)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_FORM_PRESSED;
         //--- If the cursor is inside the active area of the form
         if((this.m_mouse_state_flags & 0x0200)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED;
         //--- If the cursor is inside the form control area
         if((this.m_mouse_state_flags & 0x0400)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_PRESSED;
            
         //--- If the cursor is inside the form scrolling area
         if((this.m_mouse_state_flags & 0x0800)!=0)
           {
            //--- If above the right area
            if(CGCnvElement::CursorInsideScrollRightArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_PRESSED;
            //--- otherwise, above the bottom one
            else
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_PRESSED;
           }
            
         //--- If there are cursor flags on the top and left faces
         if((this.m_mouse_state_flags & 0x8000)!=0 && (this.m_mouse_state_flags & 0x1000)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_PRESSED;
         //--- Check the cursor flags on the top and left faces separately
         else
           {
            //--- If the cursor is on the top face
            if((this.m_mouse_state_flags & 0x8000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_PRESSED;
            //--- If the cursor is on the left face
            if((this.m_mouse_state_flags & 0x1000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_PRESSED;
           }
         //--- If there are cursor flags on the top and right faces
         if((this.m_mouse_state_flags & 0x8000)!=0 && (this.m_mouse_state_flags & 0x4000)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_PRESSED;
         //--- Check the cursor flags on the top and right faces separately
         else
           {
            //--- If the cursor is on the top face
            if((this.m_mouse_state_flags & 0x8000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_PRESSED;
            //--- If the cursor is on the right face
            if((this.m_mouse_state_flags & 0x4000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_PRESSED;
           }
         
         //--- If there are cursor flags on the bottom and left faces
         if((this.m_mouse_state_flags & 0x2000)!=0 && (this.m_mouse_state_flags & 0x1000)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_PRESSED;
         //--- Check the cursor flags on the bottom and left faces separately
         else
           {
            //--- If the cursor is on the bottom face
            if((this.m_mouse_state_flags & 0x2000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_PRESSED;
            //--- If the cursor is on the left face
            if((this.m_mouse_state_flags & 0x1000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_PRESSED;
           }
         //--- If there are cursor flags on the bottom and right faces
         if((this.m_mouse_state_flags & 0x2000)!=0 && (this.m_mouse_state_flags & 0x4000)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_PRESSED;
         //--- Check the cursor flags on the bottom and right faces separately
         else
           {
            //--- If the cursor is on the bottom face
            if((this.m_mouse_state_flags & 0x2000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_PRESSED;
            //--- If the cursor is on the right face
            if((this.m_mouse_state_flags & 0x4000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_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, control or form area)
         //--- If the cursor is inside the form
         if((this.m_mouse_state_flags & 0x0100)!=0)
           {
            //--- If the mouse wheel is being scrolled
            if((this.m_mouse_state_flags & 0x0080)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_FORM_WHEEL;
            else
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED;
           }
         //--- If the cursor is inside the active area of the form
         if((this.m_mouse_state_flags & 0x0200)!=0)
           {
            //--- If the mouse wheel is being scrolled
            if((this.m_mouse_state_flags & 0x0080)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL;
            else
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED;
           }
         //--- If the cursor is inside the form control area
         if((this.m_mouse_state_flags & 0x0400)!=0)
           {
            //--- If the mouse wheel is being scrolled
            if((this.m_mouse_state_flags & 0x0080)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_WHEEL;
            else
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_NOT_PRESSED;
           }
           
           
         //--- If the cursor is inside the form scrolling area
         if((this.m_mouse_state_flags & 0x0800)!=0)
           {
            //--- If above the right area
            if(CGCnvElement::CursorInsideScrollRightArea(this.m_mouse.CoordX(),this.m_mouse.CoordY()))
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED;
            //--- otherwise, above the bottom one
            else
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED;
           }
            
         //--- If there are cursor flags on the top and left faces
         if((this.m_mouse_state_flags & 0x8000)!=0 && (this.m_mouse_state_flags & 0x1000)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_NOT_PRESSED;
         //--- Check the cursor flags on the top and left faces separately
         else
           {
            //--- If the cursor is on the top face
            if((this.m_mouse_state_flags & 0x8000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_NOT_PRESSED;
            //--- If the cursor is on the left face
            if((this.m_mouse_state_flags & 0x1000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_NOT_PRESSED;
           }
         //--- If there are cursor flags on the top and right faces
         if((this.m_mouse_state_flags & 0x8000)!=0 && (this.m_mouse_state_flags & 0x4000)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_NOT_PRESSED;
         //--- Check the cursor flags on the top and right faces separately
         else
           {
            //--- If the cursor is on the top face
            if((this.m_mouse_state_flags & 0x8000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_NOT_PRESSED;
            //--- If the cursor is on the right face
            if((this.m_mouse_state_flags & 0x4000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_NOT_PRESSED;
           }
         
         //--- If there are cursor flags on the bottom and left faces
         if((this.m_mouse_state_flags & 0x2000)!=0 && (this.m_mouse_state_flags & 0x1000)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_NOT_PRESSED;
         //--- Check the cursor flags on the bottom and left faces separately
         else
           {
            //--- If the cursor is on the bottom face
            if((this.m_mouse_state_flags & 0x2000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_NOT_PRESSED;
            //--- If the cursor is on the left face
            if((this.m_mouse_state_flags & 0x1000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_NOT_PRESSED;
           }
         //--- If there are cursor flags on the bottom and right faces
         if((this.m_mouse_state_flags & 0x2000)!=0 && (this.m_mouse_state_flags & 0x4000)!=0)
            this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_NOT_PRESSED;
         //--- Check the cursor flags on the bottom and right faces separately
         else
           {
            //--- If the cursor is on the bottom face
            if((this.m_mouse_state_flags & 0x2000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_NOT_PRESSED;
            //--- If the cursor is on the right face
            if((this.m_mouse_state_flags & 0x4000)!=0)
               this.m_mouse_form_state=MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_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;
  }
//+------------------------------------------------------------------+

所有代码模块都进行了详细注释,实际上其中的一切都很简单 — 我们检查光标坐标相对于区域坐标的位置,例如滚动,如果光标在区域内,我们就为其设置相应的标志。 如果不是,则删除该标志。 检查和设置标志的结果,我们得到一组判定鼠标光标位置的标志。 如果设置了对象顶部和右侧位置的标志,则表明光标位于右上角。 如此,由于 ushort 值中的码位不足,我们必须组合标志,并分别写入每个标志。

在鼠标事件处理程序中,更改事件处理方法的调用,以便在滚动区域中查找光标。 由于我们有两个这样的区域,因此我们更改了位于滚动区域中的鼠标状态的名称。 现在,状态准确地指示光标在哪个滚动条上 — 在右侧或顶部:

//+--------------------------------------------+
//| 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 to the right, the mouse buttons are not clicked
      case MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED :  this.MouseScrollAreaNotPressedHandler(id,lparam,dparam,sparam);break;
      //--- The cursor is within the window scrolling area to the right, the mouse button (any) is clicked
      case MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_PRESSED     :  this.MouseScrollAreaPressedHandler(id,lparam,dparam,sparam);   break;
      //--- The cursor is within the window scrolling area to the right, the mouse wheel is being scrolled
      case MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_WHEEL       :  this.MouseScrollAreaWhellHandler(id,lparam,dparam,sparam);     break;
      
      //--- The cursor is within the window scrolling area at the bottom, the mouse buttons are not clicked
      case MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED:  this.MouseScrollAreaNotPressedHandler(id,lparam,dparam,sparam);break;
      //--- The cursor is within the window scrolling area at the bottom, the mouse button (any) is clicked
      case MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_PRESSED    :  this.MouseScrollAreaPressedHandler(id,lparam,dparam,sparam);   break;
      //--- The cursor is within the window scrolling area at the bottom, the mouse wheel is being scrolled
      case MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_WHEEL      :  this.MouseScrollAreaWhellHandler(id,lparam,dparam,sparam);     break;
      
      //--- The cursor is within the control area, the mouse buttons are not clicked
      case MOUSE_EVENT_INSIDE_CONTROL_AREA_NOT_PRESSED   :  this.MouseControlAreaNotPressedHandler(id,lparam,dparam,sparam);  break;
      //--- The cursor is within the control area, the mouse button (any) is clicked
      case MOUSE_EVENT_INSIDE_CONTROL_AREA_PRESSED       :  this.MouseControlAreaPressedHandler(id,lparam,dparam,sparam);     break;
      //--- The cursor is within the control area, the mouse wheel is being scrolled
      case MOUSE_EVENT_INSIDE_CONTROL_AREA_WHEEL         :  this.MouseControlAreaWhellHandler(id,lparam,dparam,sparam);       break;
      //--- MOUSE_EVENT_NO_EVENT
      default: break;
     }
   this.m_mouse_event_last=(ENUM_MOUSE_EVENT)id;
  }
//+------------------------------------------------------------------+

将所有新的鼠标事件添加到最后一个鼠标事件处理程序:

//+--------------------------------------------+
//| Last mouse event handler                   |
//+--------------------------------------------+
void CForm::OnMouseEventPostProcessing(void)
  {
   if(!this.IsVisible() || !this.Enabled() || !this.Displayed())
      return;
   ENUM_MOUSE_FORM_STATE state=this.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              :
      case MOUSE_FORM_STATE_NONE                            :
        if(this.MouseEventLast()==MOUSE_EVENT_INSIDE_ACTIVE_AREA_NOT_PRESSED  || 
           this.MouseEventLast()==MOUSE_EVENT_INSIDE_FORM_NOT_PRESSED         || 
           this.MouseEventLast()==MOUSE_EVENT_OUTSIDE_FORM_NOT_PRESSED        ||
           this.MouseEventLast()==MOUSE_EVENT_NO_EVENT)
          {
           this.SetBackgroundColor(this.BackgroundColorInit(),false);
           this.SetBorderColor(this.BorderColorInit(),false);
           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
      //--- The cursor is inside the form, any mouse button is clicked
      //--- The cursor is inside the form, the mouse wheel is being scrolled
      //--- The cursor is inside the active area, the mouse buttons are not clicked
      //--- The cursor is inside the active area, any mouse button is clicked
      //--- The cursor is inside the active area, the mouse wheel is being scrolled
      //--- The cursor is inside the active area, left mouse button is released
      //--- The cursor is within the window scrolling area, the mouse buttons are not clicked
      //--- The cursor is within the window scrolling area, any mouse button is clicked
      //--- The cursor is within the window scrolling area, the mouse wheel is being scrolled
      //--- The cursor is within the window resizing area, the mouse buttons are not clicked
      //--- The cursor is within the window resizing area, the mouse button (any) is clicked
      //--- The cursor is within the window resizing area, the mouse wheel is being scrolled
      //--- The cursor is within the window resizing area, the mouse buttons are not clicked
      //--- The cursor is within the window resizing area, the mouse button (any) is clicked
      //--- The cursor is within the window separator area, the mouse wheel is being scrolled
      case MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED                     :
      case MOUSE_FORM_STATE_INSIDE_FORM_PRESSED                         :
      case MOUSE_FORM_STATE_INSIDE_FORM_WHEEL                           :
//--- Within the active area
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED              :
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED                  :
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL                    :
      case MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED                 :
//--- Within the scrolling area at the bottom
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED       :
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_PRESSED           :
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_WHEEL             :
//--- Within the scrolling area to the right
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED        :
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_PRESSED            :
      case MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_WHEEL              :
//--- Within the window resizing area at the top
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_NOT_PRESSED          :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_PRESSED              :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_WHEEL                :
//--- Within the window resizing area at the bottom
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_NOT_PRESSED       :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_PRESSED           :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_WHEEL             :
//--- Within the window resizing area to the left
      case MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_NOT_PRESSED         :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_PRESSED             :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_WHEEL               :
//--- Within the window resizing area to the right
      case MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_NOT_PRESSED        :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_PRESSED            :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_WHEEL              :
//--- Within the window resizing area to the top-left
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_NOT_PRESSED     :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_PRESSED         :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_WHEEL           :
//--- Within the window resizing area to the top-right
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_NOT_PRESSED    :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_PRESSED        :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_WHEEL          :
//--- Within the window resizing area at the bottom left
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_NOT_PRESSED  :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_PRESSED      :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_WHEEL        :
//--- Within the window resizing area at the bottom-right
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_NOT_PRESSED :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_PRESSED     :
      case MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_WHEEL       :
//--- Within the control area
      case MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_NOT_PRESSED             :
      case MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_PRESSED                 :
      case MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_WHEEL                   :
        break;
      //--- MOUSE_EVENT_NO_EVENT
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

在发送事件消息的方法中,调整接收的基准对象类型:

//+--------------------------------------------+
//| Send a message about the event             |
//+--------------------------------------------+
bool CForm::SendEvent(const long chart_id,const ushort event_id)
  {
   //--- Create the event:
   //--- Get the base and main objects
   CGCnvElement *base=this.GetBase();
   CGCnvElement *main=this.GetMain();
   //--- find the names of the main and base objects
   string name_main=(main!=NULL ? main.Name() : this.IsMain() ? this.Name() : "Lost name of object");
   string name_base=(base!=NULL ? base.Name() : "Lost name of object");
   ENUM_GRAPH_ELEMENT_TYPE base_base_type=(base!=NULL ? (base.GetBase()!=NULL ? base.GetBase().TypeGraphElement() : base.TypeGraphElement()) : this.TypeGraphElement());
   //--- pass the object ID in the event 'long' parameter
   //--- pass the object type in the event 'double' parameter
   //--- in the event 'string' parameter, pass the names of the main, base and current objects separated by ";"
   long lp=this.ID();
   double dp=base_base_type;
   string sp=::StringSubstr(name_main,::StringLen(this.NamePrefix()))+";"+
             ::StringSubstr(name_base,::StringLen(this.NamePrefix()))+";"+
             ::StringSubstr(this.Name(),::StringLen(this.NamePrefix()));
   //--- Send the event of clicking on the control to the control program chart
   bool res=true;
   ::ResetLastError();
   res=::EventChartCustom(chart_id,event_id,lp,dp,sp);
   if(res)
      return true;
   ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_ENQUEUE_EVENT),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(::GetLastError()));
   return false;
  }
//+------------------------------------------------------------------+

如果成功检测到基对象还有其自己的基准对象则获取其类型否则,获取基对象类型。 在此修复之前,如果基对象没有自己的基准对象(例如,基对象是主对象),则程序会结束,且抛出访问对象无效指针严重错误。 现在它已得到修复。

以前,我在基准 WinForms 对象类的大小调整方法中对滚动条对象的位置进行了调整。 当调整对象大小时,其边框的坐标亦会更改。 由于滚动条绑定到对象的右下角,因此需要在必要时调整其坐标。 现在我们将在容器对象类中进行这样的调整,因为只有容器对象可以包容附着对象,如果它们与容器的可见区域不适配,也许就需要滚动。 我们将处理移到容器对象类。 这是最适合它的地方。

在 \MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqh 基准 WinForms 对象类,从设置新大小的方法中,删除调整滚动条大小和坐标的代码模块

//+--------------------------------------------+
//| Set the new size for the current object    |
//+--------------------------------------------+
bool CWinFormBase::Resize(const int w,const int h,const bool redraw)
  {
//--- If the object width and height are equal to the passed ones, return 'true'
   if(this.Width()==w && this.Height()==h)
      return true;
//--- Declare the variable with the property change result
   bool res=true;
//--- Save the panel initial size
   int prev_w=this.Width();
   int prev_h=this.Height();
//--- Set the property change result to the 'res' variable
//--- (if the property value is not equal to the passed value)
   if(this.Width()!=w)
      res &=this.SetWidth(w);
   if(this.Height()!=h)
      res &=this.SetHeight(h);
   if(!res)
      return false;
//--- Get the vertical scrollbar and
   CWinFormBase *scroll_v=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL,0);
   if(scroll_v!=NULL)
     {
      //--- change the vertical size to the size of the container workspace
      scroll_v.Resize(scroll_v.Width(),this.Height()-this.BorderSizeTop()-this.BorderSizeBottom(),false);
      //--- Get a button object with the down arrow from the vertical scrollbar object
      CWinFormBase *arr_d=scroll_v.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,0);
      //--- If the button has been received
      if(arr_d!=NULL)
        {
         //--- Move it to the bottom edge of the vertical scrollbar
         if(arr_d.Move(arr_d.CoordX(),scroll_v.BottomEdge()-2*arr_d.Height()))
           {
            arr_d.SetCoordXRelative(arr_d.CoordX()-scroll_v.CoordX());
            arr_d.SetCoordYRelative(arr_d.CoordY()-scroll_v.CoordY());
           }
        }
     }
//--- Get the horizontal scrollbar and
   CWinFormBase *scroll_h=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL,0);
   if(scroll_h!=NULL)
     {
      //--- change the horizontal size to the size of the container workspace
      scroll_h.Resize(this.Width()-this.BorderSizeLeft()-this.BorderSizeRight(),scroll_h.Height(),false);
      //--- Get a button object with the right arrow from the horizontal scrollbar object
      CWinFormBase *arr_r=scroll_h.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,0);
      //--- If the button has been received
      if(arr_r!=NULL)
        {
         //--- Move it to the right edge of the horizontal scrollbar
         if(arr_r.Move(scroll_h.RightEdge()-2*arr_r.Width(),arr_r.CoordY()))
           {
            arr_r.SetCoordXRelative(arr_r.CoordX()-scroll_h.CoordX());
            arr_r.SetCoordYRelative(arr_r.CoordY()-scroll_h.CoordY());
           }
        }
     }
//--- Calculate the value, by which the size should be changed
   int excess_w=this.Width()-prev_w;
   int excess_h=this.Height()-prev_h;
//--- Get the "Shadow" object
   CShadowObj *shadow=this.GetShadowObj();
//--- If the object has a shadow and the "Shadow" object has been received,
   if(this.IsShadow() && shadow!=NULL)
     {
      //--- save shadow shifts by X and Y,
      int x=shadow.CoordXRelative();
      int y=shadow.CoordYRelative();
      //--- set the shadow new width and height
      res &=shadow.SetWidth(shadow.Width()+excess_w);
      res &=shadow.SetHeight(shadow.Height()+excess_h);
      //--- If the res variable contains 'false',
      //--- there was a resize error - return 'false'
      if(!res)
         return false;
      //--- If there is no need to redraw, remove the shadow
      if(!redraw)
         shadow.Erase();
      //--- Save the previously set shadow shift values relative to the panel
      shadow.SetCoordXRelative(x);
      shadow.SetCoordYRelative(y);
     }
//--- Redraw the entire element with new size
   if(redraw)
      this.Redraw(true);
//--- All is successful - return 'true'
   return true;
  }
//+------------------------------------------------------------------+

该代码模块将完全移到容器对象类之中。

在返回元素整数型属性说明的方法中,添加返回新对象整数型属性说明的代码模块

//+------------------------------------------------------------------+
//| Return the description of the control integer property           |
//+------------------------------------------------------------------+
string CWinFormBase::GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_INTEGER property,bool only_prop=false)
  {
   return
     (
      property==CANV_ELEMENT_PROP_ID                           ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_ID)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_TYPE                         ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_TYPE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.TypeElementDescription()
         )  :

      //---...
      //---...


      property==CANV_ELEMENT_PROP_ENABLED                      ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_ENABLED)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)(bool)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_RESIZABLE                    ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_RESIZABLE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)(bool)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_FORE_COLOR                   ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_FORE_COLOR)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+ColorToString((color)this.GetProperty(property),true)
         )  :

      //---...
      //---...

      property==CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_PROGRESS_BAR_MARQUEE_ANIM_SPEED)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE            ?  CMessage::Text(MSG_CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE)+
         (only_prop ? "" : !this.SupportProperty(property)     ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+


滚动条控件捕获区域类

在上一篇文章中,在创建 ScrollBar 对象时,我们采用按钮对象类作为其滑块。 事实上,该对象适合以这种能力所用。 然而,在处理事件时,我们应该知道正在处理的对象的类型,以便调用正确的处理程序。 按钮对象有这样的处理程序,但它并不适合滑块。 滑块当然需要滑动。 在其滑动期间,应依据滚动条重新计算其可控的可见区域对象的坐标。 故此,我将基于按钮对象类创建一个新类 — 捕获区域对象类。 在该对象中,我们可以为必要的鼠标事件创建自己的处理程序。

在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ 函数库文件夹,创建 CScrollBarThumb 类的新文件 ScrollBarThumb.mqh.

该类应派生自按钮对象类,且其文件应包含在所创建类的文件之中

//+------------------------------------------------------------------+
//|                                               ScrollBarThumb.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+--------------------------------------------+
//| Include files                              |
//+--------------------------------------------+
#include "..\Common Controls\Button.mqh"
//+--------------------------------------------+
//| Label object class of WForms controls      |
//+--------------------------------------------+
class CScrollBarThumb : public CButton
  {
  }

在类的受保护部分中,声明受保护的构造函数在公开部分中,声明参数型构造函数

//+--------------------------------------------+
//| Label object class of WForms controls      |
//+--------------------------------------------+
class CScrollBarThumb : public CButton
  {
private:

protected:
//--- Protected constructor with object type, chart ID and subwindow
                     CScrollBarThumb(const ENUM_GRAPH_ELEMENT_TYPE type,
                                     CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h);
                             
public:
//--- Constructor
                     CScrollBarThumb(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                     const long chart_id,
                                     const int subwindow,
                                     const string descript,
                                     const int x,
                                     const int y,
                                     const int w,
                                     const int h);
  };
//+------------------------------------------------------------------+

至此,这就是这个对象中我们所需要的一切。 它的类型将在类构造函数中设置,并且它将是唯一的 — 捕获区域对象。

受保护的构造函数:

//+--------------------------------------------+
//| Protected constructor with an object type, |
//| chart ID and subwindow                     |
//+--------------------------------------------+
CScrollBarThumb::CScrollBarThumb(const ENUM_GRAPH_ELEMENT_TYPE type,
                                 CGCnvElement *main_obj,CGCnvElement *base_obj,
                                 const long chart_id,
                                 const int subwindow,
                                 const string descript,
                                 const int x,
                                 const int y,
                                 const int w,
                                 const int h) : CButton(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and assign the library object type to the current object
   this.SetTypeElement(type);
   this.m_type=OBJECT_DE_TYPE_GWF_HELPER;
   this.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_COLOR,true);
   this.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_DOWN);
   this.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_OVER);
   this.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_COLOR,true);
   this.SetForeColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_DOWN);
   this.SetForeColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_OVER);
  }
//+------------------------------------------------------------------+

构造函数接收传递给父类构造函数的创建对象类型图形元素类型函数库图形对象类型则在构造函数主体中设置。 此外,还设置了与鼠标光标交互时各种对象状态的所有默认颜色值。

参数型构造函数:

//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CScrollBarThumb::CScrollBarThumb(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                 const long chart_id,
                                 const int subwindow,
                                 const string descript,
                                 const int x,
                                 const int y,
                                 const int w,
                                 const int h) : CButton(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB);
   this.m_type=OBJECT_DE_TYPE_GWF_HELPER;
   this.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_COLOR,true);
   this.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_DOWN);
   this.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_OVER);
   this.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_COLOR,true);
   this.SetForeColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_DOWN);
   this.SetForeColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_OVER);
  }
//+------------------------------------------------------------------+

此处的所有内容都类似于受保护的构造函数,不同之处在于对象类型被严格设置为捕获区域

我们来优化 \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ScrollBar.mqh 中的抽象滚动条对象类。

包含捕获区域对象类文件。 在私密部分中,声明存储滚动条宽度的变量,而在受保护部分中,声明设置滚动按钮大小的方法。 在公开部分中,声明返回捕获区域对象,以便设置和返回滚动条宽度的方法,以及在滚动条按钮上设置绘制箭头大小的方法

//+------------------------------------------------------------------+
//|                                                    ScrollBar.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+--------------------------------------------+
//| Include files                              |
//+--------------------------------------------+
#include "..\WinFormBase.mqh"
#include "ScrollBarThumb.mqh"
#include "ArrowDownButton.mqh"
#include "ArrowUpButton.mqh"
#include "ArrowLeftButton.mqh"
#include "ArrowRightButton.mqh"
//+--------------------------------------------+
//| CScrollBar object class of WForms controls |
//+--------------------------------------------+
class CScrollBar : public CWinFormBase
  {
private:
   int               m_thickness;         // Scrollbar width (Width - vertical, Height - horizontal)
//--- Create the ArrowButton objects
   virtual void      CreateArrowButtons(const int width,const int height) { return; }
//--- Create a new graphical object
   virtual CGCnvElement *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                          const int element_num,
                                          const string descript,
                                          const int x,
                                          const int y,
                                          const int w,
                                          const int h,
                                          const color colour,
                                          const uchar opacity,
                                          const bool movable,
                                          const bool activity);
//--- Calculate the capture area size
   virtual int       CalculateThumbAreaSize(void);
//--- Initialize the element properties
   void              Initialize(void);

protected:
//--- Set the scroll buttons size
   void              SetArrowButtonsSize(const int size);
//--- Create the capture area object
   virtual void      CreateThumbArea(void);
//--- Protected constructor with object type, chart ID and subwindow
                     CScrollBar(const ENUM_GRAPH_ELEMENT_TYPE type,
                                CGCnvElement *main_obj,CGCnvElement *base_obj,
                                const long chart_id,
                                const int subwindow,
                                const string descript,
                                const int x,
                                const int y,
                                const int w,
                                const int h);
public:
//--- Supported object properties (1) integer, (2) real and (3) string ones
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)  { return true; }
   
//--- Return the capture area object
   CScrollBarThumb  *GetThumb(void) { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB,0);  }
   
//--- (1) Set and (2) return the scrollbar width
   virtual void      SetThickness(const int value);
   int               Thickness(void)                        const { return this.m_thickness; }
//--- Set the size of drawn arrows on scroll buttons
   void              SetArrowSize(const uchar size);
   
//--- Constructor
                     CScrollBar(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                const long chart_id,
                                const int subwindow,
                                const string descript,
                                const int x,
                                const int y,
                                const int w,
                                const int h);
//--- Timer
   virtual void      OnTimer(void);
  };
//+------------------------------------------------------------------+

在元素属性的初始化方法中,添加设置默认颜色值、滚动条宽度,以及按钮和箭头大小

//+--------------------------------------------+
//| Initialize the element properties          |
//+--------------------------------------------+
void CScrollBar::Initialize(void)
  {
   this.SetBorderSizeAll(1);
   this.SetBorderStyle(FRAME_STYLE_SIMPLE);
   this.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BACK_COLOR,true);
   this.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BACK_COLOR);
   this.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BACK_COLOR);
   this.SetBorderColor(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BORDER_COLOR,true);
   this.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_COLOR,true);
   this.SetForeColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_MOUSE_DOWN);
   this.SetForeColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_MOUSE_OVER);
   this.SetThickness(DEF_CONTROL_SCROLL_BAR_WIDTH);
   this.SetArrowButtonsSize(this.m_thickness);
   this.SetArrowSize(uchar(this.m_thickness<4 ? 1 : this.m_thickness<6 ? 2 : this.m_thickness<8 ? 3 : this.m_thickness<10 ? 4 : this.m_thickness<12 ? 5 : 6));
  }
//+------------------------------------------------------------------+

在创建新图形对象的方法中,实现创建捕获区域对象的代码模块

//+--------------------------------------------+
//| Create a new graphical object              |
//+--------------------------------------------+
CGCnvElement *CScrollBar::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type,
                                           const int obj_num,
                                           const string descript,
                                           const int x,
                                           const int y,
                                           const int w,
                                           const int h,
                                           const color colour,
                                           const uchar opacity,
                                           const bool movable,
                                           const bool activity)
  {
   CGCnvElement *element=NULL;
   switch(type)
     {
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB     :
         element=new CScrollBarThumb(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN    :
         element=new CArrowDownButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP      :
         element=new CArrowUpButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT    :
         element=new CArrowLeftButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT   :
         element=new CArrowRightButton(this.GetMain(),this.GetObject(),this.ChartID(),this.SubWindow(),descript,x,y,w,h);
        break;
      default:
        break;
     }
   if(element==NULL)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type));
   return element;
  }
//+------------------------------------------------------------------+

现在,不光箭头按钮对象,该对象还能够创建控制界面的滑块。

设置滚动条宽度的方法:

//+--------------------------------------------+
//| Set the scrollbar width                    |
//+--------------------------------------------+
void CScrollBar::SetThickness(const int value)
  {
//--- Depending on the type
   switch(this.TypeGraphElement())
     {
      //--- For the vertical scrollbar
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL  :
        //--- set the width equal to the value passed to the method and write it as the width of the object
        this.m_thickness=value;
        this.SetWidth(this.m_thickness);
        this.Redraw(false);
        break;
      //--- For the horizontal scroll bar
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL:
        //--- set the width equal to the value passed to the method and write it as the height of the object
        this.m_thickness=value;
        this.SetHeight(this.m_thickness);
        this.Redraw(false);
        break;
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

如果是垂直滚动条,则对象的宽度视同柱线的宽度。 如果是水平滚动条,则对象宽度是其高度。 该方法接收为对象设置的值。 根据滚动条的类型,为其设置宽度或高度。

设置滚动按钮大小的方法:

//+--------------------------------------------+
//| Set the size of the scroll buttons         |
//+--------------------------------------------+
void CScrollBar::SetArrowButtonsSize(const int size)
  {
//--- Declare the pointers to arrow buttons
   CArrowUpButton    *bu=NULL;
   CArrowDownButton  *bd=NULL;
   CArrowLeftButton  *bl=NULL;
   CArrowRightButton *br=NULL;
//--- Depending on the type
   switch(this.TypeGraphElement())
     {
      //--- For the vertical scrollbar
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL  :
        //--- Get the pointer to the up arrow button and set its size equal to 'size'
        bu=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,0);
        if(bu!=NULL)
           bu.Resize(size,size,false);
        //--- Get the pointer to the down arrow button and set its size equal to 'size'
        bd=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,0);
        if(bd!=NULL)
           bd.Resize(size,size,false);
        break;
      //--- For the horizontal scroll bar
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL:
        //--- Get the pointer to the left arrow button and set its size equal to 'size'
        bl=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,0);
        if(bl!=NULL)
           bl.Resize(size,size,false);
        //--- Get the pointer to the right arrow button and set its size equal to 'size'
        br=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,0);
        if(br!=NULL)
           br.Resize(size,size,false);
        break;
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

滚动条对象上的按钮具有相等的边框。 大小会被传递给方法,根据对象的类型,我们获取指向左/右或上/下按钮的指针,并取传递给方法的大小为它们设置 — 宽度和高度。

设置滚动按钮上绘制箭头大小的方法:

//+------------------------------------------------------------------+
//| Set the size of drawn arrows on scroll buttons                   |
//+------------------------------------------------------------------+
void CScrollBar::SetArrowSize(const uchar size)
  {
//--- Declare the pointers to arrow buttons
   CArrowUpButton    *bu=NULL;
   CArrowDownButton  *bd=NULL;
   CArrowLeftButton  *bl=NULL;
   CArrowRightButton *br=NULL;
//--- Depending on the type
   switch(this.TypeGraphElement())
     {
      //--- For the vertical scrollbar
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL  :
        //--- Get the pointer to the up arrow button and set its arrow size equal to 'size'
        bu=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,0);
        if(bu!=NULL)
          {
           bu.SetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,size);
           bu.Redraw(false);
          }
        //--- Get the pointer to the down arrow button and set its arrow size equal to 'size'
        bd=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,0);
        if(bd!=NULL)
          {
           bd.SetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,size);
           bd.Redraw(false);
          }
        break;
      //--- For the horizontal scroll bar
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL:
        //--- Get the pointer to the left arrow button and set its arrow size equal to 'size'
        bl=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,0);
        if(bl!=NULL)
          {
           bl.SetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,size);
           bl.Redraw(false);
          }
        //--- Get the pointer to the right arrow button and set its arrow size equal to 'size'
        br=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,0);
        if(br!=NULL)
          {
           br.SetProperty(CANV_ELEMENT_PROP_BUTTON_ARROW_SIZE,size);
           br.Redraw(false);
          }
        break;
      default:
        break;
     }
  }
//+------------------------------------------------------------------+

根据滚动条的类型,我们获得指向相应按钮的指针,为它们设置绘制箭头的大小,并重绘对象显示变化。

滚动条滑块在其可见性范围内滚动容器的内容。 当鼠标移动滑块时,它不应超出滚动条范围 — 其移动区域应限制到箭头按钮,箭头按钮也用于滚动。 在 \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ScrollBarVertical.mqh 垂直滚动条对象类中,包含捕获区域对象类文件。 在公开部分中,实现返回指向箭头按钮的指针的方法,并声明事件处理程序

//+------------------------------------------------------------------+
//|                                            ScrollBarVertical.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+--------------------------------------------+
//| Include files                              |
//+--------------------------------------------+
#include "ScrollBarThumb.mqh"
#include "ArrowDownButton.mqh"
#include "ArrowUpButton.mqh"
#include "ScrollBar.mqh"
//+------------------------------------------------------------------+
//| CScrollBarVertical object class of WForms controls               |
//+------------------------------------------------------------------+
class CScrollBarVertical : public CScrollBar
  {
private:
//--- Create the ArrowButton objects
   virtual void      CreateArrowButtons(const int width,const int height);
//--- Calculate the capture area size
   virtual int       CalculateThumbAreaSize(void);

protected:
//--- Protected constructor with object type, chart ID and subwindow
                     CScrollBarVertical(const ENUM_GRAPH_ELEMENT_TYPE type,
                                        CGCnvElement *main_obj,CGCnvElement *base_obj,
                                        const long chart_id,
                                        const int subwindow,
                                        const string descript,
                                        const int x,
                                        const int y,
                                        const int w,
                                        const int h);
public:
//--- Supported object properties (1) integer, (2) real and (3) string ones
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property)  { return true; }
   virtual bool      SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property)  { return true; }
   
//--- Return the button with the (1) up, (2) down arrow
   CArrowUpButton   *GetArrowButtonUp(void)     { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,0);      }
   CArrowDownButton *GetArrowButtonDown(void)   { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,0);    }
   
//--- Constructor
                     CScrollBarVertical(CGCnvElement *main_obj,CGCnvElement *base_obj,
                                        const long chart_id,
                                        const int subwindow,
                                        const string descript,
                                        const int x,
                                        const int y,
                                        const int w,
                                        const int h);
//--- Timer
   virtual void      OnTimer(void);
//--- Event handler
   virtual void      OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam);
  };
//+------------------------------------------------------------------+

在创建 ArrowButton 对象的方法中,我们创建所有按钮和滑块,然后获取指向它们的指针,并针对不同的鼠标交互状态设置它们的颜色:

//+--------------------------------------------+
//| Create the ArrowButton objects             |
//+--------------------------------------------+
void CScrollBarVertical::CreateArrowButtons(const int width,const int height)
  {
//--- Set the size of the buttons equal to the width of the scrollbar without the size of its frame
   int size=this.Thickness()-this.BorderSizeLeft()-this.BorderSizeRight();
//--- Create the buttons with up and down arrows and the area capture object. The arrow size is set to 2
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,  0,0,size,size,this.BackgroundColor(),255,true,false);
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,0,this.BottomEdge()-this.BorderSizeBottom()-2*size,size,size,this.BackgroundColor(),255,true,false);
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB,0,this.Height()/2-height,size,30,CLR_DEF_CONTROL_SCROLL_BAR_THUMB_COLOR,255,true,false);
   this.SetArrowSize(2);
//--- Get the pointer to the up arrow button and set the colors of its various states for it
   CArrowUpButton *bu=this.GetArrowButtonUp();
   if(bu!=NULL)
     {
      bu.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_COLOR,true);
      bu.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_DOWN);
      bu.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_OVER);
      bu.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_COLOR,true);
      bu.SetForeColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_DOWN);
      bu.SetForeColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_OVER);
     }
//--- Get the pointer to the down arrow button and set the colors of its various states for it
   CArrowDownButton *bd=this.GetArrowButtonDown();
   if(bd!=NULL)
     {
      bd.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_COLOR,true);
      bd.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_DOWN);
      bd.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_OVER);
      bd.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_COLOR,true);
      bd.SetForeColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_DOWN);
      bd.SetForeColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_OVER);
     }
//--- Get the pointer to the capture area object and set the colors of its various states for it
   CScrollBarThumb *th=this.GetThumb();
   if(th!=NULL)
     {
      th.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_COLOR,true);
      th.SetBorderColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_BORDER_COLOR,true);
      th.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_DOWN);
      th.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_OVER);
      th.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_COLOR,true);
      th.SetForeColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_DOWN);
      th.SetForeColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_OVER);
     }
  }
//+------------------------------------------------------------------+

在事件处理程序中,移动滑块对象时,计算其坐标,该坐标应受限至滚动条边缘按钮:

//+--------------------------------------------+
//| Event handler                              |
//+--------------------------------------------+
void CScrollBarVertical::OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Adjust subwindow Y shift
   CGCnvElement::OnChartEvent(id,lparam,dparam,sparam);
//--- If the event ID is an object movement
   if(id==WF_CONTROL_EVENT_MOVING)
     {
      //--- Get the pointer to the capture area object
      CScrollBarThumb *thumb=this.GetThumb();
      if(thumb==NULL)
         return;
      //--- Get the pointer to the button object with the up arrow
      CArrowUpButton *buttu=this.GetArrowButtonUp();
      if(buttu==NULL)
         return;
      //--- Get the pointer to the button object with the down arrow
      CArrowDownButton *buttd=this.GetArrowButtonDown();
      if(buttd==NULL)
         return;
      //--- Declare the variables for the coordinates of the capture area
      int x=(int)lparam;
      int y=(int)dparam;
      //--- Set the X coordinate equal to the X coordinate of the control element
      x=this.CoordX()+this.BorderSizeLeft();
      //--- Adjust the Y coordinate so that the capture area does not go beyond the control, taking into account the arrow buttons
      if(y<buttu.BottomEdge())
        y=buttu.BottomEdge();
      if(y>buttd.CoordY()-thumb.Height())
        y=buttd.CoordY()-thumb.Height();
      //--- If the capture area object is shifted by the calculated coordinates
      if(thumb.Move(x,y,true))
        {
         //--- set the object relative coordinates
         thumb.SetCoordXRelative(thumb.CoordX()-this.CoordX());
         thumb.SetCoordYRelative(thumb.CoordY()-this.CoordY());
         ::ChartRedraw(this.ChartID());
        }
     }
  }
//+------------------------------------------------------------------+

ScrollBarHorisontal.mqh 文件中的水平滚动条对象类中也进行了类似的改进。

它创建按钮和滑块对象,以及事件处理程序的方法,与上述方法的区别仅在于指向其它类型按钮的指针,以及对滑块移动的其它轴向的限制:

//+--------------------------------------------+
//| Create the ArrowButton objects             |
//+--------------------------------------------+
void CScrollBarHorisontal::CreateArrowButtons(const int width,const int height)
  {
   int size=this.Thickness()-this.BorderSizeTop()-this.BorderSizeBottom();
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,  0,0,size,size,this.BackgroundColor(),255,true,false);
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,this.RightEdge()-this.BorderSizeRight()-2*size,0,size,size,this.BackgroundColor(),255,true,false);
   this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB,this.Width()/2-width,0,30,size,CLR_DEF_CONTROL_SCROLL_BAR_THUMB_COLOR,255,true,false);
   this.SetArrowSize(2);
   CArrowLeftButton *bl=this.GetArrowButtonLeft();
   if(bl!=NULL)
     {
      bl.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_COLOR,true);
      bl.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_DOWN);
      bl.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_OVER);
      bl.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_COLOR,true);
      bl.SetForeColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_DOWN);
      bl.SetForeColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_OVER);
     }
   CArrowRightButton *br=this.GetArrowButtonRight();
   if(br!=NULL)
     {
      br.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_COLOR,true);
      br.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_DOWN);
      br.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_OVER);
      br.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_COLOR,true);
      br.SetForeColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_DOWN);
      br.SetForeColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_OVER);
     }
   CScrollBarThumb *th=this.GetThumb();
   if(th!=NULL)
     {
      th.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_COLOR,true);
      th.SetBorderColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_BORDER_COLOR,true);
      th.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_DOWN);
      th.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_OVER);
      th.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_COLOR,true);
      th.SetForeColorMouseDown(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_DOWN);
      th.SetForeColorMouseOver(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_OVER);
     }
  }
//+------------------------------------------------------------------+

//+--------------------------------------------+
//| Event handler                              |
//+--------------------------------------------+
void CScrollBarHorisontal::OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Adjust subwindow Y shift
   CGCnvElement::OnChartEvent(id,lparam,dparam,sparam);
//--- If the event ID is an object movement
   if(id==WF_CONTROL_EVENT_MOVING)
     {
      //--- Get the pointer to the capture area object
      CScrollBarThumb *thumb=this.GetThumb();
      if(thumb==NULL)
         return;
      //---  Get the pointer to the button object with the left arrow
      CArrowLeftButton *buttl=this.GetArrowButtonLeft();
      if(buttl==NULL)
         return;
      //--- Get the pointer to the button object with the right arrow
      CArrowRightButton *buttr=this.GetArrowButtonRight();
      if(buttr==NULL)
         return;
      //--- Declare the variables for the coordinates of the capture area
      int x=(int)lparam;
      int y=(int)dparam;
      //--- Set the Y coordinate equal to the Y coordinate of the control element
      y=this.CoordY()+this.BorderSizeTop();
      //--- Adjust the X coordinate so that the capture area does not go beyond the control, taking into account the arrow buttons
      if(x<buttl.RightEdge())
        x=buttl.RightEdge();
      if(x>buttr.CoordX()-thumb.Width())
        x=buttr.CoordX()-thumb.Width();
      //--- If the capture area object is shifted by the calculated coordinates
      if(thumb.Move(x,y,true))
        {
         //--- set the object relative coordinates
         thumb.SetCoordXRelative(thumb.CoordX()-this.CoordX());
         thumb.SetCoordYRelative(thumb.CoordY()-this.CoordY());
         ::ChartRedraw(this.ChartID());
        }
     }
  }
//+------------------------------------------------------------------+

改进 \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Container.mqh 中的容器对象类。

在公开部分中,声明更改对象大小的虚拟方法

//--- Set the (1) X, (2) Y coordinates, (3) element width and (4) height
   virtual bool      SetCoordX(const int coord_x)              { return CGCnvElement::SetCoordX(coord_x);   }
   virtual bool      SetCoordY(const int coord_y)              { return CGCnvElement::SetCoordY(coord_y);   }
   virtual bool      SetWidth(const int width)                 { return CGCnvElement::SetWidth(width);      }
   virtual bool      SetHeight(const int height)               { return CGCnvElement::SetHeight(height);    }
   
//--- 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);
   
//--- Create a new attached element

该方法接收从基准 WinForms 对象类中删除的代码模块。

在类构造函数中,设置默认情况下为函数库实现的已创建滚动条的大小,并设置底部滚动条的区域。 我不打算为右侧滚动条设置区域,因为我需要先优化底部滚动条的功能。 然后结果将被移植到右侧滚动条对象:

//+--------------------------------------------+
//| Protected constructor with an object type, |
//| chart ID and subwindow                     |
//+--------------------------------------------+
CContainer::CContainer(const ENUM_GRAPH_ELEMENT_TYPE type,
                       CGCnvElement *main_obj,CGCnvElement *base_obj,
                       const long chart_id,
                       const int subwindow,
                       const string descript,
                       const int x,
                       const int y,
                       const int w,
                       const int h) : CWinFormBase(type,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
//--- Set the specified graphical element type for the object and assign the library object type to the current object
   this.SetTypeElement(type);
   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);
   this.CreateScrollBars(DEF_CONTROL_SCROLL_BAR_WIDTH);
   this.SetScrollAreaBottomX(this.CoordX());
   this.SetScrollAreaBottomY(this.BottomEdge()-DEF_CONTROL_SCROLL_BAR_WIDTH);
   this.SetScrollAreaBottomHeight(DEF_CONTROL_SCROLL_BAR_WIDTH);
  }
//+------------------------------------------------------------------+
//| Constructor indicating the main and base objects,                |
//| chart ID and subwindow                                           |
//+------------------------------------------------------------------+
CContainer::CContainer(CGCnvElement *main_obj,CGCnvElement *base_obj,
                       const long chart_id,
                       const int subwindow,
                       const string descript,
                       const int x,
                       const int y,
                       const int w,
                       const int h) : CWinFormBase(GRAPH_ELEMENT_TYPE_WF_CONTAINER,main_obj,base_obj,chart_id,subwindow,descript,x,y,w,h)
  {
   this.SetTypeElement(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);
   this.CreateScrollBars(DEF_CONTROL_SCROLL_BAR_WIDTH);
   this.SetScrollAreaBottomX(this.CoordX());
   this.SetScrollAreaBottomY(this.BottomEdge()-DEF_CONTROL_SCROLL_BAR_WIDTH);
   this.SetScrollAreaBottomHeight(DEF_CONTROL_SCROLL_BAR_WIDTH);
  }
//+------------------------------------------------------------------+

在为附着对象设置参数的方法中,编写为新创建的捕获区域对象设置默认参数的代码模块

//+--------------------------------------------+
//| Set parameters for the attached object     |
//+--------------------------------------------+
void CContainer::SetObjParams(CWinFormBase *obj,const color colour)
  {
//--- Set the text color of the object to be the same as that of the base container
   obj.SetForeColor(this.ForeColor(),true);
//--- If the created object is not a container, set the same group for it as the one for its base object
   if(obj.TypeGraphElement()<GRAPH_ELEMENT_TYPE_WF_CONTAINER || obj.TypeGraphElement()>GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER)
      obj.SetGroup(this.Group());
//--- Depending on the 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             :
        obj.SetBorderColor(obj.BackgroundColor(),true);
        break;
      //--- For "Label", "CheckBox" and "RadioButton" WinForms objects
      case GRAPH_ELEMENT_TYPE_WF_LABEL                :
      case GRAPH_ELEMENT_TYPE_WF_CHECKBOX             :
      case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON          :
        obj.SetForeColor(colour==clrNONE ? this.ForeColor() : colour,true);
        obj.SetBorderColor(obj.ForeColor(),true);
        obj.SetBackgroundColor(CLR_CANV_NULL,true);
        obj.SetOpacity(0,false);
        break;
      //--- For "Button", "TabHeader", TabField and "ListBoxItem" WinForms objects
      case GRAPH_ELEMENT_TYPE_WF_BUTTON               :
      case GRAPH_ELEMENT_TYPE_WF_TAB_HEADER           :
      case GRAPH_ELEMENT_TYPE_WF_TAB_FIELD            :
      case GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM        :
        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;
      //--- For "ListBox", "CheckedListBox" and "ButtonListBox" WinForms object
      case GRAPH_ELEMENT_TYPE_WF_LIST_BOX             :
      case GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX     :
      case GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX      :
        obj.SetBackgroundColor(colour==clrNONE ? CLR_DEF_CONTROL_STD_BACK_COLOR : colour,true);
        obj.SetBorderColor(CLR_DEF_BORDER_COLOR,true);
        obj.SetForeColor(CLR_DEF_FORE_COLOR,true);
        break;
      //--- For "TabControl" WinForms object
      case GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL          :
        obj.SetBackgroundColor(colour==clrNONE ? CLR_DEF_CONTROL_TAB_BACK_COLOR : colour,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_TAB_BORDER_COLOR,true);
        obj.SetForeColor(CLR_DEF_FORE_COLOR,true);
        obj.SetOpacity(CLR_DEF_CONTROL_TAB_OPACITY);
        break;
      //--- For "SplitContainer" WinForms object
      case GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER      :
        obj.SetBackgroundColor(colour==clrNONE ? CLR_CANV_NULL : colour,true);
        obj.SetBorderColor(CLR_CANV_NULL,true);
        obj.SetForeColor(CLR_DEF_FORE_COLOR,true);
        obj.SetOpacity(0);
        break;
      //--- For "SplitContainerPanel" WinForms object
      case GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER_PANEL:
        obj.SetBackgroundColor(colour==clrNONE ? CLR_DEF_CONTROL_SPLIT_CONTAINER_BACK_COLOR : colour,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_SPLIT_CONTAINER_BORDER_COLOR,true);
        obj.SetForeColor(CLR_DEF_FORE_COLOR,true);
        break;
      //--- For "Splitter" WinForms object
      case GRAPH_ELEMENT_TYPE_WF_SPLITTER             :
        obj.SetBackgroundColor(colour==clrNONE ? CLR_CANV_NULL : colour,true);
        obj.SetBorderColor(CLR_CANV_NULL,true);
        obj.SetForeColor(CLR_DEF_FORE_COLOR,true);
        obj.SetOpacity(0);
        obj.SetDisplayed(false);
        obj.Hide();
        break;
      //--- For the "ArrowButton" WinForms object
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON         :
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP      :
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN    :
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT    :
      case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT   :
        obj.SetBorderColor(CLR_DEF_CONTROL_TAB_HEAD_BORDER_COLOR,true);
        obj.SetBorderStyle(FRAME_STYLE_SIMPLE);
        break;
      //--- For "Hint" WinForms object
      case GRAPH_ELEMENT_TYPE_WF_HINT_BASE            :
        obj.SetBackgroundColor(CLR_CANV_NULL,true);
        obj.SetBorderColor(CLR_CANV_NULL,true);
        obj.SetForeColor(CLR_CANV_NULL,true);
        obj.SetOpacity(0,false);
        obj.SetBorderStyle(FRAME_STYLE_NONE);
        break;
      //--- For "HintMoveLeft", "HintMoveRight", "HintMoveUp" and "HintMoveDown" WinForms object 
      case GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT       :
      case GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT      :
      case GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP         :
      case GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN       :
        obj.SetBackgroundColor(CLR_CANV_NULL,true);
        obj.SetBorderColor(CLR_CANV_NULL,true);
        obj.SetForeColor(CLR_DEF_CONTROL_HINT_FORE_COLOR,true);
        obj.SetOpacity(0,false);
        obj.SetBorderStyle(FRAME_STYLE_NONE);
        break;
      //--- For ToolTip WinForms object
      case GRAPH_ELEMENT_TYPE_WF_TOOLTIP              :
        obj.SetBackgroundColor(CLR_DEF_CONTROL_HINT_BACK_COLOR,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_HINT_BORDER_COLOR,true);
        obj.SetForeColor(CLR_DEF_CONTROL_HINT_FORE_COLOR,true);
        obj.SetBorderStyle(FRAME_STYLE_SIMPLE);
        obj.SetOpacity(0,false);
        obj.SetDisplayed(false);
        obj.Hide();
        break;
      //--- For BarProgressBar WinForms object
      case GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR     :
        obj.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BAR_COLOR,true);
        obj.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
        obj.SetBorderStyle(FRAME_STYLE_NONE);
        break;
      //--- For ProgressBar WinForms object
      case GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR         :
        obj.SetBackgroundColor(CLR_DEF_CONTROL_PROGRESS_BAR_BACK_COLOR,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_PROGRESS_BAR_BORDER_COLOR,true);
        obj.SetForeColor(CLR_DEF_CONTROL_PROGRESS_BAR_FORE_COLOR,true);
        obj.SetBorderStyle(FRAME_STYLE_SIMPLE);
        break;
      //--- For ScrollBar WinForms object
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR           :
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL:
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL  :
        obj.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BACK_COLOR,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BORDER_COLOR,true);
        obj.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_COLOR,true);
        obj.SetBorderSizeAll(1);
        obj.SetBorderStyle(FRAME_STYLE_SIMPLE);
        break;
      //--- For the ScrollBarThumb WinForms object
      case GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB     :
        obj.SetBackgroundColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_COLOR,true);
        obj.SetBorderColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_BORDER_COLOR,true);
        obj.SetForeColor(CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_COLOR,true);
        obj.SetBorderSizeAll(0);
        obj.SetBorderStyle(FRAME_STYLE_NONE);
        break;
      //--- For GlareObj WinForms object
      case GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ            :
        obj.SetBackgroundColor(CLR_CANV_NULL,true);
        obj.SetBorderColor(CLR_CANV_NULL,true);
        obj.SetForeColor(CLR_CANV_NULL,true);
        obj.SetBorderStyle(FRAME_STYLE_NONE);
        break;
      default:
        break;
     }
   obj.Crop();
  }
//+------------------------------------------------------------------+

对于附着到容器的每个已创建对象,此处都有一个代码模块,用于设置显示对象所需的最小参数。

由于容器对象中的对象可以按给定顺序自动排列,或根据容器的大小调整其大小,因此必须以这种方式从所处理对象中删除滚动条,因为它们是容器对象的组成部分,而不是其内容。

在调整元素大小以适应其内部内容的方法中,排除滚动条对象

//+--------------------------------------------+
//| Adjust the element size to fit its content |
//+--------------------------------------------+
bool CContainer::AutoSizeProcess(const bool redraw)
  {
//--- Get the list of bound objects with WinForms type basic and higher
   CArrayObj *list=this.GetListWinFormsObj();
   int maxcX=0;
   int maxcY=0;
//--- Calculate the maximum coordinate of the right and bottom edge from all bound objects
   for(int i=0;i<list.Total();i++)
     {
      CWinFormBase *obj=list.At(i);
      if(obj==NULL || 
         obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR             || 
         obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL  || 
         obj.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL
        ) continue;
      if(obj.RightEdge()>maxcX)
         maxcX=obj.RightEdge();
      if(obj.BottomEdge()>maxcY)
         maxcY=obj.BottomEdge();
     }
//--- Calculate the required width and height of the panel after adjusting its size to the content
   int w=maxcX-this.CoordX();
   int h=maxcY-this.CoordY();
//--- Calculate the number of pixels, by which we need to resize the container in width and height
   int excess_x=w-this.WidthWorkspace()-this.BorderSizeRight()-1;
   int excess_y=h-this.HeightWorkspace()-this.BorderSizeBottom()-1;
//--- If failed to change the container size, return 'true'
   if(excess_x==0 && excess_y==0)
      return true;
//--- Return the result of resizing the container
   return
     (
      //--- In case of size increase only
      this.AutoSizeMode()==CANV_ELEMENT_AUTO_SIZE_MODE_GROW ? 
      this.Resize(this.Width()+(excess_x>0  ? excess_x : 0),this.Height()+(excess_y>0  ? excess_y : 0),redraw) :
      //--- if both increase and decrease
      this.Resize(this.Width()+(excess_x!=0 ? excess_x : 0),this.Height()+(excess_y!=0 ? excess_y : 0),redraw)
     );
  }
//+------------------------------------------------------------------+

该方法为当前对象设置新尺寸:

//+--------------------------------------------+
//| Set the new size for the current object    |
//+--------------------------------------------+
bool CContainer::Resize(const int w,const int h,const bool redraw)
  {
//--- If it was not possible to change the size of the container, return 'false'
   if(!CWinFormBase::Resize(w,h,redraw))
      return false;

//--- Get the vertical scrollbar and
   CWinFormBase *scroll_v=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL,0);
   if(scroll_v!=NULL)
     {
      //--- change the vertical size to the size of the container workspace
      scroll_v.Resize(scroll_v.Width(),this.HeightWorkspace(),false);
      //--- Move the vertical scrollbar to new coordinates
      if(scroll_v.Move(this.RightEdgeWorkspace()-scroll_v.Width(),this.CoordYWorkspace()))
        {
         scroll_v.SetCoordXRelative(scroll_v.CoordX()-this.CoordX());
         scroll_v.SetCoordYRelative(scroll_v.CoordY()-this.CoordY());
        }
      //--- Get a button object with the down arrow from the vertical scrollbar object
      CWinFormBase *arr_d=scroll_v.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,0);
      //--- If the button has been received
      if(arr_d!=NULL)
        {
         //--- Move it to the bottom edge of the vertical scrollbar
         if(arr_d.Move(arr_d.CoordX(),scroll_v.BottomEdge()-scroll_v.BorderSizeBottom()-2*arr_d.Height()))
           {
            arr_d.SetCoordXRelative(arr_d.CoordX()-scroll_v.CoordX());
            arr_d.SetCoordYRelative(arr_d.CoordY()-scroll_v.CoordY());
           }
        }
     }
//--- Get the horizontal scrollbar and
   CWinFormBase *scroll_h=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL,0);
   if(scroll_h!=NULL)
     {
      //--- change the horizontal size to the size of the container workspace
      scroll_h.Resize(this.WidthWorkspace(),scroll_h.Height(),false);
      //--- Move the horizontal scrollbar to new coordinates
      if(scroll_h.Move(this.CoordXWorkspace(),this.BottomEdgeWorkspace()-scroll_h.Height()))
        {
         scroll_h.SetCoordXRelative(scroll_h.CoordX()-this.CoordX());
         scroll_h.SetCoordYRelative(scroll_h.CoordY()-this.CoordY());
        }
      //--- Get a button object with the right arrow from the horizontal scrollbar object
      CWinFormBase *arr_r=scroll_h.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,0);
      //--- If the button has been received
      if(arr_r!=NULL)
        {
         //--- Move it to the right edge of the horizontal scrollbar
         if(arr_r.Move(scroll_h.RightEdge()-BorderSizeRight()-2*arr_r.Width(),arr_r.CoordY()))
           {
            arr_r.SetCoordXRelative(arr_r.CoordX()-scroll_h.CoordX());
            arr_r.SetCoordYRelative(arr_r.CoordY()-scroll_h.CoordY());
           }
        }
     }
   return true;
  }
//+------------------------------------------------------------------+

此虚拟方法调整容器对象的大小。 我们把从 WinForms 对象的基类中删除的代码模块移到其中。 首先,调用 WinForms 对象调整大小方法。 然后,如果成功,将两个滚动条的大小和坐标调整为容器的新大小和坐标

我们改进位于 \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh 里的图形元素集合类。

我们需要向函数库发送一条消息,说明它在移动捕获区域对象(滚动条滑块)时的移动,以便调用其事件处理程序。 我们已拥有了一切 — 我们已经可以在 SplitContainer 对象中移动隔板。 这意味着我们需要将移动和滑块处理添加到处理隔板移动的代码方法之中。

在隔板事件处理模块程序中添加滑块处理

      //--- In case of the mouse movement event
      if(id==CHARTEVENT_MOUSE_MOVE)
        {
         //--- If the cursor is above the form
         if(::CheckPointer(form)!=POINTER_INVALID)
           {
            //--- If the move flag is set
            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)
                 {
                  //--- If the form is a separator object,
                  if(form.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_SPLITTER || form.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB)
                    {
                     //--- get its base object
                     CWinFormBase *base=form.GetBase();
                     if(base==NULL)
                        return;
                     //--- and send the "Object movement" event to the event handler of the base object
                     const long lp=x;
                     const double dp=y;
                     base.OnChartEvent(WF_CONTROL_EVENT_MOVING,lp,dp,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 to the right, no mouse buttons are clicked' event handler  |
            //+------------------------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED,lparam,dparam,sparam);
              }
            //+------------------------------------------------------------------------------------------------------------+
            //|'The cursor is inside the window scrolling area to the right, a mouse button is clicked (any)' event handler|
            //+------------------------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_PRESSED)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_PRESSED,lparam,dparam,sparam);
              }
            //+--------------------------------------------------------------------------------------------------------------+
            //|'The cursor is inside the window scrolling area to the right, the mouse wheel is being scrolled' event handler|
            //+--------------------------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_WHEEL)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_WHEEL,lparam,dparam,sparam);
              }
            //+-------------------------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the window scrolling area at the bottom, no mouse buttons are clicked' event handler  |
            //+-------------------------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED,lparam,dparam,sparam);
              }
            //+-------------------------------------------------------------------------------------------------------------+
            //|'The cursor is inside the window scrolling area at the bottom, a mouse button is clicked (any)' event handler|
            //+-------------------------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_PRESSED)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_PRESSED,lparam,dparam,sparam);
              }
            //+---------------------------------------------------------------------------------------------------------------+
            //|'The cursor is inside the window scrolling area at the bottom, the mouse wheel is being scrolled' event handler|
            //+---------------------------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_WHEEL)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_WHEEL,lparam,dparam,sparam);
              }
            //+---------------------------------------------------------------------------------------------+
            //| 'The cursor is inside the control area, no mouse buttons are clicked' event handler         |
            //+---------------------------------------------------------------------------------------------+
            if(mouse_state==MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_NOT_PRESSED)
              {
               form.OnMouseEvent(MOUSE_EVENT_INSIDE_CONTROL_AREA_NOT_PRESSED,lparam,dparam,sparam);
              }
            //+---------------------------------------------------------------------------------------------+


测试

为了执行测试,我将沿用上一篇文章中的 EA,并将其保存在 \MQL5\Experts\TestDoEasy\Part130\ 中,命名为 TestDoEasy130.mq5

只需注释掉面板上所有对象的创建,并只用一个大按钮即可测试面板上滚动条的功能。

//+--------------------------------------------+
//| 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 the required number of WinForms Panel objects
   CPanel *pnl=NULL;
   for(int i=0;i<FORMS_TOTAL;i++)
     {
      pnl=engine.CreateWFPanel("WinForms Panel"+(string)i,(i==0 ? 50 : 70),(i==0 ? 50 : 70),410,200,array_clr,200,true,true,false,-1,FRAME_STYLE_BEVEL,true,false);
      if(pnl!=NULL)
        {
         pnl.Hide();
         //--- Set Padding to 4
         pnl.SetPaddingAll(3);
         //--- 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);

         //---
         pnl.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_BUTTON,10,10,pnl.WidthWorkspace()-20,pnl.HeightWorkspace()-20,clrNONE,255,true,false);
         /*
         //--- Create TabControl
         pnl.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,InpTabControlX,InpTabControlY,pnl.Width()-30,pnl.Height()-40,clrNONE,255,true,false);
         CTabControl *tc=pnl.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,0);
         if(tc!=NULL)
           {
            tc.SetTabSizeMode((ENUM_CANV_ELEMENT_TAB_SIZE_MODE)InpTabPageSizeMode);
            tc.SetAlignment((ENUM_CANV_ELEMENT_ALIGNMENT)InpHeaderAlignment);
            tc.SetMultiline(InpTabCtrlMultiline);
            tc.SetHeaderPadding(6,0);
            tc.CreateTabPages(15,0,56,20,TextByLanguage("Вкладка","TabPage"));
            
            //--- Create Tooltip for the Left button
            tc.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_TOOLTIP,0,0,10,10,clrNONE,0,false,false);
            CToolTip *tooltip=tc.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TOOLTIP,0);
            if(tooltip!=NULL)
              {
               tooltip.SetDescription("Left Button Tooltip");
               tooltip.SetIcon(InpTooltipIcon);
               tooltip.SetTitle(InpTooltipTitle);
               tooltip.SetTooltipText(TextByLanguage("Нажмите для прокрутки заголовков вправо","Click to scroll headings to the right"));
               tc.AddTooltipToArrowLeftButton(tooltip);
              }
            //--- Create Tooltip for the Right button
            tc.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_TOOLTIP,0,0,10,10,clrNONE,0,false,false);
            tooltip=tc.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TOOLTIP,1);
            if(tooltip!=NULL)
              {
               tooltip.SetDescription("Right Button Tooltip");
               tooltip.SetIcon(ENUM_CANV_ELEMENT_TOOLTIP_ICON(InpTooltipIcon+1));
               tooltip.SetTitle(InpTooltipTitle);
               tooltip.SetTooltipText(TextByLanguage("Нажмите для прокрутки заголовков влево","Click to scroll headings to the left"));
               tc.AddTooltipToArrowRightButton(tooltip);
              }
              
            //--- Create a text label with a tab description on each tab
            for(int j=0;j<tc.TabPages();j++)
              {
               tc.CreateNewElement(j,GRAPH_ELEMENT_TYPE_WF_LABEL,322,120,80,20,clrDodgerBlue,255,true,false);
               CLabel *label=tc.GetTabElementByType(j,GRAPH_ELEMENT_TYPE_WF_LABEL,0);
               if(label==NULL)
                  continue;
               //--- If this is the very first tab, then there will be no text
               label.SetText(j<5 ? "" : "TabPage"+string(j+1));
              }
            for(int n=0;n<5;n++)
              {
               //--- Create a SplitContainer control on each tab
               tc.CreateNewElement(n,GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,10,10,tc.Width()-22,tc.GetTabField(0).Height()-22,clrNONE,255,true,false);
               //--- Get the SplitContainer control from each tab
               CSplitContainer *split_container=tc.GetTabElementByType(n,GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,0);
               if(split_container!=NULL)
                 {
                  //--- The separator will be vertical for each even tab and horizontal for each odd one
                  split_container.SetSplitterOrientation(n%2==0 ? CANV_ELEMENT_SPLITTER_ORIENTATION_VERTICAL : CANV_ELEMENT_SPLITTER_ORIENTATION_HORISONTAL,true);
                  //--- The separator distance on each tab will be 50 pixels
                  split_container.SetSplitterDistance(50,true);
                  //--- The width of the separator on each subsequent tab will increase by 2 pixels
                  split_container.SetSplitterWidth(6+2*n,false);
                  //--- Make a fixed separator for the tab with index 2, and a movable one for the rest
                  split_container.SetSplitterFixed(n==2 ? true : false);
                  //--- For a tab with index 3, the second panel will be in a collapsed state (only the first one is visible)
                  if(n==3)
                     split_container.SetPanel2Collapsed(true);
                  //--- For a tab with index 4, the first panel will be in a collapsed state (only the second one is visible)
                  if(n==4)
                     split_container.SetPanel1Collapsed(true);
                  
                  //--- On each of the control panels...
                  for(int j=0;j<2;j++)
                    {
                     //--- Get the panel by loop index
                     CSplitContainerPanel *panel=split_container.GetPanel(j);
                     if(panel==NULL)
                        continue;
                     //--- set its description for the panel
                     panel.SetDescription(TextByLanguage("Панель","Panel")+string(j+1));
                     
                     //--- If this is the first tab and the second panel
                     if(n==0 && j==1)
                       {
                        //--- Create the ProgressBar control on it
                        if(split_container.CreateNewElement(j,GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,4,4,100,12,clrNONE,255,false,false))
                          {
                           CProgressBar *progress_bar=split_container.GetPanelElementByType(j,GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,0);
                           if(progress_bar!=NULL)
                             {
                              //--- Set the style of the progress bar specified in the EA settings
                              progress_bar.SetStyle((ENUM_CANV_ELEMENT_PROGRESS_BAR_STYLE)InpProgressBarStyle);
                              //--- Set the parameters for describing the progress bar
                              progress_bar.SetBarDescriptionText("Progress Bar ");
                              progress_bar.SetBarDescriptionColor(panel.BackgroundColor());
                              progress_bar.SetBarDescriptionOpacity(255);
                              progress_bar.SetBarDescriptionY(-2);
                             }
                          }
                       }
                     
                     //--- ...create a text label with the panel name
                     if(split_container.CreateNewElement(j,GRAPH_ELEMENT_TYPE_WF_LABEL,4,4,panel.Width()-8,panel.Height()-8,clrDodgerBlue,255,true,false))
                       {
                        CLabel *label=split_container.GetPanelElementByType(j,GRAPH_ELEMENT_TYPE_WF_LABEL,0);
                        if(label==NULL)
                           continue;
                        label.SetTextAlign(ANCHOR_CENTER);
                        label.SetText(panel.Description());
                       }
                    }
                 }
              }
           }
         */
        }
     }
//--- Display and redraw all created panels
   for(int i=0;i<FORMS_TOTAL;i++)
     {
      //--- Get the panel object
      pnl=engine.GetWFPanel("WinForms Panel"+(string)i);
      if(pnl!=NULL)
        {
         //--- display and redraw the panel
         pnl.Show();
         pnl.Redraw(true);
         //--- Get the pointer to the vertical scrollbar object of the main panel
         CScrollBarVertical *sbv=pnl.GetElementByType(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL,0);
         //--- Set the display flag for the object and show the scrollbar
         sbv.SetDisplayed(true);
         sbv.Show();
         sbv.BringToTop();
         sbv.Redraw(true);
         //--- Get the pointer to the horizontal scrollbar object of the main panel
         CScrollBarHorisontal *sbh=pnl.GetElementByType(GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL,0);
         //--- Set the display flag for the object and show the scrollbar
         sbh.SetDisplayed(true);
         sbh.Show();
         sbh.BringToTop();
         sbh.Redraw(true);
         /*
         //--- Get the TabControl object from the panel
         CTabControl *tc=pnl.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,0);
         //--- Get the SplitContainer object from the first tab of the TabControl object
         CSplitContainer *sc=tc.GetTabElementByType(0,GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,0);
         //--- Get the second panel from the SplitContainer object
         CSplitContainerPanel *scp=sc.GetPanel(1);
         //--- Get the ProgressBar object from the received panel
         CProgressBar *pb=scp.GetElementByType(GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,0);
         //--- Waiting
         Sleep(1);
         //--- Get the width of the ProgressBar object
         int w=pb.Width();
         //--- In the loop, increase the width of the ProgressBar by 180 pixels
         for(int n=0;n<180;n++)
           {
            //Sleep(1);
            pb.Resize(w+n,pb.Height(),true);
           }
         //--- Set the values for PerformStep of the ProgressBar object
         pb.SetValuesForProcessing(0,350,1,0);
         //--- Reset ProgressBar to minimum
         pb.ResetProgressBar();
         //--- If the style of the progress bar is "Continuous line", display the progress bar description
         if(pb.Style()==CANV_ELEMENT_PROGRESS_BAR_STYLE_CONTINUOUS)
            pb.ShowBarDescription();
         //--- Waiting
         Sleep(1);
         //--- If the style of the progress bar is not "Continuous scrolling"
         if(pb.Style()!=CANV_ELEMENT_PROGRESS_BAR_STYLE_MARQUEE)
           {
            //--- In the loop from the minimum to the maximum value of ProgressBar
            for(int n=0;n<=pb.Maximum();n++)
              {
               //--- call the method for increasing the progress bar by a given step with a wait of 1/5 second
               pb.PerformStep();
               //--- Set the number of completed steps in the description of the progress bar
               pb.SetBarDescriptionText("Progress Bar, pass: "+(InpProgressBarPercent ? pb.ValuePercentDescription() : pb.ValueDescription()));
               Sleep(1);
              }
           }
         //--- Wait, set the description font type to Bold and write a completion message on the progress bar
         Sleep(1);
         pb.SetBarDescriptionFontFlags(FW_BOLD);
         pb.SetBarDescriptionText("Progress Bar: Done");
         //--- Set the glare object type - rectangle, opacity 40, color - white
         pb.SetGlareStyle(CANV_ELEMENT_VISUAL_EFF_STYLE_RECTANGLE);
         pb.SetGlareOpacity(40);
         pb.SetGlareColor(clrWhite);
         */
        }
     }
        
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

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


如我们所见,滑块在滚动条内被箭头按钮正确限制。 箭头按钮响应单击,对象的颜色根据对象和光标在交互过程中的状态而变化。

这里还有一个瑕疵:当我们选中任何对象时,其与界面分界的滚动条边框会消失。 发生这种情况是由于重绘对象,以及滚动条位于其它对象下层的事实,因为它们是先创建的,并且没有优先级。 在滚动条上选择要单击的箭头按钮也很困难。 这出于同样的原因,先创建对象,稍后创建的其它对象(大按钮)会覆盖它们。 我稍后会修复这一点。 目前,重要的是要看到瑕疵,了解原因,以及需要采取哪些措施来消除它们。


下一步是什么?

在下一篇文章中,我将继续开发 ScrollBar 对象。

返回内容目录

*该系列的前几篇文章:

 
DoEasy. 控件 (第 26 部分): 完成 ToolTip(工具提示)WinForms 对象,并转移至 ProgressBar(进度条)开发
DoEasy. 控件 (第 27 部分): 继续致力 ProgressBar(进度条)WinForms 对象
DoEasy. 控件 (第 28 部分): 进度条控件中的柱线样式
DoEasy. 控件 (第 29 部分): 滚动条(ScrollBar)辅助控件

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

附加的文件 |
MQL5.zip (4545.72 KB)
数据科学与机器学习(第 10 部分):岭回归 数据科学与机器学习(第 10 部分):岭回归
岭回归是一种简单的技术,可降低模型复杂度,并防止简单线性回归可能导致的过度拟合。
矩阵实用工具,扩展矩阵和向量的标准库功能 矩阵实用工具,扩展矩阵和向量的标准库功能
矩阵作为机器学习算法和计算机的基础,因为它们能够有效地处理大型数学运算,标准库拥有所需的一切,但让我们看看如何在实用工具文件中引入若干个函数来扩展它,这些函数在标准库中尚未提供。
种群优化算法:萤火虫算法(FA) 种群优化算法:萤火虫算法(FA)
在本文中,我将研究萤火虫算法(FA)优化方法。 致谢优化修订,该算法已从局外人变成了评级表上的真正领先者。
MQL5 中的范畴论 (第 1 部分) MQL5 中的范畴论 (第 1 部分)
范畴论是数学的一个多样化和不断扩展的分支,到目前为止,在 MQL 社区中还相对难以发现。 这些系列文章旨在介绍和研究其一些概念,其总体目标是建立一个开放的函数库,吸引评论和研讨,同时希望在交易者的策略开发中进一步在运用这一非凡的领域。