English Русский 中文 Español 日本語 Português
preview
DoEasy. Steuerung (Teil 30): Animieren des ScrollBar-Steuerelements

DoEasy. Steuerung (Teil 30): Animieren des ScrollBar-Steuerelements

MetaTrader 5Beispiele | 10 Februar 2023, 14:41
271 0
Artyom Trishkin
Artyom Trishkin

Inhalt


Konzept

Im vorherigen Artikel habe ich mit der Entwicklung des ScrollBar-Hilfssteuerelements begonnen. Im aktuellen Artikel werde ich die Interaktion der Steuerelemente mit der Maus implementieren. Die konstituierenden Elemente des WinForms ScrollBar-Objekts sind die Scroll-Schaltflächen und der Erfassungsbereich. Für die Bildlauftasten haben wir separate Klassen von Hilfsobjekten (Pfeiltasten), aber wir haben den Erfassungsbereich in Form einer einfachen Schaltfläche erstellt. Hier werde ich eine separate Klasse implementieren, die auf dem Button-Objekt basiert, um ein Objekt zur Bereichserfassung zu erstellen. Um die Ereignisse eines Schiebereglers korrekt zu behandeln, sollte das Objekt einen eigenen Typ haben. Daher wird es vom Schaltflächenobjekt abgeleitet - es erbt dessen Eigenschaften und wird ein unabhängiges Objekt mit einem eindeutigen Typ.

Zum größten Teil werde ich einige Vorbereitungen treffen, um Funktionen für die Größenänderung von Steuerelementen und die Handhabung von Mausinteraktionen mit Bildlaufleisten zu erstellen. Erweitern wir die Liste der Mauszustände und ihrer Ereignisse. All dies wird es mir ermöglichen, Kontrollen und ihre Funktionalität zu entwickeln, ohne durch Routinearbeiten in nachfolgenden Artikeln abgelenkt zu werden.


Verbesserung der Bibliotheksklassen

In \MQL5\Include\DoEasy\Defines.mqh fügen wir die Standardfarbkonstanten für die ScrollBar-Objektzustände hinzu:

#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

Jeder Bildlaufbereich hat eine Breite. Im Falle der vertikalen Bildlaufleiste ist dies die Breite des Objekts, im Falle der horizontalen Bildlaufleiste seine Höhe. Wir setzen den Standardwert 11 für diesen Parameter ein. Die Bildlaufleiste hat einen Rand, der sie von der Oberfläche trennt, wenn sie überlagert wird. Bei einem Breitenwert von 11 Pixeln beträgt der aktive Bereich der Bildlaufleiste 9 Pixel (ein Pixel pro Rand, oben, unten, links und rechts). Da die Pfeilschaltflächen und der Schieberegler auf der Bildlaufleiste aufgebaut werden sollen, sind 9 Pixel eine ausreichende ungerade Zahl, auf der das Pfeildreieck gleichmäßig und schön gezeichnet wird. Im Allgemeinen sollten wir bei der Größenänderung von Objekten, auf denen die Formen um ihre Mittelachse herum gezeichnet werden, immer versuchen, eine ungerade Anzahl von Pixeln zu verwenden, damit die Zeichnung gleichmäßig und ordentlich bleibt. Der Eckbereich ist ein Teil des Formulars, bei dem davon ausgegangen wird, dass sich der Cursor in der Ecke befindet. Befindet sich beispielsweise der Cursor bei der Größenänderung eines Objekts auf einer der vier Ecken, können wir zwei Parameter der Größe (Höhe und Breite) gleichzeitig ändern.

Hinzufügen neuer Werte zur Liste der möglichen Mauszustände in Bezug auf die Form. Die Größe von Objekten kann in acht Richtungen geändert werden:

  1. Wenn sich der Cursor auf der oberen Kante eines Objekts befindet, können wir seine Höhe ändern, indem wir die Kante nach oben verschieben.
  2. Wenn sich der Cursor auf der unteren Kante eines Objekts befindet, können wir seine Höhe ändern, indem wir die Kante nach unten verschieben.
  3. Wenn sich der Cursor auf dem linken Rand des Objekts befindet, können wir seine Breite ändern, indem wir den Rand nach links verschieben.
  4. Wenn sich der Cursor auf dem rechten Rand eines Objekts befindet, können wir seine Höhe ändern, indem wir den Rand nach rechts verschieben.
  5. Wenn sich der Cursor in der oberen linken Ecke des Objekts befindet, können wir seine Höhe und Breite ändern, indem wir ihn nach oben und nach links verschieben.
  6. Wenn sich der Cursor in der oberen rechten Ecke des Objekts befindet, können wir seine Höhe und Breite durch Verschieben nach oben und rechts ändern.
  7. Wenn sich der Cursor in der linken unteren Ecke des Objekts befindet, können wir die Höhe und Breite des Objekts ändern, indem wir es nach unten und nach links verschieben.
  8. Wenn sich der Cursor in der unteren rechten Ecke des Objekts befindet, können wir seine Höhe und Breite durch Verschieben nach unten und rechts ändern.

Der Container mit scrollbarem Inhalt wird rechts und unten mit Scrollbalken versehen. Wir müssen feststellen, auf welcher Bildlaufleiste sich der Cursor befindet - auf der rechten oder auf der unteren - und diese Zustände auf den Mausstatus setzen:

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

Alle diese neuen Zustände werden als Zustand der Maus relativ zum Objekt definiert und aufgezeichnet.

Wenn ein Mausereignis in einem der vordefinierten Zustände registriert wird, wird das entsprechende Ereignis an die Bibliothek gesendet, wo die dem Ereignis entsprechenden Handler in jedem der Objekte, die Mausereignisse verarbeiten, aufgerufen werden.
Tragen wir neue Zustände in die Liste der möglichen Mausereignisse ein:

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

Der Liste der grafischen Elementtypen fügen wir einen neuen Elementtyp hinzu:

//+--------------------------------------------+
//| The list of graphical element types        |
//+--------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_STANDARD,                       // Standard graphical object
   GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED,              // Extended standard graphical object
   GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                     // Shadow object
   GRAPH_ELEMENT_TYPE_ELEMENT,                        // Element
   GRAPH_ELEMENT_TYPE_FORM,                           // Form
   GRAPH_ELEMENT_TYPE_WINDOW,                         // Window
   //--- WinForms
   GRAPH_ELEMENT_TYPE_WF_UNDERLAY,                    // Panel object underlay
   GRAPH_ELEMENT_TYPE_WF_BASE,                        // Windows Forms Base
   //--- '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
  };
//+------------------------------------------------------------------+

Dies wird das neue Hilfssteuerelement „Erfassungsbereich“ (Capture Area, Schieberegler) sein.

Hinzufügen von zwei neuen Eigenschaften in der Enumeration der ganzzahligen Eigenschaften eines grafischen Elements und Erhöhung ihrer Gesamtzahl von 138 auf 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
//+------------------------------------------------------------------+

Jedes der grafischen Elemente hat eine Markierung, die anzeigt, dass es mit der Maus in der Größe verändert werden kann. Die auf dem Element gezeichneten Pfeile (z. B. eine Schaltfläche mit einem Pfeil) haben die durch diesen Parameter festgelegten relativen Größen. Ein Pfeil mit einer Größe von 1 wird beispielsweise vom Mittelpunkt aus mit einem Scheitelpunkt-Einzug von 1 Pixel gezeichnet. Ein Pfeil mit einer Größe von 2 wird vom Mittelpunkt aus gezeichnet im Abstand von zwei Pixel usw.

Zum Beispiel, der Pfeil nach oben mit der Größe 1:

⊡⊠⊡
⊠⊠⊠

Der Pfeil nach oben mit der Größe von 2:

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

Der Pfeil nach oben mit der Größe von 3:

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

Wenn wir ein Pixel in der Mitte der Basis des Dreiecks als Mittelpunkt nehmen und die Anzahl der Pixel gleich der relativen Größe der Form zu jeder ihrer Seiten setzen, erhalten wir drei Eckpunkte des Dreiecks, entlang derer die Figur aufgebaut ist. Die Größe eines Dreiecks ist also die Anzahl der Pixel von der Mitte der Basis des Dreiecks nach oben, links und rechts, um die Koordinaten jedes Scheitelpunkts anzugeben.

Die Pfeile nach unten, links und rechts sind auf ähnliche Weise aufgebaut.

In \MQL5\Include\DoEasy\Data.mqh wurden neuen Nachrichtenindizes hinzugefügt:

   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

und die Textnachrichten, die den neu hinzugefügten Indizes entsprechen:

   {"Элемент управления \"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


Um die neue Typenbeschreibung des Objektes anzuzeigen, fügen wir in \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh, und zwar in der Methode TypeElementDescription(), eine Zeichenfolge hinzu, die die Beschreibung des an die Methode übergebenen Objekttyps zurückgibt:

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

Jedes Mal, wenn eine neue Eigenschaft zur Enumeration der Eigenschaften eines grafischen Elements hinzugefügt wird, sollte sie der Objektstruktur hinzugefügt werden. Die Struktur eines grafischen Objekts wird verwendet, um die Eigenschaften von grafischen Elementen in einer Datei zu speichern und aus der Datei zu lesen. Dies ist notwendig, um die Objekte nach dem Neustart wiederherzustellen, sodass sie sich in demselben Zustand befinden wie vor dem Beenden. Bisher haben wir eine solche Funktion aufgrund der sich ständig ändernden Konstellation der Eigenschaften von grafischen Objekten nicht realisiert. Aber ich bin bereits dabei, eine solche Struktur für die Zukunft zu schaffen.

In \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh fügen wir die neue Eigenschaften zu der Objektstruktur hinzu:

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

Im öffentlichen Teil der Klasse deklarieren wir neue Methoden, die Flags für die Position des Cursors relativ zum grafischen Element zurückgeben:

//--- 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,

Im Methodenblock für den vereinfachten Zugriff auf die Objekteigenschaften setzen wir die Methoden, die die Koordinaten neuer Bereiche und grafischer Elementzonen zurückgeben, sowie die Methode, die das Flag für die Größenänderbarkeit zurückgibt:

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

Fügen wir der Methode, die das Flag für die Veränderbarkeit der Elementgröße zurückgibt hinzu:

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

Wir ändern die Deklaration der Pfeilzeichnungsmethoden:

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

Jetzt erhalten die Methoden die Koordinaten des zentralen Punktes und die relative Pfeilgröße.

In der Methode zur Initialisierung der Objekteigenschaften setzen wir die Standardwerte für die Breite der Bereiche des oberen, unteren, linken und rechten Objektrandes auf zwei Pixel, um festzulegen, ob sich der Mauszeiger in diesen Bereichen befindet. Standardmäßig ist die Möglichkeit, die Größe des Objekts mit dem Mauszeiger zu ändern, deaktiviert, und die Größe des gezeichneten Pfeils beträgt 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
  }
//+------------------------------------------------------------------+

In der Methode, die die Struktur des Objekts erstellt, setzen wir die Werte der neuen Objekteigenschaften auf die neuen Strukturfelder:

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

In der Methode, die ein Objekt aus einer Struktur erstellt, setzen wir die Werte der entsprechenden Strukturfelder auf die Werte der neuen Eigenschaften:

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

Implementierung der Methoden, die die Cursorpositionsflags relativ zu den Bildlaufbereichen zurückgeben und die Größe des Elements ändern:

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

Abhängig von den Koordinaten der Cursorposition geben die Methoden das Flag zurück, ob sich der Cursor innerhalb des durch seine Werte umrissenen Bereichs befindet.

Die Methoden zum Zeichnen von Pfeilen zeichnen nun Dreiecke in Abhängigkeit von der Startkoordinate (Zentrum der Dreiecksbasis) und der angegebenen Pfeilgröße:

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

Um die Koordinaten jedes Scheitelpunkts zu berechnen, addieren oder subtrahieren wir einfach die Größe des in den Parametern übergebenen Pfeils von den Koordinaten des zentralen Punkts.
Vergessen wir nicht, dass die Größe nur durch die untere Grenze (1), nicht aber durch die obere Grenze begrenzt ist. Hier müssen wir sicherstellen, dass der Pfeil in normaler Größe gezeichnet wird, da sich die tatsächliche Größe des Pfeils aus zwei angegebenen Größen + einem zentralen Pixel ergibt. Mit anderen Worten: Bei einer Größe von 1 ist die tatsächliche Größe 1+1+1. Bei einer Größe von 2 ist die tatsächliche Größe 2+1+2, bei einer Größe von 3: 3+1+3 usw.

Da wir nun neue Mauszustände in Bezug auf das Element und die entsprechenden Ereignisse haben, müssen diese in den Methoden zur Ereignisbehandlung des letzten Mausereignisses berücksichtigt werden.

Fügen wir in \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\Button.mqh die Liste der neuen Ereignisse zu der Methode hinzu:

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

Hier werden all diese Ereignisse nicht behandelt, aber falls erforderlich, kann die Behandlung unter jedem Ereignis hinzugefügt werden.

Die gleichen Änderungen an der Methode wurden bereits in TabHeader.mqh, CheckBox.mqh und SplitContainer.mqh vorgenommen.

Um die Farbe des gezeichneten Pfeils in der Klasse der Pfeilschaltflächen festzulegen, haben wir die private Variable m_arrow_color verwendet. Die Verwendung dieser Variable ist überflüssig, da wir die Methode ForeColor() verwenden können, um die Farbe festzulegen, die auch die Farbe des gezeichneten Textes steuern kann. Daher entfernen wir in \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ArrowButton.mqh die Variable und ihre Behandlungsmethoden:

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


Außerdem ersetzen wir den Aufruf von Remote-Methoden durch die Methoden zur Behandlung der Textfarbe:

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

In \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ArrowRightButton.mqh, nämlich in den Klassenkonstruktoren, setzen wir die Größe des gezeichneten Pfeils auf 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);
  }
//+------------------------------------------------------------------+

In der Methode, die den Pfeil zeichnet, ändern wir die Parameter, wenn wir die Methode zum Zeichnen des Pfeils aufrufen:

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

Als Mittelpunkt des Pfeils übergeben wir den Mittelpunkt des Objekts (horizontal um ein Pixel nach links verschieben) und geben die Größe des gezeichneten Pfeils in den Eigenschaften des Objekts an, seine Textfarbe und Deckkraft.

Ähnliche Änderungen wurden bereits in anderen Pfeiltasten-Objektklassen in ArrowLeftButton.mqh, ArrowDownButton.mqh und ArrowUpButton.mqh vorgenommen.

Zur vereinfachten Einstellung der Koordinaten und Größen der Bildlaufleistenbereiche fügen wir in der Datei \MQL5\Include\DoEasy\Objects\Graph\Form.mqh der Formularobjektklasse die öffentlichen Methoden hinzu:

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

In der Methode, die den Zustand der Maus in Bezug auf das Formular festlegt und zurückgibt, überprüfen wir die Position des Mauszeigers, vergleichen sie mit den Koordinaten der verschiedenen Bereiche des Formulars und weisen die Flags dieser Zustände der Variablen zu. Ferner wird auf der Grundlage dieser Flags der allgemeine Zustand des Mauszeigers in Bezug auf das Objekt ermittelt. Fügen wir die Codeblöcke der Methode für die Verfolgung der Position des Cursors relativ zu den Bildlaufleisten und Rändern hinzu, in deren Bereich es möglich ist, den Rand des Objekts mit der Maus zu greifen und zu ziehen, um die Größe des Elements zu ändern:

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

Alle Codeblöcke sind ausführlich kommentiert, und in der Tat ist alles einfach in ihnen - wir überprüfen die Position des Cursors Koordinaten relativ zu den Koordinaten der Bereiche, zum Beispiel, Scrollen, und wenn der Cursor innerhalb des Bereichs ist, setzen wir die entsprechende Flag. Wenn nicht, entfernen wir das Flag. Als Ergebnis der Überprüfung und des Setzens der Flags haben wir eine Reihe von Flags, mit denen wir entscheiden, wo sich der Mauszeiger befindet. Wenn die Flags für seine Position auf der oberen und rechten Seite des Objekts gesetzt sind, bedeutet dies, dass sich der Cursor in der oberen rechten Ecke befindet. Daher müssen wir die Flags kombinieren, da die Bits im ushort-Wert nicht ausreichen, um jedes Flag einzeln zu zuzuweisen.

Ändern wir in der Ereignishandlung der Maus den Aufruf der Ereignisbehandlungsmethoden für das Auffinden des Cursors im Bildlaufbereich. Da wir zwei dieser Bereiche haben, haben wir den Namen des Mausstatus im Bildlaufbereich geändert. Jetzt zeigt der Status genau an, auf welchem der Rollbalken sich der Cursor befindet - auf dem rechten oder auf dem oberen Balken:

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

Fügen wir alle neuen Mausereignisse der letzten Mausereignishandlung hinzu:

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

Wir korrigieren in der Methode, die die Ereignismeldung sendet, den Empfang des Basisobjekttyps:

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

Wenn ein erfolgreich abgerufenes Basisobjekt sein eigenes Basisobjekt hat, wird dessen Typ ermittelt. Andernfalls erhalten wir den Basisobjekttyp. Vor dieser Korrektur wurde das Programm mit einem kritischen Fehler beendet, wenn das Basisobjekt kein eigenes Basisobjekt hatte (z. B. wenn das Basisobjekt das Hauptobjekt war), weil der Zugriff auf das Objekt mit einem ungültigen Zeiger erfolgte. Jetzt ist das korrigiert.

Zuvor habe ich Anpassungen an der Position der Scrollbar-Objekte in der Resizing-Methode der WinForms-Basisobjektklasse vorgenommen. Wenn die Größe eines Objekts geändert wird, ändern sich die Koordinaten seiner Seiten. Da die Bildlaufleisten an die untere rechte Seite des Objekts gebunden sind, müssen ihre Koordinaten gegebenenfalls angepasst werden. Jetzt werden wir eine solche Anpassung in der Klasse der Container-Objekte vornehmen, denn nur Container-Objekte können angehängte Objekte enthalten, die möglicherweise einen Bildlauf erfordern, wenn sie nicht in den sichtbaren Bereich des Containers passen. Verschieben wir diese Verarbeitung in die Klasse des Containerobjekts. Dies ist der am besten geeignete Ort dafür.

In der Datei \MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqh der WinForms-Basisklasse entfernen wir aus der Methode zum Einstellen neuer Größen den Codeblock, der die Größe und die Koordinaten der Bildlaufleisten anpasst:

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

Dieser Codeblock wird vollständig in die Klasse des Containerobjekts verlagert.

In der Methode, die die Beschreibung der Ganzzahl-Eigenschaft des Elements zurückgibt, fügen wir den Codeblock für die Rückgabe der Beschreibungen neuer Eigenschaften hinzu:

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


Die Klasse des Erfassungsbereiches der ScrollBar

Im letzten Artikel haben wir beim Erstellen des ScrollBar-Objekts die Button-Objektklasse für den Schieberegler verwendet. Dieses Objekt eignet sich tatsächlich für diese Funktion. Bei der Behandlung von Ereignissen sollten wir jedoch den Typ des zu verarbeitenden Objekts kennen, um den richtigen Handler aufrufen zu können. Es gibt einen solchen Handler für das Button-Objekt, aber er ist nicht für den Schieberegler geeignet. Der Schieberegler muss verschoben werden. Während der Verschiebung sollten die Koordinaten der Objekte, deren Sichtbarkeitsbereich von der Bildlaufleiste gesteuert wird, neu berechnet werden. Daher werde ich eine neue Klasse erstellen, die auf der Klasse des Schaltflächenobjekts basiert - der Klasse des Capture-Bereichsobjekts. In diesem Objekt können wir unseren eigenen Handler für die notwendigen Mausereignisse erstellen.

Im Verzeichnis \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ erstellen wir die neue Datei ScrollBarThumb.mqh der Klasse CScrollBarThumb.

Die Klasse sollte von der Klasse CCheckBox abgeleitet sein, und ihre Datei sollte in die eingebunden Klassendatei eingebunden werden:

//+------------------------------------------------------------------+
//|                                               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
  {
  }

Im geschützten Abschnitt der Klasse deklarieren wir den geschützten Konstruktor und im öffentlichen Abschnitt den parametrischen Konstruktor:

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

Das ist im Moment alles, was wir von diesem Objekt brauchen. Sein Typ wird in den Klassenkonstruktoren festgelegt, und er ist eindeutig - das Objekt des Erfassungsbereichs.

Geschützter Konstruktor:

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

Der Konstruktor erhält den Typ des erstellten Objekts, der an den Konstruktor der übergeordneten Klasse übergeben wird. Der grafische Elementtyp und der grafische Objekttyp der Bibliothek werden im Konstruktorkörper festgelegt. Außerdem werden alle Standardfarbwerte für verschiedene Objektzustände bei der Interaktion mit dem Mauszeiger festgelegt.

Der parametrische Konstruktor:

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

Hier ist alles ähnlich wie beim geschützten Konstruktor, mit der Ausnahme, dass der Objekttyp starr als Erfassungsbereich festgelegt ist.

Verfeinern wir die abstrakte Scrollbar-Objektklasse in \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ScrollBar.mqh.

Die Objektklassendatei des Erfassungsbereichs wird eingebunden. Im privaten Abschnitt deklarieren wir die Variable zum Speichern der Breite der Bildlaufleiste, während wir im geschützten Abschnitt die Methode zum Einstellen der Größe der Bildlauftasten deklarieren. Im öffentlichen Abschnitt deklarieren wir die Methoden für die Rückgabe des Capture-Bereichs-Objekts, um die Breite der Bildlaufleiste festzulegen und zurückzugeben, sowie die Methode, die die Größe der gezeichneten Pfeile auf den Schaltflächen der Bildlaufleiste festlegt:

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

Fügen wir in der Initialisierungsmethode der Elementeigenschaften die Standardfarbwerte, die Breite der Bildlaufleiste sowie die Größe der Schaltflächen und Pfeile hinzu:

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

In der Methode zur Erstellung eines neuen grafischen Objekts implementieren wir den Codeblock zur Erstellung des Capture Area-Objekts:

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

Jetzt kann das Objekt zusätzlich zu den Pfeilschaltflächenobjekten auch den Schieberegler für die Erstellung der Steuerungsoberfläche erstellen.

Die Methode, die die Breite der Bildlaufleiste festlegt:

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

Handelt es sich um eine vertikale Bildlaufleiste, wird die Breite des Objekts als die Breite der Leiste betrachtet. Handelt es sich um eine horizontale Bildlaufleiste, so entspricht die Objektbreite ihrer Höhe. Die Methode empfängt den Wert, der auf das Objekt gesetzt werden soll. Je nach Art der Bildlaufleiste wird entweder ihre Breite oder ihre Höhe festgelegt.

Die Methode, mit der die Größe der Bildlauftasten festgelegt wird:

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

Die Schaltflächen des Scrollbar-Objekts haben gleiche Seiten. Die Größe wird an die Methode übergeben, und je nach Objekttyp erhalten wir die Zeiger auf die Schaltflächen links/rechts oder oben/unten und setzen die an die Methode übergebene Größe für sie - sowohl für die Breite als auch für die Höhe.

Die Methode, die die Größe der gezeichneten Pfeile auf den Bildlauftasten festlegt:

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

Je nach Art der Bildlaufleiste erhalten wir Zeiger auf die entsprechenden Schaltflächen, legen die Größe der gezeichneten Pfeile für sie fest und zeichnen das Objekt neu, um die Änderungen anzuzeigen.

Der Schieberegler für die Bildlaufleiste dient dazu, den Inhalt des Containers innerhalb seines Sichtbarkeitsbereichs zu verschieben. Wenn man den Schieberegler mit der Maus bewegen, sollte er nicht über die Bildlaufleiste hinausgehen - sein Bewegungsbereich sollte auf die Pfeiltasten beschränkt sein, die auch zum Scrollen verwendet werden. In \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ScrollBarVertical.mqh der vertikalen Bildlaufleisten-Objektklasse fügen wir die Objektklassendatei des Erfassungsbereichs ein. Im öffentlichen Abschnitt implementieren wir die Methoden, die die Zeiger auf die Pfeilschaltflächen zurückgeben, und deklarieren die Ereignisbehandlung:

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

In der Methode, die die ArrowButton-Objekte erstellt, werden alle Schaltflächen und der Schieberegler erstellt, dann die Zeiger auf sie abgerufen und ihre Farben für verschiedene Mausinteraktionszustände festgelegt:

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

In der Ereignisbehandlung, beim Verschieben des Fortschrittsbalken-Schieberegler-Objekts, berechnen wir dessen Koordinaten, die durch die Schaltflächen an den Rändern der Bildlaufleiste begrenzt sein sollten:

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

Ähnliche Verbesserungen wurden an der Klasse des horizontalen Scrollbar-Objekts in der Datei ScrollBarHorisontal.mqh vorgenommen.

Seine Methode zur Erstellung von Schaltflächen- und Schiebereglerobjekten und der Ereignishandler unterscheiden sich von den obigen Methoden nur durch Zeiger auf andere Schaltflächentypen und durch die Beschränkung auf andere Achsen der Schiebereglerbewegung:

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

Verbessern wir die Container-Objektklasse in \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Container.mqh.

Im öffentlichen Abschnitt deklarieren wir die virtuelle Methode zum Ändern der Objektgröße:

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

Die Methode erhält den aus der WinForms-Basisobjektklasse entfernten Codeblock.

In den Klassenkonstruktoren legen wir die Größe der erstellten Bildlaufleisten fest, die standardmäßig in der Bibliothek implementiert sind, und bestimmen den Bereich für die untere Bildlaufleiste. Der Bereich für die rechte Bildlaufleiste wird noch nicht festgelegt, da zunächst die Funktion der unteren Leiste verfeinert werden muss. Dann werden die Ergebnisse in das rechte Bildlaufleistenobjekt verschoben:

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

In der Methode, die Parameter für das angehängte Objekt festlegt, schreiben wir den Codeblock zum Festlegen der Standardparameter für ein neu erstelltes Capture Area-Objekt:

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

Für jedes der erstellten Objekte, die mit dem Container verbunden sind, gibt es hier einen Codeblock, der die für die Anzeige des Objekts erforderlichen Mindestparameter festlegt.

Da die Objekte im Container-Objekt automatisch in einer bestimmten Reihenfolge angeordnet werden können oder ihre Größe an die Größe des Containers angepasst werden kann, ist es notwendig, Bildlaufleisten von Objekten, die auf diese Weise behandelt werden, zu entfernen, da sie ein integraler Bestandteil des Container-Objekts und nicht seines Inhalts sind.

In einer Methode, die die Größe eines Elements an seinen inneren Inhalt anpasst, schließen wir die ScrollBar-Objekte von der Verarbeitung aus:

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

Die Methode zum Festlegen der neuen Größe für das aktuelle Objekt:

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

Diese virtuelle Methode ändert die Größe des Containerobjekts. Wir haben den Codeblock, der aus der Basisklasse von WinForms-Objekten entfernt wurde, in diese Klasse verschoben. Rufen wir zunächst die Methode zur Größenänderung von WinForms-Objekten auf. Wenn dies erfolgreich war, passen wir die Größe und die Koordinaten beider Bildlaufleisten an die neue Größe und die Koordinaten des Containers an.

Jetzt müssen wir die Kollektionsklasse der grafischen Elemente \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh verbessern.

Wir müssen der Bibliothek eine Nachricht über ihre Bewegung senden, wenn wir das Objekt des Erfassungsbereichs (den Schieberegler der Bildlaufleiste) bewegen, um seine Ereignisbehandlung aufzurufen. Wir haben bereits alles dafür - wir können den Separator im SplitContainer-Objekt bereits verschieben. Das bedeutet, dass wir die Bewegung und die Verarbeitung des Schiebereglers in die Codemethode aufnehmen müssen, in der die Bewegung des Trennzeichens verarbeitet wird.

Fügen wir eine Schieberegler-Behandlung in der Ereignisbehandlung des Separator-Handling-Blocks ein:

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

Ändern und fügen wir alle Ereignisbehandlungen hinzu, deren Namen von den Mausereignissen sich geändert haben:

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


Test

Um den Test durchzuführen, verwende ich den EA aus dem vorherigen Artikel und speichere ihn in \MQL5\Experts\TestDoEasy\Part130\ als TestDoEasy130.mq5.

Entkommentieren Sie einfach die Erstellung aller Objekte auf dem Panel und eine einzelne große Schaltfläche, um die Funktionen der Bildlaufleisten auf dem Panel zu testen.

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

Kompilieren Sie den EA und starten Sie ihn auf einem Chart:


Wie wir sehen können, werden die Schieberegler durch die Pfeilschaltflächen ordnungsgemäß in der Bildlaufleiste eingegrenzt. Die Pfeiltasten reagieren auf Klicks, die Farben der Objekte ändern sich je nach Zustand des Objekts und des Cursors während der Interaktion.

Es gibt auch einen Nachteil: Der Rahmen der Bildlaufleiste, der sie von der Oberfläche trennt, verschwindet, wenn wir eines der Objekte auswählen. Dies geschieht durch das Neuzeichnen von Objekten und die Tatsache, dass die Bildlaufleisten unter anderen Objekten liegen, da sie früher erstellt wurden und keine Priorität haben. Es ist auch schwierig, eine Pfeilschaltfläche auf der Bildlaufleiste auszuwählen, um darauf zu klicken. Aus demselben Grund werden die Objekte zuerst erstellt und die später erstellten Objekte (große Schaltfläche) überlagern sie. Ich werde das alles später reparieren. Im Moment ist es wichtig, die Mängel zu erkennen, die Ursachen zu verstehen und zu wissen, was getan werden muss, um sie zu beseitigen.


Was kommt als Nächstes?

Im nächsten Artikel werde ich die Entwicklung des ScrollBar-Objekts fortsetzen.

Zurück zum Inhalt

*Vorherige Artikel in dieser Reihe:

 
DoEasy. Steuerung (Teil 26): Fertigstellung des ToolTip WinForms-Objekts und Weiterführung der ProgressBar-Entwicklung
DoEasy. Steuerung (Teil 27): Arbeiten am WinForms Objekt der ProgressBar
DoEasy. Steuerung (Teil 28): Balkenstile im ProgressBar-Steuerelement
DoEasy. Steuerung (Teil 29): ScrollBar-Hilfssteuerelement

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/11887

Beigefügte Dateien |
MQL5.zip (4545.72 KB)
Algorithmen zur Optimierung mit Populationen Fish School Search (FSS) Algorithmen zur Optimierung mit Populationen Fish School Search (FSS)
Fish School Search (FSS, Suche mittels Fischschulen) ist ein neuer Optimierungsalgorithmus, der durch das Verhalten von Fischen in einem Schwarm inspiriert wurde, von denen die meisten (bis zu 80 %) in einer organisierten Gemeinschaft von Verwandten schwimmen. Es ist erwiesen, dass Fischansammlungen eine wichtige Rolle für die Effizienz der Nahrungssuche und den Schutz vor Räubern spielen.
DoEasy. Steuerung (Teil 29): Das Hilfssteuerelement der ScrollBar DoEasy. Steuerung (Teil 29): Das Hilfssteuerelement der ScrollBar
In diesem Artikel werde ich mit der Entwicklung des ScrollBar-Hilfssteuerelements und seiner abgeleiteten Objekte beginnen — vertikale und horizontale Bildlaufleisten. Eine Bildlaufleiste wird verwendet, um den Inhalt des Formulars zu verschieben, wenn er über den Container hinausgeht. Die Bildlaufleisten befinden sich in der Regel am unteren und rechten Rand des Formulars. Die horizontale am unteren Rand blättert den Inhalt nach links und rechts, während die vertikale nach oben und unten blättert.
Matrix Utils, Erweiterung der Funktionalität der Standardbibliothek für Matrizen und Vektoren Matrix Utils, Erweiterung der Funktionalität der Standardbibliothek für Matrizen und Vektoren
Matrizen dienen als Grundlage für Algorithmen des maschinellen Lernens und für Computer im Allgemeinen, da sie große mathematische Operationen effektiv verarbeiten können. Die Standardbibliothek bietet alles, was man braucht, aber wir wollen sehen, wie wir sie erweitern können, indem wir in der Datei utils mehrere Funktionen einführen, die in der Bibliothek noch nicht vorhanden sind
Algorithmen zur Optimierung mit Populationen Cuckoo-Optimierungsalgorithmus (COA) Algorithmen zur Optimierung mit Populationen Cuckoo-Optimierungsalgorithmus (COA)
Der nächste Algorithmus, den ich besprechen werde, ist die Optimierung der Kuckuckssuche (Cockoo) mit Levy-Flügen. Dies ist einer der neuesten Optimierungsalgorithmen und ein neuer Spitzenreiter in der Rangliste.