Gráficos na biblioteca DoEasy (Parte 93): preparando a funcionalidade para criar objetos gráficos compostos
Sumário
- Ideia
- Modificando as classes da biblioteca
- Classes para especificar as coordenadas de um objeto dependente
- Teste
- O que vem agora?
Ideia
O terminal cliente MetaTrader 5 fornece uma ampla gama de ferramentas de análise gráfica para uso em diversos tipos de construções gráficas. Mas é comum ouvir dizer que falta uma ferramenta ou outra. No terminal, temos 44 ferramentas analíticas. Agora vamos imaginar o que poderíamos fazer se pudéssemos unir estes objetos gráficos em conjuntos afins, criando assim novas ferramentas de análise técnica. Bem, a linguagem da MQL5 nos permite fazer isso!
Nossa biblioteca terá suporte para a criação de objetos gráficos compostos complexos, sendo que tais objetos podem ter qualquer hierarquia de relações. Cada um desses objetos terá um objeto gráfico de base, que terá uma lista de outros objetos gráficos vinculados aos mesmos. O objeto de base terá a funcionalidade para gerenciar propriedades de objetos gráficos subordinados, e estes últimos por sua vez terão um conjunto de coordenadas X e Y do objeto de base, ao qual estarão vinculados. Uma coordenada não pode ser tanto um único valor, mas uma lista de propriedades do objeto de base. Por exemplo, para calcular a coordenada X de um objeto dependente, podemos usar várias coordenadas X, não apenas a coordenada X de algum ponto do objeto de base, mas várias coordenadas, por exemplo, duas coordenadas X, nomeadamente os pontos 0 e 1 da linha de tendência. Dessa forma, a coordenada X do objeto dependente pode ser a média das duas coordenadas X do objeto de base.
Cada objeto dependente na lista do objeto de base também pode ser o objeto de base em relação a outros objetos gráficos de sua lista. Isto permitirá a criação de conjuntos muito diferentes de diversos objetos gráficos compostos.
Não apenas tentaremos criar tais objetos programaticamente, com cada objeto dependente sendo adicionado à lista de objetos de base no código do programa, mas também procurar gerá-los em tempo real - quando arrastamos um objeto gráfico sobre outro, o primeiro será anexado ao segundo com uma seleção visual de pontos de ancoragem, que podem então ser substituídos.
Hoje vamos criar uma funcionalidade para criar objetos gráficos padrão estendidos, gerando por um lado novas propriedades para objetos gráficos padrão, que indicam que o objeto é estendido, e por outro classes para armazenar propriedades associativas das coordenadas do objeto de base para calcular e especificar as coordenadas do objeto dependente.
Modificando as classes da biblioteca
À lista de tipos de elementos gráficos localizada no arquivo \MQL5\Include\DoEasy\Defines.mqh vamos adicionar mais um tipo, nomeadamente o objeto gráfico padrão estendido:
//+------------------------------------------------------------------+ //| 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 }; //+------------------------------------------------------------------+
Na lista de propriedades inteiras dos objetos gráficos, adicionaremos uma propriedade, nomeadamente o identificador do objeto gráfico de base e aumentaremos o número de propriedades inteiras de 54 para 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 //+------------------------------------------------------------------+
O identificador do objeto de base será indicado a cada objeto subordinado (a partir de 1). Se o valor desta propriedade for zero é porque que o objeto não está vinculado a nenhum outro e, ademais, não é subordinado.
Na lista de propriedades de string dos objetos gráficos adicionaremos outra propriedade, particularmente o nome do objeto gráfico de base, e aumentaremos o número de propriedades de string de 7 para 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 //+------------------------------------------------------------------+
Adicionaremos novas constantes à lista de possíveis critérios de classificação dos objetos gráficos, constantes essas que correspondem às novas propriedades do objeto gráfico adicionado acima:
//+------------------------------------------------------------------+ //| 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 }; //+------------------------------------------------------------------+
Agora poderemos selecionar os objetos de acordo com suas respectivas propriedades, ordená-los e criar listas de objetos que tenham as mesmas propriedades.
No arquivo \MQL5\Include\DoEasy\Data.mqh inserimos os índices das novas mensagens da 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 }; //+------------------------------------------------------------------+
e as mensagens que correspondem aos índices recém-adicionados:
{"Запрос за пределами 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"}, }; //+---------------------------------------------------------------------+
Os objetos gráficos padrão estendidos serão feitos com base em objetos padrão. Para fazer de um objeto um objeto estendido, basta especificar sua propriedade de objeto gráfico estendido, porque, a partir desse ajuste, ele usará a funcionalidade criada para manusear objetos gráficos padrão estendidos, isto é, para adicionar objetos subordinados a sua lista e controlá-los.
Já criamos classes de todos os objetos gráficos padrão que são descendentes da classe do objeto gráfico padrão abstrato, portanto, ao criar um objeto estendido só precisaremos indicar o sinalizador de que não se trata de um objeto gráfico comum, mas de um objeto estendido.
Naturalmente, como objeto é criado programaticamente, a propriedade que assinala qual a vinculação do objeto deve ser definida como "objeto pertence ao programa" (por padrão é definida a propriedade de objeto criado manualmente). Do mesmo modo, será necessário especificar o tipo objeto gráfico não apenas padrão, mas sim padrão estendido. Faremos isso tudo em função do valor do sinalizador passado ao construtor do objeto gráfico, quando criado.
Além destas modificações, precisaremos adicionar as novas propriedades do objeto gráfico - que criamos acima - aos métodos que devolvem os sinalizadores que indicam que o objeto suporta suas propriedades.
Como todas essas mudanças são as mesmas para todas as classes de objetos gráficos padrão localizados na pasta
\MQL5\Include\DoEasy\Objects\Graph\Standard\, usaremos como exemplo o arquivo GStdArrowBuyObj.mqh para analisar as alterações introduzidas.
Passaremos o sinalizador de objeto gráfico padrão estendido ao construtor de classes e, dependendo do valor deste sinalizador, especificaremos se é um objeto gráfico padrão, ou um objeto padrão estendido, e se o objeto é criado manualmente, ou 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); }
Aos métodos que retornam os sinalizadores que indicam se o objeto suporta propriedades inteiras e de string adicionamos as novas propriedade escritas acima:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Estas mudanças precisam ser feitas em todos os arquivos da pasta \MQL5\Include\DoEasy\Objects\Graph\Standard\, o que, entretanto, já está feito, e todas as modificações podem ser vistas nos arquivos anexos.
Após estas modificações, as novas propriedades serão processadas por todos os objetos das classes dos objetos gráficos padrão e, desse modo, poderão ser manuseadas por nós plenamente, pois especificamos sinalizadores que assinalam o suporte a essas novas propriedades.
No arquivo da classe do objeto gráfico de base \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh, vamos adicionar a verificação de tipo "objeto gráfico padrão estendido" ao método que retorna a descrição do tipo de elemento gráfico, para que a descrição de tal objeto gráfico possa ser corretamente gerada:
//+------------------------------------------------------------------+ //| 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" ); } //+------------------------------------------------------------------+
Classes para especificar as coordenadas de um objeto dependente
Qualquer objeto dependente na lista do objeto gráfico de base tem coordenadas próprias sobre as quais é construído. Além disso, o objeto gráfico de base precisa saber como controlar as coordenadas do objeto dependente. Para que o objeto de base saiba a qual de suas coordenadas o objeto gráfico dependente está vinculado, este último deve ter algumas propriedades que o objeto de base possa ler e tem que enviar um comando para alterar as coordenadas do objeto dependente quando suas próprias alterações forem feitas.
Para estabelecer tal relação entre as propriedades do objeto de base e o objeto dependente, vamos criar uma classe que chamaremos de classe do objeto de pontos de ancoragem vinculados.
Teremos três classes:
- Uma classe de dados de ponto de ancoragem que armazenará aquelas propriedades pelas quais o objeto dependente é vinculado ao mesmo eixo de coordenadas do objeto de base;
- Uma classe de dados de dois pontos de ancoragem que armazenará dois objetos da primeira classe. Sendo que um armazenará os dados das propriedade pelas quais o objeto dependente é ancorado na coordenada X do objeto de base, já o segundo armazenará os dados pelos quais o objeto é ancorado na coordenada Y;
- Uma classe de pontos de ancoragem vinculados. Esta classe conterá uma lista de objetos do segundo tipo, sendo que o objeto da classe de dados de dois pontos de ancoragem será responsável por cada ponto de ancoragem. Cada objeto armazenará as propriedades do objeto de base utilizado para construir um ponto de ancoragem do objeto dependente, isto é, terá suas coordenadas X e Y que, por sua vez, podem ser calculadas a partir de várias coordenadas do objeto de base. A lista dessas coordenadas é armazenada em um objeto do primeiro tipo para cada eixo.
O primeiro tipo de objeto será criado com base em uma matriz bidimensional regular.
A segunda dimensão da matriz terá valor 2, a célula zero conterá a propriedade em si, como "Tempo", ou "Preço", e já a primeira célula conterá o modificador de propriedade. Por exemplo, uma linha de tendência tem dois pontos de ancoragem, e o ponto escolhido para indicar a coordenada será escrito na célula 1 da segunda dimensão da matriz. Para o ponto esquerdo da linha de tendência este valor será 0, já para o ponto direito, 1.
Na maioria dos casos, a primeira dimensão da matriz terá uma dimensão de 1, o que assinala que apenas uma propriedade do objeto de base ao qual o dependente está vinculado. Mas se precisarmos ancorar um objeto nas coordenadas calculadas, por exemplo, entre dois pontos da linha de tendência, precisaremos aumentar a dimensão da matriz para duas, sendo que a primeira especificará as propriedades do primeiro ponto de ancoragem do objeto de base e a segunda, as propriedades da segunda. Neste caso, o objeto dependente será vinculado ao objeto base por alguma fórmula (a média padrão), que é definida pelo próprio usuário da biblioteca no código. Mas não faremos esta funcionalidade hoje. Hoje estamos preparando tudo o que precisamos para implementar o que temos em mente.
Vamos escrever estas classes diretamente no arquivo de objeto gráfico padrão abstrato \MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqh, pois elas serão declaradas neste local e usadas se o objeto que está sendo criado for o objeto gráfico padrão estendido.
Vamos inserir a classe de dados do ponto de ancoragem para o objeto dependente logo no início da listagem do arquivo:
//+------------------------------------------------------------------+ //| 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){;} }; //+------------------------------------------------------------------+
A classe contém uma matriz bidimensional e dois métodos para redimensioná-la (por meio da adição de um novo ponto de ancoragem) e definir valores da primeira dimensão especificada da matriz. A classe também tem métodos para definir quais dados de coordenadas são escritos na matriz - X ou Y. Quando mensagens são produzidas a partir da classe, este sinalizador é verificado e a mensagem de erro correspondente é impressa.
Depois da listagem desta classe, vamos escrever uma classe de dados de pontos de ancoragem X e Y do objeto composto:
//+------------------------------------------------------------------+ //| 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 classe contém os dois objetos discutidos acima, um para a coordenada X e outro para a coordenada Y, e métodos para trabalhar com estes objetos, que essencialmente apenas retornam os resultados do trabalho feito sobre os métodos da primeira classe. Os sinalizadores dos eixos X ou Y de cada um dos objetos são especificados no construtor.
A classe também tem métodos para especificar os valores de propriedades para coordenadas X e Y simultaneamente - eles chamam imediatamente os métodos das duas primeiras classes e retornam o resultado combinado de sua chamada - se pelo menos um dos métodos retornados for false, o resultado será false.
Esta classe é seguida por uma terceira classe, a classe dos dados vinculados dos pontos de ancoragem do objeto composto:
//+------------------------------------------------------------------+ //| 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){;} }; //+------------------------------------------------------------------+
A classe permite criar objetos das classes de dados de pontos de ancoragem X e Y do objeto composto, que discutimos acima, e retorna apontadores para objetos desta classe. Um desses objetos descreve completamente um único ponto de ancoragem do objeto base ao longo das coordenadas X e Y, e permite adicionar novos dados e modificar os existentes. O objeto também contém um identificador de objeto de base que pode ser usado para determinar a que objeto este objeto gráfico está vinculado.
Na seção privada da classe do objeto gráfico padrão abstrato declaramos uma lista de objetos dependentes (vinculados a ele) e o objeto da classe de pontos de ancoragem vinculados que vimos acima:
//+------------------------------------------------------------------+ //| 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:
Na seção pública da classe, vamos adicionar métodos para operar com a lista de objetos gráficos vinculados e com o objeto da classe de pontos de ancoragem vinculados mencionado acima:
//--- 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 os métodos retornam o resultado da chamada dos métodos homônimos das classes discutidas acima e só permitem manusear esses objetos. Alguns métodos permanecem comentados no código e não precisam ser explicados. Em qualquer caso, você sempre pode colocar perguntas na discussão do artigo.
Agora passaremos o tipo de elemento gráfico criado ao construtor paramétrico protegido:
//--- 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:
Ao criar um objeto, podemos agora especificar que um objeto gráfico padrão estendido está sendo criado passando o valor GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED da enumeração ENUM_GRAPH_ELEMENT_TYPE como o tipo de elemento, o que é feito nos construtores de suas classes herdeiras.
No bloco de métodos para acesso simplificado e definição de propriedades de objeto gráfico, vamos escrever métodos para trabalhar com o identificador do objeto de base e métodos para trabalhar com o nome do objeto de base:
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)
Os métodos permitem definir o identificador e o nome do objeto de base nas propriedades do objeto, bem como retornar estes dados.
Em seguida, vamos inserir uma declaração do método que retorna a descrição do número do objeto na 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
No construtor paramétrico protegido vamos escrever a variável com o tipo de elemento gráfico e registrar o valor passado a ele no objeto gráfico de base, bem como definir os valores padrão das novas propriedades do objeto gráfico criado acima:
//+------------------------------------------------------------------+ //| 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 padrão, o identificador do objeto base é zero, o que significa que ele não existe, e o nome do objeto base é igual ao nome do objeto gráfico atual, ou seja, o objeto aponta para si mesmo, o que também significa que ele não está vinculado ao objeto de base.
No método que retorna a descrição da propriedade do objeto inteiro escrevemos a exibição da descrição do identificador do objeto de base, e no bloco que retorna a descrição do número do objeto na lista de objetos vinculados escrevemos a chamada do método que irá se encarregar disso (escreveremos mais adiante):
//+------------------------------------------------------------------+ //| 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) ) : "" ); } //+------------------------------------------------------------------+
No método que retorna a descrição da propriedade do objeto de string, vamos escrever um bloco de código para retornar a descrição do nome do objeto de base:
//+------------------------------------------------------------------+ //| 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 a descrição do número do objeto gráfico na lista de objetos do objeto gráfico composto:
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
Quanto ao objeto gráfico padrão estendido, verificamos seu número, e se for igual a zero é porque será impresso o texto "Objeto básico do objeto gráfico estendido". Em todos os outros casos, o número é exibido como uma string escrita nas propriedades do objeto.
Método que retorna o nome do objeto gráfico subordinado por í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() : ""); } //+------------------------------------------------------------------+
Recupera um ponteiro para o objeto gráfico vinculado na lista pelo índice especificado e retornamos seu nome. Se o objeto não pôde ser obtido, devolvemos uma string vazia.
Método que acrescenta o objeto gráfico padrão subordinado à 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; } //+------------------------------------------------------------------+
Em geral, qualquer objeto gráfico que não seja estendido não pode trabalhar com subordinados, por isso devemos verificar todos esses métodos que recebem um ponteiro para um objeto subordinado que é suposto ser subordinado e modificado, já se o objeto não for estendido, será exibida uma mensagem e o método retornará false. E da mesma forma para o objeto atual, nos métodos para manusear parâmetros do objeto subordinado é verificado se o objeto é subordinado (se está vinculado ao objeto de base), e se não está assim, então o objeto não é subordinado, e a mesma mensagem será mostrada e retornado false.
A razão para isso é que qualquer objeto gráfico pode ser tanto de base quanto subordinado, mesmo em simultâneo. Por esta razão, ele tem métodos para manusear objetos subordinados próprios, objetos de base, e mudar suas propriedades externamente, como objeto subordinado.
Modificamos a classe-coleção de elementos gráficos no arquivo \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh.
Na seção pública da classe de gerenciamento de objetos gráficos, adicionamos um sinalizador de criação de objeto gráfico estendido ao método de criação do novo objeto da classe de objetos gráficos padrão:
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
No mesmo método de classe que verifica objetos no gráfico, inserimos o valor false ao criar o novo 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 rastreia a criação de objetos gráficos no gráfico manualmente, o objeto da classe do objeto gráfico deve ser exclusivamente não estendido. Por isso, passamos o sinalizador criado false ao método, assim criamos um objeto gráfico padrão normal.
Vamos adicionar o sinalizador de objeto gráfico estendido aos parâmetros de entrada do método, que cria um novo objeto do objeto gráfico padrão, e passamos este sinalizador a todas as strings de criação de novo objeto da classe de objeto gráfico padrão:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
Agora quando criamos um objeto da classe de objeto gráfico padrão, podemos especificar se o objeto deve ser construído como normal ou estendido. Entretanto, podemos converter um objeto gráfico comum em um objeto ampliado a qualquer momento e vice-versa.
O método da seção privada da classe-coleção de elementos gráficos que cria um novo objeto gráfico padrão e retorna o nome do objeto criado deve ser removido da listagem da classe (vamos movê-lo para o arquivo de funções de serviço para que possamos sempre criar qualquer objeto gráfico, independentemente de ser construído a partir da classe-coleção ou de outras classes ou do próprio 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:
Na seção pública da classe escrevemos dois métodos que retornam uma lista de objetos gráficos padrão e estendidos:
//--- 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
Os métodos simplesmente retornam um ponteiro para a lista criada ao filtrar a lista de objetos gráficos pelo tipo de propriedade do elemento gráfico.
No método privado que cria um novo objeto gráfico e retorna um ponteiro para objeto de controle de gráficos, agora vamos chamar o método para criar um objeto gráfico a partir do arquivo DELib.mqh (simplesmente excluímos "this." da string de chamada do 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; }
Em todos os métodos públicos para criação de objetos gráficos, fazemos o mesmo tipo de mudanças - o sinalizador do objeto estendido nos parâmetros de entrada do método e a transferência deste sinalizador para o método de criação de um novo objeto da classe do objeto gráfico padrão:
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
Aqui vemos um exemplo de dois métodos em que foram feitas as mesmas mudanças. Os outros métodos são modificados de forma idêntica e podem ser vistos nos arquivos anexados ao artigo.
A listagem da implementação do método que cria um novo objeto gráfico padrão desta classe deve ser transferida desta classe para o final do arquivo de funções de serviço da biblioteca \MQL5\Include\DoEasy\Services\DELib.mqh:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
Agora editamos a classe principal da biblioteca CEngine no arquivo \MQL5\Include\DoEasy\Engine.mqh.
Quanto ao método que retorna o nome do programa, vamos renomeá-lo de Name() para ProgramName():
//--- 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 os nomes dos nossos objetos diferem dependendo de como o objeto gráfico foi criado (manual ou programaticamente), para poder pesquisar e selecionar objetos por nome do programa, vamos fazer algumas mudanças no método que retorna a classe do objeto de objeto gráfico padrão por nome e identificador de objeto gráfico:
//--- 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; }
Se o objeto foi criado manualmente, a biblioteca não altera seu nome de forma alguma. Mas se criarmos um objeto gráfico de forma programática, os métodos de criação acrescentam o prefixo do nome do programa a seu nome. Por isso, se tivermos criado um objeto com um nome como "object_name" e tentar encontrá-lo, não teremos resultado, porque um prefixo do nome do programa foi adicionado ao nome, e agora o nome do objeto fica como "program_name_object_name". Com base nisso, o método primeiro procura pelo nome exato passado ao método, e depois, se nenhum objeto com esse nome for encontrado, tentamos encontrar um objeto com um prefixo contendo o nome do programa.
E vamos adicionar um método que retorna a classe do objeto gráfico padrão estendido por nome e ID do 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); }
Aqui primeiro obtemos toda a lista dos objetos gráficos padrão estendidos, depois verificamos se o nome passado ao método contém uma string com o nome do programa e, se a string não for encontrada, adicionamos o nome do programa ao nome. Caso contrário, se o nome do programa já existe no nome procurado, usamos o nome passado para o método como está. Em seguida, obtemos o objeto com o nome que estamos procurando a partir da lista de objetos gráficos estendida, e retornamos o único objeto da lista se ele foi encontrado, ou NULL em caso de falha.
Em todos os métodos para criação de objetos gráficos, agora passamos o sinalizador do objeto estendido e passamos este sinalizador aos devidos métodos chamados da classe-coleção 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 os métodos de criação de objetos gráficos, estas modificações são absolutamente idênticas às quatro apresentadas acima. Portanto, não consideraremos os demais métodos, porque podem ser encontrados nos arquivos anexos ao artigo.
Isto completa a modificação da biblioteca e estamos quase prontos para criar objetos gráficos padrão estendidos.
Teste
Para realizar o teste, vamos pegar o Expert Advisor do artigo anterior e
vamos salvá-lo na nova pasta \MQL5\Experts\TestDoEasy\Part93\ com o novo nome TestDoEasyPart93.mq5.
O que vamos fazer? Vamos criar um objeto gráfico padrão "Linha de tendência" e colocar em suas bordas (em seus dois pontos de ancoragem) um objeto "Etiqueta de preço à esquerda" (à esquerda na posição 0) e um "Etiqueta de à direita" (à direita na posição 1). Vamos criar a linha de tendência clicando no gráfico com a tecla Ctrl pressionada, ao passo que o ponto esquerdo da linha será posicionado no local do clique no gráfico, já o direito, no preço de abertura da primeira barra do gráfico.
Imprimimos no log a descrição completa das propriedades da linha de tendência e os valores escritos nos rótulos de objetos/preços, em seus objetos das classes vinculadas aos pontos de ancoragem. Não testaremos todo o resto, pois ainda precisamos fazer alguns ajustes nas propriedades e funcionalidade do objeto para desenvolver completamente os objetos gráficos estendidos padrão.
Colocamos o seguinte código dentro do bloco gráfico de processamento de cliques no manipulador do Expert Advisor OnChartEvent():
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)); } }
Aqui toda a lógica aparece comentada na listagem, por isso espero que não haja perguntas.
Compilamos o EA, o executamos no gráfico e clicamos em algum lugar longe da borda direita do gráfico.
Será traçada uma linha de tendência, com marcadores de preço ao longo de suas bordas:
As propriedades da linha de tendência e o número de pontos de ancoragem da mesma para o cálculo das coordenadas X e Y dois marcadores de preço serão impressas no log. Por ter especificado apenas um ponto de ancoragem para cada uma dos marcadores, isto será refletido no log.
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
Neste ponto, nós simplesmente construímos objetos gráficos em separado e assinalamos em suas propriedades que eles pertencem ao mesmo objeto gráfico padrão estendido. Caso tentarmos mover a linha de tendência, os marcadores de preço não a seguirão. Nosso objetivo hoje não era tanto esse, mas preparamos a funcionalidade necessária para criar objetos gráficos estendidos e completos.
O que vem agora?
No próximo artigo, continuaremos a trabalhar sobre os objetos gráficos padrão estendidos e começaremos a "dar-lhes vida".
*Artigos desta série:
Gráficos na biblioteca DoEasy (Parte 89): programando objetos gráficos padrão. Funcionalidade básica
Gráficos na biblioteca DoEasy (Parte 90): eventos de objetos gráficos padrão. Funcionalidade básica
Gráficos na biblioteca DoEasy (Parte 91): eventos de objetos gráficos padrão no programa. Histórico de alterações de nome do objeto
Gráficos na biblioteca do DoEasy (Parte 92): classe de memória de objetos gráficos padrão. Histórico de mudanças de propriedades do objeto
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/10331
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso