Скачать MetaTrader 5

Графические интерфейсы VI: Элементы "Слайдер" и "Двухсторонний слайдер" (Глава 2)

1 июня 2016, 10:23
Anatoli Kazharski
15
2 194

Содержание

 

Введение

Более подробно, о том, для чего предназначена эта библиотека, можно прочитать в самой первой статье: Графические интерфейсы I: Подготовка структуры библиотеки (Глава 1). В конце статей каждой части представлен список глав со ссылками, и там же есть возможность загрузить к себе на компьютер полную версию библиотеки на текущей стадии разработки. Файлы нужно разместить по тем же директориям, как они расположены в архиве.

В предыдущей статье разрабатываемая библиотека была пополнена сразу четырьмя элементами управления, которые довольно часто используются в графических интерфейсах: в нее добавились чекбокс, поле ввода, поле ввода с чекбоксом и комбобокс с чекбоксом. Вторая глава шестой части серии будет посвящена таким элементам управления, как слайдер и двухсторонний слайдер.


Элемент управления «Слайдер»

Слайдер — это разновидность элемента типа «поле ввода», который содержит в себе диапазон, ограниченный минимальным и максимальным значениями. В отличие от элемента «поле ввода», который мы рассматривали ранее, в слайдере нет кнопок переключателей, чтобы изменить значение в поле ввода. Вместо этого здесь используется полоса, в границах которой можно перемещать ползунок. Такой элемент интерфейса подходит для тех случаев, когда не нужно указывать точное значение, то есть, достаточно будет лишь приблизительного значения в известном диапазоне. Тем не менее, возможность ввести точное значение в поле ввода всё равно сохраняется.

Собирать этот элемент мы будем из шести графических объектов. Перечислим их.

  1. Фон
  2. Надпись (текстовая метка)
  3. Поле ввода
  4. Полоса слайдера
  5. Ползунок слайдера
  6. Индикатор слайдера

 Рис. 1. Составные части элемента управления «Слайдер».

Рис. 1. Составные части элемента управления «Слайдер».


Теперь рассмотрим, как устроен класс этого элемента.

 


Разработка класса для создания элемента «Слайдер»

Создаём файл Slider.mqh и подключаем его к файлу WndContainer.mqh:

//+------------------------------------------------------------------+
//|                                                 WndContainer.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Slider.mqh"

В файле Slider.mqh создаём класс CSlider со стандартным набором методов, которые должны быть в каждом элементе управления разрабатываемой библиотеки. Кроме подключаемых файлов Element.mqh и Window.mqh, подключим также файл SeparateLine.mqh с классом CSeparateLine для создания разделительной линии. Ранее в статье Графические интерфейсы II: Элементы "Разделительная линия" и "Контекстное меню" (Глава 2) этот класс (CSeparateLine) уже был рассмотрен, поэтому не будем подробно останавливаться на нём. Кратко напомню только, что если высота установлена более двух пикселей, между двумя нарисованными линиями появляется пустое пространство. Визуально это выглядит как углубление, которое подходит для создания полосы слайдера (прорезь или слот), внутри которой будет перемещаться ползунок.

//+------------------------------------------------------------------+
//|                                                       Slider.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
#include "SeparateLine.mqh"
//+------------------------------------------------------------------+
//| Класс для создания слайдера с полем ввода                        |
//+------------------------------------------------------------------+
class CSlider : public CElement
  {
private:
   //--- Указатель на форму, к которой элемент присоединён
   CWindow          *m_wnd;
public:
                     CSlider(void);
                    ~CSlider(void);
   //---
public:
   //--- Сохраняет указатель формы
   void              WindowPointer(CWindow &object)                 { m_wnd=::GetPointer(object);         }
   //---
public:
   //--- Обработчик событий графика
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Таймер
   virtual void      OnEventTimer(void);
   //--- Перемещение элемента
   virtual void      Moving(const int x,const int y);
   //--- (1) Показ, (2) скрытие, (3) сброс, (4) удаление
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- (1) Установка, (2) сброс приоритетов на нажатие левой кнопки мыши
   virtual void      SetZorders(void);
   virtual void      ResetZorders(void);
   //--- Сбросить цвет
   virtual void      ResetColors(void);
  };

Предоставим пользователю библиотеки возможность настроить свойства всех объектов, из которых будет собираться элемент «слайдер». Перечислим эти свойства.

  • Цвет общего фона элемента
  • Текст для описания слайдера
  • Цвета текстовой метки в разных состояниях
  • Текущее значение в поле ввода
  • Размеры поля ввода
  • Цвета поля ввода в разных состояниях
  • Цвета текста поля ввода в разных состояниях
  • Цвета рамки поля ввода в разных состояниях
  • Размер прорези по оси Y (высота)
  • Цвета линий прорези
  • Цвета индикатора слайдера в разных состояниях
  • Размеры ползунка слайдера
  • Цвета ползунка слайдера
  • Приоритеты на нажатие левой кнопки мыши

В листинге кода ниже представлены поля и методы класса перечисленных выше свойств объектов элемента: 

class CSlider : public CElement
  {
private:
   //--- Цвет общего фона
   color             m_area_color;
   //--- Текст для описания слайдера
   string            m_label_text;
   //--- Цвета текстовой метки в разных состояниях
   color             m_label_color;
   color             m_label_color_hover;
   color             m_label_color_locked;
   color             m_label_color_array[];
   //--- Размеры поля ввода
   int               m_edit_x_size;
   int               m_edit_y_size;
   //--- Цвета поля ввода в разных состояниях
   color             m_edit_color;
   color             m_edit_color_locked;
   //--- Цвета текста поля ввода в разных состояниях
   color             m_edit_text_color;
   color             m_edit_text_color_locked;
   //--- Цвета рамки поля ввода в разных состояниях
   color             m_edit_border_color;
   color             m_edit_border_color_hover;
   color             m_edit_border_color_locked;
   color             m_edit_border_color_array[];
   //--- Размер прорези
   int               m_slot_y_size;
   //--- Цвета прорези
   color             m_slot_line_dark_color;
   color             m_slot_line_light_color;
   //--- Цвета индикатора в разных состояниях
   color             m_slot_indicator_color;
   color             m_slot_indicator_color_locked;
   //--- Размеры ползунка слайдера
   int               m_thumb_x_size;
   int               m_thumb_y_size;
   //--- Цвета ползунка слайдера
   color             m_thumb_color;
   color             m_thumb_color_hover;
   color             m_thumb_color_locked;
   color             m_thumb_color_pressed;
   //--- Приоритеты на нажатие левой кнопкой мыши
   int               m_zorder;
   int               m_area_zorder;
   int               m_edit_zorder;
   //---
public:
   //--- (1) Цвет фона, (2) цвета текстовой метки
   void              AreaColor(const color clr)                     { m_area_color=clr;                   }
   void              LabelColor(const color clr)                    { m_label_color=clr;                  }
   void              LabelColorHover(const color clr)               { m_label_color_hover=clr;            }
   void              LabelColorLocked(const color clr)              { m_label_color_locked=clr;           }
   //--- Размеры (1) поля ввода и (2) прорези
   void              EditXSize(const int x_size)                    { m_edit_x_size=x_size;               }
   void              EditYSize(const int y_size)                    { m_edit_y_size=y_size;               }
   void              SlotYSize(const int y_size)                    { m_slot_y_size=y_size;               }
   //--- Цвета поля ввода в разных состояниях
   void              EditColor(const color clr)                     { m_edit_color=clr;                   }
   void              EditColorLocked(const color clr)               { m_edit_color_locked=clr;            }
   //--- Цвета текста поля ввода в разных состояниях
   void              EditTextColor(const color clr)                 { m_edit_text_color=clr;              }
   void              EditTextColorLocked(const color clr)           { m_edit_text_color_locked=clr;       }
   //--- Цвета рамки поля ввода в разных состояниях
   void              EditBorderColor(const color clr)               { m_edit_border_color=clr;            }
   void              EditBorderColorHover(const color clr)          { m_edit_border_color_hover=clr;      }
   void              EditBorderColorLocked(const color clr)         { m_edit_border_color_locked=clr;     }
   //--- (1) Тёмный и (2) светлый цвет разделительной линии (прорези)
   void              SlotLineDarkColor(const color clr)             { m_slot_line_dark_color=clr;         }
   void              SlotLineLightColor(const color clr)            { m_slot_line_light_color=clr;        }
   //--- Цвета индикатора слайдера в разных состояниях
   void              SlotIndicatorColor(const color clr)            { m_slot_indicator_color=clr;         }
   void              SlotIndicatorColorLocked(const color clr)      { m_slot_indicator_color_locked=clr;  }
   //--- Размеры ползунка слайдера
   void              ThumbXSize(const int x_size)                   { m_thumb_x_size=x_size;              }
   void              ThumbYSize(const int y_size)                   { m_thumb_y_size=y_size;              }
   //--- Цвета ползунка слайдера
   void              ThumbColor(const color clr)                    { m_thumb_color=clr;                  }
   void              ThumbColorHover(const color clr)               { m_thumb_color_hover=clr;            }
   void              ThumbColorLocked(const color clr)              { m_thumb_color_locked=clr;           }
   void              ThumbColorPressed(const color clr)             { m_thumb_color_pressed=clr;          }
  };

Свойства из предыдущего списка относятся в основном к цвету и размерам объектов элемента. Отдельной группой представим свойства, которые относятся к значению и диапазону в поле ввода слайдера. К таким свойствам относятся: 

  • Минимальное значение
  • Максимальное значение
  • Шаг для изменения значения в поле ввода
  • Режим выравнивания текста
  • Количество знаков после запятой

class CSlider : public CElement
  {
private:
   //--- (1) Минимальное и (2) максимальное значение, (3) шаг изменения значения
   double            m_min_value;
   double            m_max_value;
   double            m_step_value;
   //--- Количество знаков после запятой
   int               m_digits;
   //--- Режим выравнивания текста
   ENUM_ALIGN_MODE   m_align_mode;
   //---
public:
   //--- Минимальное значение
   double            MinValue(void)                           const { return(m_min_value);                }
   void              MinValue(const double value)                   { m_min_value=value;                  }
   //--- Максимальное значение
   double            MaxValue(void)                           const { return(m_max_value);                }
   void              MaxValue(const double value)                   { m_max_value=value;                  }
   //--- Шаг изменения значения
   double            StepValue(void)                          const { return(m_step_value);               }
   void              StepValue(const double value)                  { m_step_value=(value<=0)? 1 : value; }
   //--- (1) Количество знаков после запятой, (2) режим выравнивания текста
   void              SetDigits(const int digits)                    { m_digits=::fabs(digits);            }
   void              AlignMode(ENUM_ALIGN_MODE mode)                { m_align_mode=mode;                  }
  };

Для получения текущего значения, а также для корректировки и установки нового значения в поле ввода будут использоваться методы CSlider::GetValue(), CSlider::SetValue() и CSlider::ChangeValue():

class CSlider : public CElement
  {
private:
   //--- Текущее значение в поле ввода
   double            m_edit_value;
   //---
public:
   //--- Возвращение и установка значения поля ввода
   double            GetValue(void)                           const { return(m_edit_value);               }
   bool              SetValue(const double value);
   //--- Изменение значения в поле ввода
   void              ChangeValue(const double value);
  };
//+------------------------------------------------------------------+
//| Установка текущего значения                                      |
//+------------------------------------------------------------------+
bool CSlider::SetValue(const double value)
  {
//--- Для корректировки
   double corrected_value=0.0;
//--- Скорректируем с учетом шага
   corrected_value=::MathRound(value/m_step_value)*m_step_value;
//--- Проверка на минимум/максимум
   if(corrected_value<=m_min_value)
      corrected_value=m_min_value;
   if(corrected_value>=m_max_value)
      corrected_value=m_max_value;
//--- Если значение было изменено
   if(m_edit_value!=corrected_value)
     {
      m_edit_value=corrected_value;
      return(true);
     }
//--- Значение без изменений
   return(false);
  }
//+------------------------------------------------------------------+
//| Изменение значения в поле ввода                                  |
//+------------------------------------------------------------------+
void CSlider::ChangeValue(const double value)
  {
//--- Проверим, скорректируем и запомним новое значение
   SetValue(value);
//--- Установим новое значение в поле ввода
   m_edit.Description(::DoubleToString(GetValue(),m_digits));
  }

При перемещении ползунка значение в поле ввода должно рассчитываться относительно координаты X. Если же значение вводится в поле ввода вручную, то координата X ползунка должна рассчитываться относительно нового значения в поле ввода. Иными словами, при разработке элемента нужно предусмотреть возможность обратных преобразований значений этих переменных. 

Чтобы всё это корректно рассчитывалось, нам понадобятся дополнительные вспомогательные поля (переменные) класса, которые будут задействованы в расчётах. Значения этих переменных нужно рассчитать (инициализировать) один раз, сразу после создания элемента. Перечислим описания этих переменных.

  • Количество пикселей в рабочей области (m_pixels_total).
  • Количество шагов в диапазоне значений рабочей области (m_value_steps_total).
  • Размер шага относительно ширины рабочей области (m_position_step).

Для расчёта значений этих переменных напишем метод CSlider::CalculateCoefficients():

class CSlider : public CElement
  {
private:
   //--- Количество пикселей в рабочей области
   int               m_pixels_total;
   //--- Количество шагов в рабочей области
   int               m_value_steps_total;
   //--- Размер шага преобразованной ширины рабочей области
   double            m_position_step;
   //---
private:
   //--- Расчёт значений (шаги и коэффициенты)
   bool              CalculateCoefficients(void);
  };
//+------------------------------------------------------------------+
//| Расчёт значений (шаги и коэффициенты)                            |
//+------------------------------------------------------------------+
bool CSlider::CalculateCoefficients(void)
  {
//--- Выйти, если ширина элемента меньше, чем ширина ползунка слайдера
   if(CElement::XSize()<m_thumb_x_size)
      return(false);
//--- Количество пикселей в рабочей области
   m_pixels_total=CElement::XSize()-m_thumb_x_size;
//--- Количество шагов в диапазоне значений рабочей области
   m_value_steps_total=int((m_max_value-m_min_value)/m_step_value);
//--- Размер шага относительно ширины рабочей области
   m_position_step=m_step_value*(double(m_value_steps_total)/double(m_pixels_total));
   return(true);
  }

Теперь значения вышеперечисленных переменных можно использовать для расчёта координаты X ползунка относительно значения в поле ввода и обратно. Для этого напишем два отдельных метода: CSlider::CalculateThumbX() и CSlider::CalculateThumbPos().

В методе CSlider::CalculateThumbX(), в первую очередь, рассчитываются значения вспомогательной локальной переменной (neg_range) для корректировки на случай, если значение минимального ограничения отрицательное. Далее осуществляется расчёт координаты X для ползунка слайдера, и после этого, если получился выход за пределы полосы слайдера, производится корректировка значения. В конце метода ползунку слайдера устанавливается новое значение координаты X и заново рассчитывается отступ от крайней точки формы, к которой присоединён элемент.

В самом начале метода CSlider::CalculateThumbPos() мы сразу получаем позицию ползунка слайдера в диапазоне значений. Затем идёт корректировка в случае, если значение минимального ограничения отрицательное и значение переменной m_current_pos_x корректно. Далее, если был выход из рабочей области, производится соответствующая корректировка значения.

class CSlider : public CElement
  {
private:
   //--- Текущая позиция ползунка слайдера: (1) значение, (2) координата X
   double            m_current_pos;
   double            m_current_pos_x;
   //---
private:
   //--- Расчёт координаты X ползунка слайдера
   void              CalculateThumbX(void);
   //--- Изменяет позицию ползунка слайдера относительно текущего значения
   void              CalculateThumbPos(void);
  };
//+------------------------------------------------------------------+
//| Расчёт координаты X ползунка слайдера                            |
//+------------------------------------------------------------------+
void CSlider::CalculateThumbX(void)
  {
//--- Корректировка с учётом того, что минимальное значение может быть отрицательным
   double neg_range=(m_min_value<0)? ::fabs(m_min_value/m_position_step) : 0;
//--- Рассчитаем координату X для ползунка слайдера
   m_current_pos_x=m_area.X()+(m_edit_value/m_position_step)+neg_range;
//--- Если выходим за пределы рабочей области влево
   if(m_current_pos_x<m_area.X())
      m_current_pos_x=m_area.X();
//--- Если выходим за пределы рабочей области вправо
   if(m_current_pos_x+m_thumb.XSize()>m_area.X2())
      m_current_pos_x=m_area.X2()-m_thumb.XSize();
//--- Сохраним и установим новую координату X
   m_thumb.X(int(m_current_pos_x));
   m_thumb.X_Distance(int(m_current_pos_x));
   m_thumb.XGap(m_thumb.X()-m_wnd.X());
  }
//+------------------------------------------------------------------+
//| Расчёт позиции ползунка слайдера в диапазоне значений            |
//+------------------------------------------------------------------+
void CSlider::CalculateThumbPos(void)
  {
//--- Получим номер позиции ползунка слайдера
   m_current_pos=(m_thumb.X()-m_area.X())*m_position_step;
//--- Корректировка с учётом того, что минимальное значение может быть отрицательным
   if(m_min_value<0 && m_current_pos_x!=WRONG_VALUE)
      m_current_pos+=int(m_min_value);
//--- Проверка на выход из рабочей области вправо/влево
   if(m_thumb.X2()>=m_area.X2())
      m_current_pos=int(m_max_value);
   if(m_thumb.X()<=m_area.X())
      m_current_pos=int(m_min_value);
  }

При перемещении ползунка слайдера нужно рассчитывать и обновлять ширину индикатора слайдера, правый край которого должен быть «привязан» к ползунку. Для этого напишем метод CSlider::UpdateIndicator():

class CSlider : public CElement
  {
private:
   //--- Обновление индикатора слайдера
   void              UpdateIndicator(void);
  };
//+------------------------------------------------------------------+
//| Обновление индикатора слайдера                                   |
//+------------------------------------------------------------------+
void CSlider::UpdateIndicator(void)
  {
//--- Рассчитаем размер
   int x_size=m_thumb.X()-m_indicator.X();
//--- Корректировка в случае недопустимых значений
   if(x_size<=0)
      x_size=1;
//--- Установка нового размера
   m_indicator.X_Size(x_size);
  }

Для создания элемента «Слайдер» понадобится шесть приватных (private) методов и один главный публичный (public) метод:

class CSlider : public CElement
  {
public:
   //--- Методы для создания элемента
   bool              CreateSlider(const long chart_id,const int subwin,const string text,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateLabel(void);
   bool              CreateEdit(void);
   bool              CreateSlot(void);
   bool              CreateIndicator(void);
   bool              CreateThumb(void);
  };

Приведём здесь только код метода CSlider::CreateThumb(), так как именно в нём будут в первый раз вызываться все методы для расчётов, рассмотренных ранее. Во всех остальных методах создания объектов элемента нет ничего, что не описывалось бы ранее в других статьях этой серии.

//+------------------------------------------------------------------+
//| Создаёт ползунок слайдера                                        |
//+------------------------------------------------------------------+
bool CSlider::CreateThumb(void)
  {
//--- Формирование имени объекта
   string name=CElement::ProgramName()+"_slider_thumb_"+(string)CElement::Id();
//--- Координаты
   int x=CElement::X();
   int y=m_slot.Y()-((m_thumb_y_size-m_slot_y_size)/2);
//--- Установим объект
   if(!m_thumb.Create(m_chart_id,name,m_subwin,x,y,m_thumb_x_size,m_thumb_y_size))
      return(false);
//--- Установим свойства
   m_thumb.Color(m_thumb_color);
   m_thumb.BackColor(m_thumb_color);
   m_thumb.BorderType(BORDER_FLAT);
   m_thumb.Corner(m_corner);
   m_thumb.Selectable(false);
   m_thumb.Z_Order(m_zorder);
   m_thumb.Tooltip("\n");
//--- Сохраним размеры (в объекте)
   m_thumb.XSize(m_thumb.X_Size());
   m_thumb.YSize(m_thumb.Y_Size());
//--- Сохраним координаты
   m_thumb.X(x);
   m_thumb.Y(y);
//--- Отступы от крайней точки
   m_thumb.XGap(x-m_wnd.X());
   m_thumb.YGap(y-m_wnd.Y());
//--- Расчёт значений вспомогательных переменных
   CalculateCoefficients();
//--- Расчёт координаты X ползунка относительно текущего значения в поле ввода
   CalculateThumbX();
//--- Расчёт позиции ползунка слайдера в диапазоне значений
   CalculateThumbPos();
//--- Обновляем индикатор слайдера
   UpdateIndicator();
//--- Сохраним указатель объекта
   CElement::AddToArray(m_thumb);
   return(true);
  }

Методы для перемещения ползунка слайдера практически ничем не отличаются от одноимённых методов в классах CScroll и CScrollH, которые подробно рассматривались в статье Графические интерфейсы V: Вертикальная и горизонтальная полоса прокрутки (Глава 1), поэтому их код приводить здесь не будем. Ограничимся только их объявлением в теле класса CSlider

class CSlider : public CElement
  {
private:
   //--- Состояние кнопки мыши (нажата/отжата)
   ENUM_THUMB_MOUSE_STATE m_clamping_area_mouse;
   //--- Для определения режима перемещения ползунка слайдера
   bool              m_slider_thumb_state;
   //--- Переменные, связанные с перемещением ползунка
   int               m_slider_size_fixing;
   int               m_slider_point_fixing;
   //---
private:
   //--- Процесс перемещения ползунка слайдера
   void              OnDragThumb(const int x);
   //--- Обновление положения ползунка слайдера
   void              UpdateThumb(const int new_x_point);
   //--- Проверяет состояние кнопки мыши
   void              CheckMouseButtonState(void);
   //--- Обнуление переменных, связанных с перемещением ползунка слайдера
   void              ZeroThumbVariables(void);
  };

Для обработки ввода значения в поле ввода создадим метод CSlider::OnEndEdit(), который будет вызываться в обработчике событий элемента CSlider::OnEvent(). 

В методе CSlider::OnEndEdit() в самом начале метода проверяется по имени объекта, вводилось ли значение в поле этого слайдера. Затем получаем текущее значение в поле ввода. Далее происходит обязательная проверка и корректировка на предмет ввода недопустимого значения, рассчитывается координата X ползунка слайдера и позиция в диапазоне значений. После этого обновляется индикатор слайдера, и в самом конце метода нужно отправить сообщение с (1) идентификатором пользовательского события ON_END_EDIT, (2) идентификатором элемента, (3) индексом элемента и (4) описанием, которое содержится в текстовой метке. 

class CSlider : public CElement
  {
private:
   //--- Обработка ввода значения в поле ввода
   bool              OnEndEdit(const string object_name);
  };
//+------------------------------------------------------------------+
//| Обработка ввода значения в поле ввода                            |
//+------------------------------------------------------------------+
bool CSlider::OnEndEdit(const string object_name)
  {
//--- Выйдем, если чужое имя объекта
   if(object_name!=m_edit.Name())
      return(false);
//--- Получим только что введённое значение
   double entered_value=::StringToDouble(m_edit.Description());
//--- Проверим, скорректируем и запомним новое значение
   ChangeValue(entered_value);
//--- Рассчитаем координату X ползунка
   CalculateThumbX();
//--- Рассчитаем позицию в диапазоне значений
   CalculateThumbPos();
//--- Обновляем индикатор слайдера
   UpdateIndicator();
//--- Отправим сообщение об этом
   ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }

Такое же пользовательское сообщение нужно отправлять после завершения перемещения ползунка для изменения значения в поле ввода. Лучше всего для этого подходит метод CSlider::ZeroThumbVariables(), который вызывается в методе CSlider::CheckMouseButtonState(), где отслеживается область нажатия левой кнопки мыши. Всё устроено таким образом, что вызов метода CSlider::ZeroThumbVariables() уже подразумевает, что левая кнопка мыши отжата. Если же до этого она была зажата над областью ползунка слайдера, то это означает, что перемещение ползунка завершено и сейчас можно отправить сообщение о том, что значение в поле ввода было изменено.

//+------------------------------------------------------------------+
//| Обнуление переменных, связанных с перемещением полосы прокрутки   |
//+------------------------------------------------------------------+
void CSlider::ZeroThumbVariables(void)
  {
//--- Если зашли сюда, то это значит, что левая кнопка мыши отжата.
//    Если до этого зажатие левой кнопки мыши было осуществлено над ползунком слайдера...
   if(m_clamping_area_mouse==THUMB_PRESSED_INSIDE)
     {
      //--- ... отправим сообщение, что изменение значения в поле ввода посредством ползунка завершено
      ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
     }
//---
   m_slider_size_fixing  =0;
   m_clamping_area_mouse =THUMB_NOT_PRESSED;
//--- Если идентификатор элемента совпадает с идентификатором-активатором,
//    разблокируем форму и сбросим идентификатор активного элемента
   if(CElement::Id()==m_wnd.IdActivatedElement())
     {
      m_wnd.IsLocked(false);
      m_wnd.IdActivatedElement(WRONG_VALUE);
     }
  }

Полный код обработчика событий CSlider::OnEvent() в таком случае будет выглядеть так:

//+------------------------------------------------------------------+
//| Обработчик события графика                                       |
//+------------------------------------------------------------------+
void CSlider::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Обработка события перемещения курсора
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Выйти, если элемент скрыт     
      if(!CElement::IsVisible())
         return;
      //--- Координаты и состояние левой кнопки мыши
      int x=(int)lparam;
      int y=(int)dparam;
      m_mouse_state=(bool)int(sparam);
      //--- Проверка фокуса над элементами
      CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2());
      m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() && 
                         y>m_thumb.Y() && y<m_thumb.Y2());
      //--- Выйти, если элемент заблокирован
      if(!m_slider_state)
         return;
      //--- Проверим и запомним состояние кнопки мыши
      CheckMouseButtonState();
      //--- Изменим цвет ползунка слайдера
      ChangeThumbColor();
      //--- Если управление передано полосе слайдера, определим её положение
      if(m_clamping_area_mouse==THUMB_PRESSED_INSIDE)
        {
         //--- Перемещение ползунка слайдера
         OnDragThumb(x);
         //--- Расчёт позиции ползунка слайдера в диапазоне значений
         CalculateThumbPos();
         //--- Установка нового значения в поле ввода
         ChangeValue(m_current_pos);
         //--- Обновляем индикатор слайдера
         UpdateIndicator();
         return;
        }
     }
//--- Обработка события изменения значения в поле ввода
   if(id==CHARTEVENT_OBJECT_ENDEDIT)
     {
      //--- Обработка ввода значения
      if(OnEndEdit(sparam))
         return;
     }
  }

Все методы для создания и управления элементом интерфейса «слайдер» реализованы. Теперь протестируем его в MQL-приложении, с которым работали в предыдущей статье. 

 


Тест элемента «Слайдер»

В предыдущей статье в тестовом приложении мы создали четыре чекбокса, которые управляют доступностью других элементов управления. Сейчас добавим в графический интерфейс элемент «слайдер» и ещё один (пятый) чекбокс для управления его доступностью. Для этого в пользовательском классе CProgram объявляем экземпляры классов CCheckBox и CSlider, а также методы с отступами от крайней точки формы, к которой будут привязаны эти элементы управления.

//+------------------------------------------------------------------+
//| Класс для создания приложения                                    |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
   //--- Чекбоксы
   CCheckBox         m_checkbox5;
   //--- Слайдеры
   CSlider           m_slider1;
   //---
private:
   //--- Чекбоксы
#define CHECKBOX5_GAP_X       (7)
#define CHECKBOX5_GAP_Y       (200)
   bool              CreateCheckBox5(const string text);
   //--- Слайдеры
#define SLIDER1_GAP_X         (32)
#define SLIDER1_GAP_Y         (225)
   bool              CreateSlider1(const string text);
  };

Код методов для создания чекбоксов мы уже рассматривали в предыдущей статье, поэтому сразу перейдём к методу создания элемента «слайдер» CProgram::CreateSlider1(). С помощью методов CSlider::MinValue() и CSlider::MaxValue() установим диапазон значений от -1 до 1. Шаг установим с точностью до 8 знака (0.00000001). Доступность элемента будет зависеть от текущего состояния пятого чекбокса.

//+------------------------------------------------------------------+
//| Создаёт слайдер 1                                                |
//+------------------------------------------------------------------+
bool CProgram::CreateSlider1(const string text)
  {
//--- Сохраним указатель на окно
   m_slider1.WindowPointer(m_window1);
//--- Координаты
   int x=m_window1.X()+SLIDER1_GAP_X;
   int y=m_window1.Y()+SLIDER1_GAP_Y;
//--- Значение
   double v=(m_slider1.GetValue()==WRONG_VALUE) ? 0.84615385 : m_slider1.GetValue();
//--- Установим свойства перед созданием
   m_slider1.XSize(264);
   m_slider1.YSize(40);
   m_slider1.EditXSize(87);
   m_slider1.MaxValue(1);
   m_slider1.StepValue(0.00000001);
   m_slider1.MinValue(-1);
   m_slider1.SetDigits(8);
   m_slider1.SetValue(v);
   m_slider1.AreaColor(clrWhiteSmoke);
   m_slider1.LabelColor(clrBlack);
   m_slider1.LabelColorLocked(clrSilver);
   m_slider1.EditColorLocked(clrWhiteSmoke);
   m_slider1.EditBorderColor(clrSilver);
   m_slider1.EditBorderColorLocked(clrSilver);
   m_slider1.EditTextColorLocked(clrSilver);
   m_slider1.SlotLineDarkColor(clrSilver);
   m_slider1.SlotLineLightColor(clrWhite);
   m_slider1.SlotYSize(4);
   m_slider1.ThumbColorLocked(clrLightGray);
   m_slider1.ThumbColorPressed(clrSilver);
   m_slider1.SlotIndicatorColor(C'85,170,255');
   m_slider1.SlotIndicatorColorLocked(clrLightGray);
//--- Создадим элемент управления
   if(!m_slider1.CreateSlider(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- Доступность будет зависеть от текущего состояния пятого чекбокса
   m_slider1.SliderState(m_checkbox5.CheckButtonState());
//--- Добавим объект в общий массив групп объектов
   CWndContainer::AddToElementsArray(0,m_slider1);
   return(true);
  }

Вызов новых методов создания элементов нужно осуществлять в главном методе создания графического интерфейса. В листинге кода ниже представлена сокращённая версия этого метода:

//+------------------------------------------------------------------+
//| Создаёт торговую панель                                          |
//+------------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Создание формы 1 для элементов управления
//--- Создание элементов управления:
//    Главное меню
//--- Контекстные меню
//--- Создание статусной строки
//--- Чек-боксы
   if(!CreateCheckBox5("Checkbox 5"))
      return(false);
//--- Слайдеры
   if(!CreateSlider1("Slider 1:"))
      return(false);
//--- Перерисовка графика
   m_chart.Redraw();
   return(true);
  }

В обработчике событий приложения CProgram::OnEvent() будем отслеживать изменение состояния пятого чекбокса для контроля доступности слайдера. А по событию с пользовательским идентификатором ON_END_EDIT — определять, когда изменяется значение в поле ввода.

//+------------------------------------------------------------------+
//| Обработчик событий                                               |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Событие нажатия на текстовой метке
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Если нажали на пятом чекбоксе
      if(lparam==m_checkbox5.Id())
        {
         //--- Установить состояние первому слайдеру
         m_slider1.SliderState(m_checkbox5.CheckButtonState());
        }
     }
//--- Событие окончания ввода значения в поле ввода
   if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
  }

Теперь можно скомпилировать программу и загрузить её на график. Попробуйте взаимодействовать с элементами управления графического интерфейса приложения. Если всё сделано правильно, то вы увидите результат, как на скриншоте ниже:

 Рис. 2. Тест элемента управления «Слайдер».

Рис. 2. Тест элемента управления «Слайдер». 

 


Элемент «Двухсторонний слайдер»

Элемент управления «двухсторонний слайдер» отличается от обычного слайдера тем, что позволяет выбрать диапазон значений в установленном пользователем диапазоне значений. Для этого на полосе слайдера есть два ползунка. Левый ползунок можно перемещать от левого края полосы слайдера до правого ползунка. А правый ползунок, соответственно, можно перемещать от правого края полосы слайдера до левого ползунка. Также здесь уже есть два поля ввода, в которых отображается значение относительно положений ползунков на полосе слайдера. Значение в эти поля ввода можно ввести вручную, при этом будет изменяться положение ползунков.

Собираться этот элемент будет из восьми графических объектов-примитивов. Перечислим их.

  1. Фон.
  2. Надпись (текстовая метка).
  3. Левое поле ввода.
  4. Правое поле ввода.
  5. Полоса слайдера.
  6. Левый ползунок слайдера.
  7. Правый ползунок слайдера.
  8. Индикатор слайдера.

Рис. 3. Составные части элемента управления «Двухсторонний слайдер».

Рис. 3. Составные части элемента управления «Двухсторонний слайдер».


Далее рассмотрим, как устроен класс элемента управления «двухсторонний слайдер» и отметим, чем он отличается от обычного слайдера.

 


Разработка класса для создания элемента «Двухсторонний слайдер»

Подключаем файл DualSlider.mqh с классом элемента (CDualSlider) к файлу WndContainer.mqh:

//+------------------------------------------------------------------+
//|                                                 WndContainer.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "DualSlider.mqh"

Что касается свойств элемента, то класс CDualSlider — полная копия класса CSlider. Отличие заключается только в том, что для левого и правого полей ввода и ползунков слайдера нужно было реализовать отдельные поля и методы. Изменения и отличия в этих методах незначительны, поэтому не будем приводить здесь их код. С ним вы можете ознакомиться в приложенных к статье файлах.

class CDualSlider : public CElement
  {
private:
   //--- Текущие значения в полях ввода (левого и правого)
   double            m_left_edit_value;
   double            m_right_edit_value;
   //--- Текущая позиция ползунков слайдера (левого и правого)
   double            m_left_current_pos;
   double            m_left_current_pos_x;
   double            m_right_current_pos;
   double            m_right_current_pos_x;
   //--- Состояние кнопки мыши (нажата/отжата) для ползунков слайдера (левого и правого)
   ENUM_THUMB_MOUSE_STATE m_clamping_mouse_left_thumb;
   ENUM_THUMB_MOUSE_STATE m_clamping_mouse_right_thumb;
   //---
public:
   //--- Возвращение и установка значения в полях ввода (левое и правое)
   double            GetLeftValue(void)                       const { return(m_left_edit_value);          }
   double            GetRightValue(void)                      const { return(m_right_edit_value);         }
   bool              SetLeftValue(double value);
   bool              SetRightValue(double value);
   //--- Изменение значения в полях ввода (левое и правое)
   void              ChangeLeftValue(const double value);
   void              ChangeRightValue(const double value);
   //---
private:
   //--- Процесс перемещения ползунка слайдера (левого и правого)
   void              OnDragLeftThumb(const int x);
   void              OnDragRightThumb(const int x);
   //--- Обновление положения ползунка слайдера (левого и правого)
   void              UpdateLeftThumb(const int new_x_point);
   void              UpdateRightThumb(const int new_x_point);
   //--- Проверяет состояние кнопки мыши над ползунком слайдера
   void              CheckMouseOnLeftThumb(void);
   void              CheckMouseOnRightThumb(void);
   //--- Расчёт координаты X ползунка слайдера (левого и правого)
   void              CalculateLeftThumbX(void);
   void              CalculateRightThumbX(void);
   //--- Изменяет позицию левого ползунка слайдера относительно значения (левого и правого)
   void              CalculateLeftThumbPos(void);
   void              CalculateRightThumbPos(void);
  };

Приведём здесь код только тех методов, где учитываются теперь два поля ввода и ползунка слайдера. Например, вот так здесь устроен метод CDualSlider::OnEndEdit():

class CDualSlider : public CElement
  {
private:
   //--- Обработка ввода значения в поле ввода
   bool              OnEndEdit(const string object_name);
  };
//+------------------------------------------------------------------+
//| Окончание ввода значения                                         |
//+------------------------------------------------------------------+
bool CDualSlider::OnEndEdit(const string object_name)
  {
//--- Если ввод значения в левое поле
   if(object_name==m_left_edit.Name())
     {
      //--- Получим только что введённое значение
      double entered_value=::StringToDouble(m_left_edit.Description());
      //--- Проверим, скорректируем и запомним новое значение
      ChangeLeftValue(entered_value);
      //--- Рассчитаем координату X ползунка
      CalculateLeftThumbX();
      //--- Обновление положения ползунка слайдера
      UpdateLeftThumb(m_left_thumb.X());
      //--- Рассчитаем позицию в диапазоне значений
      CalculateLeftThumbPos();
      //--- Проверим, скорректируем и запомним новое значение
      ChangeLeftValue(m_left_current_pos);
      //--- Обновляем индикатор слайдера
      UpdateIndicator();
      //--- Отправим сообщение об этом
      ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
      return(true);
     }
//--- Если ввод значения в правое поле
   if(object_name==m_right_edit.Name())
     {
      //--- Получим только что введённое значение
      double entered_value=::StringToDouble(m_right_edit.Description());
      //--- Проверим, скорректируем и запомним новое значение
      ChangeRightValue(entered_value);
      //--- Рассчитаем координату X ползунка
      CalculateRightThumbX();
      //--- Обновление положения ползунка слайдера
      UpdateRightThumb(m_right_thumb.X());
      //--- Рассчитаем позицию в диапазоне значений
      CalculateRightThumbPos();
      //--- Проверим, скорректируем и запомним новое значение
      ChangeRightValue(m_right_current_pos);
      //--- Обновляем индикатор слайдера
      UpdateIndicator();
      //--- Отправим сообщение об этом
      ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
      return(true);
     }
//---
   return(false);
  }

Тоже самое относится и к перемещению левого и правого ползунков слайдера. Для каждого из них в обработчике событий CDualSlider::OnEvent() есть свои отдельные проверки и блоки кода: 

//+------------------------------------------------------------------+
//| Обработчик события графика                                       |
//+------------------------------------------------------------------+
void CDualSlider::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Обработка события перемещения курсора
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Выйти, если элемент скрыт   
      if(!CElement::IsVisible())
         return;
      //--- Координаты и состояние левой кнопки мыши
      int x=(int)lparam;
      int y=(int)dparam;
      m_mouse_state=(bool)int(sparam);
      //--- Проверка фокуса над элементами
      CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2());
      m_left_thumb.MouseFocus(x>m_left_thumb.X() && x<m_left_thumb.X2() && 
                              y>m_left_thumb.Y() && y<m_left_thumb.Y2());
      m_right_thumb.MouseFocus(x>m_right_thumb.X() && x<m_right_thumb.X2() && 
                               y>m_right_thumb.Y() && y<m_right_thumb.Y2());
      //--- Выйти, если элемент заблокирован
      if(!m_slider_state)
         return;
      //--- Проверим и запомним состояние кнопки мыши
      CheckMouseOnLeftThumb();
      CheckMouseOnRightThumb();
      //--- Изменим цвет ползунка слайдера
      ChangeThumbColor();
      //--- Если управление передано полосе слайдера (левому ползунку)
      if(m_clamping_mouse_left_thumb==THUMB_PRESSED_INSIDE)
        {
         //--- Перемещение ползунка слайдера
         OnDragLeftThumb(x);
         //--- Расчёт позиции ползунка слайдера в диапазоне значений
         CalculateLeftThumbPos();
         //--- Установка нового значения в поле ввода
         ChangeLeftValue(m_left_current_pos);
         //--- Обновляем индикатор слайдера
         UpdateIndicator();
         return;
        }
      //--- Если управление передано полосе прокрутки (правому ползунку)
      if(m_clamping_mouse_right_thumb==THUMB_PRESSED_INSIDE)
        {
         //--- Перемещение ползунка слайдера
         OnDragRightThumb(x);
         //--- Расчёт позиции ползунка слайдера в диапазоне значений
         CalculateRightThumbPos();
         //--- Установка нового значения в поле ввода
         ChangeRightValue(m_right_current_pos);
         //--- Обновляем индикатор слайдера
         UpdateIndicator();
         return;
        }
     }
  }

Более подробно Вы можете изучить код класса CDualSlider, загрузив к себе на компьютер файлы, приложенные к статье. 

 


Тест элемента «Двухсторонний слайдер»

Добавим в графический интерфейс тестового приложения один элемент управления «Двухсторонний слайдер». В пользовательском классе приложения CProgram нужно объявить экземпляр его класса (CDualSlider) и метод с отступами от крайней точки формы:

//+------------------------------------------------------------------+
//| Класс для создания приложения                                    |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
   //--- Слайдеры
   CDualSlider       m_dual_slider1;
   //---
private:
   //--- Слайдеры
#define DUALSLIDER1_GAP_X     (32)
#define DUALSLIDER1_GAP_Y     (275)
   bool              CreateDualSlider1(const string text);
  };

В листинге ниже показан код метода CProgram::CreateDualSlider1(). Диапазон значений установим от -2000 до 1000. Доступность элемента будет зависеть от текущего состояния пятого чекбокса, как и в случае с обычным слайдером, который был создан ранее в этой статье.

//+------------------------------------------------------------------+
//| Создаёт двойной слайдер 1                                        |
//+------------------------------------------------------------------+
bool CProgram::CreateDualSlider1(const string text)
  {
//--- Сохраним указатель на окно
   m_dual_slider1.WindowPointer(m_window1);
//--- Координаты
   int x=m_window1.X()+DUALSLIDER1_GAP_X;
   int y=m_window1.Y()+DUALSLIDER1_GAP_Y;
//--- Значения
   double v1=(m_dual_slider1.GetLeftValue()==WRONG_VALUE) ? 0 : m_dual_slider1.GetLeftValue();
   double v2=(m_dual_slider1.GetRightValue()==WRONG_VALUE) ? 500 : m_dual_slider1.GetRightValue();
//--- Установим свойства перед созданием
   m_dual_slider1.XSize(264);
   m_dual_slider1.YSize(40);
   m_dual_slider1.EditXSize(87);
   m_dual_slider1.MaxValue(1000);
   m_dual_slider1.StepValue(1);
   m_dual_slider1.MinValue(-2000);
   m_dual_slider1.SetDigits(0);
   m_dual_slider1.SetLeftValue(v1);
   m_dual_slider1.SetRightValue(v2);
   m_dual_slider1.AreaColor(clrWhiteSmoke);
   m_dual_slider1.LabelColor(clrBlack);
   m_dual_slider1.LabelColorLocked(clrSilver);
   m_dual_slider1.EditColorLocked(clrWhiteSmoke);
   m_dual_slider1.EditBorderColor(clrSilver);
   m_dual_slider1.EditBorderColorLocked(clrSilver);
   m_dual_slider1.EditTextColorLocked(clrSilver);
   m_dual_slider1.SlotLineDarkColor(clrSilver);
   m_dual_slider1.SlotLineLightColor(clrWhite);
   m_dual_slider1.SlotYSize(4);
   m_dual_slider1.ThumbColorLocked(clrLightGray);
   m_dual_slider1.ThumbColorPressed(clrSilver);
   m_dual_slider1.SlotIndicatorColor(C'85,170,255');
   m_dual_slider1.SlotIndicatorColorLocked(clrLightGray);
//--- Создадим элемент управления
   if(!m_dual_slider1.CreateSlider(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- Доступность будет зависеть от текущего состояния пятого чекбокса
   m_dual_slider1.SliderState(m_checkbox5.CheckButtonState());
//--- Добавим объект в общий массив групп объектов
   CWndContainer::AddToElementsArray(0,m_dual_slider1);
   return(true);
  }

Не забываем разместить вызов метода нового элемента управления в главном методе создания графического интерфейса, как это показано в сокращённой версии метода в листинге кода ниже. 

//+------------------------------------------------------------------+
//| Создаёт торговую панель                                          |
//+------------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Создание формы 1 для элементов управления
//--- Создание элементов управления:
//    Главное меню
//--- Контекстные меню
//--- Создание статусной строки
//--- Чек-боксы
//--- Слайдеры
   if(!CreateDualSlider1("Dual Slider 1:"))
      return(false);
//--- Перерисовка графика
   m_chart.Redraw();
   return(true);
  }

Теперь от текущего состояния пятого чекбокса будет зависеть два элемента управления: обычный слайдер и двухсторонний слайдер.

//+------------------------------------------------------------------+
//| Обработчик событий                                               |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Событие нажатия на текстовой метке
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Если нажали на пятом чекбоксе
      if(lparam==m_checkbox5.Id())
        {
         //--- Установить состояние слайдерам
         m_slider1.SliderState(m_checkbox5.CheckButtonState());
         m_dual_slider1.SliderState(m_checkbox5.CheckButtonState());
        }
     }
//--- Событие окончания ввода значения в поле ввода
   if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
  }

Осталось скомпилировать программу и загрузить её на график. На скриншоте ниже Вы можете увидеть результат проделанной работы:

 Рис. 4. Тест элемента управления «Двухсторонний слайдер».

Рис. 4. Тест элемента управления «Двухсторонний слайдер».

 


Заключение

В шестой части серии мы рассмотрели шесть элементов управления:

  • Чекбокс.
  • Поле ввода.
  • Поле ввода с чекбоксом.
  • Комбобокс с чекбоксом.
  • Слайдер.
  • Двухсторонний слайдер.

На текущем этапе разработки библиотеки для создания графических интерфейсов её схема выглядит так:

 Рис. 5. Структура библиотеки на текущей стадии разработки.

Рис. 5. Структура библиотеки на текущей стадии разработки.


В следующей (седьмой) части серии пополним разрабатываемую библиотеку таблицами и вкладками.

Ниже вы можете загрузить к себе на компьютер весь материал шестой части серии, чтобы у Вас сразу была возможность протестировать, как всё это работает. Если у Вас возникают вопросы по использованию материала предоставленного в этих файлах, то Вы можете обратиться к подробному описанию процесса разработки библиотеки в одной из статей в представленном списке ниже или задать вопрос в комментариях к статье.

Список статей (глав) шестой части:


Прикрепленные файлы |
Последние комментарии | Перейти к обсуждению на форуме трейдеров (15)
Alexander Bereznyak
Alexander Bereznyak | 3 июн 2016 в 16:45
если за каждую статью 200$, итого 3600$,  не так уж и безвозмездно
Anatoli Kazharski
Anatoli Kazharski | 3 июн 2016 в 17:30
Реter Konow:

...

Так, что счет не сухой... ;) 

Продемонстрировать что-то, ещё не значит забить гол. Если бы я делал только заявления, то "продемонстрировал" бы свои 25 голов уже минимум год назад. В принципе я их демонстрировал, но только в маркете:

 

 

//--- 

Поэтому Ваши голы пока мимо моих ворот. Голом считается только то, что доступно сообществу. 

Текущий счёт 18 : 0 в мою пользу. И это только по количеству статей. Вы ведь со своей стороны начали считать голы в свою пользу по функционалу. А если считать, что я публикую исходники, то один мой гол можно считать за два (минимум).

Поэтому счёт минимум 36 : 0 в мою пользу. 

Если хотите уменьшить количество моих голов до 18 (минимум), то публикуйте исходники. Иначе не знаю теперь, как Вы будете меня догонять. ;)

Artyom Trishkin
Artyom Trishkin | 27 дек 2016 в 08:00

Анатоль, вопрос: будет ли "штатная" возможность переопределять взаимное расположение объектов у составных элементов, а также изменение их размеров?

Например, для того, чтобы компактно упаковать слайдеры в небольшие размеры панели, пришлось менять/дописывать методы слайдера.

Но это не очень практично с точки зрения совместимости с дальнейшими обновлениями.

Anatoli Kazharski
Anatoli Kazharski | 27 дек 2016 в 08:22
Artyom Trishkin:

Анатоль, вопрос: будет ли "штатная" возможность переопределять взаимное расположение объектов у составных элементов, а также изменение их размеров?

Например, для того, чтобы компактно упаковать слайдеры в небольшие размеры панели, пришлось менять/дописывать методы слайдера.


Но это не очень практично с точки зрения совместимости с дальнейшими обновлениями.

Я уже отвечал тебе на этот вопрос.

//---

Но не всё сразу. В первую очередь всё самое важное. Тонкие настройки в последнюю очередь (наименьший приоритет).

Artyom Trishkin
Artyom Trishkin | 27 дек 2016 в 08:25
Anatoli Kazharski:

Я уже отвечал тебе на этот вопрос.

//---

Но не всё сразу. В первую очередь всё самое важное. Тонкие настройки в последнюю очередь (наименьший приоритет).

Эх..., память...
Регулярные выражения для трейдеров Регулярные выражения для трейдеров

Регулярные выражения (англ. regular expressions) — специальный язык для обработки текстов по заданному правилу, которое также называют шаблоном или маской регулярного выражения. В этой статье мы покажем, как обработать торговый отчет с помощью библиотеки RegularExpressions для MQL5, а также продемонстрируем результаты оптимизации с ее использованием.

Графические интерфейсы VI: Элементы "Чекбокс", "Поле ввода" и их смешанные типы (Глава 1) Графические интерфейсы VI: Элементы "Чекбокс", "Поле ввода" и их смешанные типы (Глава 1)

С этой статьи начинается шестая часть серии о разработке библиотеки для создания графических интерфейсов в терминалах MetaTrader. В первой главе речь пойдёт о таких элементах управления, как «чекбокс», «поле ввода», а также о смешанных типах этих элементов.

Создаем помощника в ручной торговле Создаем помощника в ручной торговле

Количество торговых роботов для работы на валютных рынках в последнее время растет как снежный ком. В них закладываются различные концепции и стратегии, но беспроигрышный образец искусственного интеллекта создать еще никому не удалось. Поэтому многие трейдеры остаются приверженцами ручной торговли. Но и для таких специалистов создаются роботизированные помощники, так называемые торговые панели. Данная статья — еще один пример создания торговой панели "с нуля".

Графические интерфейсы VII: Элементы "Таблицы" (Глава 1) Графические интерфейсы VII: Элементы "Таблицы" (Глава 1)

В седьмой части серии статей о графических интерфейсах в терминалах MetaTrader будут представлены три типа таблиц: таблица из текстовых меток, таблица из полей ввода и нарисованная таблица. Ещё один важный и часто используемый элемент управления — вкладки, с помощью которых можно скрывать и делать видимыми группы других элементов управления, что позволяет пользователю делать компактные графические интерфейсы в своих MQL-приложениях.