English Русский Español Deutsch 日本語 Português
图形界面 XI: 集成标准图形库 (统合构建 16)

图形界面 XI: 集成标准图形库 (统合构建 16)

MetaTrader 5示例 | 18 十月 2017, 15:00
3 632 2
Anatoli Kazharski
Anatoli Kazharski

内容


概述

首篇文章 图形界面 I: 函数库结构的准备 (第 1 章) 详细解释了这个函数库的用处。您可在每章结尾处找到相关文章列表的链接。在那里, 您还可以下载当前开发阶段的完整版本函数库。文件必须位于与存档中相同的目录下。

系列第九部分的第二章, 图形界面 IX: 进度条和线图表控件 (第 2 章), 展示了如何将一个创建折线图的类集成到 函数库。那是一个临时解决方案, 因为函数库的这部分能力严重不足。创建科学图表 (CGraphic 类) 的新版本图形库最近已发布了。这个类的一些函数说明已发表在 可视化!类似于 R 语言 "PLOT (绘图)" 的 MQL5 图形库。创建图形界面的开发中函数库在本次更新中将引入创建图表的新版本控件。不同类型数据的可视化现在更加容易了。


函数库规划的变动

早前, 开发中函数库曾用过为绘图而设计的 CCanvas 类的副本。由于最近全局重构了函数库的代码, 此副本不再需要, 可将其替换为标准库中的原始版本。相对于重构之前在文章 图形界面 XI: 重构函数库代码 (统合构建 14.1)图形界面 XI: 全新粉饰的控件 (统合构建 14.2) 中提到的版本, 新版体积减少了大约 10% 和近乎 40%。

CGraphic 类现在将用于创建图表, 因此, Objects.mqh 文件中包含 Graphic.mqh 文件。由于 CCanvas 类的文件已经在 Graphic.mqh 包含文件其一之内, 所以对于整个函数库它也可用。

//+------------------------------------------------------------------+
//|                                                      Objects.mqh |
//|                                 版权所有 2015, MetaQuotes 软件公司  |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "Enums.mqh"
#include "Defines.mqh"
#include "Fonts.mqh"
#include "Colors.mqh"
#include <Graphics\Graphic.mqh>
#include <ChartObjects\ChartObjectSubChart.mqh>
...

CLineChart 类已经改名为 CGraph。其内部内容也发生了变化。现在这个类只包含用于管理控件一般属性和状态的方法。 

class CGraph : public CElement
  {
public:
   //--- 图表事件处理程序
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- 移动控件
   virtual void      Moving(const bool only_visible=true);
   //--- 管理
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- 应用最新的变化
   virtual void      Update(const bool redraw=false);
   //---
private:
   //--- 调整大小
   void              Resize(const int width,const int height);
   //--- 更改窗口右边缘的宽度
   virtual void      ChangeWidthByRightWindowSide(void);
   //--- 更改窗口底部边缘的高度
   virtual void      ChangeHeightByBottomWindowSide(void);
  };

图表属性的控制可使用 CGraphic::GetGraphicPointer() 方法, 以便获取指向 CGraphic 类实例的指针:

class CGraph : public CElement
  {
private:
   //--- 用于创建控件的对象
   CGraphic          m_graph;
   //---
public:
   //--- 返回指向图表的指针
   CGraphic         *GetGraphicPointer(void) { return(::GetPointer(m_graph)); }
  };


用于管理图表的坐标轴 (CAxis) 和曲线 (CCurve) 的附加类已经包含在 CGraphic 类中。CColorGenerator 类设计用于生成曲线颜色。所有这些类都包括在 Graphic.mqh 文件所包含的单独文件中:

//+------------------------------------------------------------------+
//|                                                      Graphic.mqh |
//|                            版权所有 2016-2017, MetaQuotes 软件公司  |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "Curve.mqh"
#include "Axis.mqh"
#include "ColorGenerator.mqh"
...

CCanvas 类的文件已包含在 Curve.mqh 文件中, 且从这里它将对于整个函数库可用。

//+------------------------------------------------------------------+
//|                                                        Curve.mqh |
//|                            版权所有 2016-2017, MetaQuotes 软件公司  |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Object.mqh>
#include <Canvas\Canvas.mqh>
...

上述所有文件和类之间的交互联系如下图所示:

 图例. 1. 标准和开发中函数库之间类的交互联系。

图例. 1. 标准和开发中函数库之间类的交互联系。


因此, 标准库中操纵数组和文件的类在已用到它们的应用程序文件和函数里自动可用。本文将进一步展示几个 MQL 测试应用程序, 以便帮助您了解现有的新功能。


测试图表属性的应用程序

第一个 MQL 测试应用程序将实现一个图形界面, 所含控件用于管理 CGraphic 类型图表的某些属性。一个 CTabs 类型的控件位于窗体的顶部。在此情况下, 它是一组四个选项卡。含有两条随机生成数值曲线的图表将位于选项卡的工作区域下方。

第一个选项卡 (背景) 将具有用来管理以下图表属性的控件:

  • 背景颜色。
  • 图表的主要文本 (显示在顶部)。
  • 图表的辅助文本 (显示在底部)。
  • 正文的颜色。
  • 辅助文字的颜色。
  • 正文字号。
  • 辅助文字的字号。

要设置并获取这些属性, CGraphic 类提供了相应的公共方法:

//+------------------------------------------------------------------+
//| 结构 CBackground                                                  |
//| 用法: 二维图形上的背景                                               |
//+------------------------------------------------------------------+
struct CBackground
  {
   uint              clr;
   uint              clr_main;
   uint              clr_sub;
   string            main;
   string            sub;
   int               size_main;
   int               size_sub;
  };
//+------------------------------------------------------------------+
//| 类 CGraphic                                                       |
//| 用法: 绘制二维图形的类                                               |
//+------------------------------------------------------------------+
class CGraphic
  {
protected:
   //--- 图形元素
   CBackground       m_background;           // 背景
   //---
public:
   //--- 获取背景属性
   uint              BackgroundColor(void)       const { return(m_background.clr);       }
   uint              BackgroundMainColor(void)   const { return(m_background.clr_main);  }
   uint              BackgroundSubColor(void)    const { return(m_background.clr_sub);   }
   string            BackgroundMain(void)        const { return(m_background.main);      }
   string            BackgroundSub(void)         const { return(m_background.sub);       }
   int               BackgroundMainSize(void)    const { return(m_background.size_main); }
   int               BackgroundSubSize(void)     const { return(m_background.size_sub);  }
   //--- 设置背景属性
   void              BackgroundColor(const uint clr)      { m_background.clr=clr;        }
   void              BackgroundMainColor(const uint clr)  { m_background.clr_main=clr;   }
   void              BackgroundSubColor(const uint clr)   { m_background.clr_sub=clr;    }
   void              BackgroundMain(const string main)    { m_background.main=main;      }
   void              BackgroundSub(const string sub)      { m_background.sub=sub;        }
   void              BackgroundMainSize(const int size)   { m_background.size_main=size; }
   void              BackgroundSubSize(const int size)    { m_background.size_sub=size;  }
  };

这是它的样子:

 图例. 2. MQL 测试应用程序的第一个选项卡 (背景) 的控件。

图例. 2. MQL 测试应用程序的第一个选项卡 (背景) 的控件。


第二个选项卡 (缩进和历史) 将包含用于设置以下属性的控件:

  • 缩进 (左, 右, 顶, 底)。
  • 图例的宽度。
  • 图例的字号。
  • 图例标记的大小。
  • 图表所有元素的公用缩进。
  • 图表坐标轴标尺标记的大小。 

下面列出的 CGraphic 方法可用于获取和设置这些属性:

//+------------------------------------------------------------------+
//| 结构 CCurveHistory                                                |
//| 用法: 二维图形上的历史曲线                                            |
//+------------------------------------------------------------------+
struct CCurveHistory
  {
   int               name_width;
   int               name_size;
   int               symbol_size;
   int               count_total;
   int               count_points;
   int               count_lines;
   int               count_histogram;
   int               count_custom;
  };
//+------------------------------------------------------------------+
//| 类 CGraphic                                                       |
//| 用法: 绘制二维图形的类                                               |
//+------------------------------------------------------------------+
class CGraphic
  {
protected:
   //--- 图形元素
   CCurveHistory     m_history;              // 历史
   //---
public:
   //--- 获取或是设置缩进
   int               IndentUp(void)               const { return(m_up0);     }
   void              IndentUp(const int up)             { m_up0=up;          }
   int               IndentDown(void)             const { return(m_down0);   }
   void              IndentDown(const int down)         { m_down0=down;      }
   int               IndentLeft(void)             const { return(m_left0);   }
   void              IndentLeft(const int left)         { m_left0=left;      }
   int               IndentRight(void)            const { return(m_right0);  }
   void              IndentRight(const int right)       { m_right0=right;    }
   //--- 获取或是设置空白 
   int               GapSize(void)           const { return(m_gap); }
   void              GapSize(const int size)       { m_gap=size;    }
   //--- 获取或是设置主要标记大小
   int               MajorMarkSize(void)           const { return(m_mark_size); }
   void              MajorMarkSize(const int size)       { m_mark_size=size;    }
   //--- 获取曲线历史属性
   int               HistoryNameWidth(void)            const { return(m_history.name_width);  }
   int               HistoryNameSize(void)             const { return(m_history.name_size);   }
   int               HistorySymbolSize(void)           const { return(m_history.symbol_size); }
   //--- 设置曲线历史属性
   void              HistoryNameWidth(const int width) { m_history.name_width=width; }
   void              HistoryNameSize(const int size)   { m_history.name_size=size;   }
   void              HistorySymbolSize(const int size) { m_history.symbol_size=size; }
  };

这是 MQL 测试应用程序的图形界面的样子:

 图例. 3. MQL 测试应用程序的第二个选项卡 (缩进和历史) 的控件。

图例. 3. MQL 测试应用程序的第二个选项卡 (缩进和历史) 的控件。


第三个选项卡 (网格) 包含用于设置下面列出的网格属性的控件:

  • 网格线的颜色。
  • 坐标轴零线颜色。
  • 网格背景颜色。
  • 在网格节点中绘制圆点。
  • 圆点半径。
  • 圆点颜色。

相应的方法体现在 CGraphic 类中, 以便获取和设置这些属性 (参见下面的代码清单):

//+------------------------------------------------------------------+
//| 结构 CGrid                                                        |
//| 用法: 二维图形上的网格                                               |
//+------------------------------------------------------------------+
struct CGrid
  {
   uint              clr_line;
   uint              clr_background;
   uint              clr_circle;
   uint              clr_axis_line;
   uint              clr_frame;
   int               r_circle;
   bool              has_circle;
  };
//+------------------------------------------------------------------+
//| 类 CGraphic                                                       |
//| 用法: 绘制二维图形的类                                               |
//+------------------------------------------------------------------+
class CGraphic
  {
protected:
   //--- 图形元素
   CGrid             m_grid;                 // 网格
   //---
public:
   //--- 获取网格属性
   uint              GridLineColor(void)        const { return(m_grid.clr_line);       }
   uint              GridAxisLineColor(void)    const { return(m_grid.clr_axis_line);  }
   uint              GridBackgroundColor(void)  const { return(m_grid.clr_background); }
   int               GridCircleRadius(void)     const { return(m_grid.r_circle);       }
   uint              GridCircleColor(void)      const { return(m_grid.clr_circle);     }
   bool              GridHasCircle(void)        const { return(m_grid.has_circle);     }
   //--- 设置网格属性
   void              GridLineColor(const uint clr)        { m_grid.clr_line=clr;       }
   void              GridAxisLineColor(const uint clr)    { m_grid.clr_axis_line=clr;  }
   void              GridBackgroundColor(const uint clr)  { m_grid.clr_background=clr; }
   void              GridCircleRadius(const int r)        { m_grid.r_circle=r;         }
   void              GridCircleColor(const uint clr)      { m_grid.clr_circle=clr;     }
   void              GridHasCircle(const bool has)        { m_grid.has_circle=has;     }
  };

这是最后的样子:

 图例. 4. MQL 测试应用程序的第三个选项卡 (网格) 的控件。

图例. 4. MQL 测试应用程序的第三个选项卡 (网格) 的控件。


用于管理图表坐标轴属性的控件将放置在第四个选项卡 (坐标轴) 上。位于选项卡工作区左侧的单选按钮允许在某个配置中坐标轴之间进行切换。这些按钮与 坐标轴 选项卡的其它控件通过分隔线分离。

以下是可用于修改的属性:

  • 自动缩放。
  • 最小坐标轴数值。
  • 最大坐标轴数值。
  • 坐标轴最小公差值。
  • 坐标轴最大公差值。
  • 坐标轴数字的大小。
  • 坐标轴数字的最大显示长度。
  • 坐标轴名称的字号。
  • 坐标轴的初始步长值。
  • 坐标轴上的数字最大数量。
  • 坐标轴名称。
  • 坐标轴名称的文字颜色。

下面的列表显示了获取和设置上述属性的 CAxis 类方法的名称:

//+------------------------------------------------------------------+
//| 类 CAxis                                                          |
//| 用法: 二维图形上创建坐标轴的类                                         |
//+------------------------------------------------------------------+
class CAxis
  {
private:
   double            m_min;
   double            m_max;
   uint              m_clr;
   string            m_name;
   int               m_name_size;
   int               m_values_size;
   int               m_values_width;
   bool              m_auto_scale;
   double            m_default_step;   // 默认步长的长度
   double            m_max_labels;     // 最大标记数量
   double            m_min_grace;      // 应用于最小数据范围的 "grace" 值
   double            m_max_grace;      // 应用于最大数据范围的 "grace" 值
   //---
public:
                     CAxis(void);
                    ~CAxis(void);
   //--- 属性
   double            Min(void)                  const { return(m_min);  }
   void              Min(const double min)            { m_min=min;      }
   double            Max(void)                  const { return(m_max);  }
   void              Max(const double max)            { m_max=max;      }
   string            Name(void)                 const { return(m_name); }
   void              Name(const string name)          { m_name=name;    }
   //--- 默认属性 
   uint              Color(void)                        const { return(m_clr);            }
   void              Color(const uint clr)                    { m_clr=clr;                }
   bool              AutoScale(void)                    const { return(m_auto_scale);     }
   void              AutoScale(const bool auto)               { m_auto_scale=auto;        }
   int               ValuesSize(void)                   const { return(m_values_size);    }
   void              ValuesSize(const int size)               { m_values_size=size;       }
   int               ValuesWidth(void)                  const { return(m_values_width);   }
   void              ValuesWidth(const int width)             { m_values_width=width;     }
   int               NameSize(void)                     const { return(m_name_size);      }
   void              NameSize(const int size)                 { m_name_size=size;         }
   double            DefaultStep(void)                  const { return(m_default_step);   }
   void              DefaultStep(const double value)          { m_default_step=value;     }
   double            MaxLabels(void)                    const { return(m_max_labels);     }
   void              MaxLabels(const double value)            { m_max_labels=value;       }
   double            MinGrace(void)                     const { return(m_min_grace);      }
   void              MinGrace(const double value)             { m_min_grace=value;        }
   double            MaxGrace(void)                     const { return(m_max_grace);      }
   void              MaxGrace(const double value)             { m_max_grace=value;        }
  };

结果如下所示:

 图例. 5. MQL 测试应用程序的第四个选项卡 (坐标轴) 的控件。

图例. 5. MQL 测试应用程序的第四个选项卡 (坐标轴) 的控件。


文章中列出的测试应用程序可从以下链接进行下载, 以供进一步学习。


测试图表曲线属性的应用程序

已经编写了一个单独的 MQL 应用程序来测试图表上 CGraphic 类型曲线的某些属性。管理图表曲线属性的控件将位于此应用程序窗体的顶部, 在它之下有两个 CGraphic 类型 (CGraph 控件) 的图表。第一个图表将显示随机数据的序列, 第二个将绘制其导数, 它们是基于 动量 指标的公式计算的, 如示例。

此处是用于管理图表曲线属性的控件:

  • 动画 复选框 - 开始数据自动输入到图表。
  • 数组大小 旋转编辑框 – 数据数组中显示在图表上的当前元素数量。
  • 随机 按钮 – 在图表上顺序生成随机数据序列。
  • 周期 旋转编辑框 – 用来计算 动量 指标的变量值。
  • 曲线类型 组合框 – 图表上的曲线类型。
  • 圆点类型 组合框 – 用来在图表上绘制曲线的数据圆点类型。

应用程序的自定义类 (CProgram) 实现了上述控件相关的方法, 并执行以下任务:

  • 设置要在图表上显示的数据数组的大小。
  • 用数据初始化数组。
  • 刷新图表以反映最近的变化。
  • 将一个元素添加到数组的末尾。
  • 删除数组末尾的一个元素。
  • 依据计时器刷新图表。
  • 自动输入新数据的动画图表。

以下是实现这些功能的所有方法的代码清单。下载文章末尾的文件, 以便找到有关这些方法代码的更多细节。

class CProgram : public CWndEvents
  {
protected:
   //--- 用于在图表上输出的数据数组
   double            data1[];
   double            data2[];
   //---
   double            data3[];
   double            data4[];
   //---
private:
   //--- 调整数组的大小
   void              ResizeGraph1Arrays(void);
   void              ResizeGraph2Arrays(void);
   void              ResizeGraph1Arrays(const int new_size);
   void              ResizeGraph2Arrays(const int new_size);
   //--- 数组初始化
   void              InitGraph1Arrays(void);
   void              InitGraph2Arrays(void);
   //--- 数组清零
   void              ZeroGraph1Arrays(void);
   void              ZeroGraph2Arrays(void);
   //--- 在指定的索引处设置随机值
   void              SetGraph1Value(const int index);
   void              SetGraph2Value(const int index);
   //--- 更新图表上的序列
   void              UpdateGraph(void);
   void              UpdateGraph1(void);
   void              UpdateGraph2(void);
   
   //--- 重新计算图表上的序列
   void              RecalculatingSeries(void);
   //--- 添加一个或多个值到数组的末尾
   void              AddValue(void);
   //--- 删除数组末尾的一个值
   void              DeleteValue(void);

   //--- 按计时器刷新图表
   void              UpdateGraphByTimer(void);
   //--- 图表序列动画
   void              AnimateGraphSeries(void);
  };

这是它的样子:

 图例. 6. 用于测试图表曲线属性的应用程序图形界面。

图例. 6. 用于测试图表曲线属性的应用程序图形界面。


文章中列出的测试应用程序可从以下链接进行下载, 以供进一步学习。


动态内摆线图表应用程序

在 John Walkenbach 的一本关于 VBA 编程的 Microsoft Excel 书中, 他为读者提供了带有测试文件的光盘。其中一个文件实现了一个示意图, 其中生成了无限数量的内摆线。 

参考: 维基百科给出以下定义:

一条 内摆线 (来自希腊语 ὑπό — 下边, 低于和 κύκλος — 圆, 圆圈) 是由在较大圆圈内滚动的小圆上的固定点的迹线产生的特殊平面曲线。

John Walkenbach 在他的书中给出的定义:

内摆线 - 由在另一个圆内滚动的圆上的点形成的路径。

让我们在 MQL 中实现类似的应用, 并添加一个用于管理参数的图形界面。我们来看看它是如何工作的细节。

三个参数用于生成一个新的内摆线, 按照指定步长初始化数字序列。然后根据这些序列中的值进行计算, 以获得图表上的点坐标。之后, 将所得结果常规化。

在自定义类中, 我们声明多个数组来计算序列和字段, 并计算平均值和标准偏差。

//+------------------------------------------------------------------+
//|                                                      Program.mqh |
//|                                 版权所有 2017, MetaQuotes 软件公司  |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Math\Stat\Stat.mqh>
#include <EasyAndFastGUI\WndEvents.mqh>
#include <EasyAndFastGUI\TimeCounter.mqh>
//+------------------------------------------------------------------+
//| 创建应用程序的类                                                    |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
protected:
...
   //--- 用于计算的数据数组
   double            a_inc[];
   double            b_inc[];
   double            t_inc[];
   double            x_source[];
   double            y_source[];
   //--- 用于输出到图表的数据数组
   double            x_norm[];
   double            y_norm[];
   //--- 计算平均值和标准差
   double            x_mean;
   double            y_mean;
   double            x_sdev;
   double            y_sdev;
...
  };
//+------------------------------------------------------------------+
//| 构造器                                                             |
//+------------------------------------------------------------------+
CProgram::CProgram(void) : x_mean(0),
                           y_mean(0),
                           x_sdev(0),
                           y_sdev(0)
  {
...
  }

这些值将在 CProgram::InitArrays() 方法里计算。在此, 第一个循环计算初始数据。然后获得平均值和标准偏差, 第二个循环对数据进行常规化。设置数组大小则使用 CProgram::ResizeArrays() 方法。数组大小的值取自应用程序图形界面的文本框控件 (CTextEdit)。

class CProgram : public CWndEvents
  {
private:
   //--- 调整数组的大小
   void              ResizeArrays(void);
   //--- 初始化辅助数组进行计算
   void              InitArrays(void);
  };
//+------------------------------------------------------------------+
//| 调整数组大小                                                       |
//+------------------------------------------------------------------+
void CProgram::ResizeArrays(void)
  {
   int array_size =::ArraySize(x_norm);
   int new_size   =(int)m_array_size.GetValue();
//--- 如果大小没有改变, 离开
   if(array_size==new_size)
      return;
//--- 设置新的大小
   ::ArrayResize(a_inc,new_size);
   ::ArrayResize(b_inc,new_size);
   ::ArrayResize(t_inc,new_size);
   ::ArrayResize(x_source,new_size);
   ::ArrayResize(y_source,new_size);
   ::ArrayResize(x_norm,new_size);
   ::ArrayResize(y_norm,new_size);
  }
//+------------------------------------------------------------------+
//| 数组初始化                                                         |
//+------------------------------------------------------------------+
void CProgram::InitArrays(void)
  {
//--- 调整数组的大小
   ResizeArrays();
//--- 使用公式计算值
   int total=(int)m_array_size.GetValue();
   for(int i=0; i<total; i++)
     {
      if(i<1)
        {
         a_inc[i] =1+(double)m_animate.GetValue();
         b_inc[i] =1+(double)m_animate.GetValue();
         t_inc[i] =1+(double)m_animate.GetValue();
        }
      else
        {
         a_inc[i] =a_inc[i-1]+(double)m_a_inc.GetValue();
         b_inc[i] =b_inc[i-1]+(double)m_b_inc.GetValue();
         t_inc[i] =t_inc[i-1]+(double)m_t_inc.GetValue();
        }
      //---
      double a=a_inc[i];
      double b=b_inc[i];
      double t=t_inc[i];
      //---
      x_source[i] =(a-b)*cos(t)+b*cos((a/b-1)*t);
      y_source[i] =(a-b)*sin(t)+b*sin((a/b-1)*t);
     }
//--- 计算平均值
   x_mean=MathMean(x_source);
   y_mean=MathMean(y_source);
//--- 计算标准偏差
   x_sdev=MathStandardDeviation(x_source);
   y_sdev=MathStandardDeviation(y_source);
//--- 调整以避免除零
   x_sdev =(x_sdev==0)? 1 : x_sdev;
   y_sdev =(y_sdev==0)? 1 : y_sdev;
//--- 常规化数据
   for(int i=0; i<total; i++)
     {
      x_norm[i] =(x_source[i]-x_mean)/x_sdev;
      y_norm[i] =(y_source[i]-y_mean)/y_sdev;
     }
  }

CGraphic 类包含的方法, 允许在已创建的图表工作区域内向坐标轴标尺上添加额外缺口, 线和文本。

在此情况下, CProgram::TextAdd() 方法将在示意图的左上角输出 XY 序列的平均值和标准偏差。CGraphic::ScaleX()CGraphic::ScaleY() 方法用于获取示意图的极值点坐标 (左上角)。它们设计用于将实际图表值变换为像素坐标。此处, X 轴当中的最小值和 Y 轴当中的最大值 作为真实数值。 

class CProgram : public CWndEvents
  {
private:
   //--- 向图表添加文本
   void              TextAdd(void);
  };
//+------------------------------------------------------------------+
//| 向图表添加文本                                                      |
//+------------------------------------------------------------------+
void CProgram::TextAdd(void)
  {
//--- 获取指向图表的指针
   CGraphic *graph=m_graph1.GetGraphicPointer();
//---  
   int  x     =graph.ScaleX(graph.XAxis().Min())+50;
   int  y     =graph.ScaleY(graph.YAxis().Max())+10;
   int  y2    =y+20;
   uint clr   =::ColorToARGB(clrBlack);
   uint align =TA_RIGHT;
//---
   string str[8];
   str[0] ="x mean:";
   str[1] ="y mean:";
   str[2] =::DoubleToString(x_mean,2);
   str[3] =::DoubleToString(y_mean,2);
   str[4] ="x sdev:";
   str[5] ="y sdev:";
   str[6] =::DoubleToString(x_sdev,2);
   str[7] =::DoubleToString(y_sdev,2);
//--- Calculate the coordinates and output the text on the chart
   int l_x=0,l_y=0;
   for(int i=0; i<8; i++)
     {
      if(i<2)
         l_x=x;
      else if(i<6)
         l_x=(i%2==0)? l_x+50 : l_x;
      else
         l_x=(i%2==0)? l_x+60 : l_x;
      //---
      l_y=(i%2==0)? y : y2;
      //---
      graph.TextAdd(l_x,l_y,str[i],clr,align);
     }
  }

在图表上设置所有必要的数据之后, 需要刷新以反映最新的变化。这是通过 CProgram::UpdateSeries() 方法完成的。此处, 它首先检查图表上是否有序列。如果有, 那么它 设置最后计算的数据。此外, 使用图形界面的控件设置曲线的属性。这里, (1) 线的平滑, (2) 点的类型和 (3) 曲线的类型。应注意的是, 只有在所有其它属性和数据已被设置和渲染之后再将文本应用到图表上。在最靠后的地方, 有必要刷新图表以便看到结果。

class CProgram : public CWndEvents
  {
private:
   //--- 在图表上设置并更新序列
   void              UpdateSeries(void);
  };
//+------------------------------------------------------------------+
//| 在图表上设置并更新序列                                               |
//+------------------------------------------------------------------+
void CProgram::UpdateSeries(void)
  {
//--- 获取指向图表的指针
   CGraphic *graph=m_graph1.GetGraphicPointer();
//--- 更新图表的所有序列
   int total=graph.CurvesTotal();
   if(total>0)
     {
      //--- 获取曲线指针
      CCurve *curve=graph.CurveGetByIndex(0);
      //--- 设置数据数组
      curve.Update(x_norm,y_norm);
      //--- 获取曲线属性的值
      ENUM_CURVE_TYPE curve_type =(ENUM_CURVE_TYPE)m_curve_type.GetListViewPointer().SelectedItemIndex();
      ENUM_POINT_TYPE point_type =(ENUM_POINT_TYPE)m_point_type.GetListViewPointer().SelectedItemIndex();
      //--- 设置属性
      curve.LinesSmooth(m_line_smooth.IsPressed());
      curve.PointsType(point_type);
      curve.Type(curve_type);
     }
//--- 应用 
   graph.Redraw(true);
//--- 输出文本
   TextAdd();
//--- 刷新图表
   graph.Update();
  }

CProgram::RecalculatingSeries() 方法用于在单次调用中计算并应用获得的结果:

class CProgram : public CWndEvents
  {
private:
   //--- 重新计算图表上的序列
   void              RecalculatingSeries(void);
  };
//+------------------------------------------------------------------+
//| 重新计算图表上的序列                                                 |
//+------------------------------------------------------------------+
void CProgram::RecalculatingSeries(void)
  {
//--- 计算值并初始化数组
   InitArrays();
//--- 更新序列
   UpdateSeries();
  }

基于这些公式绘制的示意图如果变成动画, 那么看上去会更加有趣, 。为了将计算的序列设置为动感, 需要改变这些序列的初始值。这可以通过旋转编辑框输入值, 或以自动模式运行进程来实现。在自动模式下, 该编辑框中的值在 CProgram::AnimateGraphSeries() 方法里递增或递减。该方法是在 CProgram::UpdateGraphByTimer() 方法中被调用, 而后者是在应用程序的定时器中调用。

class CProgram : public CWndEvents
  {
private:
   //--- 按计时器刷新图表
   void              UpdateGraphByTimer(void);
   //--- 图表序列动画
   void              AnimateGraphSeries(void);
  };
//+------------------------------------------------------------------+
//| 定时器                                                            |
//+------------------------------------------------------------------+
void CProgram::OnTimerEvent(void)
  {
   CWndEvents::OnTimerEvent();
//--- 按计时器刷新图表
   if(m_counter1.CheckTimeCounter())
     {
      UpdateGraphByTimer();
     }
...
  }
//+------------------------------------------------------------------+
//| 按计时器刷新图表                                                    |
//+------------------------------------------------------------------+
void CProgram::UpdateGraphByTimer(void)
  {
//--- 如果 (1) 窗体最小化或 (2) 动画被禁用, 离开
   if(m_window.IsMinimized() || !m_animate.IsPressed())
      return;
//--- 图表序列动画
   AnimateGraphSeries();
//--- 更新图表上的数组和序列
   RecalculatingSeries();
  }
//+------------------------------------------------------------------+
//| 将图表序列变为动画                                                   |
//+------------------------------------------------------------------+
void CProgram::AnimateGraphSeries(void)
  {
//--- 指定调整数组大小的方向
   static bool counter_direction=false;
//--- 如果达到最小值, 则切换方向
   if((double)m_animate.GetValue()<=(double)m_animate.MinValue())
      counter_direction=false;
//--- 如果达到最大值, 则切换方向
   if((double)m_animate.GetValue()>=(double)m_animate.MaxValue())
      counter_direction=true;
//--- 按指定的方向调整数组的大小
   string value="";
   if(!counter_direction)
      value=string((double)m_animate.GetValue()+m_animate.StepValue());
   else
      value=string((double)m_animate.GetValue()-m_animate.StepValue());
//--- 设置新值并更新文本框
   m_animate.SetValue(value,false);
   m_animate.GetTextBoxPointer().Update(true);
  }

得到的结果如下所示:

 图例. 7. 动态内摆线演示。

图例. 7. 动态内摆线演示。


文章中列出的测试应用程序可从以下链接进行下载, 以供进一步学习。


来自前次更新的测试应用程序新版本

在文章 图形界面 IX: 进度条和折线图表控件 (第 2 章) 中的测试应用程序已根据此次更新的变化进行了更新。

更新后的 MQL 应用程序新版本的图形界面如下所示:

 图例. 8. 来自前次更新的测试应用程序新版本。

图例. 8. 来自前次更新的测试应用程序新版本。


文章中列出的测试应用程序可从以下链接进行下载, 以供进一步学习。


结束语

在本文中, 绘制科学图表的标准库的一部分已经集成到开发中的用于创建图形界面的函数库里。所有演示的示例可以从本文附带的文件中下载, 以供更深入地学习源代码。

当前开发阶段的函数库如下图所示:

 图例. 9. 处于当前开发阶段的函数库结构

图例. 9. 处于当前开发阶段的函数库结构


所提供的函数库代码是免费的。您可以在您的项目中使用它, 包括商业项目, 撰写文章和履行订单。

如果您对使用本文中的素材有任何疑问, 可以在评论中提问咨询。

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/3527

附加的文件 |
最近评论 | 前往讨论 (2)
y763447167
y763447167 | 8 12月 2021 在 02:24
为什么看不到附件了?
yue zhao
yue zhao | 18 5月 2022 在 04:16

thank you!so good GUI!

I am sorry!

Element.mqh have some errors!

can you  correct them! thank you!@Anatoli Kazharski

class CWindow;  //have no body

bool CElement::CheckMainPointer(void)

  {

//--- Если нет указателя

   if(::CheckPointer(m_main)==POINTER_INVALID)

     {

      //--- Вывести сообщение в журнал терминала

      ::Print(__FUNCTION__,

              " > Перед созданием элемента... \n...нужно передать указатель на главный элемент: "+

              ClassName()+"::MainPointer(CElementBase &object)");

      //--- Прервать построение графического интерфейса приложения

      return(false);

     }

//--- Сохранение указателя на форму

   m_wnd=m_main.WindowPointer();

//--- Если нет указателя на форму

   if(::CheckPointer(m_wnd)==POINTER_INVALID)

     {

      //--- Вывести сообщение в журнал терминала

      ::Print(__FUNCTION__,

              " > У элемента "+ClassName()+" нет указателя на форму!...\n"+

              "...Элементы должны создаваться в порядке своей вложенности!");

      //--- Прервать построение графического интерфейса приложения

      return(false);

     }

//--- Сохранение указателя на курсор мыши

   m_mouse=m_main.MousePointer();

//--- Сохранение свойств

   m_id       =m_wnd.LastId()+1;        // 'LastId' - undeclared identifier    Element.mqh 842 22

   m_chart_id =m_wnd.ChartId();     // 'ChartId' - undeclared identifier Element.mqh 843 22

   m_subwin   =m_wnd.SubwindowNumber();  // 'SubwindowNumber' - undeclared identifier Element.mqh 844 22

   m_corner   =(ENUM_BASE_CORNER)m_wnd.Corner();  // 'Corner' - undeclared identifier Element.mqh 845 40

   m_anchor   =(ENUM_ANCHOR_POINT)m_wnd.Anchor();  // 'Anchor' - undeclared identifier Element.mqh 846 41

//--- Отправить признак наличия указателя

   return(true);

  }

通用EA交易: CUnIndicator 和挂单的使用(第9部分) 通用EA交易: CUnIndicator 和挂单的使用(第9部分)
本文讲述的是通过通用的 CUnIndicator 类来操作指标,另外,还探讨了操作挂单的新方法。请注意,从这一点开始,CStrategy 项目的结构开始发生本质改变,现在所有的文件都位于一个目录中以便用户方便使用。
单一资产交易顺序中的风险评估 单一资产交易顺序中的风险评估
本文介绍在交易系统分析中使用概率论方法和数学统计。
本文讨论如何在跨平台智能交易系统中设置自定义停止价位。它还讨论了一种紧密相关的方法, 即随着时间的推移, 定义停止位的演化。 本文讨论如何在跨平台智能交易系统中设置自定义停止价位。它还讨论了一种紧密相关的方法, 即随着时间的推移, 定义停止位的演化。
本文讨论如何在跨平台智能交易系统中设置自定义停止价位。它还讨论了一种紧密相关的方法, 即随着时间的推移, 定义停止位的演化。
TradeObjects: 基于 MetaTrader 图形对象的自动化交易 TradeObjects: 基于 MetaTrader 图形对象的自动化交易
本文探讨基于图表线性标记创建自动交易系统的一种简单方法, 并提供了一款使用 MetaTrader 4/5 标准对象属性的现成智能交易系统, 可支持主要交易操作。