DoEasy. Elementos de control (Parte 30): Animando el elemento de control "ScrollBar"
Contenido
- Concepto
- Mejorando las clases de la biblioteca
- Clase de área de captura del control ScrollBar
- Simulación
- ¿Qué es lo próximo?
Concepto
En el último artículo, comenzamos a desarrollar el control auxiliar ScrollBar. Hoy seguiremos trabajando con él, y también implementaremos la reacción de sus elementos a la interacción con el ratón. Los elementos que componen el objeto WinForms ScrollBar son los botones de desplazamiento y el área de captura. Para los botones de desplazamiento, tendremos clases separadas de objetos auxiliares (botones con flechas), mientras que el área de captura la implementamos como un botón simple. Hoy crearemos una clase aparte basada en el objeto de botón para crear un objeto de área de captura. La cosa es que, para procesar correctamente los eventos de movimiento del control deslizante de la barra de desplazamiento, este objeto deberá tener su propio tipo. Por lo tanto, será derivado del objeto de botón: heredará sus propiedades y se convertirá en un objeto independiente con un tipo único.
Hoy, en su mayor parte, haremos el trabajo preparatorio para crear una funcionalidad que nos permita cambiar el tamaño de los controles y procesar la interacción del ratón con las barras de desplazamiento. Asimismo, ampliaremos la lista de estados del ratón y sus eventos. Todo esto nos permitirá en artículos posteriores desarrollar con calma los controles y su funcionalidad sin distraernos con el trabajo de rutina.
Mejorando las clases de la biblioteca
En el archivo \MQL5\Include\DoEasy\Defines.mqh, para el objeto ScrollBar, añadiremos las constantes de color predeterminadas para sus estados:
#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
Cada área de desplazamiento tiene un grosor. Para la barra de desplazamiento vertical, este será la anchura del objeto, mientras que para la barra de desplazamiento horizontal, será su altura. Para este parámetro, estableceremos un valor predeterminado de 11. La barra de desplazamiento tendrá un borde que la separará de la interfaz cuando se superponga a ella. Con un valor de anchura de 11 píxeles, el área activa de la barra de desplazamiento será de 9 píxeles (un píxel para el marco, por arriba, abajo, a la izquierda y a la derecha). Como en la barra de desplazamiento se construirán los objetos para controlarla -botones con flechas y un control deslizante (área de captura)-, entonces 9 píxeles será un número impar suficiente en el que el triángulo de la flecha se dibujará de manera uniforme y hermosa. En general, al cambiar el tamaño de los objetos en los que se dibujan figuras que están delineadas alrededor de su eje central, siempre deberemos intentar usar un número impar de píxeles, y así el dibujo será uniforme y preciso. El área de la esquina será la parte del formulario donde se considerará que el cursor se encuentra en la esquina. Por ejemplo, al cambiar el tamaño de un objeto, si el cursor se halla en una de las cuatro esquinas, podremos cambiar dos parámetros de su tamaño a la vez: la altura y la anchura.
A continuación, añadiremos a la lista de posibles estados del ratón en relación con el formulario los nuevos valores. Las dimensiones del objeto se podrán cambiar de tamaño en ocho direcciones:
- Cuando el cursor está en el borde superior de un objeto, podremos cambiar su altura desplazando el borde hacia arriba,
- Cuando el cursor está en el borde inferior de un objeto, podremos cambiar su altura desplazando el borde hacia abajo,
- Cuando el cursor está en el borde izquierdo de un objeto, podremos cambiar su anchura desplazando el borde hacia la izquierda,
- Cuando el cursor está en el borde derecho de un objeto, podremos cambiar su anchura desplazando el borde hacia la derecha,
- Cuando el cursor está en la zona de la esquina superior izquierda del objeto, podremos cambiar su altura y anchura desplazándonos hacia arriba y hacia la izquierda,
- Cuando el cursor está en la zona de la esquina superior derecha del objeto, podremos cambiar su altura y anchura desplazándonos hacia arriba y hacia la derecha,
- Cuando el cursor está en la zona de la esquina inferior izquierda del objeto, podremos cambiar su altura y anchura desplazándonos hacia abajo y hacia la izquierda,
- Cuando el cursor está en la zona de la esquina inferior derecha del objeto, podremos cambiar su altura y anchura desplazándonos hacia abajo y hacia la derecha,
El contenedor en el que se pueda desplazar su contenido tendrá barras de desplazamiento en las partes derecha y inferior. Solo necesitaremos determinar en qué barra de desplazamiento se encuentra el cursor, a la derecha o en la parte inferior, y escribir dichos estados en el estado del ratón:
//+------------------------------------------------------------------+ //| 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 }; //+------------------------------------------------------------------+
Todos estos nuevos estados se definirán y registrarán como el estado del ratón en relación con el objeto.
Cuando se registra un evento del ratón en uno de los estados predefinidos, el evento correspondiente se enviará a la biblioteca, donde se llamarán los manejadores correspondientes al evento en cada uno de los objetos que posibilitan el procesamiento de los eventos del ratón.
Vamos a escribir los nuevos estados en la lista de posibles eventos del ratón:
//+------------------------------------------------------------------+ //| 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 //+------------------------------------------------------------------+
Luego añadiremos el nuevo tipo de objeto a la lista de tipos de elementos gráficos:
//+------------------------------------------------------------------+ //| 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 }; //+------------------------------------------------------------------+
Este será el nuevo control auxiliar "Área de captura" (control deslizante de la barra de desplazamiento).
Luego, añadiremos a la enumeración de propiedades enteras del elemento gráfico en el lienzo las dos nuevas propiedades y aumentaremos su número total de 138 a 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 //+------------------------------------------------------------------+
Cada uno de los elementos gráficos tendrá una bandera que indicará que su tamaño se puede modificar con el ratón, mientras que las flechas dibujadas en el elemento (por ejemplo, un botón con una flecha) tendrán los tamaños relativos especificados por este parámetro. Por ejemplo, una flecha con un tamaño de 1 se dibujará desde el punto central con una sangría de vértice de 1 píxel. Una flecha con un tamaño de 2 se dibujará desde el punto central con una sangría de dos píxeles, y así sucesivamente.
Por ejemplo, una flecha hacia arriba con un tamaño de 1:
⊡⊠⊡ ⊠⊠⊠
Flecha hacia arriba con tamaño de 2:
⊡⊡⊠⊡⊡ ⊡⊠⊠⊠⊡ ⊠⊠⊠⊠⊠
Flecha hacia arriba con tamaño de 3:
⊡⊡⊡⊠⊡⊡⊡ ⊡⊡⊠⊠⊠⊡⊡ ⊡⊠⊠⊠⊠⊠⊡ ⊠⊠⊠⊠⊠⊠⊠
Como podemos ver, si tomamos el píxel en el centro de la base del triángulo como el central y apartamos de él a cada lado un número de píxeles igual al tamaño relativo de la figura, obtendremos los tres vértices de un triángulo a lo largo del cual se construirá la figura. Por lo tanto, el tamaño de un triángulo será el número de píxeles desde el centro de la base del triángulo hacia arriba, hacia la izquierda y hacia la derecha para indicar las coordenadas de cada vértice.
Del mismo modo, construiremos las flechas hacia abajo, izquierda y derecha.
En el archivo \MQL5\Include\DoEasy\Data.mqh, escribiremos los índices de los nuevos mensajes:
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
y los textos de los mensajes correspondientes a los nuevos índices añadidos:
{"Элемент управления \"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
Para mostrar la descripción del tipo de un nuevo objeto, en el archivo \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh, en su método TypeElementDescription(), introduciremos una línea que retornará la descripción del tipo del objeto cuyo tipo se ha transmitido al método:
//+------------------------------------------------------------------+ //| 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" ); } //+------------------------------------------------------------------+
Cada vez que se añada una nueva propiedad a la enumeración de propiedades de un elemento gráfico, dicha nueva propiedad deberá agregarse a la estructura del objeto. La estructura del objeto gráfico se utilizará para guardar las propiedades de los elementos gráficos en un archivo y leerlos desde el mismo. Esto será necesario para restaurar los objetos después del reinicio, de modo que se encuentren en el mismo estado que antes de salir. Hasta ahora, no hemos implementado dicha funcionalidad debido al cambio constante en la composición de las propiedades de los objetos gráficos, pero ya estamos creando una estructura de este tipo para el futuro.
En el archivo \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh, añadiremos las nuevas propiedades enteras a la estructura del objeto:
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
En la sección pública de la clase, declararemos los nuevos métodosque retornarán las banderas con la posición del cursor en relación con el elemento gráfico:
//--- 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,
En el bloque de métodos para el acceso simplificado a las propiedades del objeto, escribiremos los métodos que retornarán las coordenadas de las nuevas zonas y áreas del elemento gráfico, así como el método que retornará la bandera de redimensionamiento:
//--- 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); }
A continuación, añadiremos un método que retornará la bandera de cambio de tamaño del elemento:
//--- 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
Asimismo, cambiaremos la declaración de los métodos que dibujan las flechas:
//+------------------------------------------------------------------+ //| 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); }; //+------------------------------------------------------------------+
Ahora, transmitiremos a los métodos las coordenadas del punto central y el tamaño relativo de la flecha.
En el método que inicializa las propiedades del objeto, estableceremos los valores predeterminados en dos píxeles para la anchura de las zonas de los bordes superior, inferior, izquierdo y derecho del objeto para determinar si el cursor del ratón está en estas áreas. Por defecto, el cursor del ratón no podrá cambiar el tamaño del objeto y el tamaño de la flecha dibujada será de 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 } //+------------------------------------------------------------------+
En el método que crea la estructura del objeto, escribiremos las nuevas propiedades enteras del objeto en los campos de la estructura:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
En el método que crea un objeto a partir de una estructura, escribiremos en las propiedades del objeto los valores de los campos relevantes de la estructura:
//+------------------------------------------------------------------+ //| 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 } //+------------------------------------------------------------------+
Implementación de los métodos que retornarán las banderas de la posición del cursor en relación con las áreas de desplazamiento y el cambio de tamaño de los elementos:
//+------------------------------------------------------------------+ //|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 | //+------------------------------------------------------------------+
Los métodos, según las coordenadas de la ubicación del cursor, retornarán la bandera del cursor dentro del área delineada por sus valores.
Los métodos que dibujan las flechas ahora dibujarán triángulos según la coordenada inicial (el centro de la base del triángulo) y el tamaño de la flecha especificado:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Para calcular las coordenadas de cada vértice, simplemente sumaremos o restaremos a las coordenadas del punto central el tamaño de la flecha transmitido en los parámetros.
Tenga en cuenta que el tamaño estará limitado solo por el borde inferior (1), pero no habrá límite en cuanto al superior. Aquí deberemos asegurarnos de que la flecha se dibuje de un tamaño normal, ya que el tamaño real de la flecha se obtiene como dos tamaños especificados (size) + un píxel central. Es decir, con un tamaño de 1, el tamaño real será de 1+1+1; con un tamaño de 2, el tamaño real será de 2+1+2; con un tamaño de 3, el tamaño real será de 3+1+3, y así sucesivamente.
Como ahora tenemos nuevos estados del ratón en relación con el elemento y los eventos correspondientes, estos deberán reflejarse en los métodos del manejador del último evento del ratón.
En el archivo \MQL5\Include\DoEasy\Objects\Graph\WForms\Common Controls\Button.mqh, añadiremos al método la lista de nuevos eventos:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
Aquí, todos estos eventos no se procesarán, pero si fuera necesario, siempre podemos añadir su procesamiento debajo de cada evento.
Ya hemos realizado exactamente los mismos cambios en este método en los archivos TabHeader.mqh, CheckBox.mqh y SplitContainer.mqh.
Para indicar el color de la flecha dibujada en la clase de botón con flecha, usaremos la variable privada m_arrow_color. El uso de esta variable es superfluo, ya que podemos usar el método ForeColor() para indicar el color, que también sabe cómo controlar el color del texto dibujado. Por lo tanto, en el archivo \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ArrowButton.mqh, eliminaremos esta variable y los métodos para trabajar con ella:
//+------------------------------------------------------------------+ //| 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
Como consecuencia, reemplazaremos la llamada a los métodos remotos con los métodos para trabajar con el color del texto:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
En el archivo \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ArrowRightButton.mqh, en los constructores de clase, , estableceremos en 3 el tamaño de la flecha dibujada:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
En el método que dibuja la flecha, cambiaremos los parámetros al llamar al método para dibujar la flecha:
//+------------------------------------------------------------------+ //| 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()); } //+------------------------------------------------------------------+
Como punto central de la flecha, transmitiremos el centro del objeto (horizontalmente desplazaremos un píxel hacia la izquierda), especificaremos el tamaño de la flecha dibujada establecida en las propiedades del objeto, su color de texto y su opacidad.
Ya hemos realizado cambios similares en otras clases de objetos de botones de flecha ubicados en los archivos ArrowLeftButton.mqh, ArrowDownButton.mqh y ArrowUpButton.mqh.
Para simplificar la configuración de las coordenadas y los tamaños de las áreas de las barras de desplazamiento, en el archivo \MQL5\Include\DoEasy\Objects\Graph\Form.mqh de la clase de objeto de formulario, añadiremos los métodos públicos:
//--- 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);
En el método que establece y retorna el estado del ratón en relación con el formulario, verificaremos la ubicación del cursor del ratón, la compararemos con las coordenadas de diversas regiones del formulario y estableceremos las banderas de estos estados en una variable. Además, en función de estas banderas, formaremos el estado general del cursor del ratón en relación con el objeto. Asimismo, añadiremos bloques de código al método para monitorear la posición del cursor en relación con las barras de desplazamiento y los bordes en el área de los cuales es posible capturar el borde del objeto con el ratón para arrastrar y cambiar el tamaño del elemento:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Todos los bloques de código se comentan en detalle y, de hecho, todo resulta simple en ellos: verificaremos la ubicación de las coordenadas del cursor en relación con las coordenadas de las áreas, por ejemplo, el desplazamiento, y si el cursor se encuentra dentro del área, estableceremos la bandera correspondiente. Si no, quitaremos la bandera. Como resultado de la verificación y configuración de las banderas, tendremos un conjunto de ellas, en base al cual podremos decidir dónde se encuentra el cursor del ratón. Si establecemos las banderas para su ubicación en los bordes superior y derecho del objeto, esto indicará que el cursor está en la esquina superior derecha. Por lo tanto, deberemos combinar las banderas, porque en el valor ushort, el número de bits resulta insuficiente para escribir cada bandera por separado.
En el manejador de eventos del ratón, cambiaremos la llamada a los métodos para procesar los eventos cuando el cursor se encuentra en el área de desplazamiento. Como tenemos dos de estas áreas, cambiaremos el nombre de los estados del ratón ubicados en el área de desplazamiento. Ahora el estado indicará con precisión en cuál de las barras de desplazamiento se halla el cursor: en la derecha o en la superior:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Ahora, en el manejador del último evento del ratón, añadiremos todos los nuevos eventos del ratón:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
En el método que envía el mensaje sobre un evento, corregiremos la obtención del tipo del objeto básico:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Si el objeto básico obtenido con éxito tiene su propio objeto básico, obtendremos su tipo; de lo contrario, obtendremos el tipo del objeto básico. Antes de realizar esta corrección, si el objeto básico no tenía su propio objeto básico (el objeto básico era, por ejemplo, el principal), el programa finalizaba con un error crítico, porque se accedía al objeto usando un puntero no válido. Ahora, hemos arreglado esto.
Antes, realizamos ajustes en la ubicación de los objetos de barra de desplazamiento en el método de cambio de tamaño de la clase de objeto básico WinForms. Al cambiarse el tamaño de un objeto, las coordenadas de sus lados cambian. Como las barras de desplazamiento están vinculadas a los lados derecho e inferior del objeto, sus coordenadas deberán ajustarse si es necesario. Ahora realizaremos un ajuste de este tipo en la clase de objeto contenedor, porque solo los objetos contenedor pueden contener objetos adjuntos que puedan requerir desplazamiento si no caben en el área visible del contenedor. Transferiremos dicho procesamiento a la clase del objeto contenedor, que es donde debe estar.
En el archivo \MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqh de la clase de objeto WinForms básico, eliminaremos el bloque de código que ajusta los tamaños y las coordenadas de las barras de desplazamiento del método para establecer nuevos tamaños:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Este bloque de código se desplazará por completo a la clase del objeto contenedor.
En el método que retorna la descripción de una propiedad entera del elemento, escribiremos los bloques de código necesarios para retornar la descripción de las propiedades del nuevo objeto:
//+------------------------------------------------------------------+ //| 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) ) : "" ); } //+------------------------------------------------------------------+
Clase de área de captura del control ScrollBar
En el último artículo, al crear un objeto ScrollBar, usábamos una clase de objeto de botón para su control deslizante. De hecho, este objeto resulta adecuado para su uso en esta capacidad. Sin embargo, hay un "Pero". Al procesar eventos, deberemos conocer el tipo de objeto procesado para poder llamar al manejador correcto. Existe un manejador de este tipo para el objeto de botón, pero no resultará adecuado para el control deslizante. Después de todo, el control deslizante deberá desplazarse y, durante su movimiento, se deberán recalcular las coordenadas de los objetos cuya área de visibilidad está controlada por la barra de desplazamiento. Por ello, basándonos en la clase del objeto de botón, crearemos una nueva clase: la clase de objeto de área de captura, y ya en ella podremos crear nuestro propio manejador para los eventos necesarios del ratón.
En la carpeta de la biblioteca \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\, crearemos el nuevo archivo ScrollBarVertical.mqh de la clase CScrollBarVertical.
La clase deberá heredar de la clase de objeto de botón, mientras que su archivo deberá incluirse en el archivo de la clase creada:
//+------------------------------------------------------------------+ //| 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 { }
Luego, en la sección protegida de la clase, declararemos un constructor protegido, mientras que declararemos un constructor paramétrico en la sección pública:
//+------------------------------------------------------------------+ //| 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); }; //+------------------------------------------------------------------+
Por ahora, eso es todo lo necesario en este objeto. Su tipo lo estableceremos en los constructores de la clase, y será único: el objeto de área de captura.
Constructor protegido:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
A continuación, transmitiremos al constructor el tipo de objeto creado, que se transmitirá al constructor de la clase padre. En el cuerpo del constructor, estableceremos el tipo de elemento gráfico y el tipo de objeto gráfico de la biblioteca, así como todos los valores de color predeterminados para varios estados del objeto al interactuar con el cursor del ratón.
Constructor paramétrico:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Aquí todo será similar al constructor protegido, solo que el tipo de objeto estará codificado de forma rígida: el área de captura.
Vamos a mejorar la clase de objeto de barra de desplazamiento abstracta en el archivo \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ScrollBar.mqh.
Así, incluiremos en el archivo de clase el archivo de clase del objeto de área de captura. En la sección privada declararemos una variable para almacenar el grosor de la barra de desplazamiento; en la sección protegida, declararemos el método para configurar el tamaño de los botones para el desplazamiento. En la sección pública, declararemos los métodos para retornar el objeto del área de captura, para establecer y retornar el grosor de la barra de desplazamiento, así como el método que establecerá el tamaño de las flechas dibujadas en los botones de la barra de desplazamiento:
//+------------------------------------------------------------------+ //| 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); }; //+------------------------------------------------------------------+
En el método de inicialización de las propiedades del elemento, añadiremos la configuración de los colores predeterminados, el grosor de la barra de desplazamiento, y el tamaño de los botones y flechas:
//+------------------------------------------------------------------+ //| 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)); } //+------------------------------------------------------------------+
En el método que crea un nuevo objeto gráfico, escribiremos el bloque de código para crear un objeto de área de captura:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Ahora el objeto podrá crear dentro de sí mismo, junto con los objetos de botón con flechas, un objeto de control deslizante para crear una interfaz de control.
Método que establece la anchura de la barra de desplazamiento:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
Si se trata de una barra de desplazamiento vertical, la anchura del objeto se considerará la anchura de la barra. Si se trata de una barra de desplazamiento horizontal, entonces el grosor del objeto será su altura. Luego transmitiremos al método el valor que se establecerá para el objeto y, dependiendo del tipo de barra de desplazamiento, se establecerá su anchura o su altura.
Método que establece el tamaño de los botones de desplazamiento:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
Los botones del objeto de barra de desplazamiento tienen los lados iguales. El tamaño se transmitirá al método y, según el tipo de objeto, obtendremos los punteros a los botones izquierda/derecha o arriba/abajo y estableceremos el tamaño transmitido al método para ellos, tanto para la anchura como para la altura.
Método que establece el tamaño de las flechas dibujadas en los botones de desplazamiento:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
Según el tipo de barra de desplazamiento, obtendremos los punteros a los botones correspondientes, estableceremos el tamaño de las flechas dibujadas para ellos y redibujaremos el objeto para mostrar los cambios.
El control deslizante de la barra de desplazamiento se utilizará para desplazar el contenido del contenedor dentro de su área visible. Al mover el control deslizante con el ratón, no debería ir más allá de la barra de desplazamiento; su área de movimiento deberá limitarse a los botones con flechas, que también sirven para desplazarse. En el archivo \MQL5\Include\DoEasy\Objects\Graph\WForms\Helpers\ScrollBarVertical.mqh de la clase de objeto de la barra de desplazamiento vertical, incluiremos el archivo de clase del objeto de área de captura; en la sección pública, escribiremos los métodos que retornan los punteros a los botones de flecha y declararemos el controlador de eventos:
//+------------------------------------------------------------------+ //| 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); }; //+------------------------------------------------------------------+
En el método que crea los objetos ArrowButton, crearemos todos los botones y el control deslizante, luego les asignaremos los punteros y estableceremos sus colores para diferentes estados de interacción del ratón:
//+------------------------------------------------------------------+ //| 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); } } //+------------------------------------------------------------------+
En el controlador de eventos, al mover el objeto deslizante de la barra de progreso, calcularemos sus coordenadas, que deberán estar limitadas por botones en los bordes de la barra de desplazamiento:
//+------------------------------------------------------------------+ //| 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()); } } } //+------------------------------------------------------------------+
Asimismo, hemos realizado mejoras similares en la clase del objeto de barra de desplazamiento horizontal, en el archivo ScrollBarHorisontal.mqh.
Su método para crear objetos de botón y el control deslizante, así como el manejador de eventos difieren de los métodos anteriores solo en los punteros a otros tipos de botones y en la restricción de otros ejes de movimiento del control deslizante:
//+------------------------------------------------------------------+ //| 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()); } } } //+------------------------------------------------------------------+
Vamos a mejorar la clase del objeto contenedor, en el archivo \MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Container.mqh.
En la sección pública, declararemos un método virtual para cambiar el tamaño del objeto:
//--- 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
Luego transmitiremos a este método el bloque de código eliminado de la clase del objeto WinForms básico.
En los constructores de clase, indicaremos los tamaños de las barras de desplazamiento creadas establecidas por defecto para la biblioteca, y estableceremos el área para la barra de desplazamiento inferior (todavía no lo haremos para la derecha, ya que trabajaremos primero en la funcionalidad de la barra inferior, y luego la transferiremos terminada al objeto de la barra de desplazamiento derecha):
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
En el método que establece los parámetros para el objeto adjunto, escribiremos un bloque de código para establecer los parámetros predeterminados para el objeto del área de captura recién creado:
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
Para cada uno de los objetos creados adjuntos al contenedor, aquí habrá un bloque de código que establecerá los parámetros mínimos necesarios para mostrar el objeto.
Como en un objeto contenedor, sus objetos adjuntos se podrán organizar automáticamente en un orden de ubicación dado, o bien ajustar sus tamaños al tamaño del contenedor, deberemos eliminar las barras de desplazamiento de los objetos procesados de esta forma; después de todo, suponen una parte integral del objeto contenedor, y no su contenido.
En el método que ajusta el tamaño del elemento a su contenido interno, excluiremos del procesamiento los objetos de barra de desplazamiento:
//+------------------------------------------------------------------+ //| 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) ); } //+------------------------------------------------------------------+
Método que establece las nuevas dimensiones del objeto actual:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Este método virtual cambiará el tamaño del objeto contenedor. Hemos trasladado a él el bloque de código eliminado de la clase básica de los objetos WinForms. Primero, llamaremos al método de cambio de tamaño en el objeto WinForms, y luego, si tiene éxito, ajustaremos los tamaños y las coordenadas de ambas barras de desplazamiento a los nuevos tamaños y coordenadas del contenedor.
Vamos a mejorar la clase de colección de elementos gráficos en el archivo \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh.
Ahora, al mover el objeto de área de captura (el control deslizante de la barra de desplazamiento), necesitaremos enviar un mensaje a la biblioteca informando sobre su movimiento, para llamar a su controlador de eventos. Ya tenemos todo listo para ello: podemos mover el separador en el objeto SplitContainer. Y eso significa que necesitaremos añadir el manejo del movimiento y el control deslizante al método del código donde se procesa el movimiento del separador.
En el manejador de eventos, en el bloque de procesamiento del separador, añadiremos el procesamiento del control deslizante:
//--- 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); }
Luego cambiaremos y completaremos todos los manejadores de eventos en los que han cambiado los nombres de los eventos de ratón:
//+---------------------------------------------------------------------------------------------+ //| '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); } //+---------------------------------------------------------------------------------------------+
Simulación
Para la prueba, tomaremos el asesor del artículo anterior y lo guardaremos en la nueva carpeta \MQL5\Experts\TestDoEasy\Part130\ con el nuevo nombre TestDoEasy130.mq5.
Solo comentaremos la creación de todos los objetos en el panel y crearemos solo un botón grande; lo usaremos como ejemplo para probar la funcionalidad de las barras de desplazamiento en el panel ahora y en el futuro.
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Vamos a compilar el asesor y a ejecutarlo en el gráfico:
Como podemos ver, los controles deslizantes están correctamente limitados dentro de la barra de desplazamiento por los botones con flechas. Los botones con flechas responden a los clics, y los colores de los objetos cambian según el estado del objeto y el cursor cuando interactúan.
Entre las deficiencias, vemos que el marco de la barra de desplazamiento que la separa de la interfaz, desaparece al seleccionar cualquiera de los objetos. Esto se debe al rediseño de los objetos y al hecho de que las barras de desplazamiento se encuentran debajo de otros objetos, ya que se crearon antes y no tienen prioridad. También resulta difícil seleccionar un botón con flecha en la barra de desplazamiento para hacer clic, por la misma razón: los objetos se crean primero y los otros creados después (botón grande) se superponen. Todo esto se arreglará tras mejorar los objetos de barra de desplazamiento. Ahora lo importante es detectar los defectos, analizar las causas y hallar las soluciones correspondientes.
¿Qué es lo próximo?
En el próximo artículo, seguiremos desarrollando el objeto ScrollBar.
*Artículos de esta serie:
DoEasy. Elementos de control (Parte 26): Mejoramos el objeto WinForms "ToolTip" y comenzamos a desarrollar "ProgressBar"
DoEasy. Elementos de control (Parte 27): Seguimos trabajando en el objeto WinForms "ProgressBar"
DoEasy. Elementos de control (Parte 28): Estilos de barra en el control «ProgressBar»
DoEasy. Elementos de control (Parte 29): Control auxiliar "ScrollBar"
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/11887
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso