![DoEasy 函数库中的图形(第九十二部分):标准图形对象记忆类。 对象属性变更历史记录](https://c.mql5.com/i/articles/overlay.png)
DoEasy 函数库中的图形(第九十二部分):标准图形对象记忆类。 对象属性变更历史记录
内容
概述
我们已经测试了图形对象属性重命名的历史的实现。 实际上,上一篇文章中创建的功能,已经允许我们定义图形对象重命名的整个序列。 很难预测它能有多大用处。 不过,考虑到重命名过程中会删除以前的对象,并创建一个拥有另一个名称的新对象,故此,掌握图表上过往存在的对象也许会很有用处。 如果我们考虑到存储对象整个变更历史的可能性,那么我们将在任何图形对象中掌控其所有状态,包括以前的名称。 因此,这个对象可令我们知道它以前的名字。 通过匹配所需的名称及其存储在记忆中的属性,我们可以轻松地恢复图表上的对象。
我不打算讨论它会在哪里以及如何派上用场,但它肯定是技术分析能用到的另一个工具。 例如,对象名称可用于标记图形对象构建的日期、周、月、或任何其它时间区间。 当新的时间片段到达时,旧对象将被重命名,以便其名称与新的时间片段吻合,且在图表上重建对象。 相应地,它的所有属性都将存储在其记忆中(我将在本文中实现这种功能),包括它的重命名历史。 如果我们要用图形对象在图表上为某个东西作标记,并要每天重建该对象,则可为该对象重命名匹配的新日期。 当手动滚动图表时,我们可以发现一根可见柱线的时间,并从其记忆中“提取”图形对象状态。 该状态应与滚动图表上的柱线时间相对应,并将其属性应用到当前对象。 如此,我们将能够创建一个智能对象,该对象能根据图表上可见柱线的时间自行改变其状态。
故此,上述示例将令我们在一个交易周内,根据每天的当时市场状态调整图形对象属性。 在每个周末,我们可以简单地将图表向回滚动,图形对象将在图表的可视区域显示过往的每个交易日。 由于对象有自己的记忆,因此每次对象属性变更时,它都会保存所有变更。 如果图表拥有一个由函数库控制的 EA,那么某个图形对象应该能针对图表一天的可视区域状态制作“快照”,并将这些参数应用于自身;滚动图表可作为触发更改图形对象属性的条件,它能显示在交易周内所做的所有修改。
我们为什么需要这个? 我相信,这个功能对于分析一个交易周是很方便的。 此外,这只是一个浮现在脑海,并立即被我捕捉到的似乎很有用的例子。
改进库类
标准图形对象属性的枚举有一个 Group 属性。 它当前用于指定图形对象所属的分组:
然而,如果我们还记得,其它函数库对象也有它们的分组,并且它们被用来根据某些属性对对象进行排序,所以为图形对象建立相同的顺序也是合理的。 当前的 Group 属性将重命名为 Species,而新的 Group 属性将用于按对象的某些属性对对象进行排序。 为了测试我在这里创建的功能,我将把分组 #1 分配给图表上创建的图形对象。 分组中的所有对象在修改时都会保存其状态。
在 \MQL5\Include\DoEasy\Defines.mqh 里,替换 "Graphical object group" 枚举:
//+------------------------------------------------------------------+ //| The list of graphical element types | //+------------------------------------------------------------------+ enum ENUM_GRAPH_ELEMENT_TYPE { GRAPH_ELEMENT_TYPE_STANDARD, // 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 }; //+------------------------------------------------------------------+ //| Graphical object group | //+------------------------------------------------------------------+ enum ENUM_GRAPH_OBJ_GROUP { GRAPH_OBJ_GROUP_LINES, // Lines GRAPH_OBJ_GROUP_CHANNELS, // Channels GRAPH_OBJ_GROUP_GANN, // Gann GRAPH_OBJ_GROUP_FIBO, // Fibo GRAPH_OBJ_GROUP_ELLIOTT, // Elliott GRAPH_OBJ_GROUP_SHAPES, // Shapes GRAPH_OBJ_GROUP_ARROWS, // Arrows GRAPH_OBJ_GROUP_GRAPHICAL, // Graphical objects }; //+------------------------------------------------------------------+ //| Integer properties of a standard graphical object | //+------------------------------------------------------------------+
新枚举是 "Graphical object species":
//+------------------------------------------------------------------+
//| Graphical object species |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_SPECIES
{
GRAPH_OBJ_SPECIES_LINES, // Lines
GRAPH_OBJ_SPECIES_CHANNELS, // Channels
GRAPH_OBJ_SPECIES_GANN, // Gann
GRAPH_OBJ_SPECIES_FIBO, // Fibo
GRAPH_OBJ_SPECIES_ELLIOTT, // Elliott
GRAPH_OBJ_SPECIES_SHAPES, // Shapes
GRAPH_OBJ_SPECIES_ARROWS, // Arrows
GRAPH_OBJ_SPECIES_GRAPHICAL, // Graphical objects
};
//+------------------------------------------------------------------+
在标准图形对象的整数型属性枚举中,替换 Group 属性
//--- Additional properties GRAPH_OBJ_PROP_ID = 0, // 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_GROUP, // Graphical object group (ENUM_GRAPH_OBJ_GROUP) 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
新属性为 Species,并加入两个新参数 — 存储历史记录变更的标志和对象分组:
//+------------------------------------------------------------------+ //| 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_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
默认情况下,图形对象并不会存储属性变更历史记录。 因此,我实现了存储标志的属性,该标志指明图形对象是否记录了其变更历史。 如上所述,我已将 Group 属性重命名为 Species,并创建了新的 Group 属性,存储按特定属性排序的对象组的索引。
由于我们在整数型图形对象属性的枚举中添加了两个新属性,故需指定它们的新数量(54 替换 52):
#define GRAPH_OBJ_PROP_INTEGER_TOTAL (54) // Total number of integer properties #define GRAPH_OBJ_PROP_INTEGER_SKIP (0) // Number of integer properties not used in sorting //+------------------------------------------------------------------+ //| Real properties of a standard graphical object | //+------------------------------------------------------------------+
在可能的图形对象排序标准的枚举中添加新属性:
//+------------------------------------------------------------------+ //| 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_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_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 }; //+------------------------------------------------------------------+
在 \MQL5\Include\DoEasy\Data.mqh 里,添加新的消息索引,并修复枚举常量的名称:
//--- GStdGraphObj MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ, // Failed to create the class object for a graphical object MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_STD_GRAPH_OBJ, // Failed to create a graphical object MSG_GRAPH_STD_OBJ_ERR_NOT_FIND_SUBWINDOW, // Failed to find the chart subwindow MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_SNAPSHOT, // Failed to create a snapshot of the graphical object change history MSG_GRAPH_STD_OBJ_SUCCESS_CREATE_SNAPSHOT, // Created a snapshot of the graphical object change history
...
MSG_GRAPH_OBJ_PROP_ID, // 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_BELONG, // Graphical object affiliation MSG_GRAPH_OBJ_PROP_CHART_ID, // Chart ID MSG_GRAPH_OBJ_PROP_WND_NUM, // Chart subwindow index MSG_GRAPH_OBJ_PROP_CHANGE_MEMORY, // Change history MSG_GRAPH_OBJ_PROP_CREATETIME, // Creation time MSG_GRAPH_OBJ_PROP_TIMEFRAMES, // Object visibility on timeframes
...
MSG_GRAPH_OBJ_PROP_SPECIES, // Graphical object species MSG_GRAPH_OBJ_PROP_SPECIES_LINES, // Lines MSG_GRAPH_OBJ_PROP_SPECIES_CHANNELS, // Channels MSG_GRAPH_OBJ_PROP_SPECIES_GANN, // Gann MSG_GRAPH_OBJ_PROP_SPECIES_FIBO, // Fibo MSG_GRAPH_OBJ_PROP_SPECIES_ELLIOTT, // Elliott MSG_GRAPH_OBJ_PROP_SPECIES_SHAPES, // Shapes MSG_GRAPH_OBJ_PROP_SPECIES_ARROWS, // Arrows MSG_GRAPH_OBJ_PROP_SPECIES_GRAPHICAL, // Graphical objects MSG_GRAPH_OBJ_PROP_GROUP, // Group of objects MSG_GRAPH_OBJ_TEXT_CLICK_COORD, // (Chart click coordinate) MSG_GRAPH_OBJ_TEXT_ANCHOR_TOP, // Arrow anchor point is located at the top MSG_GRAPH_OBJ_TEXT_ANCHOR_BOTTOM, // Arrow anchor point is located at the bottom
...
//--- CDataPropObj MSG_DATA_PROP_OBJ_OUT_OF_PROP_RANGE, // Passed property is out of object property range MSG_GRAPH_OBJ_FAILED_CREATE_NEW_HIST_OBJ, // Failed to create an object of the graphical object change history MSG_GRAPH_OBJ_FAILED_ADD_OBJ_TO_HIST_LIST, // Failed to add the change history object to the list MSG_GRAPH_OBJ_FAILED_GET_HIST_OBJ, // Failed to receive the change history object MSG_GRAPH_OBJ_FAILED_INC_ARRAY_SIZE, // Failed to increase the array size
和与新添加的索引对应的文本消息:
//--- GStdGraphObj {"Не удалось создать объект класса для графического объекта ","Failed to create class object for graphic object"}, {"Не удалось создать графический объект ","Failed to create graphic object "}, {"Не удалось найти подокно графика","Could not find chart subwindow"}, {"Не удалось создать снимок истории изменений графического объекта","Failed to create a snapshot of the change history of a graphic object"}, {"Создан снимок истории изменений графического объекта","A snapshot of the history of changes to a graphical object has been created"},
...
{"Идентификатор объекта","Object ID"}, {"Тип объекта","Object type"}, {"Тип графического элемента","Graphic element type"}, {"Принадлежность объекта","Object belongs to"}, {"Идентификатор графика объекта","Object chart ID"}, {"Номер подокна графика","Chart subwindow number"}, {"История изменений","Change history"}, {"Время создания","Time of creation"}, {"Видимость объекта на таймфреймах","Visibility of an object at timeframes"},
...
{"Вид графического объекта","Graphic object species"}, {"Линии","Lines"}, {"Каналы","Channels"}, {"Ганн","Gann"}, {"Фибоначчи","Fibonacci"}, {"Эллиотт","Elliott"}, {"Фигуры","Shapes"}, {"Стрелки","Arrows"}, {"Графические объекты","Graphical"}, {"Группа объектов","Object group"},
...
//--- CDataPropObj {"Переданное свойство находится за пределами диапазона свойств объекта","The passed property is outside the range of the object's properties"}, {"Не удалось создать объект истории изменений графического объекта","Failed to create a graphical object change history object"}, {"Не удалось добавить объект истории изменений в список","Failed to add change history object to the list"}, {"Не удалось получить объект истории изменений","Failed to get change history object"}, {"Не удалось увеличить размер массива","Failed to increase array size"},
我们需要针对 \MQL5\Include\DoEasy\Objects\Graph\Standard\(GStdArrowBuyObj.mqh 作为示例)中的抽象标准图形对象派生的所有对象进行修改。
在类构造函数的初始化清单中,修复指示图形对象种类的枚举常量的名称:
//--- Constructor CGStdArrowBuyObj(const long chart_id,const string name) : CGStdGraphObj(OBJECT_DE_TYPE_GSTD_ARROW_BUY,GRAPH_OBJ_BELONG_NO_PROGRAM,GRAPH_OBJ_SPECIES_ARROWS,chart_id,1,name) { //--- Specify the object property CGStdGraphObj::SetProperty(GRAPH_OBJ_PROP_ANCHOR,0,ANCHOR_TOP); }
在其它文件中,还会有其它类型的图形对象。 但在所有地方 _GROUP_ 都应替换为 _SPECIES_。
在对象返回所支持整数型属性标志的方法中,添加 “Flag of saving object change history(保存对象变更历史标志)”属性:
//+------------------------------------------------------------------+ //| 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_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; } //+------------------------------------------------------------------+
在指定文件夹中进行了所有修改。 它们与已研究过的雷同,所以我不打算再复述它们。 您可在文后的附件中找到它们。
在所有函数库图形对象的基准图形对象文件 \MQL5\Include\DoEasy\objects\Graph\GBaseObj.mqh 中,添加存储图形对象种类和分组的变量:
//+------------------------------------------------------------------+ //| Class of the base object of the library graphical objects | //+------------------------------------------------------------------+ class CGBaseObj : public CObject { protected: CArrayObj m_list_events; // Object event list ENUM_OBJECT m_type_graph_obj; // Graphical object type ENUM_GRAPH_ELEMENT_TYPE m_type_element; // Graphical element type ENUM_GRAPH_OBJ_BELONG m_belong; // Program affiliation ENUM_GRAPH_OBJ_SPECIES m_species; // Graphical object species string m_name_prefix; // Object name prefix string m_name; // Object name long m_chart_id; // Object chart ID long m_object_id; // Object ID long m_zorder; // Priority of a graphical object for receiving the mouse click event int m_subwindow; // Subwindow index int m_shift_y; // Subwindow Y coordinate shift int m_type; // Object type int m_timeframes_visible; // Visibility of an object on timeframes (a set of flags) int m_digits; // Number of decimal places in a quote int m_group; // Graphical object group bool m_visible; // Object visibility bool m_back; // "Background object" flag bool m_selected; // "Object selection" flag bool m_selectable; // "Object availability" flag bool m_hidden; // "Disable displaying the name of a graphical object in the terminal object list" flag datetime m_create_time; // Object creation time
以及设置和返回这些变量值的方法:
public: //--- Set the values of the class variables void SetObjectID(const long value) { this.m_object_id=value; } void SetBelong(const ENUM_GRAPH_OBJ_BELONG belong){ this.m_belong=belong; } void SetTypeGraphObject(const ENUM_OBJECT obj) { this.m_type_graph_obj=obj; } void SetTypeElement(const ENUM_GRAPH_ELEMENT_TYPE type) { this.m_type_element=type; } void SetSpecies(const ENUM_GRAPH_OBJ_SPECIES species){ this.m_species=species; } void SetGroup(const int group) { this.m_group=group; } void SetName(const string name) { this.m_name=name; } void SetChartID(const long chart_id) { this.m_chart_id=chart_id; } void SetDigits(const int value) { this.m_digits=value; }
...
//--- Return the values of class variables ENUM_GRAPH_ELEMENT_TYPE TypeGraphElement(void) const { return this.m_type_element; } ENUM_GRAPH_OBJ_BELONG Belong(void) const { return this.m_belong; } ENUM_GRAPH_OBJ_SPECIES Species(void) const { return this.m_species; } ENUM_OBJECT TypeGraphObject(void) const { return this.m_type_graph_obj; } datetime TimeCreate(void) const { return this.m_create_time; } string Name(void) const { return this.m_name; } long ChartID(void) const { return this.m_chart_id; } long ObjectID(void) const { return this.m_object_id; } long Zorder(void) const { return this.m_zorder; } int SubWindow(void) const { return this.m_subwindow; } int ShiftY(void) const { return this.m_shift_y; } int VisibleOnTimeframes(void) const { return this.m_timeframes_visible; } int Digits(void) const { return this.m_digits; } int Group(void) const { return this.m_group; } bool IsBack(void) const { return this.m_back; } bool IsSelected(void) const { return this.m_selected; } bool IsSelectable(void) const { return this.m_selectable; } bool IsHidden(void) const { return this.m_hidden; } bool IsVisible(void) const { return this.m_visible; }
将之前返回图形对象描述的方法重命名为返回图形对象种类描述的方法:
//--- Return the description of the type of the graphical object (1) type, (2) element, (3) affiliation and (4) species string TypeGraphObjectDescription(void); string TypeElementDescription(void); string BelongDescription(void); string SpeciesDescription(void);
并根据对象物种枚举常量的新名称修复其实现:
//+------------------------------------------------------------------+ //| Return the description of the graphical object group | //+------------------------------------------------------------------+ string CGBaseObj::SpeciesDescription(void) { return ( this.Species()==GRAPH_OBJ_SPECIES_LINES ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SPECIES_LINES) : this.Species()==GRAPH_OBJ_SPECIES_CHANNELS ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SPECIES_CHANNELS) : this.Species()==GRAPH_OBJ_SPECIES_GANN ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SPECIES_GANN) : this.Species()==GRAPH_OBJ_SPECIES_FIBO ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SPECIES_FIBO) : this.Species()==GRAPH_OBJ_SPECIES_ELLIOTT ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SPECIES_ELLIOTT) : this.Species()==GRAPH_OBJ_SPECIES_SHAPES ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SPECIES_SHAPES) : this.Species()==GRAPH_OBJ_SPECIES_ARROWS ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SPECIES_ARROWS) : this.Species()==GRAPH_OBJ_SPECIES_GRAPHICAL ? CMessage::Text(MSG_GRAPH_OBJ_PROP_SPECIES_GRAPHICAL) : "Unknown" ); }
在类构造函数中,将默认对象分组设置为 0,这对应于省缺:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CGBaseObj::CGBaseObj() : m_shift_y(0),m_visible(false), m_name_prefix(::MQLInfoString(MQL_PROGRAM_NAME)+"_"),m_belong(GRAPH_OBJ_BELONG_PROGRAM) { this.m_list_events.Clear(); // Clear the event list this.m_list_events.Sort(); // Sorted list flag this.m_type=OBJECT_DE_TYPE_GBASE; // Object type this.m_type_graph_obj=WRONG_VALUE; // Graphical object type this.m_type_element=WRONG_VALUE; // Graphical object type this.m_belong=WRONG_VALUE; // Program/terminal affiliation this.m_group=0; // Graphical object group this.m_name_prefix=""; // Object name prefix this.m_name=""; // Object name this.m_chart_id=0; // Object chart ID this.m_object_id=0; // Object ID this.m_zorder=0; // Priority of a graphical object for receiving the mouse click event this.m_subwindow=0; // Subwindow index this.m_shift_y=0; // Subwindow Y coordinate shift this.m_timeframes_visible=OBJ_ALL_PERIODS; // Visibility of an object on timeframes (a set of flags) this.m_visible=true; // Object visibility this.m_back=false; // "Background object" flag this.m_selected=false; // "Object selection" flag this.m_selectable=false; // "Object availability" flag this.m_hidden=true; // "Disable displaying the name of a graphical object in the terminal object list" flag this.m_create_time=0; // Object creation time } //+------------------------------------------------------------------+
标准图形对象记忆类
图形对象记忆类是一个对象列表,在任何图形对象属性(整数型、实数型和字符串型)发生变化时,这些对象都含有全部图形对象属性(整数型、实数型和字符串型)。 为什么不只保存变化的属性? 仅仅知道哪些属性已经变化是不够的。 我们还应该能设置对象的所有属性,从而获得其状态。 因此,我们将存储其属性的完整快照。 在此情况下,我们就能够把所有这些属性从对象记忆复制到其真实属性,而无需计算从记忆中获取哪些属性,以及从其当前状态获取哪些属性。
为了实现已变更对象属性的快照类,我将使用 CDATA PropObj 对象属性类。 但是,由于我们需要知道和考虑一些附加参数(变更时间、品种、及其小数位),所以变更对象属性快照类应从图形对象属性对象类继承。
图形对象记忆类包含已变更属性快照对象的列表,并提供处理这些列表和其中所包含对象的访问权限。
这两个类都位于 \MQL5\Include\DoEasy\Services\Properties.mqh 对象属性类文件当中。
在其中包括函数库服务函数的文件:
//+------------------------------------------------------------------+ //| Properties.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 "DELib.mqh" #include "XDimArray.mqh" //+------------------------------------------------------------------+
在对象属性类的公开部分,添加返回整数型、实数型和字符串型对象属性数的方法:
//--- Return the number of (1) integer, (2) real and (3) string parameters int TotalLong(void) const { return this.m_total_int; } int TotalDouble(void) const { return this.m_total_dbl; } int TotalString(void) const { return this.m_total_str; } //--- Constructor
这些方法对于设置历史变更类对象的属性数量非常有用。
对象属性类之后是对象变更属性快照类:
//+------------------------------------------------------------------+ //| Object changed property snapshot class | //+------------------------------------------------------------------+ class CChangedProps : public CDataPropObj { private: long m_time_change; // Property modification time string m_symbol; // Chart window symbol int m_digits; // Symbol's Digits public: //--- Set the (1) change time value, (2) symbol and (3) symbol's Digits void SetTimeChanged(const long time) { this.m_time_change=time; } void SetSymbol(const string symbol) { this.m_symbol=symbol; } void SetDigits(const int digits) { this.m_digits=digits; } //--- Return the (1) change time value, (2) change time, (3) symbol and (4) symbol's Digits long TimeChanged(void) const { return this.m_time_change; } string TimeChangedToString(void) const { return TimeMSCtoString(this.m_time_change);} string Symbol(void) const { return this.m_symbol; } int Digits(void) const { return this.m_digits; } //--- Constructor/destructor CChangedProps (const int prop_total_integer,const int prop_total_double,const int prop_total_string,const long time_changed) : CDataPropObj(prop_total_integer,prop_total_double,prop_total_string) { this.m_time_change=time_changed;} ~CChangedProps (void){;} }; //+------------------------------------------------------------------+
正如我们所见,该类是从图形对象属性对象类派生而来的。 故此,它拥有其父类的所有属性,以及类中的其它属性集合。 在此,我们只有对象修改时间(以毫秒为单位)、图形对象变更的图表品种,以及对象价格属性中正确显示品种小数位的长度。
在类构造函数中,传递整数型、实数型和字符串型属性的数量,及其变更时间(以毫秒为单位)。
如此,我们可以创建图形对象参数的副本,并将其放在参数变更历史类对象的列表当中。 该类在同一个文件中编写 — 就在对象变更属性快照类的正下方:
//+------------------------------------------------------------------+ //| Class of the history of graphical object property changes | //+------------------------------------------------------------------+ class CChangeHistory { private: CArrayObj m_list_changes; // List of the property change history public: //--- Return (1) the pointer to the property change history object and (2) the number of changes CChangedProps *GetChangedPropsObj(const string source,const int index) { CChangedProps *props=this.m_list_changes.At(index<0 ? 0 : index); if(props==NULL) CMessage::ToLog(source,MSG_GRAPH_OBJ_FAILED_GET_HIST_OBJ); return props; } int TotalChanges(void) { return this.m_list_changes.Total(); } //--- Create a new object of the graphical object property change history bool CreateNewElement(CDataPropObj *element,const long time_change) { //--- Create a new object of the graphical object property snapshot CChangedProps *obj=new CChangedProps(element.TotalLong(),element.TotalDouble(),element.TotalString(),time_change); //--- If failed to create an object, inform of that and return 'false' if(obj==NULL) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_CREATE_NEW_HIST_OBJ); return false; } //--- If failed to add the object to the list, inform of that, remove the object and return 'false' if(!this.m_list_changes.Add(obj)) { CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_ADD_OBJ_TO_HIST_LIST); delete obj; return false; } //--- Get the ID of the chart the graphical object is located on long chart_id=element.GetLong(GRAPH_OBJ_PROP_CHART_ID,0); //--- Set a chart symbol and symbol's Digits for the graphical object property snapshot object obj.SetSymbol(::ChartSymbol(chart_id)); obj.SetDigits((int)::SymbolInfoInteger(obj.Symbol(),SYMBOL_DIGITS)); //--- Copy all integer properties for(int i=0;i<element.TotalLong();i++) { int total=element.Long().Size(i); if(obj.SetSizeRange(i,total)) { for(int r=0;r<total;r++) obj.Long().Set(i,r,element.Long().Get(i,r)); } else CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_INC_ARRAY_SIZE); } //--- Copy all real properties for(int i=0;i<element.TotalDouble();i++) { int total=element.Double().Size(i); if(obj.Double().SetSizeRange(i,total)) { for(int r=0;r<total;r++) obj.Double().Set(i,r,element.Double().Get(i,r)); } else CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_INC_ARRAY_SIZE); } //--- Copy all string properties for(int i=0;i<element.TotalString();i++) { int total=element.String().Size(i); if(obj.String().SetSizeRange(i,total)) { for(int r=0;r<total;r++) obj.String().Set(i,r,element.String().Get(i,r)); } else CMessage::ToLog(DFUN,MSG_GRAPH_OBJ_FAILED_INC_ARRAY_SIZE); } return true; } //--- Return by index in the list of the graphical object change history object //--- the value from the specified index of the (1) long, (2) double and (3) string array long GetLong(const int time_index,const ENUM_GRAPH_OBJ_PROP_INTEGER prop,const int index) { CChangedProps *properties=this.GetChangedPropsObj(DFUN,time_index); if(properties==NULL) return 0; return properties.GetLong(prop,index); } double GetDouble(const int time_index,const ENUM_GRAPH_OBJ_PROP_DOUBLE prop,const int index) { CChangedProps *properties=this.GetChangedPropsObj(DFUN,time_index); if(properties==NULL) return 0; return properties.GetDouble(prop,index); } string GetString(const int time_index,const ENUM_GRAPH_OBJ_PROP_STRING prop,const int index) { CChangedProps *properties=this.GetChangedPropsObj(DFUN,time_index); if(properties==NULL) return ""; return properties.GetString(prop,index); } //--- Constructor/destructor CChangeHistory(void){;} ~CChangeHistory(void){;} }; //+------------------------------------------------------------------+
该类也很简单。 它提供了一个列表,该列表将包含所有图形对象的变更,其对象由图形对象变更属性快照类表述。
为已变更属性创建新快照的方法接收当前(已变更)图形对象属性,和变更时间(以毫秒为单位)。 创建一个新的属性快照对象,并将其添加到列表当中。 进而,还要为对象设置其它参数。 然后, 把所有已变更图形对象的所有属性传递给该方法,并通过三个循环复制到所创建的对象。
因此,在更改每个图形对象时,会为其属性创建副本,并将其添加到列表之中。 因此,我们可以获得指向任何已保存属性对象的指针,并可随时将其用于程序。
所有的类方法都是雷同。 它们的逻辑相当透明:从列表中获取所需的属性对象,并从中返回所请求的属性。
您可以在下面的评论区中咨询有关这些方法的所有问题。 我相信,在此讲述它们并无什么意义。 在以前的文章中曾反复研究过这种方法的逻辑。
当前和以前的属性类数据接收指向已变更历史对象的指针,和返回图形对象变更次数的方法。 在类构造函数中,创建一个新的变更历史对象,且需在析构函数中删除它:
//+------------------------------------------------------------------+ //| Data class of the current and previous properties | //+------------------------------------------------------------------+ class CProperties : public CObject { private: CArrayObj m_list; // List for storing the pointers to property objects public: CDataPropObj *Curr; // Pointer to the current properties object CDataPropObj *Prev; // Pointer to the previous properties object CChangeHistory *History; // Pointer to the change history object //--- Set the array size ('size') in the specified dimension ('range') bool SetSizeRange(const int range,const int size) { return(this.Curr.SetSizeRange(range,size) && this.Prev.SetSizeRange(range,size) ? true : false); } //--- Return the size of the specified array of the (1) current and (2) previous first dimension data int CurrSize(const int range) const { return Curr.Size(range); } int PrevSize(const int range) const { return Prev.Size(range); } //--- Copy the current data to the previous one void CurrentToPrevious(void) { //--- Copy all integer properties for(int i=0;i<this.Curr.Long().Total();i++) for(int r=0;r<this.Curr.Long().Size(i);r++) this.Prev.Long().Set(i,r,this.Curr.Long().Get(i,r)); //--- Copy all real properties for(int i=0;i<this.Curr.Double().Total();i++) for(int r=0;r<this.Curr.Double().Size(i);r++) this.Prev.Double().Set(i,r,this.Curr.Double().Get(i,r)); //--- Copy all string properties for(int i=0;i<this.Curr.String().Total();i++) for(int r=0;r<this.Curr.String().Size(i);r++) this.Prev.String().Set(i,r,this.Curr.String().Get(i,r)); } //--- Return the amount of graphical object changes since the start of recording them int TotalChanges(void) { return this.History.TotalChanges(); } //--- Constructor CProperties(const int prop_int_total,const int prop_double_total,const int prop_string_total) { //--- Create new objects of the current and previous properties this.Curr=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); this.Prev=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total); //--- Add newly created objects to the list this.m_list.Add(this.Curr); this.m_list.Add(this.Prev); //--- Create the change history object this.History=new CChangeHistory(); } //--- Destructor ~CProperties() { this.m_list.Clear(); this.m_list.Shutdown(); if(this.History!=NULL) delete this.History; } }; //+------------------------------------------------------------------+
现在,每个图形对象都将在其属性中存储属性变更列表。
为了与图形对象变改历史进行交互,在 \MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqh 文件里(也就是说,在抽象标准图形对象类中),在对象属性中加入返回指向变更历史列表指针的方法:
public: //--- Set object's (1) integer, (2) real and (3) string properties void SetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Prop.Curr.SetLong(property,index,value); } void SetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value) { this.Prop.Curr.SetDouble(property,index,value); } void SetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value) { this.Prop.Curr.SetString(property,index,value); } //--- Return object’s (1) integer, (2) real and (3) string property from the properties array long GetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index) const { return this.Prop.Curr.GetLong(property,index); } double GetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index) const { return this.Prop.Curr.GetDouble(property,index); } string GetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index) const { return this.Prop.Curr.GetString(property,index); } //--- Set object's previous (1) integer, (2) real and (3) string properties void SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Prop.Prev.SetLong(property,index,value); } void SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value){ this.Prop.Prev.SetDouble(property,index,value); } void SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value){ this.Prop.Prev.SetString(property,index,value); } //--- Return object’s (1) integer, (2) real and (3) string property from the previous properties array long GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index) const { return this.Prop.Prev.GetLong(property,index); } double GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index) const { return this.Prop.Prev.GetDouble(property,index); } string GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index) const { return this.Prop.Prev.GetString(property,index); } //--- Return (1) itself, (2) properties and (3) the change history CGStdGraphObj *GetObject(void) { return &this; } CProperties *Properties(void) { return this.Prop; } CChangeHistory *History(void) { return this.Prop.History;} //--- Return the flag of the object supporting this property
在类的默认构造函数中,以种类指示替代对象分组指示。 在闭合参数构造函数中,传递对象种类,而非分组:
//--- 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_OBJ_BELONG belong, const ENUM_GRAPH_OBJ_SPECIES species, const long chart_id, const int pivots, const string name);
在简化访问和设置图形对象属性的方法模块中,添加设置和返回存储变更历史标志,和图形对象分组的方法:
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); } //--- 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); } //--- Graphical element type ENUM_GRAPH_ELEMENT_TYPE GraphElementType(void) const { return (ENUM_GRAPH_ELEMENT_TYPE)this.GetProperty(GRAPH_OBJ_PROP_ELEMENT_TYPE,0);} void SetGraphElementType(const ENUM_GRAPH_ELEMENT_TYPE elm_type) { CGBaseObj::SetTypeElement(elm_type); this.SetProperty(GRAPH_OBJ_PROP_ELEMENT_TYPE,0,elm_type); } //--- Graphical object affiliation ENUM_GRAPH_OBJ_BELONG Belong(void) const { return (ENUM_GRAPH_OBJ_BELONG)this.GetProperty(GRAPH_OBJ_PROP_BELONG,0); } void SetBelong(const ENUM_GRAPH_OBJ_BELONG belong) { CGBaseObj::SetBelong(belong); this.SetProperty(GRAPH_OBJ_PROP_BELONG,0,belong); } //--- Group of graphical objects int Group(void) const { return (int)this.GetProperty(GRAPH_OBJ_PROP_GROUP,0); } void SetGroup(const int group) { CGBaseObj::SetGroup(group); this.SetProperty(GRAPH_OBJ_PROP_GROUP,0,group); } //--- Chart ID
默认情况下,图表上的每个图形对象都不会记录其变更历史。 若要开始执行此操作,需调用方法设置允许记录变更历史的标志。 图形对象分组包括图表上的各种图形对象,它们组合成一个分组,可用于选择它们,来执行必要的操作。
添加处理对象变更历史记录的方法:
//--- Re-write all graphical object properties void PropertiesRefresh(void); //--- Check object property changes void PropertiesCheckChanged(void); //--- Copy the current data to the previous one void PropertiesCopyToPrevData(void); //--- Return (1) the number of property changes in history specified (2) by the property index, (3) the last and (4) the first changed object int HistoryChangesTotal(void) { return this.History().TotalChanges(); } CChangedProps *GetHistoryChangedProps(const string source,const int index) { return this.History().GetChangedPropsObj(source,index); } CChangedProps *GetHistoryChangedPropsLast(const string source) { return this.History().GetChangedPropsObj(source,this.HistoryChangesTotal()-1); } CChangedProps *GetHistoryChangedPropsFirst(const string source) { return this.History().GetChangedPropsObj(source,0); } //--- Using the specified index in the list of change history objects, return //--- the specified value of (1) integer, (2) real and (3) string property long HistoryChangedObjGetLong(const int time_index,const ENUM_GRAPH_OBJ_PROP_INTEGER prop,const int prop_index) { CChangedProps *obj=this.GetHistoryChangedProps(DFUN,time_index); return(obj!=NULL ? obj.GetLong(prop,prop_index) : 0); } double HistoryChangedObjGetDouble(const int time_index,const ENUM_GRAPH_OBJ_PROP_DOUBLE prop,const int prop_index) { CChangedProps *obj=this.GetHistoryChangedProps(DFUN,time_index); return(obj!=NULL ? obj.GetDouble(prop,prop_index) : 0); } string HistoryChangedObjGetString(const int time_index,const ENUM_GRAPH_OBJ_PROP_STRING prop,const int prop_index) { CChangedProps *obj=this.GetHistoryChangedProps(DFUN,time_index); return(obj!=NULL ? obj.GetString(prop,prop_index) : "ERROR"); } //--- Return (1) a symbol, (2) symbol's Digits and (3) the time of changing the change history object string HistoryChangedObjSymbol(const int time_index) { CChangedProps *obj=this.GetHistoryChangedProps(DFUN,time_index); return(obj!=NULL ? obj.Symbol() : "ERROR"); } int HistoryChangedObjDigits(const int time_index) { CChangedProps *obj=this.GetHistoryChangedProps(DFUN,time_index); return(obj!=NULL ? obj.Digits() : 0); } long HistoryChangedObjTimeChanged(const int time_index) { CChangedProps *obj=this.GetHistoryChangedProps(DFUN,time_index); return(obj!=NULL ? obj.TimeChanged() : 0); } string HistoryChangedObjTimeChangedToString(const int time_index) { CChangedProps *obj=this.GetHistoryChangedProps(DFUN,time_index); return(obj!=NULL ? obj.TimeChangedToString() : "ERROR"); } //--- Set object parameters from the specified history snapshot bool SetPropertiesFromHistory(const int time_index) { CChangedProps *obj=this.GetHistoryChangedProps(DFUN,time_index); if(obj==NULL) return false; int begin=0, end=GRAPH_OBJ_PROP_INTEGER_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_INTEGER prop=(ENUM_GRAPH_OBJ_PROP_INTEGER)i; for(int j=0;j<this.Prop.CurrSize(prop);j++) if(this.GetProperty(prop,j)!=obj.GetLong(prop,j)) this.SetHistoryINT(prop,obj.GetLong(prop,j),j); } begin=end; end+=GRAPH_OBJ_PROP_DOUBLE_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_DOUBLE prop=(ENUM_GRAPH_OBJ_PROP_DOUBLE)i; for(int j=0;j<this.Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=obj.GetDouble(prop,j)) this.SetHistoryDBL(prop,obj.GetDouble(prop,j),j); } } begin=end; end+=GRAPH_OBJ_PROP_STRING_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_STRING prop=(ENUM_GRAPH_OBJ_PROP_STRING)i; for(int j=0;j<this.Prop.CurrSize(prop);j++) if(this.GetProperty(prop,j)!=obj.GetString(prop,j)) this.SetHistorySTR(prop,obj.GetString(prop,j),j); } return true; }
几乎所有方法都调用图形对象变更历史类的同名方法,并返回结果。
从指定的历史快照里设置图形对象属性的方法,通过索引接收对象,并在三重循环中调用 SetHistoryINT(),SetHistoryDBL() 和 SetHistorySTR() 方法(如下所述),将历史快照对象的所有属性设置到图形对象。
将方法添加到类的私密部分:
private: //--- Get and save (1) integer, (2) real and (3) string properties void GetAndSaveINT(void); void GetAndSaveDBL(void); void GetAndSaveSTR(void); //--- Create a new object of the graphical object change history bool CreateNewChangeHistoryObj(const bool first) { bool res=true; if(first) res &=this.History().CreateNewElement(this.Prop.Prev,this.GetMarketWatchTime()); res &=this.History().CreateNewElement(this.Prop.Curr,this.GetMarketWatchTime()); if(!res) CMessage::ToLog(DFUN,MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_SNAPSHOT); return res; } //--- Set (1) integer, (2) real and (3) string property values from the change history void SetHistoryINT(const ENUM_GRAPH_OBJ_PROP_INTEGER prop,const long value,const int modifier); void SetHistoryDBL(const ENUM_GRAPH_OBJ_PROP_DOUBLE prop,const double value,const int modifier); void SetHistorySTR(const ENUM_GRAPH_OBJ_PROP_STRING prop,const string value,const int modifier); //--- Return the time of the last symbol tick long GetSymbolTime(const string symbol) { MqlTick tick; return(::SymbolInfoTick(symbol,tick) ? tick.time_msc : 0); } //--- Return the time of the last Market Watch tick long GetMarketWatchTime(void) { long res=0; for(int i=::SymbolsTotal(true)-1;i>WRONG_VALUE;i--) { const long time=this.GetSymbolTime(::SymbolName(i,true)); if(time>res) res=time; } return res; } }; //+------------------------------------------------------------------+
创建图形对象变更历史新对象的方法传递初次图形对象变更的标志。
如果设置了标志,则这是第一次变更。 首先,我们需要保存历史记录中以前的图形对象状态(在属性变更之前)。 接下来,将当前对象状态写入历史记录。 如果未设置任何标志,则在变更历史记录中保存当前对象状态:
//--- Create a new object of the graphical object change history bool CreateNewChangeHistoryObj(const bool first) { bool res=true; if(first) res &=this.History().CreateNewElement(this.Prop.Prev,this.GetMarketWatchTime()); res &=this.History().CreateNewElement(this.Prop.Curr,this.GetMarketWatchTime()); if(!res) CMessage::ToLog(DFUN,MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_SNAPSHOT); return res; }
把调用方法的结果添加到生成的 res 变量中,且仅当任何被调用方法返回 false 时才等于 false。 结果就是,返回变量值。
返回上次市场观察即时报价时间的方法,迭代市场观察窗口中的所有品种,以毫秒为单位读取当前时间,并比较每个品种的时间,从而返回最新时间:
//--- Return the time of the last Market Watch tick long GetMarketWatchTime(void) { long res=0; for(int i=::SymbolsTotal(true)-1;i>WRONG_VALUE;i--) { const long time=this.GetSymbolTime(::SymbolName(i,true)); if(time>res) res=time; } return res; }
在类的受保护参数化构造函数中,传递图形对象种类(替代分组),并为对象设置所有新属性:
//+------------------------------------------------------------------+ //| Protected parametric constructor | //+------------------------------------------------------------------+ CGStdGraphObj::CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_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(GRAPH_ELEMENT_TYPE_STANDARD); 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_NUM,0,0); // Object index in the list this.SetProperty(GRAPH_OBJ_PROP_CHANGE_HISTORY,0,false); // Flag of storing the change history< //--- 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(); } //+-------------------------------------------------------------------+
返回对象整数型属性描述的方法将接收新对象属性的描述 :
//+------------------------------------------------------------------+ //| 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_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) : ": "+(string)this.GetProperty(property,0) ) : 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) ) : "" ); } //+------------------------------------------------------------------+
在检查对象属性变更的方法中,添加创建图形对象变改历史新对象的代码模块,前提是设置了允许记录历史变更的标志:
//+------------------------------------------------------------------+ //| Check object property changes | //+------------------------------------------------------------------+ void CGStdGraphObj::PropertiesCheckChanged(void) { CGBaseObj::ClearEventsList(); bool changed=false; int begin=0, end=GRAPH_OBJ_PROP_INTEGER_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_INTEGER prop=(ENUM_GRAPH_OBJ_PROP_INTEGER)i; if(!this.SupportProperty(prop)) continue; for(int j=0;j<Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j)) { changed=true; this.CreateAndAddNewEvent(GRAPH_OBJ_EVENT_CHANGE,this.ChartID(),prop,this.Name()); } } } begin=end; end+=GRAPH_OBJ_PROP_DOUBLE_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_DOUBLE prop=(ENUM_GRAPH_OBJ_PROP_DOUBLE)i; if(!this.SupportProperty(prop)) continue; for(int j=0;j<Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j)) { changed=true; this.CreateAndAddNewEvent(GRAPH_OBJ_EVENT_CHANGE,this.ChartID(),prop,this.Name()); } } } begin=end; end+=GRAPH_OBJ_PROP_STRING_TOTAL; for(int i=begin; i<end; i++) { ENUM_GRAPH_OBJ_PROP_STRING prop=(ENUM_GRAPH_OBJ_PROP_STRING)i; if(!this.SupportProperty(prop)) continue; for(int j=0;j<Prop.CurrSize(prop);j++) { if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j) && prop!=GRAPH_OBJ_PROP_NAME) { changed=true; this.CreateAndAddNewEvent(GRAPH_OBJ_EVENT_CHANGE,this.ChartID(),prop,this.Name()); } } } if(changed) { for(int i=0;i<this.m_list_events.Total();i++) { CGBaseEvent *event=this.m_list_events.At(i); if(event==NULL) continue; ::EventChartCustom(::ChartID(),event.ID(),event.Lparam(),event.Dparam(),event.Sparam()); } if(this.AllowChangeHistory()) { int total=HistoryChangesTotal(); if(this.CreateNewChangeHistoryObj(total<1)) ::Print ( DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_SUCCESS_CREATE_SNAPSHOT)," #",(total==0 ? "0-1" : (string)total), ": ",this.HistoryChangedObjTimeChangedToString(total-1) ); } this.PropertiesCopyToPrevData(); } } //+------------------------------------------------------------------+
此处,我们得到已变更图形对象的数量,并将它们传递给创建对象属性新快照对象的方法,该方法的形式为 bool 标志(如果 'total' 小于 1,传递的值为 true,这意味着这是图形对象的首次变更)。 如果创建了对象,并将其添加到变更列表中,则在日志中一同显示相应的消息与变改索引。 如果这是首次变更,则消息包含 “0-1”,这意味着同时创建了两个对象(0 — 变更其属性前的图形对象状态,1 — 对象当前状态)。
从图形对象的变更历史记录中设置整数型、实数型和字符串型属性值的方法:
//+------------------------------------------------------------------+ //| Set integer property values from the change history | //| for the graphical object | //+------------------------------------------------------------------+ void CGStdGraphObj::SetHistoryINT(const ENUM_GRAPH_OBJ_PROP_INTEGER prop,const long value,const int modifier) { switch(prop) { case GRAPH_OBJ_PROP_TIMEFRAMES : this.SetVisibleOnTimeframes((int)value,false); break; // Object visibility on timeframes case GRAPH_OBJ_PROP_BACK : this.SetFlagBack(value,false); break; // Background object case GRAPH_OBJ_PROP_ZORDER : this.SetZorder(value,false); break; // Priority of a graphical object for receiving the event of clicking on a chart case GRAPH_OBJ_PROP_HIDDEN : this.SetFlagHidden(value,false); break; // Disable displaying the name of a graphical object in the terminal object list case GRAPH_OBJ_PROP_SELECTED : this.SetFlagSelected(value,false); break; // Object selection case GRAPH_OBJ_PROP_SELECTABLE : this.SetFlagSelectable(value,false); break; // Object availability case GRAPH_OBJ_PROP_TIME : this.SetTime(value,modifier); break; // Time coordinate case GRAPH_OBJ_PROP_COLOR : this.SetColor((color)value); break; // Color case GRAPH_OBJ_PROP_STYLE : this.SetStyle((ENUM_LINE_STYLE)value); break; // Style case GRAPH_OBJ_PROP_WIDTH : this.SetWidth((int)value); break; // Line width case GRAPH_OBJ_PROP_FILL : this.SetFlagFill(value); break; // Filling an object with color case GRAPH_OBJ_PROP_READONLY : this.SetFlagReadOnly(value); break; // Ability to edit text in the Edit object case GRAPH_OBJ_PROP_LEVELS : this.SetLevels((int)value); break; // Number of levels case GRAPH_OBJ_PROP_LEVELCOLOR : this.SetLevelColor((color)value,modifier); break; // Level line color case GRAPH_OBJ_PROP_LEVELSTYLE : this.SetLevelStyle((ENUM_LINE_STYLE)value,modifier); break; // Level line style case GRAPH_OBJ_PROP_LEVELWIDTH : this.SetLevelWidth((int)value,modifier); break; // Level line width case GRAPH_OBJ_PROP_ALIGN : this.SetAlign((ENUM_ALIGN_MODE)value); break; // Horizontal text alignment in the Edit object (OBJ_EDIT) case GRAPH_OBJ_PROP_FONTSIZE : this.SetFontSize((int)value); break; // Font size case GRAPH_OBJ_PROP_RAY_LEFT : this.SetFlagRayLeft(value); break; // Ray goes to the left case GRAPH_OBJ_PROP_RAY_RIGHT : this.SetFlagRayRight(value); break; // Ray goes to the right case GRAPH_OBJ_PROP_RAY : this.SetFlagRay(value); break; // Vertical line goes through all windows of a chart case GRAPH_OBJ_PROP_ELLIPSE : this.SetFlagEllipse(value); break; // Display the full ellipse of the Fibonacci Arc object case GRAPH_OBJ_PROP_ARROWCODE : this.SetArrowCode((uchar)value); break; // Arrow code for the Arrow object case GRAPH_OBJ_PROP_ANCHOR : this.SetAnchor((int)value); break; // Position of the binding point of the graphical object case GRAPH_OBJ_PROP_XDISTANCE : this.SetXDistance((int)value); break; // Distance from the base corner along the X axis in pixels case GRAPH_OBJ_PROP_YDISTANCE : this.SetYDistance((int)value); break; // Distance from the base corner along the Y axis in pixels case GRAPH_OBJ_PROP_DIRECTION : this.SetDirection((ENUM_GANN_DIRECTION)value); break; // Gann object trend case GRAPH_OBJ_PROP_DEGREE : this.SetDegree((ENUM_ELLIOT_WAVE_DEGREE)value); break; // Elliott wave markup level case GRAPH_OBJ_PROP_DRAWLINES : this.SetFlagDrawLines(value); break; // Display lines for Elliott wave markup case GRAPH_OBJ_PROP_STATE : this.SetFlagState(value); break; // Button state (pressed/released) case GRAPH_OBJ_PROP_CHART_OBJ_CHART_ID : this.SetChartObjChartID(value); break; // Chart object ID (OBJ_CHART) case GRAPH_OBJ_PROP_CHART_OBJ_PERIOD : this.SetChartObjPeriod((ENUM_TIMEFRAMES)value); break; // Chart object period case GRAPH_OBJ_PROP_CHART_OBJ_DATE_SCALE : this.SetChartObjChartScale((int)value); break; // Time scale display flag for the Chart object case GRAPH_OBJ_PROP_CHART_OBJ_PRICE_SCALE : this.SetFlagChartObjPriceScale(value); break; // Price scale display flag for the Chart object case GRAPH_OBJ_PROP_CHART_OBJ_CHART_SCALE : this.SetFlagChartObjDateScale(value); break; // Chart object scale case GRAPH_OBJ_PROP_XSIZE : this.SetXSize((int)value); break; // Object distance along the X axis in pixels case GRAPH_OBJ_PROP_YSIZE : this.SetYSize((int)value); break; // Object height along the Y axis in pixels case GRAPH_OBJ_PROP_XOFFSET : this.SetXOffset((int)value); break; // X coordinate of the upper-left corner of the visibility area case GRAPH_OBJ_PROP_YOFFSET : this.SetYOffset((int)value); break; // Y coordinate of the upper-left corner of the visibility area case GRAPH_OBJ_PROP_BGCOLOR : this.SetBGColor((color)value); break; // Background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL case GRAPH_OBJ_PROP_CORNER : this.SetCorner((ENUM_BASE_CORNER)value); break; // Chart corner for binding a graphical object case GRAPH_OBJ_PROP_BORDER_TYPE : this.SetBorderType((ENUM_BORDER_TYPE)value); break; // Border type for "Rectangle border" case GRAPH_OBJ_PROP_BORDER_COLOR : this.SetBorderColor((color)value); break; // Border color for the OBJ_EDIT and OBJ_BUTTON objects case GRAPH_OBJ_PROP_ID : // Object ID case GRAPH_OBJ_PROP_TYPE : // Graphical object type (ENUM_OBJECT) case GRAPH_OBJ_PROP_ELEMENT_TYPE : // Graphical element type (ENUM_GRAPH_ELEMENT_TYPE) case GRAPH_OBJ_PROP_SPECIES : // Graphical object species (ENUM_GRAPH_OBJ_SPECIES) case GRAPH_OBJ_PROP_GROUP : // Graphical object group case GRAPH_OBJ_PROP_BELONG : // Graphical object affiliation case GRAPH_OBJ_PROP_CHART_ID : // Chart ID case GRAPH_OBJ_PROP_WND_NUM : // Chart subwindow index case GRAPH_OBJ_PROP_NUM : // Object index in the list case GRAPH_OBJ_PROP_CHANGE_HISTORY : // Flag of storing the change history case GRAPH_OBJ_PROP_CREATETIME : // Object creation time default : break; } } //+------------------------------------------------------------------+ //| Set real property values from the change history | //| for the graphical object | //+------------------------------------------------------------------+ void CGStdGraphObj::SetHistoryDBL(const ENUM_GRAPH_OBJ_PROP_DOUBLE prop,const double value,const int modifier) { switch(prop) { case GRAPH_OBJ_PROP_PRICE : this.SetPrice(value,modifier); break; // Price coordinate case GRAPH_OBJ_PROP_LEVELVALUE : this.SetLevelValue(value,modifier); break; // Level value case GRAPH_OBJ_PROP_SCALE : this.SetScale(value); break; // Scale (property of Gann objects and Fibonacci Arcs objects) case GRAPH_OBJ_PROP_ANGLE : this.SetAngle(value); break; // Angle case GRAPH_OBJ_PROP_DEVIATION : this.SetDeviation(value); break; // Deviation of the standard deviation channel default: break; } } //+------------------------------------------------------------------+ //| Set string property values from the change history | //| for the graphical object | //+------------------------------------------------------------------+ void CGStdGraphObj::SetHistorySTR(const ENUM_GRAPH_OBJ_PROP_STRING prop,const string value,const int modifier) { switch(prop) { case GRAPH_OBJ_PROP_TEXT : this.SetText(value); break; // Object description (the text contained in the object) case GRAPH_OBJ_PROP_TOOLTIP : this.SetTooltip(value); break; // Tooltip text case GRAPH_OBJ_PROP_LEVELTEXT : this.SetLevelText(value,modifier); break; // Level description case GRAPH_OBJ_PROP_FONT : this.SetFont(value); break; // Font case GRAPH_OBJ_PROP_BMPFILE : this.SetBMPFile(value,modifier); break; // BMP file name for the "Bitmap Level" object case GRAPH_OBJ_PROP_CHART_OBJ_SYMBOL : this.SetChartObjSymbol(value); break; // Chart object symbol case GRAPH_OBJ_PROP_NAME : // Object name default : break; } } //+------------------------------------------------------------------+
此处,根据传递给方法的属性,在 “switch” 操作符中选择用于设置类对象和图形对象中的对象属性值的相应方法。 属性变更历史对象不需要的属性没有对应的 case 处理程序,因此代码执行直达 default 操作符,并于break 操作符处结束。
在图形元素集合类 \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh 中,添加按图表 ID 和分组返回对象列表的方法:
//--- Return (1) the last removed graphical object and (2) the array size of graphical object properties CGStdGraphObj *GetLastDeletedGraphObj(void) const { return this.m_list_deleted_obj.At(this.m_list_deleted_obj.Total()-1); } int GetSizeProperty(const string name,const long chart_id,const int prop) { CGStdGraphObj *obj=this.GetStdGraphObject(name,chart_id); return(obj!=NULL ? obj.Properties().CurrSize(prop) : 0); } //--- Return the list of objects by chart ID and group CArrayObj *GetListStdGraphObjByGroup(const long chart_id,const int group) { CArrayObj *list=GetList(GRAPH_OBJ_PROP_CHART_ID,0,chart_id,EQUAL); return CSelect::ByGraphicStdObjectProperty(list,GRAPH_OBJ_PROP_GROUP,0,group,EQUAL); } //--- Constructor
方法按照图表 ID 接收所有图形对象的列表,从获取的列表中返回含有指定分组值的对象列表。
在我们的程序中运用这种方法,我们可以得到图形对象的列表,并为它们指定一个分组,从而能以我们需要的方式处理这些对象。
为了在基于函数库的程序中获取整个变更历史数据,我们需要在 \MQL5\Include\DoEasy\Engine.mqh 中的 CEngine 函数库主对象中进行修改 。
添加返回现有图形对象列表的方法,和按图表名称和 ID 返回标准图形对象对象类指针的方法:
//--- Return the (1) collection of graphical objects, the list of (2) existing and (3) removed graphical objects CGraphElementsCollection *GetGraphicObjCollection(void) { return &this.m_graph_objects; } CArrayObj *GetListStdGraphObj(void) { return this.m_graph_objects.GetListGraphObj(); } CArrayObj *GetListDeletedObj(void) { return this.m_graph_objects.GetListDeletedObj(); } //--- Return (1) the number of removed graphical objects and (2) the size of the property array int TotalDeletedGraphObjects(void) { return this.GetListDeletedObj().Total(); } int GraphGetSizeProperty(const string name,const long chart_id,const int prop) { return this.m_graph_objects.GetSizeProperty(name,chart_id,prop); } //--- 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) { return this.m_graph_objects.GetStdGraphObject(name,chart_id); } //--- Fill in the array with IDs of the charts opened in the terminal
这些方法返回调用图形元素集合类的同名方法的结果。
这些都是测试处理图形对象变更历史所必需的函数库类的修改和改进。
测试
为了执行测试,我们借助上一篇文章中的 EA,并将其保存到 \MQL5\Experts\TestDoEasy\Part92\,命名为 TestDoEasyPart92.mq5。
要为图表上每个新创建的图形对象设置允许保存变更历史的标志,并创建分组 1。 因此,把图表中的所有图形对象都归类到一个分组,且允许它们写入变更历史。 接下来,更改每个图形对象。 所有更改都将写入其记忆类。
设置查看变更历史记录的关键字。
- ">"("." 无平移)将对象变更列表中的索引按其增加的方向平移 1 步,
- "<"("," 无平移)将对象变更列表中的索引按其减少的方向平移 1,
- "/" 将对象变更列表中的索引平移到最开始处 — 图形对象属性对象将以其首次变更之前的初始值一起存储在那里。
通过按键,我们将看到图形对象在每次变更时如何接收其所有属性。
针对指定按钮设置宏替换:
//+------------------------------------------------------------------+ //| TestDoEasyPart92.mq5 | //| 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" //--- includes #include <DoEasy\Engine.mqh> //--- defines #define FORMS_TOTAL (4) // Number of created forms #define START_X (4) // Initial X coordinate of the shape #define START_Y (4) // Initial Y coordinate of the shape #define KEY_LEFT (188) // Left #define KEY_RIGHT (190) // Right #define KEY_ORIGIN (191) // Initial properties //--- input parameters sinput bool InpMovable = true; // Movable forms flag sinput ENUM_INPUT_YES_NO InpUseColorBG = INPUT_YES; // Use chart background color to calculate shadow color sinput color InpColorForm3 = clrCadetBlue; // Third form shadow color (if not background color) //--- global variables CEngine engine; CArrayObj list_forms; color array_clr[]; //+------------------------------------------------------------------+
在事件处理程序中,添加处理击键的代码模块。 在处理图形对象创建事件的块中,添加允许保存更改历史记录的标志和分组 1:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- If working in the tester, exit if(MQLInfoInteger(MQL_TESTER)) return; //--- If the mouse is moved /* if(id==CHARTEVENT_MOUSE_MOVE) { CForm *form=NULL; datetime time=0; double price=0; int wnd=0; //--- If Ctrl is not pressed, if(!IsCtrlKeyPressed()) { //--- clear the list of created form objects, allow scrolling a chart with the mouse and show the context menu list_forms.Clear(); ChartSetInteger(ChartID(),CHART_MOUSE_SCROLL,true); ChartSetInteger(ChartID(),CHART_CONTEXT_MENU,true); return; } //--- If X and Y chart coordinates are successfully converted into time and price, if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- get the bar index the cursor is hovered over int index=iBarShift(Symbol(),PERIOD_CURRENT,time); if(index==WRONG_VALUE) return; //--- Get the bar index by index CBar *bar=engine.SeriesGetBar(Symbol(),Period(),index); if(bar==NULL) return; //--- Convert the coordinates of a chart from the time/price representation of the bar object to the X and Y coordinates int x=(int)lparam,y=(int)dparam; if(!ChartTimePriceToXY(ChartID(),0,bar.Time(),(bar.Open()+bar.Close())/2.0,x,y)) return; //--- Disable moving a chart with the mouse and showing the context menu ChartSetInteger(ChartID(),CHART_MOUSE_SCROLL,false); ChartSetInteger(ChartID(),CHART_CONTEXT_MENU,false); //--- Create the form object name and hide all objects except one having such a name string name="FormBar_"+(string)index; HideFormAllExceptOne(name); //--- If the form object with such a name does not exist yet, if(!IsPresentForm(name)) { //--- create a new form object form=bar.CreateForm(index,name,x,y,114,16); if(form==NULL) return; //--- Set activity and unmoveability flags for the form form.SetActive(true); form.SetMovable(false); //--- Set the opacity of 200 form.SetOpacity(200); //--- The form background color is set as the first color from the color array form.SetColorBackground(array_clr[0]); //--- Form outlining frame color form.SetColorFrame(C'47,70,59'); //--- Draw the shadow drawing flag form.SetShadow(true); //--- Calculate the shadow color as the chart background color converted to the monochrome one color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100); //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units //--- Otherwise, use the color specified in the settings for drawing the shadow color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3); //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes //--- Set the shadow opacity to 200, while the blur radius is equal to 4 form.DrawShadow(2,2,clr,200,3); //--- Fill the form background with a vertical gradient form.Erase(array_clr,form.Opacity()); //--- Draw an outlining rectangle at the edges of the form form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity()); //--- If failed to add the form object to the list, remove the form and exit the handler if(!list_forms.Add(form)) { delete form; return; } //--- Capture the form appearance form.Done(); } //--- If the form object exists, if(form!=NULL) { //--- draw a text with the bar type description on it and show the form. The description corresponds to the mouse cursor position form.TextOnBG(0,bar.BodyTypeDescription(),form.Width()/2,form.Height()/2-1,FRAME_ANCHOR_CENTER,C'7,28,21'); form.Show(); } //--- Re-draw the chart ChartRedraw(); } } */ //--- If a key is pressed if(id==CHARTEVENT_KEYDOWN) { //---Declare the index of the current graphical object change history object static int index=0; //--- Get the list of all graphical objects with the specified group index (1) CArrayObj *list=engine.GetListStdGraphObj(); list=CSelect::ByGraphicStdObjectProperty(list,GRAPH_OBJ_PROP_GROUP,0,1,EQUAL); if(list==NULL || list.Total()==0) return; //--- If "/" is pressed if(lparam==KEY_ORIGIN) { //--- Set the index 0 in the list of the graphical object change history object index=0; //--- In the loop by the number of group 1 objects on the chart for(int i=0;i<list.Total();i++) { //--- Get the next object from the list and set the initial properties from the change history to it CGStdGraphObj *obj=list.At(i); if(obj==NULL) continue; obj.SetPropertiesFromHistory(index); } } //--- If "." is pressed if(lparam==KEY_RIGHT) { //--- Declare the variables to search for the maximum number of changes of all group 1 graphical objects int change_max=0, changes_total=0; //--- Increase the object index in the list of the graphical object change history index++; //--- In the loop by the number of group 1 objects on the chart for(int i=0;i<list.Total();i++) { //--- Get the next object from the list CGStdGraphObj *obj=list.At(i); if(obj==NULL) continue; //--- Calculate the maximum number of changes of all group 1 graphical objects changes_total=obj.HistoryChangesTotal(); if(changes_total>change_max) change_max=changes_total; //--- Set the properties (by 'index' from the list) from the change history obj.SetPropertiesFromHistory(index>obj.HistoryChangesTotal()-1 ? obj.HistoryChangesTotal()-1 : index); } //--- If the change history object index exceeds the maximum number of changes of all objects, //--- set the index equal to the maximum amount of changes of all graphical objects if(index>change_max-1) index=change_max-1; } //--- If "," is pressed if(lparam==KEY_LEFT) { //--- Decrease the object index in the list of the graphical object change history index--; //--- If the index is less than zero, set it to 0 if(index<0) index=0; //--- In the loop by the number of group 1 objects on the chart for(int i=0;i<list.Total();i++) { //--- Get the next object from the list CGStdGraphObj *obj=list.At(i); if(obj==NULL) continue; //--- Set the properties (by 'index' from the list) from the change history obj.SetPropertiesFromHistory(index); } } //--- Re-draw the chart for displaying changes in graphical objects ChartRedraw(); } if(id==CHARTEVENT_CLICK) { if(!IsCtrlKeyPressed()) return; datetime time=0; double price=0; int sw=0; if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,sw,time,price)) { long array[]; engine.GraphGetArrayChartsID(array); for(int i=0;i<ArraySize(array);i++) engine.CreateLineVertical(array[i],"LineVertical",0,time); } } engine.GetGraphicObjCollection().OnChartEvent(id,lparam,dparam,sparam); //--- Handle standard graphical object events ushort idx=ushort(id-CHARTEVENT_CUSTOM); CGStdGraphObj *obj=NULL; if(idx>GRAPH_OBJ_EVENT_NO_EVENT && idx<GRAPH_OBJ_EVENTS_NEXT_CODE) { CChartObjectsControl *chart_ctrl=NULL; int end=0; string evn=""; //--- Depending on the event type, display an appropriate message in the journal switch(idx) { //--- Graphical object creation event case GRAPH_OBJ_EVENT_CREATE : //--- Display the message about creating a new graphical object Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_CREATE),":"); //--- Get the pointer to the object by chart name and ID passed to sparam and lparam, respectively //--- display the short description of a newly created object to the journal and set the flag of storing the change history obj=engine.GraphGetStdGraphObject(sparam,lparam); if(obj!=NULL) { obj.PrintShort(); obj.SetAllowChangeMemory(true); obj.SetGroup(1); } break; //--- Event of changing the graphical object property case GRAPH_OBJ_EVENT_CHANGE : //--- Display the message about changing the graphical object property Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_CHANGE),":"); //--- Get the pointer to the object by chart name and ID passed to sparam and lparam, respectively obj=engine.GetGraphicObjCollection().GetStdGraphObject(sparam,lparam); if(obj!=NULL) { //--- Display a short description of the changed object in the journal obj.PrintShort(); //--- calculate the code of the changed property passed to dparam and get the property description if(dparam<GRAPH_OBJ_PROP_INTEGER_TOTAL) evn=obj.GetPropertyDescription((ENUM_GRAPH_OBJ_PROP_INTEGER)dparam); else if(dparam<GRAPH_OBJ_PROP_INTEGER_TOTAL+GRAPH_OBJ_PROP_DOUBLE_TOTAL) evn=obj.GetPropertyDescription((ENUM_GRAPH_OBJ_PROP_DOUBLE)dparam); else evn=obj.GetPropertyDescription((ENUM_GRAPH_OBJ_PROP_STRING)dparam); //--- Display the description of the graphical object's changed property in the journal Print(DFUN,evn); } break; //--- Graphical object renaming event case GRAPH_OBJ_EVENT_RENAME : //--- Display the message about renaming the graphical object Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_RENAME)); //--- Get the pointer to the object by chart name and ID passed to sparam and lparam, respectively obj=engine.GetGraphicObjCollection().GetStdGraphObject(sparam,lparam); if(obj!=NULL) { //--- Display the previous and new object name, as well as its entire renaming history, in the journal Print(DFUN,obj.GetProperty(GRAPH_OBJ_PROP_NAME,obj.Properties().CurrSize(GRAPH_OBJ_PROP_NAME)-1)," >>> ",obj.GetProperty(GRAPH_OBJ_PROP_NAME,0)); obj.PrintRenameHistory(); } break; //--- Graphical object deletion event case GRAPH_OBJ_EVENT_DELETE : //--- Display the message about removing the graphical object Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_DELETE),":"); //--- Get the pointer to the removed object by chart name and ID passed to sparam and lparam, respectively //--- and display a short description of the removed object in the journal obj=engine.GetGraphicObjCollection().GetStdDelGraphObject(sparam,lparam); if(obj!=NULL) { obj.PrintShort(); } break; //--- Event of removing the graphical object together with the chart window case GRAPH_OBJ_EVENT_DEL_CHART: //--- Display the message about removing graphical objects together with the chart window, whose ID and symbol are passed to lparam and sparam Print(DFUN,CMessage::Text(MSG_GRAPH_OBJ_EVN_GRAPH_OBJ_DEL_CHART),": #",lparam,", ",sparam,":"); //--- Calculate the end value for the loop by the list of removed graphical objects end=engine.TotalDeletedGraphObjects()-(int)dparam; if(end<0) end=0; //--- In the loop from the end of the removed graphical objects list up to the value calculated in the 'end' variable, for(int i=engine.TotalDeletedGraphObjects()-1;i>=end;i--) { //--- get the next removed graphical object from the list obj=engine.GetListDeletedObj().At(i); if(obj==NULL) continue; //--- and display its brief description in the journal obj.PrintShort(); } break; //--- default: break; } } } //+------------------------------------------------------------------+
处理击键的整个逻辑在代码的注释中均有描述。
编译 EA,并在图表上启动它。 添加图形对象,修改其属性,然后按 “/” — 对象会提取首次修改之前的数值。 按下 "." 和 "," — 对象将采用与属性变更历史记录列表相对应的属性和外观:
下一步是什么?
在下一篇文章中,我将着手开发复合图形对象。
*该系列的前几篇文章:
DoEasy 函数库中的图形(第八十九部分):标准图形对象编程。 基本功能
DoEasy 函数库中的图形(第九十部分):标准图形对象事件。 基本功能
DoEasy 函数库中的图形(第九十一部分):标准图形对象事件。 对象名称变更历史记录
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/10237
![从市场里选择智能交易系统的正确途径](https://c.mql5.com/2/44/mql5_avatar_adviser_choose.png)
![优化结果的可视化评估](https://c.mql5.com/2/44/visual-estimation.png)
![交易中的数学:夏普(Sharpe)和索蒂诺(Sortino)比率](https://c.mql5.com/2/45/math_trading.png)