DoEasy. 控件(第三十部分):动画态滚动条控件
内容
概述
在上一篇文章中,我启动了滚动条(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 个像素是一个足够的奇数,箭头的三角形能均匀且美观地在上面绘制。 通常,在调整对象的大小时,在其上绘制围绕其中心轴勾勒的造型,我们应该始终尝试使用奇数个像素,以便绘图保持均匀整洁。 边角区域是窗体的一部分,其中光标被视为位于角落上。 例如,在调整对象大小时,如果光标位于四个边角之一上,我们可以一次性修改其大小的两个参数(高度和宽度)。
将新值添加到相对于造型的可能鼠标状态列表之中。 对象尺寸可以在八个方向上调整大小:
- 当光标位于对象的上边缘时,我们可以向上移动边缘来更改其高度,
- 当光标位于对象的底部边缘时,我们可以向下移动边缘来更改其高度,
- 当光标位于对象的左边缘时,我们可以向左移动边缘来更改其宽度,
- 当光标位于对象的右边缘时,我们可以向右移动边缘来更改其宽度,
- 当光标位于对象的左上角时,我们可以向上和向左移动来更改其高度和宽度,
- 当光标位于对象的右上角时,我们可以向上和向右移动来更改其高度和宽度,
- 当光标位于对象的左下角时,我们可以通过向下和向左移动来更改其高度和宽度,
- 当光标位于对象的右下角时,我们可以向下和向右移动来更改其高度和宽度,
具有可滚动内容的容器,在其右侧和底部将会有滚动条。 我们需要判定光标在哪个滚动条上 — 在右侧或底部,并把这些状态设置为鼠标状态:
//+------------------------------------------------------------------+ //| 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.mqh、CheckBox.mqh 和 SplitContainer.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.mqh、ArrowDownButton.mqh 和 ArrowUpButton.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