Gráficos en la biblioteca DoEasy (Parte 93): Preparando la funcionalidad para crear objetos gráficos compuestos
Contenido
- Concepto
- Mejorando las clases de la biblioteca
- Clases para indicar las coordenadas de un objeto dependiente
- Simulación
- ¿Qué es lo próximo?
Concepto
El terminal de cliente de MetaTrader 5 ofrece una amplia gama de herramientas analíticas gráficas para su uso en diversas construcciones gráficas en los gráficos. Sin embargo, muchas veces se escucha que la gente echa en falta una u otra herramienta. En la terminal tenemos 44 herramientas analíticas. Ahora, imaginemos qué se podría hacer si estos objetos gráficos se combinaran en conjuntos vinculados, creando así nuevas herramientas para el análisis técnico. ¡El lenguaje MQL5 nos permite hacer esto!
Nuestra biblioteca ofrecerá soporte a la creación de objetos gráficos compuestos complejos en los que dichos objetos podrán tener cualquier jerarquía de relaciones. Cada uno de estos objetos tendrá un objeto gráfico de base básico que contendrá una lista con los otros objetos gráficos adjuntos. El objeto básico tendrá la funcionalidad necesaria para controlar las propiedades de los objetos gráficos subordinados, y los objetos subordinados, a su vez, tendrán el conjunto de coordenadas X e Y del objeto básico al que se fijarán. En este caso, la coordenada puede ser no solo un valor, sino la lista completa de propiedades del objeto básico. Por ejemplo, para calcular la coordenada X de un objeto dependiente, podemos usar no solo la coordenada X de algún punto del objeto básico, sino varias, por ejemplo, dos coordenadas X: los puntos 0 y 1 de la línea de tendencia. Entonces, la coordenada X del objeto subordinado podrá ser la media de las dos coordenadas X del objeto básico.
Cada objeto dependiente en la lista de objetos básicos también podrá ser el objeto básico para otros objetos gráficos en su lista. Esto nos permitirá crear una variedad de conjuntos a partir de diferentes objetos gráficos compuestos.
Además, intentaremos implementar no solo una creación programática de dichos objetos donde cada objeto dependiente se añada a la lista del objeto básico en el código del programa, sino también su creación en tiempo real: al arrastrar un objeto gráfico a otro, se fijará a él con una selección visual de los puntos de anclaje, que se podrán redefinir más adelante.
Hoy implementaremos la funcionalidad necesaria para crear objetos gráficos estándar extendidos: las nuevas propiedades de los objetos gráficos estándar que indican que este es un objeto extendido, así como las clases para almacenar las propiedades relacionadas de las coordenadas del objeto básico para calcular y especificar las coordenadas del objeto dependiente.
Mejorando las clases de la biblioteca
En el archivo \MQL5\Include\DoEasy\Defines.mqh, en la lista de tipos de elementos gráficos, añadimos un tipo más, el objeto gráfico estándar extendido:
//+------------------------------------------------------------------+ //| 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_ELEMENT, // Element GRAPH_ELEMENT_TYPE_SHADOW_OBJ, // Shadow object GRAPH_ELEMENT_TYPE_FORM, // Form GRAPH_ELEMENT_TYPE_WINDOW, // Window }; //+------------------------------------------------------------------+
En la enumeración de propiedades enteras de los objetos gráficos, añadimos una propiedad, el identificador del objeto gráfico básico, y aumentamos el número de propiedades enteras de 54 a 55:
//+------------------------------------------------------------------+ //| Integer properties of a standard graphical object | //+------------------------------------------------------------------+ enum ENUM_GRAPH_OBJ_PROP_INTEGER { //--- Additional properties GRAPH_OBJ_PROP_ID = 0, // Object ID GRAPH_OBJ_PROP_BASE_ID, // Base object ID GRAPH_OBJ_PROP_TYPE, // Graphical object type (ENUM_OBJECT) GRAPH_OBJ_PROP_ELEMENT_TYPE, // Graphical element type (ENUM_GRAPH_ELEMENT_TYPE) GRAPH_OBJ_PROP_SPECIES, // Graphical object species (ENUM_GRAPH_OBJ_SPECIES) GRAPH_OBJ_PROP_BELONG, // Graphical object affiliation GRAPH_OBJ_PROP_CHART_ID, // Chart ID GRAPH_OBJ_PROP_WND_NUM, // Chart subwindow index GRAPH_OBJ_PROP_NUM, // Object index in the list GRAPH_OBJ_PROP_CHANGE_HISTORY, // Flag of storing the change history GRAPH_OBJ_PROP_GROUP, // Group of objects the graphical object belongs to //--- Common properties of all graphical objects GRAPH_OBJ_PROP_CREATETIME, // Object creation time GRAPH_OBJ_PROP_TIMEFRAMES, // Object visibility on timeframes GRAPH_OBJ_PROP_BACK, // Background object GRAPH_OBJ_PROP_ZORDER, // Priority of a graphical object for receiving the event of clicking on a chart GRAPH_OBJ_PROP_HIDDEN, // Disable displaying the name of a graphical object in the terminal object list GRAPH_OBJ_PROP_SELECTED, // Object selection GRAPH_OBJ_PROP_SELECTABLE, // Object availability //--- Properties belonging to different graphical objects GRAPH_OBJ_PROP_TIME, // Time coordinate GRAPH_OBJ_PROP_COLOR, // Color GRAPH_OBJ_PROP_STYLE, // Style GRAPH_OBJ_PROP_WIDTH, // Line width GRAPH_OBJ_PROP_FILL, // Object color filling GRAPH_OBJ_PROP_READONLY, // Ability to edit text in the Edit object GRAPH_OBJ_PROP_LEVELS, // Number of levels GRAPH_OBJ_PROP_LEVELCOLOR, // Level line color GRAPH_OBJ_PROP_LEVELSTYLE, // Level line style GRAPH_OBJ_PROP_LEVELWIDTH, // Level line width GRAPH_OBJ_PROP_ALIGN, // Horizontal text alignment in the Edit object (OBJ_EDIT) GRAPH_OBJ_PROP_FONTSIZE, // Font size GRAPH_OBJ_PROP_RAY_LEFT, // Ray goes to the left GRAPH_OBJ_PROP_RAY_RIGHT, // Ray goes to the right GRAPH_OBJ_PROP_RAY, // Vertical line goes through all windows of a chart GRAPH_OBJ_PROP_ELLIPSE, // Display the full ellipse of the Fibonacci Arc object GRAPH_OBJ_PROP_ARROWCODE, // Arrow code for the "Arrow" object GRAPH_OBJ_PROP_ANCHOR, // Position of the binding point of the graphical object GRAPH_OBJ_PROP_XDISTANCE, // Distance from the base corner along the X axis in pixels GRAPH_OBJ_PROP_YDISTANCE, // Distance from the base corner along the Y axis in pixels GRAPH_OBJ_PROP_DIRECTION, // Gann object trend GRAPH_OBJ_PROP_DEGREE, // Elliott wave marking level GRAPH_OBJ_PROP_DRAWLINES, // Display lines for Elliott wave marking GRAPH_OBJ_PROP_STATE, // Button state (pressed/released) GRAPH_OBJ_PROP_CHART_OBJ_CHART_ID, // Chart object ID (OBJ_CHART). GRAPH_OBJ_PROP_CHART_OBJ_PERIOD, // Chart object period GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE, // Time scale display flag for the Chart object GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE, // Price scale display flag for the Chart object GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE, // Chart object scale GRAPH_OBJ_PROP_XSIZE, // Object width along the X axis in pixels. GRAPH_OBJ_PROP_YSIZE, // Object height along the Y axis in pixels. GRAPH_OBJ_PROP_XOFFSET, // X coordinate of the upper-left corner of the visibility area. GRAPH_OBJ_PROP_YOFFSET, // Y coordinate of the upper-left corner of the visibility area. GRAPH_OBJ_PROP_BGCOLOR, // Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL GRAPH_OBJ_PROP_CORNER, // Chart corner for binding a graphical object GRAPH_OBJ_PROP_BORDER_TYPE, // Border type for "Rectangle border" GRAPH_OBJ_PROP_BORDER_COLOR, // Border color for OBJ_EDIT and OBJ_BUTTON }; #define GRAPH_OBJ_PROP_INTEGER_TOTAL (55) // Total number of integer properties #define GRAPH_OBJ_PROP_INTEGER_SKIP (0) // Number of integer properties not used in sorting //+------------------------------------------------------------------+
El ID del objeto básico se escribirá en cada objeto subordinado (del 1 en adelante). El valor cero de esta propiedad indica que el objeto no está vinculado a ningún otro objeto, y no es un objeto subordinado.
En la enumeración de las propiedades de tipo string de los objetos gráficos, añadimos una propiedad, el nombre del objeto gráfico básico y aumentamos el número de propiedades string de 7 a 8:
//+------------------------------------------------------------------+ //| String properties of a standard graphical object | //+------------------------------------------------------------------+ enum ENUM_GRAPH_OBJ_PROP_STRING { GRAPH_OBJ_PROP_NAME = (GRAPH_OBJ_PROP_INTEGER_TOTAL+GRAPH_OBJ_PROP_DOUBLE_TOTAL), // Object name GRAPH_OBJ_PROP_BASE_NAME, // Base object name GRAPH_OBJ_PROP_TEXT, // Object description (text contained in the object) GRAPH_OBJ_PROP_TOOLTIP, // Tooltip text GRAPH_OBJ_PROP_LEVELTEXT, // Level description GRAPH_OBJ_PROP_FONT, // Font GRAPH_OBJ_PROP_BMPFILE, // BMP file name for the "Bitmap Level" object GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL, // Symbol for the Chart object }; #define GRAPH_OBJ_PROP_STRING_TOTAL (8) // Total number of string properties //+------------------------------------------------------------------+
Añadimos a la lista de posibles criterios de clasificación de los objetos gráficos las nuevas constantes correspondientes a las nuevas propiedades del objeto gráfico anteriormente añadidas:
//+------------------------------------------------------------------+ //| Possible sorting criteria of graphical objects | //+------------------------------------------------------------------+ #define FIRST_GRAPH_OBJ_DBL_PROP (GRAPH_OBJ_PROP_INTEGER_TOTAL-GRAPH_OBJ_PROP_INTEGER_SKIP) #define FIRST_GRAPH_OBJ_STR_PROP (GRAPH_OBJ_PROP_INTEGER_TOTAL-GRAPH_OBJ_PROP_INTEGER_SKIP+GRAPH_OBJ_PROP_DOUBLE_TOTAL-GRAPH_OBJ_PROP_DOUBLE_SKIP) enum ENUM_SORT_GRAPH_OBJ_MODE { //--- Sort by integer properties SORT_BY_GRAPH_OBJ_ID = 0, // Sort by object ID SORT_BY_GRAPH_OBJ_BASE_ID, // Sort by object ID SORT_BY_GRAPH_OBJ_TYPE, // Sort by object type SORT_BY_GRAPH_OBJ_ELEMENT_TYPE, // Sort by graphical element type SORT_BY_GRAPH_OBJ_SPECIES, // Sort by a graphical object species SORT_BY_GRAPH_OBJ_BELONG, // Sort by a graphical element affiliation SORT_BY_GRAPH_OBJ_CHART_ID, // Sort by chart ID SORT_BY_GRAPH_OBJ_WND_NUM, // Sort by chart subwindow index SORT_BY_GRAPH_OBJ_NUM, // Sort by object index in the list SORT_BY_GRAPH_OBJ_CHANGE_HISTORY, // Sort by the flag of storing the change history SORT_BY_GRAPH_OBJ_GROUP, // Sort by the group of objects the graphical object belongs to SORT_BY_GRAPH_OBJ_CREATETIME, // Sort by object creation time SORT_BY_GRAPH_OBJ_TIMEFRAMES, // Sort by object visibility on timeframes SORT_BY_GRAPH_OBJ_BACK, // Sort by the "Background object" property SORT_BY_GRAPH_OBJ_ZORDER, // Sort by the priority of a graphical object for receiving the event of clicking on a chart SORT_BY_GRAPH_OBJ_HIDDEN, // Sort by a disabling display of the name of a graphical object in the terminal object list SORT_BY_GRAPH_OBJ_SELECTED, // Sort by the "Object selection" property SORT_BY_GRAPH_OBJ_SELECTABLE, // Sort by the "Object availability" property SORT_BY_GRAPH_OBJ_TIME, // Sort by time coordinate SORT_BY_GRAPH_OBJ_COLOR, // Sort by color SORT_BY_GRAPH_OBJ_STYLE, // Sort by style SORT_BY_GRAPH_OBJ_WIDTH, // Sort by line width SORT_BY_GRAPH_OBJ_FILL, // Sort by the "Object color filling" property SORT_BY_GRAPH_OBJ_READONLY, // Sort by the ability to edit text in the Edit object SORT_BY_GRAPH_OBJ_LEVELS, // Sort by number of levels SORT_BY_GRAPH_OBJ_LEVELCOLOR, // Sort by line level color SORT_BY_GRAPH_OBJ_LEVELSTYLE, // Sort by line level style SORT_BY_GRAPH_OBJ_LEVELWIDTH, // Sort by line level width SORT_BY_GRAPH_OBJ_ALIGN, // Sort by the "Horizontal text alignment in the Entry field" property SORT_BY_GRAPH_OBJ_FONTSIZE, // Sort by font size SORT_BY_GRAPH_OBJ_RAY_LEFT, // Sort by "Ray goes to the left" property SORT_BY_GRAPH_OBJ_RAY_RIGHT, // Sort by "Ray goes to the right" property SORT_BY_GRAPH_OBJ_RAY, // Sort by the "Vertical line goes through all windows of a chart" property SORT_BY_GRAPH_OBJ_ELLIPSE, // Sort by the "Display the full ellipse of the Fibonacci Arc object" property SORT_BY_GRAPH_OBJ_ARROWCODE, // Sort by an arrow code for the Arrow object SORT_BY_GRAPH_OBJ_ANCHOR, // Sort by the position of a binding point of a graphical object SORT_BY_GRAPH_OBJ_XDISTANCE, // Sort by a distance from the base corner along the X axis in pixels SORT_BY_GRAPH_OBJ_YDISTANCE, // Sort by a distance from the base corner along the Y axis in pixels SORT_BY_GRAPH_OBJ_DIRECTION, // Sort by the "Gann object trend" property SORT_BY_GRAPH_OBJ_DEGREE, // Sort by the "Elliott wave marking level" property SORT_BY_GRAPH_OBJ_DRAWLINES, // Sort by the "Display lines for Elliott wave marking" property SORT_BY_GRAPH_OBJ_STATE, // Sort by button state (pressed/released) SORT_BY_GRAPH_OBJ_OBJ_CHART_ID, // Sort by Chart object ID. SORT_BY_GRAPH_OBJ_CHART_OBJ_PERIOD, // Sort by Chart object period SORT_BY_GRAPH_OBJ_CHART_OBJ_DATE_SCALE, // Sort by time scale display flag for the Chart object SORT_BY_GRAPH_OBJ_CHART_OBJ_PRICE_SCALE, // Sort by price scale display flag for the Chart object SORT_BY_GRAPH_OBJ_CHART_OBJ_CHART_SCALE, // Sort by Chart object scale SORT_BY_GRAPH_OBJ_XSIZE, // Sort by Object width along the X axis in pixels SORT_BY_GRAPH_OBJ_YSIZE, // Sort by object height along the Y axis in pixels SORT_BY_GRAPH_OBJ_XOFFSET, // Sort by X coordinate of the upper-left corner of the visibility area SORT_BY_GRAPH_OBJ_YOFFSET, // Sort by Y coordinate of the upper-left corner of the visibility area SORT_BY_GRAPH_OBJ_BGCOLOR, // Sort by background color for OBJ_EDIT, OBJ_BUTTON and OBJ_RECTANGLE_LABEL SORT_BY_GRAPH_OBJ_CORNER, // Sort by chart corner for binding a graphical object SORT_BY_GRAPH_OBJ_BORDER_TYPE, // Sort by border type for the "Rectangle border" object SORT_BY_GRAPH_OBJ_BORDER_COLOR, // Sort by frame color for the OBJ_EDIT and OBJ_BUTTON objects //--- Sort by real properties SORT_BY_GRAPH_OBJ_PRICE = FIRST_GRAPH_OBJ_DBL_PROP, // Sort by price coordinate SORT_BY_GRAPH_OBJ_LEVELVALUE, // Sort by level value SORT_BY_GRAPH_OBJ_SCALE, // Sort by scale (property of Gann objects and Fibonacci Arcs objects) SORT_BY_GRAPH_OBJ_ANGLE, // Sort by angle SORT_BY_GRAPH_OBJ_DEVIATION, // Sort by a deviation of the standard deviation channel //--- Sort by string properties SORT_BY_GRAPH_OBJ_NAME = FIRST_GRAPH_OBJ_STR_PROP, // Sort by object name SORT_BY_GRAPH_OBJ_BASE_NAME, // Sort by base object name SORT_BY_GRAPH_OBJ_TEXT, // Sort by object description SORT_BY_GRAPH_OBJ_TOOLTIP, // Sort by tooltip text SORT_BY_GRAPH_OBJ_LEVELTEXT, // Sort by level description SORT_BY_GRAPH_OBJ_FONT, // Sort by font SORT_BY_GRAPH_OBJ_BMPFILE, // Sort by BMP file name for the "Bitmap Level" object SORT_BY_GRAPH_OBJ_CHART_OBJ_SYMBOL, // Sort by Chart object period symbol }; //+------------------------------------------------------------------+
Ahora podemos seleccionar los objetos según sus respectivas propiedades, ordenarlos y crear listas de objetos con las mismas propiedades.
En el archivo \MQL5\Include\DoEasy\Data.mqh, escribimos los índices de los nuevos mensajes de la biblioteca:
MSG_LIB_SYS_REQUEST_OUTSIDE_LONG_ARRAY, // Request outside long array MSG_LIB_SYS_REQUEST_OUTSIDE_DOUBLE_ARRAY, // Request outside double array MSG_LIB_SYS_REQUEST_OUTSIDE_STRING_ARRAY, // Request outside string array MSG_LIB_SYS_REQUEST_OUTSIDE_ARRAY, // Request outside the array
...
MSG_GRAPH_ELEMENT_TYPE_STANDARD, // Standard graphical object MSG_GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED, // Extended standard graphical object MSG_GRAPH_ELEMENT_TYPE_ELEMENT, // Element MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ, // Shadow object MSG_GRAPH_ELEMENT_TYPE_FORM, // Form MSG_GRAPH_ELEMENT_TYPE_WINDOW, // Window
...
MSG_GRAPH_OBJ_PROP_ID, // Object ID MSG_GRAPH_OBJ_PROP_BASE_ID, // Base object ID MSG_GRAPH_OBJ_PROP_TYPE, // Graphical object type (ENUM_OBJECT) MSG_GRAPH_OBJ_PROP_ELEMENT_TYPE, // Graphical element type (ENUM_GRAPH_ELEMENT_TYPE)
...
MSG_GRAPH_OBJ_PROP_NAME, // Object name MSG_GRAPH_OBJ_PROP_BASE_NAME, // Base object name MSG_GRAPH_OBJ_PROP_TEXT, // Object description (text contained in the object) MSG_GRAPH_OBJ_PROP_TOOLTIP, // Tooltip text MSG_GRAPH_OBJ_PROP_LEVELTEXT, // Level description MSG_GRAPH_OBJ_PROP_FONT, // Font MSG_GRAPH_OBJ_PROP_BMPFILE, // BMP file name for the "Bitmap Level" object MSG_GRAPH_OBJ_PROP_SYMBOL, // Chart object symbol
...
MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_CREATE, // New graphical object created MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_CHANGE, // Changed the graphical object property MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_RENAME, // Graphical object renamed MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_DELETE, // Graphical object removed MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_DEL_CHART, // Graphical object removed together with the chart //--- CGStdGraphObj (Extended) MSG_GRAPH_OBJ_FAILED_CREATE_NEW_EXT_OBJ, // Failed to create the class object of an extended graphical object MSG_GRAPH_OBJ_FAILED_CREATE_NEW_BASE_EXT_OBJ, // Failed to create the base object for an extended graphical object MSG_GRAPH_OBJ_FAILED_ADD_EXT_OBJ_TO_LIST, // Failed to add the extended standard graphical object to the list MSG_GRAPH_OBJ_FAILED_ADD_BASE_EXT_OBJ_TO_LIST, // Failed to add the base object to the list MSG_GRAPH_OBJ_FAILED_CREATE_NEW_DEP_EXT_OBJ, // Failed to create the subordinate object of an extended graphical object MSG_GRAPH_OBJ_FAILED_ADD_DEP_EXT_OBJ_TO_LIST, // Failed to add the subordinate object to the list MSG_GRAPH_OBJ_FAILED_GET_EXT_OBJ_FROM_LIST, // Failed to receive the extended graphical object from the list MSG_GRAPH_OBJ_PROP_NUM_EXT_BASE_OBJ, // Base object of the extended graphical object MSG_GRAPH_OBJ_NOT_EXT_OBJ, // The object is not an extended standard graphical object //--- CLinkedPivotPoint MSG_GRAPH_OBJ_EXT_NOT_ANY_PIVOTS_X, // Not a single pivot point is set for the object along the X axis MSG_GRAPH_OBJ_EXT_NOT_ANY_PIVOTS_Y, // Not a single pivot point is set for the object along the Y axis MSG_GRAPH_OBJ_EXT_NOT_ATACHED_TO_BASE, // The object is not attached to the basic graphical object MSG_GRAPH_OBJ_EXT_FAILED_CREATE_PP_DATA_OBJ, // Failed to create a data object for the X and Y pivot points }; //+------------------------------------------------------------------+
y los mensajes de texto que se corresponden con los índices nuevamente añadidos:
{"Запрос за пределами long-массива","Data requested outside the long-array"}, {"Запрос за пределами double-массива","Data requested outside the double-array"}, {"Запрос за пределами string-массива","Data requested outside the string-array"}, {"Запрос за пределами массива","Data requested outside the array"},
...
{"Стандартный графический объект","Standard graphic object"}, {"Расширенный стандартный графический объект","Extended standard graphic object"}, {"Элемент","Element"}, {"Объект тени","Shadow object"}, {"Форма","Form"}, {"Окно","Window"},
...
{"Идентификатор объекта","Object ID"}, {"Идентификатор базового объекта","Base object ID"}, {"Тип объекта","Object type"}, {"Тип графического элемента","Graphic element type"},
...
{"Имя","Name"}, {"Имя базового объекта","Base object name"}, {"Описание","Description"}, {"Текст всплывающей подсказки","The text of a tooltip"}, {"Описание уровня","Level description"}, {"Шрифт","Font"}, {"Имя BMP-файла","BMP-file name"}, {"Символ графика","Chart Symbol"},
...
{"Создан новый графический объект","New graphic object created"}, {"Изменено свойство графического объекта","Changed graphic object property"}, {"Графический объект переименован","Graphic object renamed"}, {"Удалён графический объект","Graphic object deleted"}, {"Графический объект удалён вместе с графиком","The graphic object has been removed along with the chart"}, //--- CGStdGraphObj (Extended) {"Не удалось создать объект класса расширенного графического объекта","Failed to create the class object of extended standart graphics object"}, {"Не удалось создать базовый объект расширенного графического объекта","Failed to create the base object of a extended graphics object"}, {"Не удалось добавить расширенный стандартный графический объект в список","Failed to add extended standard graphic object to the list"}, {"Не удалось добавить базовый объект в список","Failed to add base object to list"}, {"Не удалось создать подчинённый объект расширенного графического объекта","Failed to create the dependent object of a extended graphics object"}, {"Не удалось добавить подчинённый объект в список","Failed to add dependent object to list"}, {"Не удалось получить расширенный графический объект из списка","Failed to get extended graphic object from list"}, {"Базовый объект расширенного графического объекта","The base object of the extended graphical object"}, {"Объект не является расширенным стандартным графическим объектом","The object is not an extended standard graphical object"}, //--- CLinkedPivotPoint {"Для объекта не установлено ни одной опорной точки по оси X","The object does not have any pivot points set along the x-axis"}, {"Для объекта не установлено ни одной опорной точки по оси Y","The object does not have any pivot points set along the y-axis"}, {"Объект не привязан к базовому графическому объекту","The object is not attached to the base graphical object"}, {"Не удалось создать объект данных опорной точки X и Y.","Failed to create X and Y reference point data object"}, }; //+---------------------------------------------------------------------+
Los objetos gráficos estándar extendidos se implementarán sobre la base de los estándar. Para que un objeto se extienda, bastará con asignarle la propiedad de objeto gráfico extendido, y entonces usará la funcionalidad creada para trabajar con objetos gráficos estándar extendidos: es decir, la capacidad de añadir objetos subordinados a su lista y administrarlos.
Ya hemos creado las clases para todos los objetos gráficos estándar herederos de la clase de objeto gráfico estándar abstracto, por lo que, al crear un objeto extendido, bastará con establecer la bandera que indica que no se está creando un objeto gráfico normal, sino uno extendido.
Obviamente, este objeto se creará de forma programática, así que deberemos establecer la propiedad de pertenencia del objeto como "el objeto pertenece al programa" (por defecto, estableceremos la propiedad que indica que el objeto se ha creado manualmente). Y de la misma forma, necesitaremos establecer el tipo de objeto gráfico, no como estándar, sino como estándar extendido. Implementaremos todo ello según el valor de bandera transmitido al constructor del objeto gráfico al crear este.
Además de estas mejoras, necesitaremos añadir a los métodos que retornan las banderas de soporte de propiedades por parte del objeto, las nuevas propiedades del objeto gráfico que hemos creado anteriormente.
Como todos estos cambios son del mismo tipo para todas las clases de objetos gráficos estándar ubicados en la carpeta
\MQL5\Include\DoEasy\Objects\Graph\Standard\, analizaremos los cambios realizados solo en el ejemplo del archivo GStdArrowBuyObj.mqh.
Transmitimos al constructor de clase la bandera del objeto gráfico estándar extendido, y dependiendo del valor de esta bandera, indicamos si se trata de un objeto gráfico estándar, o estándar extendido, además de si el objeto ha sido creado manualmente o de forma programática:
public: //--- Constructor CGStdArrowBuyObj(const long chart_id,const string name,const bool extended) : CGStdGraphObj(OBJECT_DE_TYPE_GSTD_ARROW_BUY,(!extended ? GRAPH_ELEMENT_TYPE_STANDARD : GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED),(!extended ? GRAPH_OBJ_BELONG_NO_PROGRAM : GRAPH_OBJ_BELONG_PROGRAM),GRAPH_OBJ_SPECIES_ARROWS,chart_id,1,name) { //--- Specify the object property CGStdGraphObj::SetProperty(GRAPH_OBJ_PROP_ANCHOR,0,ANCHOR_TOP); }
En los métodos que retornan las banderas de soporte de las propiedades enteras y string por parte del objeto, añadimos las nuevas propiedades que hemos escrito anteriormente:
//+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdArrowBuyObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property) { switch((int)property) { //--- Supported properties case GRAPH_OBJ_PROP_ID : case GRAPH_OBJ_PROP_BASE_ID : case GRAPH_OBJ_PROP_TYPE : case GRAPH_OBJ_PROP_ELEMENT_TYPE : case GRAPH_OBJ_PROP_GROUP : case GRAPH_OBJ_PROP_BELONG : case GRAPH_OBJ_PROP_CHART_ID : case GRAPH_OBJ_PROP_WND_NUM : case GRAPH_OBJ_PROP_NUM : case GRAPH_OBJ_PROP_CREATETIME : case GRAPH_OBJ_PROP_CHANGE_HISTORY: case GRAPH_OBJ_PROP_TIMEFRAMES : case GRAPH_OBJ_PROP_BACK : case GRAPH_OBJ_PROP_ZORDER : case GRAPH_OBJ_PROP_HIDDEN : case GRAPH_OBJ_PROP_SELECTED : case GRAPH_OBJ_PROP_SELECTABLE : case GRAPH_OBJ_PROP_TIME : case GRAPH_OBJ_PROP_COLOR : case GRAPH_OBJ_PROP_STYLE : case GRAPH_OBJ_PROP_WIDTH : case GRAPH_OBJ_PROP_ANCHOR : return true; //--- Other properties are not supported //--- Default is 'false' default: break; } return false; } //+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdArrowBuyObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property) { switch((int)property) { //--- Supported properties case GRAPH_OBJ_PROP_PRICE : return true; //--- Other properties are not supported //--- Default is 'false' default: break; } return false; } //+------------------------------------------------------------------+ //| Return 'true' if an object supports a passed | //| string property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CGStdArrowBuyObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_STRING property) { switch((int)property) { //--- Supported properties case GRAPH_OBJ_PROP_NAME : case GRAPH_OBJ_PROP_BASE_NAME : case GRAPH_OBJ_PROP_TEXT : case GRAPH_OBJ_PROP_TOOLTIP : return true; //--- Other properties are not supported //--- Default is 'false' default: break; } return false; } //+------------------------------------------------------------------+
Dichos cambios deben realizarse en todos los archivos ubicados en la carpeta \MQL5\Include\DoEasy\Objects\Graph\Standard\, cosa que, por cierto, ya hemos realizado. Podrá ver todas las mejoras en los archivos adjuntos al artículo.
Después de realizar estas mejoras, las nuevas propiedades serán procesadas por todos los objetos de clase de los objetos gráficos estándar, y podremos trabajar de forma totalmente funcional con estas propiedades, ya que se han establecido las banderas necesarias para ofrecer soporte a estas nuevas propiedades para cada uno de esos objetos.
En el archivo de clase del objeto gráfico básico \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh, en el método que retorna la descripción del tipo de elemento gráfico, añadimos la comprobación del elemento gráfico "objeto gráfico estándar extendido, para que podamos mostrar correctamente la descripción de dicho objeto gráfico:
//+------------------------------------------------------------------+ //| Return the description of the graphical element type | //+------------------------------------------------------------------+ string CGBaseObj::TypeElementDescription(void) { return ( this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_STANDARD ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_ELEMENT ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_ELEMENT) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_SHADOW_OBJ ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_FORM ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_FORM) : this.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WINDOW ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WINDOW) : "Unknown" ); } //+------------------------------------------------------------------+
Clases para indicar las coordenadas de un objeto dependiente
Cualquier objeto dependiente en la lista del objeto gráfico básico tendrá sus propias coordenadas sobre las que se construirá. Al mismo tiempo, el objeto gráfico básico deberá saber cómo gestionar las coordenadas del objeto dependiente. Para que el objeto básico sepa a qué coordenadas está vinculado el objeto gráfico dependiente, este último deberá tener algunas propiedades que el objeto básico pueda leer, y así enviar un comando de cambio en las coordenadas del objeto dependiente cuando cambien las suyas.
Para posibilitar esta relación entre las propiedades del objeto básico y el dependiente, crearemos una clase que conoceremos como clase de objeto de puntos de pivote vinculados.
Tendremos tres clases:
- La clase de datos del punto de pivote, que almacenará aquellas propiedades según las cuales el objeto dependiente se vincula al eje de coordenadas del objeto básico;
- La clase de datos de los dos puntos de pivote, que almacenará los dos objetos de la primera clase. Una los almacenará datos de la propiedad según los cuales el objeto dependiente se fija a lo largo de la coordenada X a la base, y el segundo contendrá los datos según los cuales el objeto se fija a lo largo de la coordenada Y;
- La clase de puntos de pivote vinculados. Esta clase almacenará una lista con los objetos del segundo tipo: un objeto de clase de datos de los dos puntos de anclaje será responsable de cada uno de sus puntos de pivote, es decir, cada objeto almacenará en sí mismo aquellas propiedades del objeto básico sobre las cuales se construirá el punto de anclaje del objeto dependiente: sus coordenadas X e Y, que a su vez se pueden calcular partiendo de varias coordenadas del objeto básico cuya lista para cada eje se almacena en el objeto del primer tipo.
Un objeto del primer se creará usando como base una matriz bidimensional regular.
La segunda dimensión de la matriz tendrá una dimensionalidad de 2; la celda cero contendrá la propiedad en sí, por ejemplo, "Tiempo" o "Precio", mientras que la primera celda contendrá el modificador de propiedad. Por ejemplo, una línea de tendencia tiene dos puntos de anclaje, y el punto que se usará precisamente para especificar la coordenada se registrará en la celda 1 de la segunda dimensión de matriz. Para el punto izquierdo de la línea de tendencia, este valor será 0, para el derecho, 1.
En la mayoría de los casos, la matriz en su primera dimensión tendrá un tamaño de 1, la indicación de una sola propiedad del objeto básico a cuyas coordenadas se fijará el objeto dependiente. Pero, si necesitamos fijar un objeto a las coordenadas calculadas, por ejemplo, entre dos puntos de una línea de tendencia, entonces necesitaremos aumentar la dimensionalidad de la matriz a dos: la primera dimensión contendrá las propiedades del primer punto de pivote del objeto básico, y la segunda, las del segundo. En este caso, el objeto dependiente se fijará al objeto básico según alguna fórmula (por defecto, la media) que el usuario de la biblioteca establecerá en el código de forma independiente. No obstante, no vamos a implementar esta funcionalidad hoy. Hoy estamos preparando todo lo necesario para implementar nuestros planes.
Vamos a escribir estas clases directamente en el archivo del objeto gráfico estándar abstracto \MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqh, ya que es en este archivo donde se declararán y usarán las clases si el objeto creado es un objeto gráfico estándar extendido.
Al comienzo de la lista de archivos, escribimos la clase de datos del punto de pivote del objeto dependiente:
//+------------------------------------------------------------------+ //| GStdGraphObj.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\GBaseObj.mqh" #include "..\..\..\Services\Properties.mqh" //+------------------------------------------------------------------+ //| Class of the dependent object pivot point data | //+------------------------------------------------------------------+ class CPivotPointData { private: bool m_axis_x; int m_property_x[][2]; public: //--- (1) Set and (2) return the flag indicating that the pivot point belongs to the X coordinate void SetAxisX(const bool axis_x) { this.m_axis_x=axis_x; } bool IsAxisX(void) const { return this.m_axis_x; } //--- Return the number of base object pivot points for calculating the coordinate of the dependent one int GetBasePivotsNum(void) const { return ::ArrayRange(this.m_property_x,0); } //--- Add the new pivot point of the base object for calculating the coordinate of a dependent one bool AddNewBasePivotPoint(const string source,const int pivot_prop,const int pivot_num) { //--- Get the array size int pivot_index=this.GetBasePivotsNum(); //--- if failed to increase the array size, inform of that and return 'false' if(::ArrayResize(this.m_property_x,pivot_index+1)!=pivot_index+1) { CMessage::ToLog(source,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); return false; } //--- Return the result of changing the values of a newly added new array dimension return this.ChangeBasePivotPoint(source,pivot_index,pivot_prop,pivot_num); } //--- Change the specified pivot point of the base object for calculating the coordinate of a dependent one bool ChangeBasePivotPoint(const string source,const int pivot_index,const int pivot_prop,const int pivot_num) { //--- Get the array size. If it is zero, inform of that and return 'false' int n=this.GetBasePivotsNum(); if(n==0) { CMessage::ToLog(source,(this.IsAxisX() ? MSG_GRAPH_OBJ_EXT_NOT_ANY_PIVOTS_X : MSG_GRAPH_OBJ_EXT_NOT_ANY_PIVOTS_Y)); return false; } //--- If the specified index goes beyond the array range, inform of that and return 'false' if(pivot_index<0 || pivot_index>n-1) { CMessage::ToLog(source,MSG_LIB_SYS_REQUEST_OUTSIDE_ARRAY); return false; } //--- Set the values, passed to the method, in the specified array cells by index this.m_property_x[pivot_index][0]=pivot_prop; this.m_property_x[pivot_index][1]=pivot_num; return true; } //--- Constructor/destructor CPivotPointData(void){;} ~CPivotPointData(void){;} }; //+------------------------------------------------------------------+
La clase contiene una matriz bidimensional, así como dos métodos para cambiar su tamaño (añadir un nuevo punto de pivote) y establecer los valores de la primera dimensión especificada de la matriz. La clase también tiene los métodos necesarios para indicar qué datos de coordenadas se establecen en la matriz: X o Y. Al mostrar mensajes desde la clase, esta bandera se marcará, y se mostrará el mensaje de error correspondiente.
Justo después del listado de esta clase, escribimos la clase de datos de los puntos de pivote X e Y del objeto compuesto:
//+------------------------------------------------------------------+ //| Class of data on X and Y pivot points of a composite object | //+------------------------------------------------------------------+ class CPivotPointXY : public CObject { private: CPivotPointData m_pivot_point_x; // X coordinate pivot point CPivotPointData m_pivot_point_y; // Y coordinate pivot point public: //--- Return the pointer to the (1) X and (2) Y coordinate pivot point data object CPivotPointData *GetPivotPointDataX(void) { return &this.m_pivot_point_x; } CPivotPointData *GetPivotPointDataY(void) { return &this.m_pivot_point_y; } //--- Return the number of base object pivot points for calculating the (1) X and (2) Y coordinate int GetBasePivotsNumX(void) const { return this.m_pivot_point_x.GetBasePivotsNum(); } int GetBasePivotsNumY(void) const { return this.m_pivot_point_y.GetBasePivotsNum(); } //--- Add the new pivot point of the base object for calculating the X coordinate of a dependent one bool AddNewBasePivotPointX(const int pivot_prop,const int pivot_num) { return this.m_pivot_point_x.AddNewBasePivotPoint(DFUN,pivot_prop,pivot_num); } //--- Add the new pivot point of the base object for calculating the Y coordinate of a dependent one bool AddNewBasePivotPointY(const int pivot_prop,const int pivot_num) { return this.m_pivot_point_y.AddNewBasePivotPoint(DFUN,pivot_prop,pivot_num); } //--- Add new pivot points of the base object for calculating the X and Y coordinates of a dependent one bool AddNewBasePivotPointXY(const int pivot_prop_x,const int pivot_num_x, const int pivot_prop_y,const int pivot_num_y) { bool res=true; res &=this.m_pivot_point_x.AddNewBasePivotPoint(DFUN,pivot_prop_x,pivot_num_x); res &=this.m_pivot_point_y.AddNewBasePivotPoint(DFUN,pivot_prop_y,pivot_num_y); return res; } //--- Change the specified pivot point of the base object for calculating the X coordinate of a dependent one bool ChangeBasePivotPointX(const int pivot_index,const int pivot_prop,const int pivot_num) { return this.m_pivot_point_x.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop,pivot_num); } //--- Change the specified pivot point of the base object for calculating the Y coordinate of a dependent one bool ChangeBasePivotPointY(const int pivot_index,const int pivot_prop,const int pivot_num) { return this.m_pivot_point_y.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop,pivot_num); } //--- Change specified pivot points of the base object for calculating the X and Y coordinates bool ChangeBasePivotPointXY(const int pivot_index, const int pivot_prop_x,const int pivot_num_x, const int pivot_prop_y,const int pivot_num_y) { bool res=true; res &=this.m_pivot_point_x.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop_x,pivot_num_x); res &=this.m_pivot_point_y.ChangeBasePivotPoint(DFUN,pivot_index,pivot_prop_y,pivot_num_y); return res; } //--- Constructor/destructor CPivotPointXY(void){ this.m_pivot_point_x.SetAxisX(true); this.m_pivot_point_y.SetAxisX(false); } ~CPivotPointXY(void){;} }; //+------------------------------------------------------------------+
Esta clase contiene los dos objetos anteriores: para la coordenada X y para la coordenada Y, así como los métodos para trabajar con estos objetos que, de hecho, simplemente retornan los resultados del trabajo con los métodos de primera clase. En el constructor, a cada uno de los objetos se les asignan las banderas del eje X o Y.
La clase también contiene los métodos para establecer simultáneamente los valores de propiedad para las coordenadas X e Y: ahí se llaman de inmediato los métodos de las dos primeras clases y se retorna el resultado combinado de su llamada; si al menos uno de los métodos retorna false, entonces el resultado será false.
Después de esta clase, escribiremos la tercera, a saber, la clase de datos vinculados de los puntos de pivote del objeto compuesto:
//+------------------------------------------------------------------+ //| Class of connected data on composite object pivot points | //+------------------------------------------------------------------+ class CLinkedPivotPoint { private: CArrayObj m_list; // List of pivot points of the bound object X and Y coordinates int m_base_obj_index; // Base object index public: //--- (1) Set and (2) return the base object index void SetBaseObjIndex(const int index) { this.m_base_obj_index=index; } int GetBaseObjIndex(void) const { return this.m_base_obj_index; } //--- Create a new object of the class of data on X and Y pivot points of a composite object and add it to the object list bool CreateNewLinkedPivotPoint(const int pivot_prop_x,const int pivot_num_x,const int pivot_prop_y,const int pivot_num_y) { //--- Create an object of data on X and Y pivot points CPivotPointXY *obj=new CPivotPointXY(); if(obj==NULL) return false; //--- Add a single dimension with data on pivot points of the base object by X and Y to each object if(!obj.AddNewBasePivotPointXY(pivot_prop_x,pivot_num_x,pivot_prop_y,pivot_num_y)) return false; //--- If failed to add the newly created object to the list, inform of that, remove the object and return 'false' if(!this.m_list.Add(obj)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); delete obj; return false; } //--- If all is successful, return 'true' return true; } //--- Return the amount of data on pivot points of X and Y coordinates int GetNumLinkedPivotPoints(void) const { return this.m_list.Total(); } //--- Return the pointer to the (1) first and (2) the last object of data on X and Y pivot points (3) by index CPivotPointXY *GetLinkedPivotPointXYFirst(void) const { return this.m_list.At(0); } CPivotPointXY *GetLinkedPivotPointXYLast(void) const { return this.m_list.At(this.m_list.Total()-1); } CPivotPointXY *GetLinkedPivotPointXY(const int index) const { return this.m_list.At(index); } //--- Return the pointer to the X coordinate pivot point data object by index CPivotPointData *GetBasePivotPointDataX(const int index) const { CPivotPointXY *obj=this.GetLinkedPivotPointXY(index); if(obj==NULL) return NULL; return obj.GetPivotPointDataX(); } //--- Return the pointer to the Y coordinate pivot point data object by index CPivotPointData *GetBasePivotPointDataY(const int index) const { CPivotPointXY *obj=this.GetLinkedPivotPointXY(index); if(obj==NULL) return NULL; return obj.GetPivotPointDataY(); } //--- Return the number of base object pivot points for calculating the X coordinate by index int GetBasePivotsNumX(const int index) const { CPivotPointData *obj=this.GetBasePivotPointDataX(index); if(obj==NULL) return NULL; return obj.GetBasePivotsNum(); } //--- Return the number of base object pivot points for calculating the Y coordinate by index int GetBasePivotsNumY(const int index) const { CPivotPointData *obj=this.GetBasePivotPointDataY(index); if(obj==NULL) return NULL; return obj.GetBasePivotsNum(); } //--- Constructor/destructor CLinkedPivotPoint(void){;} ~CLinkedPivotPoint(void){;} }; //+------------------------------------------------------------------+
La clase nos permite crear los objetos de clase de datos de los puntos de pivote X e Y del objeto compuesto anteriormente analizado, y retorna los punteros a los objetos de esta clase con los que necesitamos trabajar. Uno de estos objetos describe al completo el punto de anclaje del objeto básico según las coordenadas X e Y, y nos permite añadir nuevos puntos de anclaje y cambiar los existentes. El objeto también contiene el identificador del objeto básico según el cual es posible determinar a qué objeto está vinculado este objeto gráfico.
En la sección privada de la clase de objeto gráfico estándar abstracto, declaramos la lista de objetos dependientes (fijados a ella) y el objeto de la clase de puntos de anclaje vinculados que hemos analizado anteriormente:
//+------------------------------------------------------------------+ //| The class of the abstract standard graphical object | //+------------------------------------------------------------------+ class CGStdGraphObj : public CGBaseObj { private: CArrayObj m_list; // List of dependent graphical objects CProperties *Prop; // Pointer to the property object CLinkedPivotPoint m_linked_pivots; // Connected pivot points int m_pivots; // Number of object reference points //--- Read and set (1) the time and (2) the price of the specified object pivot point void SetTimePivot(const int index); void SetPricePivot(const int index); //--- Read and set (1) color, (2) style, (3) width, (4) value, (5) text of the specified object level void SetLevelColor(const int index); void SetLevelStyle(const int index); void SetLevelWidth(const int index); void SetLevelValue(const int index); void SetLevelText(const int index); //--- Read and set the BMP file name for the "Bitmap Level" object. Index: 0 - ON, 1 - OFF void SetBMPFile(const int index); public:
En la sección pública de la clase, añadimos los métodos necesarios para trabajar con la lista de objetos gráficos anclados y el objeto de puntos de pivote vinculados:
//--- Set the object previous name bool SetNamePrev(const string name) { if(!this.Prop.SetSizeRange(GRAPH_OBJ_PROP_NAME,this.Prop.CurrSize(GRAPH_OBJ_PROP_NAME)+1)) return false; this.SetProperty(GRAPH_OBJ_PROP_NAME,this.Prop.CurrSize(GRAPH_OBJ_PROP_NAME)-1,name); return true; } //--- Return (1) the list of dependent objects and (2) dependent graphical object by index CArrayObj *GetListDependentObj(void) { return &this.m_list; } CGStdGraphObj *GetDependentObj(const int index) { return this.m_list.At(index); } //--- Return the name of the dependent object by index string NameDependent(const int index); //--- Add the dependent graphical object to the list bool AddDependentObj(CGStdGraphObj *obj); //--- Return the object of data on pivot points CLinkedPivotPoint*GetLinkedPivotPoint(void) { return &this.m_linked_pivots; } //--- Add a new pivot point for calculating X and Y coordinates to the current object bool AddNewLinkedPivotPointXY(const int pivot_prop_x,const int pivot_num_x,const int pivot_prop_y,const int pivot_num_y) { //--- If the current object is not bound to the base one, display the appropriate message and return 'false' if(this.BaseObjectID()==0) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_EXT_NOT_ATACHED_TO_BASE); return false; } //--- Return the result of adding a new connected pivot point from the CLinkedPivotPoint class to the current object return this.m_linked_pivots.CreateNewLinkedPivotPoint(pivot_prop_x,pivot_num_x,pivot_prop_y,pivot_num_y); } //--- Add a new pivot point for calculating X and Y coordinates to the specified object bool AddNewLinkedPivotPointXY(CGStdGraphObj *obj,const int pivot_prop_x,const int pivot_num_x,const int pivot_prop_y,const int pivot_num_y) { //--- If the current object is not an extended one, display the appropriate message and return 'false' if(this.TypeGraphElement()!=GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_NOT_EXT_OBJ); return false; } //--- If a zero pointer to the object is passed, return 'false' if(obj==NULL) return false; //--- Return the result of adding a new connected pivot point from the CLinkedPivotPoint class to the specified object return obj.AddNewLinkedPivotPointXY(pivot_prop_x,pivot_num_x,pivot_prop_y,pivot_num_y); } //--- Add the new base object anchor point for calculating the X coordinate bool AddNewBaseLinkedPivotX(const int index,const int pivot_prop,const int pivot_num) { //--- If the current object is not bound to the base one, display the appropriate message and return 'false' if(this.BaseObjectID()==0) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_EXT_NOT_ATACHED_TO_BASE); return false; } //--- Get the pointer to the necessary pivot point data CPivotPointData *data=m_linked_pivots.GetBasePivotPointDataX(index); if(data==NULL) return false; //--- Return the result of adding a new anchor point to the current object return data.AddNewBasePivotPoint(DFUN,pivot_prop,pivot_num); } //--- Add the new base object anchor point for calculating the Y coordinate bool AddNewBaseLinkedPivotY(const int index,const int pivot_prop,const int pivot_num) { //--- If the current object is not bound to the base one, display the appropriate message and return 'false' if(this.BaseObjectID()==0) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_EXT_NOT_ATACHED_TO_BASE); return false; } //--- Get the pointer to the necessary pivot point data CPivotPointData *data=m_linked_pivots.GetBasePivotPointDataY(index); if(data==NULL) return false; //--- Return the result of adding a new anchor point to the current object return data.AddNewBasePivotPoint(DFUN,pivot_prop,pivot_num); } //--- Add the new base object anchor point for calculating the X coordinate to the specified subordinate graphical object bool AddNewBaseLinkedPivotX(CGStdGraphObj *obj,const int index,const int pivot_prop,const int pivot_num) { //--- If the current object is not an extended one, display the appropriate message and return 'false' if(this.TypeGraphElement()!=GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_NOT_EXT_OBJ); return false; } //--- If a zero pointer to the object is passed, return 'false' if(obj==NULL) return false; //--- Return the result of adding a new anchor point to the specified object return obj.AddNewBaseLinkedPivotX(index,pivot_prop,pivot_num); } //--- Add the new base object anchor point for calculating the Y coordinate to the specified subordinate graphical object bool AddNewBaseLinkedPivotY(CGStdGraphObj *obj,const int index,const int pivot_prop,const int pivot_num) { //--- If the current object is not an extended one, display the appropriate message and return 'false' if(this.TypeGraphElement()!=GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_NOT_EXT_OBJ); return false; } //--- If a zero pointer to the object is passed, return 'false' if(obj==NULL) return false; //--- Return the result of adding a new anchor point to the specified object return obj.AddNewBaseLinkedPivotY(index,pivot_prop,pivot_num); } //--- Return the number of base object pivot points for calculating the (1) X and (2) Y coordinate in the current object int GetBasePivotsNumX(const int index) { return this.m_linked_pivots.GetBasePivotsNumX(index); } int GetBasePivotsNumY(const int index) { return this.m_linked_pivots.GetBasePivotsNumY(index); } //--- Return the number of base object pivot points for calculating the (1) X and (2) Y coordinate in the specified object int GetBasePivotsNumX(CGStdGraphObj *obj,const int index) const { return(obj!=NULL ? obj.GetBasePivotsNumX(index): 0); } int GetBasePivotsNumY(CGStdGraphObj *obj,const int index) const { return(obj!=NULL ? obj.GetBasePivotsNumY(index): 0); } //--- Return the number of base object pivot points for calculating the coordinates in the (1) current (2) object int GetLinkedPivotsNum(void) const { return this.m_linked_pivots.GetNumLinkedPivotPoints(); } int GetLinkedPivotsNum(CGStdGraphObj *obj) const { return(obj!=NULL ? obj.GetLinkedPivotsNum() : 0); } //--- Default constructor CGStdGraphObj(){ this.m_type=OBJECT_DE_TYPE_GSTD_OBJ; this.m_species=WRONG_VALUE; } //--- Destructor ~CGStdGraphObj() { if(this.Prop!=NULL) delete this.Prop; } protected:
Todos los métodos retornan el resultado de la llamada a los métodos homónimos de las clases anteriormente analizadas, y solo ofrecen acceso para trabajar con estos objetos. Algunos métodos están comentados en el código, por lo que no necesitan explicaciones. En cualquier caso, siempre podrá plantear cualquier duda en los comentarios al artículo.
Ahora, vamos a transmitir al constructor paramétrico protegido el tipo del elemento gráfico creado:
//--- Default constructor CGStdGraphObj(){ this.m_type=OBJECT_DE_TYPE_GSTD_OBJ; this.m_species=WRONG_VALUE; } //--- Destructor ~CGStdGraphObj() { if(this.Prop!=NULL) delete this.Prop; } protected: //--- Protected parametric constructor CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type, const ENUM_GRAPH_ELEMENT_TYPE elm_type, const ENUM_GRAPH_OBJ_BELONG belong, const ENUM_GRAPH_OBJ_SPECIES species, const long chart_id, const int pivots, const string name); public:
Al crear un objeto, ahora podemos indicar que se está creando un objeto gráfico estándar extendido transmitiendo como el tipo de elemento el valor GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED de la enumeración ENUM_GRAPH_ELEMENT_TYPE, lo cual se hace en los constructores de sus clases descendientes.
En el bloque de métodos para el acceso simplificado y la configuración de las propiedades de un objeto gráfico, introducimos los métodos para trabajar con el identificador del objeto básico y los métodos para trabajar con el nombre del objeto básico:
public: //+--------------------------------------------------------------------+ //|Methods of simplified access and setting graphical object properties| //+--------------------------------------------------------------------+ //--- Object index in the list int Number(void) const { return (int)this.GetProperty(GRAPH_OBJ_PROP_NUM,0); } void SetNumber(const int number) { this.SetProperty(GRAPH_OBJ_PROP_NUM,0,number); } //--- Flag of storing the change history bool AllowChangeHistory(void) const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_CHANGE_HISTORY,0); } void SetAllowChangeMemory(const bool flag){ this.SetProperty(GRAPH_OBJ_PROP_CHANGE_HISTORY,0,flag); } //--- Object ID long ObjectID(void) const { return this.GetProperty(GRAPH_OBJ_PROP_ID,0); } void SetObjectID(const long obj_id) { CGBaseObj::SetObjectID(obj_id); this.SetProperty(GRAPH_OBJ_PROP_ID,0,obj_id); this.SetPropertyPrev(GRAPH_OBJ_PROP_ID,0,obj_id); } //--- Base object ID long BaseObjectID(void) const { return this.GetProperty(GRAPH_OBJ_PROP_BASE_ID,0); } void SetBaseObjectID(const long obj_id) { this.SetProperty(GRAPH_OBJ_PROP_BASE_ID,0,obj_id); this.SetPropertyPrev(GRAPH_OBJ_PROP_BASE_ID,0,obj_id); } //--- Graphical object type ENUM_OBJECT GraphObjectType(void) const { return (ENUM_OBJECT)this.GetProperty(GRAPH_OBJ_PROP_TYPE,0); } void SetGraphObjectType(const ENUM_OBJECT obj_type) { CGBaseObj::SetTypeGraphObject(obj_type); this.SetProperty(GRAPH_OBJ_PROP_TYPE,0,obj_type); }
...
//--- Object name string Name(void) const { return this.GetProperty(GRAPH_OBJ_PROP_NAME,0); } bool SetName(const string name) { if(CGBaseObj::Name()==name) return true; if(CGBaseObj::Name()=="") { CGBaseObj::SetName(name); this.SetProperty(GRAPH_OBJ_PROP_NAME,0,name); return true; } else { if(!::ObjectSetString(CGBaseObj::ChartID(),CGBaseObj::Name(),OBJPROP_NAME,name)) return false; CGBaseObj::SetName(name); this.SetProperty(GRAPH_OBJ_PROP_NAME,0,name); return true; } } //--- Base object name string BaseName(void) const { return this.GetProperty(GRAPH_OBJ_PROP_BASE_NAME,0); } bool SetBaseName(const string name) { this.SetProperty(GRAPH_OBJ_PROP_BASE_NAME,0,name); return true; } //--- Object description (text contained in the object)
Los métodos nos permiten establecer el identificador y el nombre del objeto básico en las propiedades del objeto y retornar estos datos.
A continuación, escribimos la declaración del método que retorna la descripción del número de objeto en la lista de objetos gráficos vinculados:
//--- Return the flags indicating object visibility on timeframes bool IsVisibleOnTimeframeM1(void) const { return IsVisibleOnTimeframe(PERIOD_M1, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM2(void) const { return IsVisibleOnTimeframe(PERIOD_M2, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM3(void) const { return IsVisibleOnTimeframe(PERIOD_M3, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM4(void) const { return IsVisibleOnTimeframe(PERIOD_M4, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM5(void) const { return IsVisibleOnTimeframe(PERIOD_M5, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM6(void) const { return IsVisibleOnTimeframe(PERIOD_M6, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM10(void) const { return IsVisibleOnTimeframe(PERIOD_M10,(int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM12(void) const { return IsVisibleOnTimeframe(PERIOD_M12,(int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM15(void) const { return IsVisibleOnTimeframe(PERIOD_M15,(int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM20(void) const { return IsVisibleOnTimeframe(PERIOD_M20,(int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeM30(void) const { return IsVisibleOnTimeframe(PERIOD_M30,(int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeH1(void) const { return IsVisibleOnTimeframe(PERIOD_H1, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeH2(void) const { return IsVisibleOnTimeframe(PERIOD_H2, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeH3(void) const { return IsVisibleOnTimeframe(PERIOD_H3, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeH4(void) const { return IsVisibleOnTimeframe(PERIOD_H4, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeH6(void) const { return IsVisibleOnTimeframe(PERIOD_H6, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeH8(void) const { return IsVisibleOnTimeframe(PERIOD_H8, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeH12(void) const { return IsVisibleOnTimeframe(PERIOD_H12,(int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeD1(void) const { return IsVisibleOnTimeframe(PERIOD_D1, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeW1(void) const { return IsVisibleOnTimeframe(PERIOD_W1, (int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } bool IsVisibleOnTimeframeMN1(void) const { return IsVisibleOnTimeframe(PERIOD_MN1,(int)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0)); } //--- Return the description of the (1) object visibility on timeframes and (2) the index in the composite graphical object list string VisibleOnTimeframeDescription(void); string NumberDescription(void); //--- Re-write all graphical object properties
En el constructor paramétrico protegido, escribimos la variable con el tipo del elemento gráfico y registramos el valor transmitido en ella al objeto gráfico básico; a continuación, establecemos los valores por defecto para las nuevas propiedades del nuevo objeto gráfico creadas anteriormente:
//+------------------------------------------------------------------+ //| Protected parametric constructor | //+------------------------------------------------------------------+ CGStdGraphObj::CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type, const ENUM_GRAPH_ELEMENT_TYPE elm_type, const ENUM_GRAPH_OBJ_BELONG belong, const ENUM_GRAPH_OBJ_SPECIES species, const long chart_id,const int pivots, const string name) { //--- Create the property object with the default values this.Prop=new CProperties(GRAPH_OBJ_PROP_INTEGER_TOTAL,GRAPH_OBJ_PROP_DOUBLE_TOTAL,GRAPH_OBJ_PROP_STRING_TOTAL); //--- Set the number of pivot points and object levels this.m_pivots=pivots; int levels=(int)::ObjectGetInteger(chart_id,name,OBJPROP_LEVELS); //--- Set the property array dimensionalities according to the number of pivot points and levels this.Prop.SetSizeRange(GRAPH_OBJ_PROP_TIME,this.m_pivots); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_PRICE,this.m_pivots); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELCOLOR,levels); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELSTYLE,levels); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELWIDTH,levels); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELVALUE,levels); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELTEXT,levels); this.Prop.SetSizeRange(GRAPH_OBJ_PROP_BMPFILE,2); //--- Set the object (1) type, type of graphical (2) object, (3) element, (4) subwindow affiliation and (5) index, as well as (6) chart symbol Digits this.m_type=obj_type; this.SetName(name); CGBaseObj::SetChartID(chart_id); CGBaseObj::SetTypeGraphObject(CGBaseObj::GraphObjectType(obj_type)); CGBaseObj::SetTypeElement(elm_type); CGBaseObj::SetBelong(belong); CGBaseObj::SetSpecies(species); CGBaseObj::SetSubwindow(chart_id,name); CGBaseObj::SetDigits((int)::SymbolInfoInteger(::ChartSymbol(chart_id),SYMBOL_DIGITS)); //--- Save the integer properties inherent in all graphical objects but not present in the current one this.SetProperty(GRAPH_OBJ_PROP_CHART_ID,0,CGBaseObj::ChartID()); // Chart ID this.SetProperty(GRAPH_OBJ_PROP_WND_NUM,0,CGBaseObj::SubWindow()); // Chart subwindow index this.SetProperty(GRAPH_OBJ_PROP_TYPE,0,CGBaseObj::TypeGraphObject()); // Graphical object type (ENUM_OBJECT) this.SetProperty(GRAPH_OBJ_PROP_ELEMENT_TYPE,0,CGBaseObj::TypeGraphElement()); // Graphical element type (ENUM_GRAPH_ELEMENT_TYPE) this.SetProperty(GRAPH_OBJ_PROP_BELONG,0,CGBaseObj::Belong()); // Graphical object affiliation this.SetProperty(GRAPH_OBJ_PROP_SPECIES,0,CGBaseObj::Species()); // Graphical object species this.SetProperty(GRAPH_OBJ_PROP_GROUP,0,0); // Graphical object group this.SetProperty(GRAPH_OBJ_PROP_ID,0,0); // Object ID this.SetProperty(GRAPH_OBJ_PROP_BASE_ID,0,0); // Base object ID this.SetProperty(GRAPH_OBJ_PROP_NUM,0,0); // Object index in the list this.SetProperty(GRAPH_OBJ_PROP_CHANGE_HISTORY,0,false); // Flag of storing the change history this.SetProperty(GRAPH_OBJ_PROP_BASE_NAME,0,this.Name()); // Base object name //--- Save the properties inherent in all graphical objects and present in a graphical object this.PropertiesRefresh(); //--- Save basic properties in the parent object this.m_create_time=(datetime)this.GetProperty(GRAPH_OBJ_PROP_CREATETIME,0); this.m_back=(bool)this.GetProperty(GRAPH_OBJ_PROP_BACK,0); this.m_selected=(bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTED,0); this.m_selectable=(bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTABLE,0); this.m_hidden=(bool)this.GetProperty(GRAPH_OBJ_PROP_HIDDEN,0); //--- Save the current properties to the previous ones this.PropertiesCopyToPrevData(); } //+-------------------------------------------------------------------+
Por defecto, el identificador del objeto básico es igual a cero, lo cual significa que no existe, y el nombre del objeto básico es igual al nombre del objeto gráfico actual, es decir, el objeto se indica a sí mismo, lo cual también significa que no hay vinculación con el objeto básico.
En el método que retorna la descripción de una propiedad entera del objeto, escribimos la muestra de la descripción del identificador del objeto básico, y en el bloque que retorna la descripción del número de objeto en la lista de objetos vinculados, escribimos la llamada al método que hará esto (lo escribiremos más adelante):
//+------------------------------------------------------------------+ //| Return description of object's integer property | //+------------------------------------------------------------------+ string CGStdGraphObj::GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_INTEGER property) { return ( property==GRAPH_OBJ_PROP_ID ? CMessage::Text(MSG_GRAPH_OBJ_PROP_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_BASE_ID ? CMessage::Text(MSG_GRAPH_OBJ_PROP_BASE_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_TYPE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_TYPE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.TypeDescription() ) : property==GRAPH_OBJ_PROP_ELEMENT_TYPE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_ELEMENT_TYPE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+CGBaseObj::TypeElementDescription() ) : property==GRAPH_OBJ_PROP_SPECIES ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SPECIES)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+CGBaseObj::SpeciesDescription() ) : property==GRAPH_OBJ_PROP_GROUP ? CMessage::Text(MSG_GRAPH_OBJ_PROP_GROUP)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(CGBaseObj::Group()>0 ? (string)this.GetProperty(property,0) : CMessage::Text(MSG_LIB_PROP_EMPTY)) ) : property==GRAPH_OBJ_PROP_BELONG ? CMessage::Text(MSG_GRAPH_OBJ_PROP_BELONG)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+CGBaseObj::BelongDescription() ) : property==GRAPH_OBJ_PROP_CHART_ID ? CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_WND_NUM ? CMessage::Text(MSG_GRAPH_OBJ_PROP_WND_NUM)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_CHANGE_HISTORY ? CMessage::Text(MSG_GRAPH_OBJ_PROP_CHANGE_MEMORY)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_CREATETIME ? CMessage::Text(MSG_GRAPH_OBJ_PROP_CREATETIME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::TimeToString(this.GetProperty(property,0),TIME_DATE|TIME_MINUTES|TIME_SECONDS) ) : property==GRAPH_OBJ_PROP_TIMEFRAMES ? CMessage::Text(MSG_GRAPH_OBJ_PROP_TIMEFRAMES)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.VisibleOnTimeframeDescription() ) : property==GRAPH_OBJ_PROP_BACK ? CMessage::Text(MSG_GRAPH_OBJ_PROP_BACK)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.IsBack() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_ZORDER ? CMessage::Text(MSG_GRAPH_OBJ_PROP_ZORDER)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_HIDDEN ? CMessage::Text(MSG_GRAPH_OBJ_PROP_HIDDEN)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.IsHidden() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_SELECTED ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SELECTED)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.IsSelected() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_SELECTABLE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SELECTABLE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.IsSelectable() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_NUM ? CMessage::Text(MSG_GRAPH_OBJ_PROP_NUM)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.NumberDescription() ) : property==GRAPH_OBJ_PROP_TIME ? CMessage::Text(MSG_GRAPH_OBJ_PROP_TIME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+"\n"+this.TimesDescription() ) : property==GRAPH_OBJ_PROP_COLOR ? CMessage::Text(MSG_GRAPH_OBJ_PROP_COLOR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::ColorToString((color)this.GetProperty(property,0),true) ) : property==GRAPH_OBJ_PROP_STYLE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_STYLE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+LineStyleDescription((ENUM_LINE_STYLE)this.GetProperty(property,0)) ) : property==GRAPH_OBJ_PROP_WIDTH ? CMessage::Text(MSG_GRAPH_OBJ_PROP_WIDTH)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_FILL ? CMessage::Text(MSG_GRAPH_OBJ_PROP_FILL)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_READONLY ? CMessage::Text(MSG_GRAPH_OBJ_PROP_READONLY)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_LEVELS ? CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELS)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_LEVELCOLOR ? CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELCOLOR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ":\n"+this.LevelsColorDescription() ) : property==GRAPH_OBJ_PROP_LEVELSTYLE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELSTYLE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ":\n"+this.LevelsStyleDescription() ) : property==GRAPH_OBJ_PROP_LEVELWIDTH ? CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELWIDTH)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ":\n"+this.LevelsWidthDescription() ) : property==GRAPH_OBJ_PROP_ALIGN ? CMessage::Text(MSG_GRAPH_OBJ_PROP_ALIGN)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+AlignModeDescription((ENUM_ALIGN_MODE)this.GetProperty(property,0)) ) : property==GRAPH_OBJ_PROP_FONTSIZE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_FONTSIZE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_RAY_LEFT ? CMessage::Text(MSG_GRAPH_OBJ_PROP_RAY_LEFT)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_RAY_RIGHT ? CMessage::Text(MSG_GRAPH_OBJ_PROP_RAY_RIGHT)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_RAY ? CMessage::Text(MSG_GRAPH_OBJ_PROP_RAY)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_ELLIPSE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_ELLIPSE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_ARROWCODE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_ARROWCODE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_ANCHOR ? CMessage::Text(MSG_GRAPH_OBJ_PROP_ANCHOR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.AnchorDescription() ) : property==GRAPH_OBJ_PROP_XDISTANCE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_XDISTANCE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_YDISTANCE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_YDISTANCE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_DIRECTION ? CMessage::Text(MSG_GRAPH_OBJ_PROP_DIRECTION)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+GannDirectDescription((ENUM_GANN_DIRECTION)this.GetProperty(property,0)) ) : property==GRAPH_OBJ_PROP_DEGREE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_DEGREE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+ElliotWaveDegreeDescription((ENUM_ELLIOT_WAVE_DEGREE)this.GetProperty(property,0)) ) : property==GRAPH_OBJ_PROP_DRAWLINES ? CMessage::Text(MSG_GRAPH_OBJ_PROP_DRAWLINES)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_STATE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_STATE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_BUTTON_STATE_PRESSED) : CMessage::Text(MSG_LIB_TEXT_BUTTON_STATE_DEPRESSED)) ) : property==GRAPH_OBJ_PROP_CHART_OBJ_CHART_ID ? CMessage::Text(MSG_CHART_OBJ_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_CHART_OBJ_PERIOD ? CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_OBJ_PERIOD)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+TimeframeDescription((ENUM_TIMEFRAMES)this.GetProperty(property,0)) ) : property==GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_XSIZE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_XSIZE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_YSIZE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_YSIZE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_XOFFSET ? CMessage::Text(MSG_GRAPH_OBJ_PROP_XOFFSET)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_YOFFSET ? CMessage::Text(MSG_GRAPH_OBJ_PROP_YOFFSET)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property,0) ) : property==GRAPH_OBJ_PROP_BGCOLOR ? CMessage::Text(MSG_GRAPH_OBJ_PROP_BGCOLOR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::ColorToString((color)this.GetProperty(property,0),true) ) : property==GRAPH_OBJ_PROP_CORNER ? CMessage::Text(MSG_GRAPH_OBJ_PROP_CORNER)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+BaseCornerDescription((ENUM_BASE_CORNER)this.GetProperty(property,0)) ) : property==GRAPH_OBJ_PROP_BORDER_TYPE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_BORDER_TYPE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+BorderTypeDescription((ENUM_BORDER_TYPE)this.GetProperty(property,0)) ) : property==GRAPH_OBJ_PROP_BORDER_COLOR ? CMessage::Text(MSG_GRAPH_OBJ_PROP_BORDER_COLOR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::ColorToString((color)this.GetProperty(property,0),true) ) : "" ); } //+------------------------------------------------------------------+
En el método que retorna la descripción de una propiedad string del objeto, escribimos el bloque de código que retorna la descripción del nombre del objeto básico:
//+------------------------------------------------------------------+ //| Return description of object's string property | //+------------------------------------------------------------------+ string CGStdGraphObj::GetPropertyDescription(ENUM_GRAPH_OBJ_PROP_STRING property) { return ( property==GRAPH_OBJ_PROP_NAME ? CMessage::Text(MSG_GRAPH_OBJ_PROP_NAME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+"\""+this.GetProperty(property,0)+"\"" ) : property==GRAPH_OBJ_PROP_BASE_NAME ? CMessage::Text(MSG_GRAPH_OBJ_PROP_BASE_NAME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+"\""+this.GetProperty(property,0)+"\"" ) : property==GRAPH_OBJ_PROP_TEXT ? CMessage::Text(MSG_GRAPH_OBJ_PROP_TEXT)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0)=="" ? CMessage::Text(MSG_LIB_PROP_EMPTY) : "\""+this.GetProperty(property,0)+"\"") ) : property==GRAPH_OBJ_PROP_TOOLTIP ? CMessage::Text(MSG_GRAPH_OBJ_PROP_TOOLTIP)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property,0)=="" ? CMessage::Text(MSG_LIB_PROP_AUTO) : this.GetProperty(property,0)=="\n" ? CMessage::Text(MSG_LIB_PROP_EMPTY) : "\""+this.GetProperty(property,0)+"\"") ) : property==GRAPH_OBJ_PROP_LEVELTEXT ? CMessage::Text(MSG_GRAPH_OBJ_PROP_LEVELTEXT)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ":\n"+this.LevelsTextDescription() ) : property==GRAPH_OBJ_PROP_FONT ? CMessage::Text(MSG_GRAPH_OBJ_PROP_FONT)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+"\""+this.GetProperty(property,0)+"\"" ) : property==GRAPH_OBJ_PROP_BMPFILE ? CMessage::Text(MSG_GRAPH_OBJ_PROP_BMPFILE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ":\n"+this.BMPFilesDescription() ) : property==GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SYMBOL)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetProperty(property,0) ) : "" ); } //+------------------------------------------------------------------+
Método que retorna la descripción del número de un objeto gráfico en la lista de objetos de un objeto gráfico compuesto:
//+------------------------------------------------------------------+ //| Return the description of the graphical object index | //| in the list of objects of a composite graphical object | //+------------------------------------------------------------------+ string CGStdGraphObj::NumberDescription(void) { if(CGBaseObj::TypeGraphElement()==GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) { if(this.Number()==0) return CMessage::Text(MSG_GRAPH_OBJ_PROP_NUM_EXT_BASE_OBJ); } return (string)this.Number(); } //+------------------------------------------------------------------+
Para un objeto gráfico estándar extendido, comprobamos su número, y si es cero, se mostrará el texto "Objeto básico de un objeto gráfico extendido". En todos los demás casos, el número se mostrará como una línea escrita en las propiedades del objeto.
Método que retorna el nombre del objeto gráfico subordinado según el índice:
//+------------------------------------------------------------------+ //| Return the name of a subordinate graphical object by index | //+------------------------------------------------------------------+ string CGStdGraphObj::NameDependent(const int index) { CGStdGraphObj *obj=this.GetDependentObj(index); return(obj!=NULL ? obj.Name() : ""); } //+------------------------------------------------------------------+
Obtenemos el puntero al objeto gráfico vinculado en la lista según el índice especificado y retornamos su nombre. Si no hemos podido obtener el objeto, retornaremos una línea vacía.
Método que añade un objeto gráfico estándar subordinado a la lista:
//+------------------------------------------------------------------+ //| Add a subordinate standard graphical object to the list | //+------------------------------------------------------------------+ bool CGStdGraphObj::AddDependentObj(CGStdGraphObj *obj) { //--- If the current object is not an extended one, inform of that and return 'false' if(this.TypeGraphElement()!=GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) { CMessage::ToLog(MSG_GRAPH_OBJ_NOT_EXT_OBJ); return false; } //--- If failed to add the pointer to the passed object into the list, inform of that and return 'false' if(!this.m_list.Add(obj)) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_ADD_DEP_EXT_OBJ_TO_LIST); return false; } //--- Object added to the list - set its number in the list, //--- name and ID of the current object as the base one obj.SetNumber(this.m_list.Total()-1); obj.SetBaseName(this.Name()); obj.SetBaseObjectID(this.ObjectID()); return true; } //+------------------------------------------------------------------+
En general, si no está extendido, ningún objeto gráfico puede trabajar con subordinados; por consiguiente, en todos esos métodos a los que se les transmite un puntero a un objeto que debería estar subordinado, y en los que es necesario realizar cambios, se realiza una verificación y, si el objeto no es un objeto extendido, se mostrará un mensaje, y el método retornará false. Y de la misma forma, para el objeto actual, en los métodos necesarios para trabajar con los parámetros de un objeto subordinado, se verifica si el objeto es un objeto subordinado (si está fiado al básico), y si el objeto no está fijado, entonces no será un objeto subordinado, y también se mostrará un mensaje sobre esto, retornando igualmente false.
Esto se hace porque cualquier objeto gráfico puede ser básico y subordinado, incluso de forma simultánea. Por lo tanto, tenemos métodos para gestionar nuestros propios objetos subordinados (modo de objeto básico) y para cambiar sus propiedades desde el exterior (modo de objeto subordinado)
Vamos a mejorar la clase de colección de elementos gráficos en el archivo \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh.
En la sección pública de la clase de gestión de objetos gráficos, añadimos al método para crear un nuevo objeto de la clase de objeto gráfico estándar una bandera que indique la necesidad de crear un objeto gráfico extendido:
public: //--- Return the variable values ENUM_TIMEFRAMES Timeframe(void) const { return this.m_chart_timeframe; } long ChartID(void) const { return this.m_chart_id; } string Symbol(void) const { return this.m_chart_symbol; } bool IsEvent(void) const { return this.m_is_graph_obj_event; } int TotalObjects(void) const { return this.m_total_objects; } int Delta(void) const { return this.m_delta_graph_obj; } //--- Create a new standard (or extended) graphical object CGStdGraphObj *CreateNewGraphObj(const ENUM_OBJECT obj_type,const string name,const bool extended); //--- Return the list of newly added objects
En el método de la misma clase que verifica los objetos en el gráfico, introducimos el valor false al crear un nuevo objeto:
//+------------------------------------------------------------------+ //| CChartObjectsControl: Check objects on a chart | //+------------------------------------------------------------------+ void CChartObjectsControl::Refresh(void) { //--- Clear the list of newly added objects this.m_list_new_graph_obj.Clear(); //--- Calculate the number of new objects on the chart this.m_total_objects=::ObjectsTotal(this.ChartID()); this.m_delta_graph_obj=this.m_total_objects-this.m_last_objects; //--- If an object is added to the chart if(this.m_delta_graph_obj>0) { //--- Create the list of added graphical objects for(int i=0;i<this.m_delta_graph_obj;i++) { //--- Get the name of the last added object (if a single new object is added), //--- or a name from the terminal object list by index (if several objects have been added) string name=(this.m_delta_graph_obj==1 ? this.LastAddedGraphObjName() : ::ObjectName(this.m_chart_id,i)); //--- Handle only non-programmatically created objects if(name==NULL || ::StringFind(name,this.m_name_program)>WRONG_VALUE) continue; //--- Create the object of the graphical object class corresponding to the added graphical object type ENUM_OBJECT type=(ENUM_OBJECT)::ObjectGetInteger(this.ChartID(),name,OBJPROP_TYPE); ENUM_OBJECT_DE_TYPE obj_type=ENUM_OBJECT_DE_TYPE(type+OBJECT_DE_TYPE_GSTD_OBJ+1); CGStdGraphObj *obj=this.CreateNewGraphObj(type,name,false); //--- If failed to create an object, inform of that and move on to the new iteration if(obj==NULL) { CMessage::ToLog(DFUN,MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ); continue; } //--- Set the object affiliation and add the created object to the list of new objects obj.SetBelong(GRAPH_OBJ_BELONG_NO_PROGRAM); //--- If failed to add the object to the list, inform of that, remove the object and move on to the next iteration if(!this.m_list_new_graph_obj.Add(obj)) { CMessage::ToLog(DFUN_ERR_LINE,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); delete obj; continue; } } //--- Send events to the control program chart from the created list for(int i=0;i<this.m_list_new_graph_obj.Total();i++) { CGStdGraphObj *obj=this.m_list_new_graph_obj.At(i); if(obj==NULL) continue; //--- Send an event to the control program chart ::EventChartCustom(this.m_chart_id_main,GRAPH_OBJ_EVENT_CREATE,this.ChartID(),obj.TimeCreate(),obj.Name()); } } //--- save the index of the last added graphical object and the difference with the last check this.m_last_objects=this.m_total_objects; this.m_is_graph_obj_event=(bool)this.m_delta_graph_obj; } //+------------------------------------------------------------------+
Como este método monitorea la creación de objetos gráficos en el gráfico solo de forma manual, el objeto de la clase de objeto gráfico definitivamente no deberá extenderse. Por ello, transmitimos la bandera false al método de creación: creamos un objeto gráfico estándar normal.
En el método que crea un nuevo objeto del objeto gráfico estándar, añadimos la bandera de objeto gráfico extendido a los parámetros de entrada, y luego transmitimos esta bandera a todas las líneas que crean un nuevo objeto de la clase de objeto gráfico estándar:
//+------------------------------------------------------------------+ //| CChartObjectsControl: | //| Create a new standard graphical object | //+------------------------------------------------------------------+ CGStdGraphObj *CChartObjectsControl::CreateNewGraphObj(const ENUM_OBJECT obj_type,const string name,const bool extended) { switch((int)obj_type) { //--- Lines case OBJ_VLINE : return new CGStdVLineObj(this.ChartID(),name,extended); case OBJ_HLINE : return new CGStdHLineObj(this.ChartID(),name,extended); case OBJ_TREND : return new CGStdTrendObj(this.ChartID(),name,extended); case OBJ_TRENDBYANGLE : return new CGStdTrendByAngleObj(this.ChartID(),name,extended); case OBJ_CYCLES : return new CGStdCyclesObj(this.ChartID(),name,extended); case OBJ_ARROWED_LINE : return new CGStdArrowedLineObj(this.ChartID(),name,extended); //--- Channels case OBJ_CHANNEL : return new CGStdChannelObj(this.ChartID(),name,extended); case OBJ_STDDEVCHANNEL : return new CGStdStdDevChannelObj(this.ChartID(),name,extended); case OBJ_REGRESSION : return new CGStdRegressionObj(this.ChartID(),name,extended); case OBJ_PITCHFORK : return new CGStdPitchforkObj(this.ChartID(),name,extended); //--- Gann case OBJ_GANNLINE : return new CGStdGannLineObj(this.ChartID(),name,extended); case OBJ_GANNFAN : return new CGStdGannFanObj(this.ChartID(),name,extended); case OBJ_GANNGRID : return new CGStdGannGridObj(this.ChartID(),name,extended); //--- Fibo case OBJ_FIBO : return new CGStdFiboObj(this.ChartID(),name,extended); case OBJ_FIBOTIMES : return new CGStdFiboTimesObj(this.ChartID(),name,extended); case OBJ_FIBOFAN : return new CGStdFiboFanObj(this.ChartID(),name,extended); case OBJ_FIBOARC : return new CGStdFiboArcObj(this.ChartID(),name,extended); case OBJ_FIBOCHANNEL : return new CGStdFiboChannelObj(this.ChartID(),name,extended); case OBJ_EXPANSION : return new CGStdExpansionObj(this.ChartID(),name,extended); //--- Elliott case OBJ_ELLIOTWAVE5 : return new CGStdElliotWave5Obj(this.ChartID(),name,extended); case OBJ_ELLIOTWAVE3 : return new CGStdElliotWave3Obj(this.ChartID(),name,extended); //--- Shapes case OBJ_RECTANGLE : return new CGStdRectangleObj(this.ChartID(),name,extended); case OBJ_TRIANGLE : return new CGStdTriangleObj(this.ChartID(),name,extended); case OBJ_ELLIPSE : return new CGStdEllipseObj(this.ChartID(),name,extended); //--- Arrows case OBJ_ARROW_THUMB_UP : return new CGStdArrowThumbUpObj(this.ChartID(),name,extended); case OBJ_ARROW_THUMB_DOWN : return new CGStdArrowThumbDownObj(this.ChartID(),name,extended); case OBJ_ARROW_UP : return new CGStdArrowUpObj(this.ChartID(),name,extended); case OBJ_ARROW_DOWN : return new CGStdArrowDownObj(this.ChartID(),name,extended); case OBJ_ARROW_STOP : return new CGStdArrowStopObj(this.ChartID(),name,extended); case OBJ_ARROW_CHECK : return new CGStdArrowCheckObj(this.ChartID(),name,extended); case OBJ_ARROW_LEFT_PRICE : return new CGStdArrowLeftPriceObj(this.ChartID(),name,extended); case OBJ_ARROW_RIGHT_PRICE : return new CGStdArrowRightPriceObj(this.ChartID(),name,extended); case OBJ_ARROW_BUY : return new CGStdArrowBuyObj(this.ChartID(),name,extended); case OBJ_ARROW_SELL : return new CGStdArrowSellObj(this.ChartID(),name,extended); case OBJ_ARROW : return new CGStdArrowObj(this.ChartID(),name,extended); //--- Graphical objects case OBJ_TEXT : return new CGStdTextObj(this.ChartID(),name,extended); case OBJ_LABEL : return new CGStdLabelObj(this.ChartID(),name,extended); case OBJ_BUTTON : return new CGStdButtonObj(this.ChartID(),name,extended); case OBJ_CHART : return new CGStdChartObj(this.ChartID(),name,extended); case OBJ_BITMAP : return new CGStdBitmapObj(this.ChartID(),name,extended); case OBJ_BITMAP_LABEL : return new CGStdBitmapLabelObj(this.ChartID(),name,extended); case OBJ_EDIT : return new CGStdEditObj(this.ChartID(),name,extended); case OBJ_EVENT : return new CGStdEventObj(this.ChartID(),name,extended); case OBJ_RECTANGLE_LABEL : return new CGStdRectangleLabelObj(this.ChartID(),name,extended); default : return NULL; } } //+------------------------------------------------------------------+
Ahora, al crear un objeto de la clase de objeto gráfico estándar, podemos especificar de inmediato qué tipo de objeto se está construyendo: normal o extendido. No obstante, en cualquier momento podemos convertir un objeto gráfico normal en uno extendido y viceversa.
El método de la sección privada de la clase de colección de elementos gráficos que crea un nuevo objeto gráfico estándar y retorna el nombre del objeto creado, es eliminado de la lista de clases (se trasladará al archivo de funciones de servicio para que siempre podemos crear cualquier objeto gráfico en el gráfico, independientemente de si lo construimos a partir de una clase de colección de objetos gráficos, o de otras clases, o del propio programa):
//+------------------------------------------------------------------+ //| Collection of graphical objects | //+------------------------------------------------------------------+ #resource "\\"+PATH_TO_EVENT_CTRL_IND; // Indicator for controlling graphical object events packed into the program resources class CGraphElementsCollection : public CBaseObj { private: CArrayObj m_list_charts_control; // List of chart management objects CListObj m_list_all_canv_elm_obj; // List of all graphical elements on canvas CListObj m_list_all_graph_obj; // List of all graphical objects CArrayObj m_list_deleted_obj; // List of removed graphical objects bool m_is_graph_obj_event; // Event flag in the list of graphical objects int m_total_objects; // Number of graphical objects int m_delta_graph_obj; // Difference in the number of graphical objects compared to the previous check //--- Return the flag indicating the graphical element class object presence in the collection list of graphical elements bool IsPresentGraphElmInList(const int id,const ENUM_GRAPH_ELEMENT_TYPE type_obj); //--- Return the flag indicating the presence of the graphical object class in the graphical object collection list bool IsPresentGraphObjInList(const long chart_id,const string name); //--- Return the flag indicating the presence of a graphical object on a chart by name bool IsPresentGraphObjOnChart(const long chart_id,const string name); //--- Return the pointer to the object of managing objects of the specified chart CChartObjectsControl *GetChartObjectCtrlObj(const long chart_id); //--- Create a new object of managing graphical objects of a specified chart and add it to the list CChartObjectsControl *CreateChartObjectCtrlObj(const long chart_id); //--- Update the list of graphical objects by chart ID CChartObjectsControl *RefreshByChartID(const long chart_id); //--- Check if the chart window is present bool IsPresentChartWindow(const long chart_id); //--- Handle removing the chart window void RefreshForExtraObjects(void); //--- Return the first free ID of the graphical (1) object and (2) element on canvas long GetFreeGraphObjID(bool program_object); long GetFreeCanvElmID(void); //--- Add a graphical object to the collection bool AddGraphObjToCollection(const string source,CChartObjectsControl *obj_control); //--- Find an object present in the collection but not on a chart CGStdGraphObj *FindMissingObj(const long chart_id); CGStdGraphObj *FindMissingObj(const long chart_id,int &index); //--- Find the graphical object present on a chart but not in the collection string FindExtraObj(const long chart_id); //--- Remove the graphical object class object from the graphical object collection list: (1) specified object, (2) by chart ID bool DeleteGraphObjFromList(CGStdGraphObj *obj); void DeleteGraphObjectsFromList(const long chart_id); //--- Move the graphical object class object to the list of removed graphical objects: (1) specified object, (2) by index bool MoveGraphObjToDeletedObjList(CGStdGraphObj *obj); bool MoveGraphObjToDeletedObjList(const int index); //--- Move all objects by chart ID to the list of removed graphical objects void MoveGraphObjectsToDeletedObjList(const long chart_id); //--- Remove the object of managing charts from the list bool DeleteGraphObjCtrlObjFromList(CChartObjectsControl *obj); //--- Create a new standard graphical object, return an object name bool CreateNewStdGraphObject(const long chart_id, const string name, const ENUM_OBJECT type, const int subwindow, const datetime time1, const double price1, const datetime time2=0, const double price2=0, const datetime time3=0, const double price3=0, const datetime time4=0, const double price4=0, const datetime time5=0, const double price5=0); public:
En la sección pública de la clase, escribimos dos métodos que retornarán una lista con los objetos gráficos estándar y extendidos:
//--- Return an (1) existing and (2) removed graphical object by chart name and ID CGStdGraphObj *GetStdGraphObject(const string name,const long chart_id); CGStdGraphObj *GetStdDelGraphObject(const string name,const long chart_id); //--- Return the list of (1) chart management objects and (2) removed graphical objects CArrayObj *GetListChartsControl(void) { return &this.m_list_charts_control; } CArrayObj *GetListDeletedObj(void) { return &this.m_list_deleted_obj; } //--- Return the list of (1) standard and (2) extended graphical objects CArrayObj *GetListStdGraphObject(void) { return CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_ELEMENT_TYPE,0,GRAPH_ELEMENT_TYPE_STANDARD,EQUAL); } CArrayObj *GetListStdGraphObjectExt(void) { return CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_ELEMENT_TYPE,0,GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED,EQUAL); } //--- Return (1) the last removed graphical object and (2) the array size of graphical object properties
Los métodos simplemente retornan un puntero a la lista creada tras filtrar la lista con todos los objetos gráficos según la propiedad del tipo de elemento gráfico.
En el método privado que crea un nuevo objeto gráfico y retorna un puntero al objeto de control del gráfico, llamamos al método para crear un objeto gráfico no desde el contexto de esta clase, sino desde el archivo DELib.mqh (eliminamos "this." de la línea de llamada al método):
private: //--- Create a new graphical object, return the pointer to the chart management object CChartObjectsControl *CreateNewStdGraphObjectAndGetCtrlObj(const long chart_id, const string name, int subwindow, const ENUM_OBJECT type_object, const datetime time1, const double price1, const datetime time2=0, const double price2=0, const datetime time3=0, const double price3=0, const datetime time4=0, const double price4=0, const datetime time5=0, const double price5=0) { //--- If an object with a chart ID and name is already present in the collection, inform of that and return NULL if(this.IsPresentGraphObjInList(chart_id,name)) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELM_COLLECTION_ERR_GR_OBJ_ALREADY_EXISTS)," ChartID ",(string)chart_id,", ",name); return NULL; } //--- If failed to create a new standard graphical object, inform of that and return NULL if(!CreateNewStdGraphObject(chart_id,name,type_object,subwindow,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5)) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_STD_GRAPH_OBJ),StdGraphObjectTypeDescription(type_object)); CMessage::ToLog(::GetLastError(),true); return NULL; } //--- If failed to get a chart management object, inform of that CChartObjectsControl *ctrl=this.GetChartObjectCtrlObj(chart_id); if(ctrl==NULL) ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_GET_CTRL_OBJ),(string)chart_id); //--- Return the pointer to a chart management object or NULL in case of a failed attempt to get it return ctrl; }
En todos los métodos públicos para crear objetos gráficos, añadiremos el mismo tipo de cambios, es decir, la bandera de objeto extendido en los parámetros de entrada del método y la transmisión de esta bandera al método de creación de un nuevo objeto de la clase de objeto gráfico estándar:
public: //--- Create the "Vertical line" graphical object bool CreateLineVertical(const long chart_id,const string name,const int subwindow,const bool extended,const datetime time) { //--- Set the name and type of a created object string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_VLINE; //--- Create a new graphical object and get the pointer to the chart management object CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,0); if(ctrl==NULL) return false; //--- Create a new class object corresponding to the newly created graphical object CGStdVLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm,extended); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true,false); obj.SetFlagSelected(true,false); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); //--- Return the result of adding the object to the list return this.AddCreatedObjToList(DFUN,chart_id,nm,obj); } //--- Create the "Horizontal line" graphical object bool CreateLineHorizontal(const long chart_id,const string name,const int subwindow,const bool extended,const double price) { string nm=this.m_name_program+"_"+name; ENUM_OBJECT type_object=OBJ_HLINE; CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,price); if(ctrl==NULL) return false; CGStdHLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm,extended); if(obj==NULL) { ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object)); return false; } //--- Set the necessary minimal parameters for an object obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM); obj.SetFlagSelectable(true,false); obj.SetFlagSelected(true,false); obj.SetObjectID(this.GetFreeGraphObjID(true)); obj.PropertiesCopyToPrevData(); //--- Return the result of adding the object to the list return this.AddCreatedObjToList(DFUN,chart_id,nm,obj); } //--- Create the "Trend line" graphical object
Aquí vemos un ejemplo de dos métodos en los que se han realizado el mismo tipo de cambios. El resto de métodos se han modificado de forma idéntica, y se pueden visualizar en los archivos adjuntos al artículo.
Por otra parte, moveremos el listado con la implementación del método que crea un nuevo objeto gráfico estándar de esta clase al archivo de funciones de servicio de la biblioteca \MQL5\Include\DoEasy\Services\DELib.mqh, a su parte final:
//+------------------------------------------------------------------+ //| Create a new standard graphical object | //+------------------------------------------------------------------+ bool CreateNewStdGraphObject(const long chart_id, const string name, const ENUM_OBJECT type, const int subwindow, const datetime time1, const double price1, const datetime time2=0, const double price2=0, const datetime time3=0, const double price3=0, const datetime time4=0, const double price4=0, const datetime time5=0, const double price5=0) { ::ResetLastError(); switch(type) { //--- Lines case OBJ_VLINE : return ::ObjectCreate(chart_id,name,OBJ_VLINE,subwindow,time1,0); case OBJ_HLINE : return ::ObjectCreate(chart_id,name,OBJ_HLINE,subwindow,0,price1); case OBJ_TREND : return ::ObjectCreate(chart_id,name,OBJ_TREND,subwindow,time1,price1,time2,price2); case OBJ_TRENDBYANGLE : return ::ObjectCreate(chart_id,name,OBJ_TRENDBYANGLE,subwindow,time1,price1,time2,price2); case OBJ_CYCLES : return ::ObjectCreate(chart_id,name,OBJ_CYCLES,subwindow,time1,price1,time2,price2); case OBJ_ARROWED_LINE : return ::ObjectCreate(chart_id,name,OBJ_ARROWED_LINE,subwindow,time1,price1,time2,price2); //--- Channels case OBJ_CHANNEL : return ::ObjectCreate(chart_id,name,OBJ_CHANNEL,subwindow,time1,price1,time2,price2,time3,price3); case OBJ_STDDEVCHANNEL : return ::ObjectCreate(chart_id,name,OBJ_STDDEVCHANNEL,subwindow,time1,price1,time2,price2); case OBJ_REGRESSION : return ::ObjectCreate(chart_id,name,OBJ_REGRESSION,subwindow,time1,price1,time2,price2); case OBJ_PITCHFORK : return ::ObjectCreate(chart_id,name,OBJ_PITCHFORK,subwindow,time1,price1,time2,price2,time3,price3); //--- Gann case OBJ_GANNLINE : return ::ObjectCreate(chart_id,name,OBJ_GANNLINE,subwindow,time1,price1,time2,price2); case OBJ_GANNFAN : return ::ObjectCreate(chart_id,name,OBJ_GANNFAN,subwindow,time1,price1,time2,price2); case OBJ_GANNGRID : return ::ObjectCreate(chart_id,name,OBJ_GANNGRID,subwindow,time1,price1,time2,price2); //--- Fibo case OBJ_FIBO : return ::ObjectCreate(chart_id,name,OBJ_FIBO,subwindow,time1,price1,time2,price2); case OBJ_FIBOTIMES : return ::ObjectCreate(chart_id,name,OBJ_FIBOTIMES,subwindow,time1,price1,time2,price2); case OBJ_FIBOFAN : return ::ObjectCreate(chart_id,name,OBJ_FIBOFAN,subwindow,time1,price1,time2,price2); case OBJ_FIBOARC : return ::ObjectCreate(chart_id,name,OBJ_FIBOARC,subwindow,time1,price1,time2,price2); case OBJ_FIBOCHANNEL : return ::ObjectCreate(chart_id,name,OBJ_FIBOCHANNEL,subwindow,time1,price1,time2,price2,time3,price3); case OBJ_EXPANSION : return ::ObjectCreate(chart_id,name,OBJ_EXPANSION,subwindow,time1,price1,time2,price2,time3,price3); //--- Elliott case OBJ_ELLIOTWAVE5 : return ::ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE5,subwindow,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5); case OBJ_ELLIOTWAVE3 : return ::ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE3,subwindow,time1,price1,time2,price2,time3,price3); //--- Shapes case OBJ_RECTANGLE : return ::ObjectCreate(chart_id,name,OBJ_RECTANGLE,subwindow,time1,price1,time2,price2); case OBJ_TRIANGLE : return ::ObjectCreate(chart_id,name,OBJ_TRIANGLE,subwindow,time1,price1,time2,price2,time3,price3); case OBJ_ELLIPSE : return ::ObjectCreate(chart_id,name,OBJ_ELLIPSE,subwindow,time1,price1,time2,price2,time3,price3); //--- Arrows case OBJ_ARROW_THUMB_UP : return ::ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_UP,subwindow,time1,price1); case OBJ_ARROW_THUMB_DOWN : return ::ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_DOWN,subwindow,time1,price1); case OBJ_ARROW_UP : return ::ObjectCreate(chart_id,name,OBJ_ARROW_UP,subwindow,time1,price1); case OBJ_ARROW_DOWN : return ::ObjectCreate(chart_id,name,OBJ_ARROW_DOWN,subwindow,time1,price1); case OBJ_ARROW_STOP : return ::ObjectCreate(chart_id,name,OBJ_ARROW_STOP,subwindow,time1,price1); case OBJ_ARROW_CHECK : return ::ObjectCreate(chart_id,name,OBJ_ARROW_CHECK,subwindow,time1,price1); case OBJ_ARROW_LEFT_PRICE : return ::ObjectCreate(chart_id,name,OBJ_ARROW_LEFT_PRICE,subwindow,time1,price1); case OBJ_ARROW_RIGHT_PRICE : return ::ObjectCreate(chart_id,name,OBJ_ARROW_RIGHT_PRICE,subwindow,time1,price1); case OBJ_ARROW_BUY : return ::ObjectCreate(chart_id,name,OBJ_ARROW_BUY,subwindow,time1,price1); case OBJ_ARROW_SELL : return ::ObjectCreate(chart_id,name,OBJ_ARROW_SELL,subwindow,time1,price1); case OBJ_ARROW : return ::ObjectCreate(chart_id,name,OBJ_ARROW,subwindow,time1,price1); //--- Graphical objects case OBJ_TEXT : return ::ObjectCreate(chart_id,name,OBJ_TEXT,subwindow,time1,price1); case OBJ_LABEL : return ::ObjectCreate(chart_id,name,OBJ_LABEL,subwindow,0,0); case OBJ_BUTTON : return ::ObjectCreate(chart_id,name,OBJ_BUTTON,subwindow,0,0); case OBJ_CHART : return ::ObjectCreate(chart_id,name,OBJ_CHART,subwindow,0,0); case OBJ_BITMAP : return ::ObjectCreate(chart_id,name,OBJ_BITMAP,subwindow,time1,price1); case OBJ_BITMAP_LABEL : return ::ObjectCreate(chart_id,name,OBJ_BITMAP_LABEL,subwindow,0,0); case OBJ_EDIT : return ::ObjectCreate(chart_id,name,OBJ_EDIT,subwindow,0,0); case OBJ_EVENT : return ::ObjectCreate(chart_id,name,OBJ_EVENT,subwindow,time1,0); case OBJ_RECTANGLE_LABEL : return ::ObjectCreate(chart_id,name,OBJ_RECTANGLE_LABEL,subwindow,0,0); //--- default: return false; } } //+------------------------------------------------------------------+
Ahora, realizaremos algunas mejoras en la clase principal de la biblioteca CEngine, en el archivo \MQL5\Include\DoEasy\Engine.mqh.
El método que retorna el nombre del programa será renombrado de Name(), que no aporta nada especial, a ProgramName(), más preciso:
//--- Return event (1) milliseconds, (2) reason and (3) source from its 'long' value ushort EventMSC(const long lparam) const { return this.LongToUshortFromByte(lparam,0); } ushort EventReason(const long lparam) const { return this.LongToUshortFromByte(lparam,1); } ushort EventSource(const long lparam) const { return this.LongToUshortFromByte(lparam,2); } //--- Return the program name string ProgramName(void) const { return this.m_name; } //--- Set the new (1) pause countdown start time and (2) pause in milliseconds
Como tenemos diferentes nombres de objetos dependiendo de cómo se ha creado el objeto gráfico (manual o programáticamente), vamos a hacer algunos cambios en el método que retorna la clase de objeto del objeto gráfico estándar según el nombre del gráfico y el identificador, para así poder buscar y seleccionar objetos según el nombre del programa:
//--- Return the class of the object of the standard graphical object by chart name and ID CGStdGraphObj *GraphGetStdGraphObject(const string name,const long chart_id) { CGStdGraphObj *obj=this.m_graph_objects.GetStdGraphObject(name,chart_id); if(obj==NULL) obj=this.m_graph_objects.GetStdGraphObject(this.ProgramName()+"_"+name,chart_id); return obj; }
Si el objeto se ha creado manualmente, la biblioteca no cambiará su nombre de ninguna forma. Pero si creamos un objeto gráfico programáticamente, entonces los métodos encargados de crearlo añadirán a su nombre un prefijo con el nombre del programa. Por lo tanto, si creamos un objeto de nuestro programa con un nombre, por ejemplo, "object_name", y estamos tratando de encontrarlo, no lograremos nada, ya que al nombre se le ha añadido el prefijo con el nombre del programa., y ahora el nombre del objeto sería "nombre_del_programa_object_name". Partiendo de ello, primero buscamos en el método el nombre exacto transmitido al mismo, y luego, si no encontramos un objeto con el mismo nombre, intentamos encontrar el objeto con el prefijo del nombre del programa agregado a su nombre.
Luego, añadimos el método que retorna la clase de objeto del objeto gráfico estándar extendido según el nombre y el identificador del gráfico:
//--- Return the class of the object of the extended standard graphical object by chart name and ID CGStdGraphObj *GraphGetStdGraphObjectExt(const string name,const long chart_id) { CArrayObj *list=this.m_graph_objects.GetListStdGraphObjectExt(); string nm=(::StringFind(name,this.ProgramName()+"_")==WRONG_VALUE ? this.ProgramName()+"_"+name : name); list=CSelect::ByGraphicStdObjectProperty(list,GRAPH_OBJ_PROP_NAME,0,nm,EQUAL); return(list!=NULL ? list.At(0) : NULL); }
Aquí primero obtenemos una lista con todos los objetos gráficos estándar extendidos, luego verificamos si el nombre transmitido al método contiene la línea con el nombre del programa y si no encontramos la línea, añadimos el nombre del programa al nombre. De lo contrario, si el nombre buscado ya contiene el nombre del programa, usaremos tal cual el nombre transmitido al método. A continuación, de la lista de objetos gráficos extendidos obtenida anteriormente, obtenemos el objeto con el nombre deseado y retornamos el único objeto de la lista si lo hemos encontrado, o NULL, si no tenemos éxito.
Ahora, transmitimos la bandera de objeto extendido a todos los métodos encargados de crear los objetos gráficos y transmitimos esta bandera a los métodos llamados correspondientes de la clase de colección de elementos gráficos:
//--- Create the "Vertical line" graphical object bool CreateLineVertical(const long chart_id,const string name,const int subwindow,const bool extended,const datetime time) { return this.m_graph_objects.CreateLineVertical(chart_id,name,subwindow,extended,time); } bool CreateLineVertical(const string name,const int subwindow,const bool extended,const datetime time) { return this.m_graph_objects.CreateLineVertical(::ChartID(),name,subwindow,extended,time); } //--- Create the "Horizontal line" graphical object bool CreateLineHorizontal(const long chart_id,const string name,const int subwindow,const bool extended,const double price) { return this.m_graph_objects.CreateLineHorizontal(chart_id,name,subwindow,extended,price); } bool CreateLineHorizontal(const string name,const int subwindow,const bool extended,const double price) { return this.m_graph_objects.CreateLineHorizontal(::ChartID(),name,subwindow,extended,price); }
Para todos los métodos encargados de crear objetos gráficos, estas mejoras son completamente idénticas a las cuatro presentadas anteriormente. Por consiguiente, no vamos analizar los otros métodos aquí: el lector podrá encontrarlos en los archivos adjuntos al artículo.
Con esto, damos por completas las mejoras de la biblioteca y estamos casi listos para crear objetos gráficos estándar extendidos.
Simulación
Para las pruebas, tomaremos el asesor del artículo anterior y
lo guardaremos en la nueva carpeta \MQL5\Experts\TestDoEasy\Part93\ con el nuevo nombre TestDoEasyPart93.mq5.
¿Que vamos a hacer? Crearemos un objeto gráfico estándar de "Línea de tendencia" y colocaremos a lo largo de sus bordes (en sus dos puntos de pivote) un objeto de "Etiqueta de precio a la izquierda" a la izquierda en el punto 0, y una "Etiqueta de precio a la derecha" a la derecha en el punto 1. A continuación, crearemos una línea de tendencia clicando en el gráfico mientras mantenemos presionada la tecla Ctrl. En este caso, el punto de anclaje izquierdo de la línea se ubicará en el lugar donde cliquemos en el gráfico, y el derecho, en el precio de apertura de la primera barra del gráfico.
Después, mostramos en el diario una descripción completa de las propiedades de la línea de tendencia y los valores registrados en los objetos de etiqueta de precio, en sus objetos de clase de puntos de pivote vinculados. No vamos a probar todo lo demás, ya que aún tenemos que hacer algunas mejoras en las propiedades de los objetos y la funcionalidad para la creación completa de objetos gráficos estándar extendidos, que trataremos en artículos posteriores.
En el manejador OnChartEvent() del asesor experto, en el bloque de procesamiento de clics del gráfico, añadimos el código siguiente:
if(id==CHARTEVENT_CLICK) { if(!IsCtrlKeyPressed()) return; //--- Get the chart click coordinates datetime time=0; double price=0; int sw=0; if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,sw,time,price)) { //--- Get the right point coordinates for a trend line datetime time2=iTime(Symbol(),PERIOD_CURRENT,1); double price2=iOpen(Symbol(),PERIOD_CURRENT,1); //--- Create the "Trend line" object string name_base="TrendLineExt"; engine.CreateLineTrend(name_base,0,true,time,price,time2,price2); //--- Get the object from the list of graphical objects by chart name and ID and pass its properties to the journal CGStdGraphObj *obj=engine.GraphGetStdGraphObjectExt(name_base,ChartID()); obj.Print(); //--- Create the "Left price label" object string name_dep="PriceLeft"; engine.CreatePriceLabelLeft(name_dep,0,false,time,price); //--- Get the object from the list of graphical objects by chart name and ID and CGStdGraphObj *dep=engine.GraphGetStdGraphObject(name_dep,ChartID()); //--- add it to the list of graphical objects bound to the "Trend line" object obj.AddDependentObj(dep); //--- Set its pivot point by X and Y axis to the trend line left point obj.AddNewLinkedPivotPointXY(dep,GRAPH_OBJ_PROP_TIME,0,GRAPH_OBJ_PROP_PRICE,0); //--- Send the number of pivot anchor points by both axes (one point per axis) to the journal Print(DFUN,"PriceLeft: Num linked coord X: ",dep.GetBasePivotsNumX(0),", Num linked coord Y: ",dep.GetBasePivotsNumY(0)); //--- Create the "Right price label" object name_dep="PriceRight"; engine.CreatePriceLabelRight(name_dep,0,false,time2,price2); //--- Get the object from the list of graphical objects by chart name and ID and dep=engine.GraphGetStdGraphObject(name_dep,ChartID()); //--- add it to the list of graphical objects bound to the "Trend line" object obj.AddDependentObj(dep); //--- Set its pivot point by X and Y axis to the trend line right point obj.AddNewLinkedPivotPointXY(dep,GRAPH_OBJ_PROP_TIME,1,GRAPH_OBJ_PROP_PRICE,1); //--- Send the number of pivot anchor points by both axes (one point per axis) to the journal Print(DFUN,"PriceRight: Num linked coord X: ",dep.GetBasePivotsNumX(0),", Num linked coord Y: ",dep.GetBasePivotsNumY(0)); } }
Aquí, la lógica al completo se comenta con detalle en el listado, por lo que no generará dudas.
Compilamos el asesor experto, lo ejecutamos en el gráfico y clicamos en algún lugar alejado del borde derecho del gráfico.
Se construirá una línea de tendencia y, a lo largo de sus bordes, habrá objetos de etiqueta de precio:
El diario mostrará las propiedades de la línea de tendencia y el número de puntos de pivote de la misma para calcular las coordenadas X e Y de ambas etiquetas de precio. Como para ellas solo hemos especificado un punto de pivote para cada una de las etiquetas, esto se verá reflejado en el diario.
2022.01.20 16:37:29.340 ============= The beginning of the parameter list (Trend Line) ============= 2022.01.20 16:37:29.340 Object ID: 1 2022.01.20 16:37:29.340 Base object ID: 0 2022.01.20 16:37:29.340 Object type: Trend Line 2022.01.20 16:37:29.340 Graphic element type: Extended standard graphic object 2022.01.20 16:37:29.340 Object belongs to: The graphic object belongs to the program 2022.01.20 16:37:29.340 Object chart ID: 131733844391938630 2022.01.20 16:37:29.340 Chart subwindow number: 0 2022.01.20 16:37:29.340 Object number in the list: The base object of the extended graphical object 2022.01.20 16:37:29.340 Change history: No 2022.01.20 16:37:29.340 Object group: Not set 2022.01.20 16:37:29.340 Time of creation: 2022.01.20 16:37:29 2022.01.20 16:37:29.340 Visibility of an object at timeframes: Drawn on all timeframes 2022.01.20 16:37:29.340 Object in the background: No 2022.01.20 16:37:29.340 Priority of a graphical object for receiving events of clicking on a chart: 0 2022.01.20 16:37:29.340 Prohibit showing of the name of a graphical object in the terminal objects list: Yes 2022.01.20 16:37:29.340 Object is selected: Yes 2022.01.20 16:37:29.340 Object availability: Yes 2022.01.20 16:37:29.340 Time coordinate: 2022.01.20 16:37:29.340 - Pivot point 0: 2022.01.13 09:00 2022.01.20 16:37:29.340 - Pivot point 1: 2022.01.20 10:00 2022.01.20 16:37:29.340 Color: clrRed 2022.01.20 16:37:29.340 Style: Solid line 2022.01.20 16:37:29.340 Line thickness: 1 2022.01.20 16:37:29.340 Ray goes to the left: No 2022.01.20 16:37:29.340 Ray goes to the right: No 2022.01.20 16:37:29.340 ------ 2022.01.20 16:37:29.340 Price coordinate: 2022.01.20 16:37:29.340 - Pivot point 0: 1.14728 2022.01.20 16:37:29.340 - Pivot point 1: 1.13598 2022.01.20 16:37:29.340 ------ 2022.01.20 16:37:29.340 Name: "TestDoEasyPart93_TrendLineExt" 2022.01.20 16:37:29.340 Base object name: "TestDoEasyPart93_TrendLineExt" 2022.01.20 16:37:29.340 Description: Not set 2022.01.20 16:37:29.340 The text of a tooltip: Formed by the terminal 2022.01.20 16:37:29.340 ============= End of the parameter list (Trend Line) ============= 2022.01.20 16:37:29.340 2022.01.20 16:37:29.352 OnChartEvent: PriceLeft: Num linked coord X: 1, Num linked coord Y: 1 2022.01.20 16:37:29.364 OnChartEvent: PriceRight: Num linked coord X: 1, Num linked coord Y: 1
Por el momento, solo estamos construyendo objetos gráficos separados y escribiendo en sus propiedades que pertenecen al mismo objeto gráfico estándar extendido. Si intentamos mover la línea de tendencia, las etiquetas de precio no la seguirán. Pero hoy no nos hemos establecido ese objetivo, solo hemos preparado la funcionalidad necesaria para crear objetos gráficos extendidos completos.
¿Qué es lo próximo?
En el próximo artículo, continuaremos trabajando con los objetos gráficos estándar extendidos, y comenzaremos a "animarlos".
*Artículos de esta serie:
Gráficos en la biblioteca DoEasy (Parte 89): Creación programática de objetos gráficos estándar. Funcionalidad básica
Gráficos en la biblioteca DoEasy (Parte 90): Eventos de objetos gráficos estándar. Funcionalidad básica
Gráficos en la biblioteca DoEasy (Parte 91): Eventos de objetos gráficos estándar en el programa. Historia de cambio de nombre del objeto
Gráficos en la biblioteca DoEasy (Parte 92): Clase de memoria de objetos gráficos estándar Historia de cambio de propiedades del objeto
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/10331
- 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