Графические интерфейсы XI: Интеграция графической стандартной библиотеки (build 16)
Содержание
- Введение
- Изменения в схеме библиотеки
- Приложение для теста свойств графика
- Приложение для теста свойств кривых графика
- Приложение с анимированным графиком гипоциклоиды
- Новая версия тестового приложения из предыдущих обновлений
- Заключение
Введение
Более подробно о том, для чего предназначена эта библиотека, можно прочитать в самой первой статье: Графические интерфейсы I: Подготовка структуры библиотеки (Глава 1). В конце статей каждой части представлен список глав со ссылками, там же есть возможность загрузить к себе на компьютер полную версию библиотеки на текущей стадии разработки. Файлы нужно разместить по тем же директориям, как они расположены в архиве.
Во второй главе девятой части серии был продемонстрирован пример того, как можно интегрировать в библиотеку класс для создания линейных графиков. Это было временным решением, так как возможностей этой части стандартной библиотеки сильно не хватало. Недавно разработчики MQL5 представили новую версию графической библиотеки для создания научных графиков (класс CGraphic). Некоторые функции этого класса описаны в статье Визуализируй это! Графическая библиотека в MQL5 как аналог plot из R. В этой статье я представлю обновление библиотеки для создания графических интерфейсов с новым элементом для создания графиков. Теперь визуализировать данные различных типов можно будет ещё проще.
Изменения в схеме библиотеки
До сих пор мы использовали для рисования копию класса CCanvas. В связи с недавно проведённым глобальным рефакторингом кода библиотеки теперь в этой копии нет необходимости. Её можно заменить оригинальной версией из стандартной библиотеки. Это уменьшило объём библиотеки ещё приблизительно на 10% и почти на 40% относительно версии, которая была представлена до рефакторинга.
Для создания графиков теперь будет использоваться класс CGraphic, поэтому подключим файл Graphic.mqh к файлу Objects.mqh. Так как файл с классом CCanvas подключен к одному из файлов, подключенных, в свою очередь, к файлу Graphic.mqh, то он также станет доступным для всей библиотеки.
//+------------------------------------------------------------------+ //| Objects.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| 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)); } };
К классу CGraphic подключены дополнительные классы для управления свойствами осей (CAxis) и кривых (CCurve) графика. Для генерации цвета кривых предназначен класс CColorGenerator. Все эти классы содержатся в отдельных файлах, подключенных к файлу Graphic.mqh:
//+------------------------------------------------------------------+ //| Graphic.mqh | //| Copyright 2016-2017, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> #include "Curve.mqh" #include "Axis.mqh" #include "ColorGenerator.mqh" ...
Файл с классом CCanvas подключен к файлу Curve.mqh, и отсюда он будет доступен во всей библиотеке.
//+------------------------------------------------------------------+ //| Curve.mqh | //| Copyright 2016-2017, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include <Object.mqh> #include <Canvas\Canvas.mqh> ...
Все вышеописанные взаимосвязи между файлами и классами отображены на рисунке:
Рис. 1. Взаимосвязи между классами стандартной и разрабатываемой библиотеки.
Таким образом, для библиотеки и файлов приложения, в котором она используется, автоматически становятся доступными классы стандартной библиотеки для работы с массивами и файлами. Ниже продемонстрирую несколько тестовых MQL-приложений, чтобы лучше разобраться в новых возможностях.
Приложение для теста свойств графика
В первом тестовом приложении реализуем графический интерфейс с элементами для управления некоторыми свойствами графика типа CGraphic. В верхней части формы расположим элемент типа CTabs. В данном случае это группа из четырёх вкладок. Сразу под рабочей областью вкладок будет график с двумя кривыми, значения которых сгенерируем случайным образом.
На первой вкладке (Background) создадим элементы управления следующими свойствами графика:
- Цвет фона
- Главный текст графика (отображается в верхней части)
- Вспомогательный текст графика (отображается в нижней части)
- Цвет главного текста
- Цвет вспомогательного текста
- Размер шрифта главного текста
- Размер шрифта вспомогательного текста
Для установки и получения этих свойств в классе CGraphic есть соответствующие публичные методы:
//+------------------------------------------------------------------+ //| Structure CBackground | //| Usage: background on a two-dimensional graphics | //+------------------------------------------------------------------+ struct CBackground { uint clr; uint clr_main; uint clr_sub; string main; string sub; int size_main; int size_sub; }; //+------------------------------------------------------------------+ //| Class CGraphic | //| Usage: class for drawing two-dimensional graphics | //+------------------------------------------------------------------+ class CGraphic { protected: //--- element of graphic CBackground m_background; // background //--- public: //--- gets the background properties 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); } //--- sets the background properties 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. Элементы первой вкладки (Background) тестового MQL-приложения.
На второй вкладке (Indents & history) расположим элементы для установки следующих свойств:
- Отступы (слева, справа, сверху, снизу)
- Ширина легенды
- Размер шрифта легенды
- Размер маркеров легенды
- Общие отступы между всеми элементами графика
- Размер отметок на шкалах осей графика
Для получения и установки этих свойств можно воспользоваться методами CGraphic, которые показаны в листинге кода ниже:
//+------------------------------------------------------------------+ //| Structure CCurveHistory | //| Usage: history of curves on a two-dimensional graphics | //+------------------------------------------------------------------+ 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; }; //+------------------------------------------------------------------+ //| Class CGraphic | //| Usage: class for drawing two-dimensional graphics | //+------------------------------------------------------------------+ class CGraphic { protected: //--- element of graphic CCurveHistory m_history; // history //--- public: //--- gets or sets indents 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; } //--- gets or sets gap int GapSize(void) const { return(m_gap); } void GapSize(const int size) { m_gap=size; } //--- gets or sets major mark size int MajorMarkSize(void) const { return(m_mark_size); } void MajorMarkSize(const int size) { m_mark_size=size; } //--- gets the curve history properties 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); } //--- sets the curve history properties 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. Элементы второй вкладки (Indents & history) тестового MQL-приложения.
На третьей вкладке (Grid) находятся элементы управления для установки свойств сетки:
- Цвет линий сетки
- Цвет нулевой линии осей
- Цвет фона сетки
- Отрисовка точек в узлах сетки
- Радиус точек
- Цвет точек
Для получения и установки этих свойств в классе CGraphic есть соответствующие методы:
//+------------------------------------------------------------------+ //| Structure CGrid | //| Usage: grid on a two-dimensional graphics | //+------------------------------------------------------------------+ struct CGrid { uint clr_line; uint clr_background; uint clr_circle; uint clr_axis_line; uint clr_frame; int r_circle; bool has_circle; }; //+------------------------------------------------------------------+ //| Class CGraphic | //| Usage: class for drawing two-dimensional graphics | //+------------------------------------------------------------------+ class CGraphic { protected: //--- element of graphic CGrid m_grid; // grid //--- public: //--- gets the grid properties 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); } //--- sets the grid properties 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. Элементы третьей вкладки (Grid) тестового MQL-приложения.
На четвёртой вкладке (Axes) расположились элементы, с помощью которых можно изменять свойства осей графика. Переключаться для настройки той или иной оси можно радио-кнопками в левой части рабочей области вкладок, которые отделены от других элементов вкладки Axes разделительной линией.
Перечислим свойства, которые будут доступны для изменения:
- Автомасштабирование
- Минимальное значение оси
- Максимальное значение оси
- Значение допуска для минимума оси
- Значение допуска для максимума оси
- Размер цифр на оси
- Максимальная отображаемая длина цифр на оси
- Размер шрифта для имени оси
- Начальное значение шага по оси
- Максимальное количество цифр на оси
- Имя оси
- Цвет текста имени оси
В листинге ниже показаны названия методов класса CAxis для получения и изменения вышеописанных свойств:
//+------------------------------------------------------------------+ //| Class CAxis | //| Usage: class for create axes on a two-dimensional graphics | //+------------------------------------------------------------------+ 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; // length of the default step double m_max_labels; // the maximum number of marks double m_min_grace; // "grace" value applied to the minimum data range double m_max_grace; // "grace" value applied to the maximum data range //--- public: CAxis(void); ~CAxis(void); //--- properties 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; } //--- default properties 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. Элементы четвёртой вкладки (Axes) тестового MQL-приложения.
В конце статьи вы можете загрузить к себе на компьютер это тестовое приложение для более подробного изучения.
Приложение для теста свойств кривых графика
Для тестов некоторых свойств кривых графика типа CGraphic было написано отдельное MQL-приложение. В верхней части его формы расположены элементы для управления свойствами кривых графика, а сразу за ними — два графика типа CGraphic (элемент CGraph). На первом графике будут отображаться серии со случайными данными, а на втором — их производные, которые для примера будут рассчитываться по формуле индикатора Momentum.
Перечислим элементы для управления свойствами кривых графика.
- Чекбокс Animate предназначен для запуска автоматического поступления данных на график.
- Поле ввода Array size — текущее количество элементов в массиве данных, отображаемых на графике.
- Кнопка Random генерирует случайные последовательности данных в сериях на графике.
- Поле ввода Period — значение переменной для расчёта индикатора Momentum.
- Комбо-бокс Curve type — выбор типа кривых на графике.
- Комбо-бокс Point type — выбор типа точек данных, по которым строятся кривые.
В пользовательском классе приложения (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. Графический интерфейс приложения для тестирования свойств кривых графика.
В конце статьи вы можете загрузить к себе на компьютер это тестовое приложение для более подробного изучения.
Приложение с анимированным графиком гипоциклоиды
В одной из своих книг по программированию на VBA в среде программы Microsoft Excel Джон Уокенбах предоставляет читателям компакт-диск с файлами для тестов. В одном из файлов реализована диаграмма, в которой генерируется бесконечное количество гипоциклоид.
Википедия даёт такое определение:
Гипоциклоида (от греческих слов ὑπό — под, внизу и κύκλος — круг, окружность) — плоская кривая, образуемая точкой окружности, катящейся по внутренней стороне другой окружности без скольжения.
Определение Джона Уокенбаха в своей книге:
Реализуем такое же приложение на MQL, а для управления параметрами добавим графический интерфейс. Рассмотрим подробнее, как это устроено.
Для генерации новой гипоциклоиды используются три параметра, по которым инициализируются числовые последовательности с указанным шагом. Затем по значениям в этих последовательностях осуществляются расчёты для получения координат точек на графике. После этого результаты нормализуются.
В пользовательском классе объявим несколько массивов для расчёта последовательностей и полей для расчёта среднего и стандартного отклонения:
//+------------------------------------------------------------------+ //| Program.mqh | //| Copyright 2017, MetaQuotes Software Corp. | //| 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; ... }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ 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() будем выводить в левом верхнем углу диаграммы значения среднего и стандартного отклонения для X- и Y-последовательностей. Для получения координат крайней точки (левый верхний угол) диаграммы используются методы 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); //--- Рассчитываем координаты и выводим текст на график 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. Демонстрация анимированного гипоциклоида.
В конце статьи вы можете загрузить к себе на компьютер это тестовое приложение для более подробного изучения.
Новая версия тестового приложения из предыдущих обновлений
Тестовое приложение, которое было продемонстрировано в статье Графические интерфейсы IX: Элементы "Индикатор выполнения" и "Линейный график" (Глава 2), было обновлено в соответствии с изменениями в данном обновлении.
Ниже показано, как выглядит новая версия этого MQL-приложения с обновлённым графическим интерфейсом:
Рис. 8. Новая версия тестового приложения из предыдущих обновлений.
В конце статьи вы можете загрузить к себе на компьютер это тестовое приложение для более подробного изучения.
Заключение
В этой статье в разрабатываемую библиотеку для создания графических интерфейсов была интегрирована часть стандартной библиотеки для построения научных графиков. Все продемонстрированные примеры вы можете загрузить к себе на компьютер в конце статьи для более подробного изучения исходных кодов.
На текущем этапе разработки библиотеки её общая схема выглядит так:
Рис. 9. Структура библиотеки на текущей стадии разработки.
Представленный код библиотеки бесплатный. Вы можете использовать его в своих проектах, в том числе и коммерческих, писать статьи и выполнять заказы.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
@Ilyas, без приведения к CA нет варианта?
@Ilyas, без приведения к CA нет варианта?
1. у Вас наследование приватное
class CB : CA
2. правильное предупреждение, по правилам теперь так:
CC(void) { m_b.CA::func(); }
1. у Вас наследование приватное
2. правильное предупреждение, по правилам теперь так:
1. Семен Семеныч! Так работает:
Благодарю.
2. В МТ4 не компилируется. Будут там изменения?
2. В МТ4 не компилируется. Будут там изменения?
Нет, не планируются
Здравствуйте.
А как другой сложный объект засунуть в ячейку таблицы? Если это, например, график или еще что-то, не просто имаг.