English 中文 Español Deutsch 日本語 Português
Графические интерфейсы IX: Элемент "Палитра для выбора цвета" (Глава 1)

Графические интерфейсы IX: Элемент "Палитра для выбора цвета" (Глава 1)

MetaTrader 5Примеры | 14 июля 2016, 09:02
3 722 11
Anatoli Kazharski
Anatoli Kazharski

Содержание

 

 

Введение

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

Девятая часть серии расскажет о следующих элементах управления и интерфейса:

1. Первая глава:

  • Элемент «Палитра для выбора цвета» (класс CColorPicker).
  • Элемент «Кнопка для вызова цветовой палитры» (класс CColorButton).

2. Вторая глава:

  • Элемент «Индикатор выполнения» (класс CProgressBar).
  • Элемент «Линейный график» (класс CLineGraph).

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

 

Элемент «Палитра для выбора цвета»

Цветовую палитру можно увидеть во множестве различных приложений, в которых предоставляется возможность указать цвет какого-нибудь объекта. В торговых терминалах MetaTrader цветовая палитра может понадобиться для быстрого изменения цвета элементов в вашем  MQL-приложении. Допустим, при создании визуальной студии для создания графических интерфейсов, когда нужно настроить цветовое решение для каждого элемента, без цветовой палитры это делать было бы довольно неудобно.

Цветовая палитра — это сложный составной элемент управления, в котором, кроме самой палитры, отображающей выбранную цветовую модель, есть и другие объекты и группы элементов. Перечислим все составные части этого элемента.

  1. Фон
  2. Цветовая палитра, отображающая указанную цветовую модель
  3. Маркер установленного цвета
  4. Маркер выбранного цвета
  5. Маркер цвета по наведению курсора мыши
  6. Группа радио-кнопок с полями ввода для ручной настройки компонентов цветовой модели
  7. Кнопка для отмены выбранного цвета
  8. Кнопка для установки (фиксации) цвета, указанного во втором маркере

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

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

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

1. Цветовая модель HSL:

  • H (Hue) – цветовой тон. Диапазон значений от 0 до 360
  • S (Saturation) – насыщенность. Диапазон значений от 0 до 100.
  • L (Lightness) – светлота. Диапазон значений от 0 до 100.

2. Цветовая модель RGB:

  • R (Red) – красный цвет. Диапазон значений от 0 до 255.
  • G (Green) – зелёный цвет. Диапазон значений от 0 до 255.
  • B (Blue) – синий цвет. Диапазон значений от 0 до 255.

3. Цветовая модель Lab:

  • L (Luminance) – яркость. Диапазон значений от 0 до 100.
  • a – первая хроматическая координата, определяющая оттенок цвета от зелёного до пурпурного. Диапазон значений от -128 до 127.
  • b – вторая хроматическая координата, определяющая оттенок цвета от синего до жёлтого. Диапазон значений от -128 до 127.

Далее рассмотрим, как устроен класс CColorPicker для создания цветовой палитры.

 

Разработка класса CColorPicker

Создаём файл ColorPicker.mqh в той же директории, где расположены сейчас файлы всех остальных элементов управления (<каталог данных>\MQLX\Include\EasyAndFastGUI\Controls). В этом файле нужно создать класс CColorPicker со стандартными членами, как показано в листинге кода ниже:

//+------------------------------------------------------------------+
//|                                                  ColorPicker.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
//+------------------------------------------------------------------+
//| Класс для создания цветовой палитры для выбора цвета             |
//+------------------------------------------------------------------+
class CColorPicker : public CElement
  {
private:
   //--- Указатель на форму, к которой элемент присоединён
   CWindow          *m_wnd;
   //---
public:
                     CColorPicker(void);
                    ~CColorPicker(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) {}
  };

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

  • Цвет фона элемента
  • Цвет рамки фона элемента
  • Цвет рамки цветовой палитры и маркеров цвета

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

class CColorPicker : public CElement
  {
private:
   //--- Цвет (1) фона и (2) рамки фона
   color             m_area_color;
   color             m_area_border_color;
   //--- Цвет рамки палитры
   color             m_palette_border_color;
   //---
public:
   //--- Установка цвета (1) фона и (2) рамки фона, (3) рамки палитры
   void              AreaBackColor(const color clr)           { m_area_color=clr;                      }
   void              AreaBorderColor(const color clr)         { m_area_border_color=clr;               }
   void              PaletteBorderColor(const color clr)      { m_palette_border_color=clr;            }
  };

Так как в качестве составных частей цветовой палитры будут использоваться и другие элементы, то к файлу ColorPicker.mqh нужно подключить файлы с классами этих элементов. Для создания цветовой палитры понадобятся семнадцать приватных (private) методов и один публичный (public).

//+------------------------------------------------------------------+
//|                                                  ColorPicker.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
#include "SpinEdit.mqh"
#include "SimpleButton.mqh"
#include "RadioButtons.mqh"
//+------------------------------------------------------------------+
//| Класс для создания цветовой палитры             |
//+------------------------------------------------------------------+
class CColorPicker : public CElement
  {
private:
   //--- Объекты для создания элемента
   CRectLabel        m_area;
   CRectCanvas       m_canvas;
   CRectLabel        m_current;
   CRectLabel        m_picked;
   CRectLabel        m_hover;
   //---
   CRadioButtons     m_radio_buttons;
   CSpinEdit         m_hsl_h_edit;
   CSpinEdit         m_hsl_s_edit;
   CSpinEdit         m_hsl_l_edit;
   //---
   CSpinEdit         m_rgb_r_edit;
   CSpinEdit         m_rgb_g_edit;
   CSpinEdit         m_rgb_b_edit;
   //---
   CSpinEdit         m_lab_l_edit;
   CSpinEdit         m_lab_a_edit;
   CSpinEdit         m_lab_b_edit;
   //---
   CSimpleButton     m_button_ok;
   CSimpleButton     m_button_cancel;
   //---
public:
   //--- Методы для создания элемента
   bool              CreateColorPicker(const long chart_id,const int subwin,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreatePalette(void);
   bool              CreateCurrentSample(void);
   bool              CreatePickedSample(void);
   bool              CreateHoverSample(void);
   bool              CreateRadioButtons(void);
   bool              CreateHslHEdit(void);
   bool              CreateHslSEdit(void);
   bool              CreateHslLEdit(void);
   bool              CreateRgbREdit(void);
   bool              CreateRgbGEdit(void);
   bool              CreateRgbBEdit(void);
   bool              CreateLabLEdit(void);
   bool              CreateLabAEdit(void);
   bool              CreateLabBEdit(void);
   bool              CreateButtonOK(const string text);
   bool              CreateButtonCancel(const string text);
  };

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

Для преобразования цвета мы используем методы экземпляра класса CColors, который объявлен в базовом классе элемента (CElement). Для конвертации из формата RGB в формат Lab в классе CColors нет подходящего метода. Поэтому, там где нужна конвертация RGB->Lab, будет использоваться двойное преобразование через цветовую мастер-модель XYZ, то есть: RGB->XYZ->Lab. Для расчётов и хранения значений компонент всех цветовых моделей в классе CColorPicker нужно объявить соответствующие поля.

class CColorPicker : public CElement
  {
private:
   //--- Значения компонентов в разных цветовых моделях:
   //    HSL
   double            m_hsl_h;
   double            m_hsl_s;
   double            m_hsl_l;
   //--- RGB
   double            m_rgb_r;
   double            m_rgb_g;
   double            m_rgb_b;
   //--- Lab
   double            m_lab_l;
   double            m_lab_a;
   double            m_lab_b;
   //--- XYZ
   double            m_xyz_x;
   double            m_xyz_y;
   double            m_xyz_z;
   //---
private:
   //--- Рисует палитру по цветовой модели HSL (0: H, 1: S, 2: L)
   void              DrawHSL(const int index);
   //--- Рисует палитру по цветовой модели RGB (3: R, 4: G, 5: B)
   void              DrawRGB(const int index);
   //--- Рисует палитру по цветовой модели LAB (6: L, 7: a, 8: b)
   void              DrawLab(const int index);
  };

В качестве примера приведём здесь код только одного из этих методов - CColorPicker::DrawHSL(), так как отличие между ними состоит только в предварительном расчёте значения компонент перед преобразованием. С кодом остальных методов вы можете ознакомиться в приложенных к статье файлах. 

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

 Рис. 2. Пример цветовой палитры с размером 500x255 пикселей.

Рис. 2. Пример цветовой палитры с размером 500x255 пикселей. 


//+------------------------------------------------------------------+
//| Рисует палитру HSL                                               |
//+------------------------------------------------------------------+
void CColorPicker::DrawHSL(const int index)
  {
   switch(index)
     {
      //--- Hue (H) - цветовой тон в диапазоне от 0 до 360
      case 0 :
        {
         //--- Рассчитаем H-компоненту
         m_hsl_h=m_hsl_h_edit.GetValue()/360.0;
         //---
         for(int ly=0; ly<m_canvas.YSize(); ly++)
           {
            //--- Рассчитаем L-компоненту
            m_hsl_l=ly/(double)m_canvas.YSize();
            //---
            for(int lx=0; lx<m_canvas.XSize(); lx++)
              {
               //--- Рассчитаем S-компоненту
               m_hsl_s=lx/(double)m_canvas.XSize();
               //--- Конвертация HSL-компонент в RGB-компоненты
               m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b);
               //--- Соединим каналы
               uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b);
               m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color);
              }
           }
         break;
        }
      //--- Saturation (S) - насыщенность в диапазоне от 0 до 100
      case 1 :
        {
         //--- Рассчитаем S-компоненту
         m_hsl_s=m_hsl_s_edit.GetValue()/100.0;
         //---
         for(int ly=0; ly<m_canvas.YSize(); ly++)
           {
            //--- Рассчитаем L-компоненту
            m_hsl_l=ly/(double)m_canvas.YSize();
            //---
            for(int lx=0; lx<m_canvas.XSize(); lx++)
              {
               //--- Рассчитаем H-компоненту
               m_hsl_h=lx/(double)m_canvas.XSize();
               //--- Конвертация HSL-компонент в RGB-компоненты
               m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b);
               //--- Соединим каналы
               uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b);
               m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color);
              }
           }
         break;
        }
      //--- Lightness (L) - яркость в диапазоне от 0 до 100
      case 2 :
        {
         //--- Рассчитаем L-компоненту
         m_hsl_l=m_hsl_l_edit.GetValue()/100.0;
         //---
         for(int ly=0; ly<m_canvas.YSize(); ly++)
           {
            //--- Рассчитаем S-компоненту
            m_hsl_s=ly/(double)m_canvas.YSize();
            //---
            for(int lx=0; lx<m_canvas.XSize(); lx++)
              {
               //--- Рассчитаем H-компоненту
               m_hsl_h=lx/(double)m_canvas.XSize();
               //--- Конвертация HSL-компонент в RGB-компоненты
               m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b);
               //--- Соединим каналы
               uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b);
               m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color);
              }
           }
         break;
        }
     }
  }

Для рисования рамки на полотне цветовой палитры напишем метод CColorPicker::DrawPaletteBorder(): 

class CColorPicker : public CElement
  {
private:
   //--- Рисует рамку палитры
   void              DrawPaletteBorder(void);
  };
//+------------------------------------------------------------------+
//| Рисует рамку палитры                                             |
//+------------------------------------------------------------------+
void CColorPicker::DrawPaletteBorder(void)
  {
//--- Размер палитры
   int x_size=m_canvas.XSize()-1;
   int y_size=m_canvas.YSize()-1;
//--- Нарисовать рамку
   m_canvas.Line(0,0,x_size,0,m_palette_border_color);
   m_canvas.Line(0,y_size,x_size,y_size,m_palette_border_color);
   m_canvas.Line(0,0,0,y_size,m_palette_border_color);
   m_canvas.Line(x_size,0,x_size,y_size,m_palette_border_color);
  }

Все перечисленные методы для рисования в итоге будут вызываться в главном методе для рисования цветовой палитры CColorPicker::DrawPalette():

class CColorPicker : public CElement
  {
private:
   //--- Рисует палитру
   void              DrawPalette(const int index);
  };
//+------------------------------------------------------------------+
//| Рисует палитру                                                   |
//+------------------------------------------------------------------+
void CColorPicker::DrawPalette(const int index)
  {
   switch(index)
     {
      //--- HSL (0: H, 1: S, 2: L)
      case 0 : case 1 : case 2 :
        {
         DrawHSL(index);
         break;
        }
      //--- RGB (3: R, 4: G, 5: B)
      case 3 : case 4 : case 5 :
        {
         DrawRGB(index);
         break;
        }
      //--- LAB (6: L, 7: a, 8: b)
      case 6 : case 7 : case 8 :
        {
         DrawLab(index);
         break;
        }
     }
//--- Нарисуем рамку палитры
   DrawPaletteBorder();
//--- Обновим палитру
   m_canvas.Update();
  }

При выборе цвета на палитре или во время настройки той или иной компоненты любой из представленных в элементе цветовых моделей, автоматически будут пересчитываться значения во всех полях ввода. Нужны методы, с помощью которых будут рассчитываться компоненты всех цветовых моделей элемента относительно той, чей срез (выделенная радио-кнопка) отображается на палитре в текущий момент. 

Прежде всего, для работы понадобятся методы корректировки компонент RGB- и HSL-моделей, которые будут вызываться во многих других методах класса:

class CColorPicker : public CElement
  {
private:
   //--- Корректировка компонент RGB
   void              AdjustmentComponentRGB(void);
   //--- Корректировка компонент HSL
   void              AdjustmentComponentHSL(void);
  };
//+------------------------------------------------------------------+
//| Корректировка компонент RGB                                      |
//+------------------------------------------------------------------+
void CColorPicker::AdjustmentComponentRGB(void)
  {
   m_rgb_r=::fmin(::fmax(m_rgb_r,0),255);
   m_rgb_g=::fmin(::fmax(m_rgb_g,0),255);
   m_rgb_b=::fmin(::fmax(m_rgb_b,0),255);
  }
//+------------------------------------------------------------------+
//| Корректировка компонент HSL                                      |
//+------------------------------------------------------------------+
void CColorPicker::AdjustmentComponentHSL(void)
  {
   m_hsl_h*=360;
   m_hsl_s*=100;
   m_hsl_l*=100;
  }

После расчёта всех компонент нужно установить новые значения в поля вода элемента. В некоторых случаях может понадобится (1) установить значения всех компонент, а иногда (2) для всех, кроме выделенной в текущий момент. Для таких ситуаций напишем метод CColorPicker::SetControls(), который может работать в двух режимах.

class CColorPicker : public CElement
  {
private:
   //--- Установка текущих параметров в поля ввода
   void              SetControls(const int index,const bool fix_selected);
  };
//+------------------------------------------------------------------+
//| Установка текущих параметров в поля ввода                        |
//+------------------------------------------------------------------+
void CColorPicker::SetControls(const int index,const bool fix_selected)
  {
//--- Если нужно зафиксировать значение в поле ввода выделенной радио-кнопки
   if(fix_selected)
     {
      //--- Компоненты HSL
      if(index!=0)
         m_hsl_h_edit.ChangeValue(m_hsl_h);
      if(index!=1)
         m_hsl_s_edit.ChangeValue(m_hsl_s);
      if(index!=2)
         m_hsl_l_edit.ChangeValue(m_hsl_l);
      //--- Компоненты RGB
      if(index!=3)
         m_rgb_r_edit.ChangeValue(m_rgb_r);
      if(index!=4)
         m_rgb_g_edit.ChangeValue(m_rgb_g);
      if(index!=5)
         m_rgb_b_edit.ChangeValue(m_rgb_b);
      //--- Компоненты Lab
      if(index!=6)
         m_lab_l_edit.ChangeValue(m_lab_l);
      if(index!=7)
         m_lab_a_edit.ChangeValue(m_lab_a);
      if(index!=8)
         m_lab_b_edit.ChangeValue(m_lab_b);
      return;
     }
//--- Если нужно скорректировать значения в полях ввода всех цветовых моделей
   m_hsl_h_edit.ChangeValue(m_hsl_h);
   m_hsl_s_edit.ChangeValue(m_hsl_s);
   m_hsl_l_edit.ChangeValue(m_hsl_l);
//---
   m_rgb_r_edit.ChangeValue(m_rgb_r);
   m_rgb_g_edit.ChangeValue(m_rgb_g);
   m_rgb_b_edit.ChangeValue(m_rgb_b);
//---
   m_lab_l_edit.ChangeValue(m_lab_l);
   m_lab_a_edit.ChangeValue(m_lab_a);
   m_lab_b_edit.ChangeValue(m_lab_b);
  }

Для расчёта компонент всех цветовых моделей элемента, относительно той, чей срез (выделенная радио-кнопка) отображается на палитре в текущий момент, напишем три отдельных метода: CColorPicker::SetHSL(), CColorPicker::SetRGB() и CColorPicker::SetLab(). Так как эти методы очень похожи по своему содержанию, приведём здесь код только одного из них — CColorPicker::SetRGB(). В самом начале этого метода получаем в поля класса значения из полей ввода RGB-модели. Полученные значения преобразовываем в HSL- и Lab-формат. После этого в самом конце вызываем метод CColorPicker::SetControls() в режиме установки значений для всех цветовых моделей элемента (false). 

class CColorPicker : public CElement
  {
private:
   //--- Установка параметров цветовых моделей относительно (1) HSL, (2) RGB, (3) Lab
   void              SetHSL(void);
   void              SetRGB(void);
   void              SetLab(void);
  };
//+------------------------------------------------------------------+
//| Установка параметров цветовых моделей относительно RGB           |
//+------------------------------------------------------------------+
void CColorPicker::SetRGB(void)
  {
//--- Получим текущие значения компонентов RGB
   m_rgb_r=m_rgb_r_edit.GetValue();
   m_rgb_g=m_rgb_g_edit.GetValue();
   m_rgb_b=m_rgb_b_edit.GetValue();
//--- Конвертация RGB-компонент в HSL-компоненты
   m_clr.RGBtoHSL(m_rgb_r,m_rgb_g,m_rgb_b,m_hsl_h,m_hsl_s,m_hsl_l);
//--- Корректировка компонент HSL
   AdjustmentComponentHSL();
//--- Конвертация RGB-компонент в Lab-компоненты
   m_clr.RGBtoXYZ(m_rgb_r,m_rgb_g,m_rgb_b,m_xyz_x,m_xyz_y,m_xyz_z);
   m_clr.XYZtoCIELab(m_xyz_x,m_xyz_y,m_xyz_z,m_lab_l,m_lab_a,m_lab_b);
//--- Установка текущих параметров в поля ввода
   SetControls(0,false);
  }

И, наконец, нужен главный метод, в котором будут вызваться все вышеперечисленные методы для расчётов, отрисовки и установки значений компонент в поля ввода элемента. Здесь это метод CColorPicker::SetComponents(). Он тоже работает в двух режимах. В случае, если аргумент fix_selected равен true, то компоненты будут рассчитываться относительно выбранного цвета, а установка значений в поля ввода будет относительно выделенного радио-кнопкой компонента. Если же аргумент fix_selected равен false, то расчет идет относительно указанной цветовой модели. После всех расчётов цветовая палитра перерисовывается

class CColorPicker : public CElement
  {
private:
   //--- Расчёт и установка компонентов цвета
   void              SetComponents(const int index,const bool fix_selected);
  };
//+------------------------------------------------------------------+
//| Расчёт и установка компонентов цвета                             |
//+------------------------------------------------------------------+
void CColorPicker::SetComponents(const int index=0,const bool fix_selected=true)
  {
//--- Если нужно скорректировать цвета относительно выделенного радио-кнопкой компонента
   if(fix_selected)
     {
      //--- Разложим на RGB-компоненты выбранный цвет
      m_rgb_r=m_clr.GetR(m_picked_color);
      m_rgb_g=m_clr.GetG(m_picked_color);
      m_rgb_b=m_clr.GetB(m_picked_color);
      //--- Конвертируем RGB-компоненты в HSL-компоненты
      m_clr.RGBtoHSL(m_rgb_r,m_rgb_g,m_rgb_b,m_hsl_h,m_hsl_s,m_hsl_l);
      //--- Корректировка компонент HSL
      AdjustmentComponentHSL();
      //--- Конвертируем RGB-компоненты в LAB-компоненты
      m_clr.RGBtoXYZ(m_rgb_r,m_rgb_g,m_rgb_b,m_xyz_x,m_xyz_y,m_xyz_z);
      m_clr.XYZtoCIELab(m_xyz_x,m_xyz_y,m_xyz_z,m_lab_l,m_lab_a,m_lab_b);
      //--- Установим цвета в поля ввода
      SetControls(m_radio_buttons.SelectedButtonIndex(),true);
      return;
     }
//--- Установка параметров цветовых моделей
   switch(index)
     {
      case 0 : case 1 : case 2 :
         SetHSL();
         break;
      case 3 : case 4 : case 5 :
         SetRGB();
         break;
      case 6 : case 7 : case 8 :
         SetLab();
         break;
     }
//--- Нарисовать палитру относительно выделенной радио-кнопки
   DrawPalette(m_radio_buttons.SelectedButtonIndex());
  }

Для установки текущего цвета палитры, который будет присваиваться сразу всем объектам-маркерам, напишем метод CColorPicker::CurrentColor(). Далее в статье будет показано, где он будет использоваться. 

class CColorPicker : public CElement
  {
public:
   //--- Установка цвета выбранного пользователем цвета на палитре
   void              CurrentColor(const color clr);
  };
//+------------------------------------------------------------------+
//| Установка текущего цвета                                         |
//+------------------------------------------------------------------+
void CColorPicker::CurrentColor(const color clr)
  {
   m_hover_color=clr;
   m_hover.Color(clr);
   m_hover.BackColor(clr);
   m_hover.Tooltip(::ColorToString(clr));
//---
   m_picked_color=clr;
   m_picked.Color(clr);
   m_picked.BackColor(clr);
   m_picked.Tooltip(::ColorToString(clr));
//---
   m_current_color=clr;
   m_current.BackColor(clr);
   m_current.Tooltip(::ColorToString(clr));
  }

Все методы для расчётов готовы. Перейдем к методам обработки событий элемента.

 

Методы для обработки событий элемента

Для обработки событий и управления цветовой палитрой понадобятся следующие методы:

  • Метод CColorPicker::OnHoverColor() — получение цвета (над палитрой) под курсором мыши. Программа выходит из метода, если курсор мыши вне области палитры. Если же курсор в её области, то определяем его координаты над ней и получаем цвет под курсором. Сразу же после этого новый цвет устанавливается предназначенному для этого маркеру, а с помощью метода ColorToString() графическим объектам маркера и цветовой палитре устанавливается всплывающая подсказка – строка цвета в формате RGB

//+------------------------------------------------------------------+
//| Получение цвета под курсором мыши                                |
//+------------------------------------------------------------------+
bool CColorPicker::OnHoverColor(const int x,const int y)
  {
//--- Выйти, если фокус не на палитре
   if(!m_canvas.MouseFocus())
      return(false);
//--- Определим цвет на палитре под курсором мыши
   int lx =x-m_canvas.X();
   int ly =y-m_canvas.Y();
   m_hover_color=(color)::ColorToARGB(m_canvas.PixelGet(lx,ly),0);
//--- Установим цвет и всплывающую подсказку в соответствующий образец (маркер)
   m_hover.Color(m_hover_color);
   m_hover.BackColor(m_hover_color);
   m_hover.Tooltip(::ColorToString(m_hover_color));
//--- Установим всплывающую подсказку палитре
   m_canvas.Tooltip(::ColorToString(m_hover_color));
   return(true);
  }

  • Метод CColorPicker::OnClickPalette() — обработка нажатия на цветовой палитре. В начале метода стоит проверка на имя объекта. Если нажатие было на палитре, то сохраняется и устанавливается цвет, который находится под курсором мыши, а также всплывающая подсказка для соответствующего маркера. В самом конце вызывается метод CColorPicker::SetComponents() для расчёта и установки компонентов цветовых моделей, относительно выделенного радио-кнопкой компонента.

//+------------------------------------------------------------------+
//| Обработка нажатия на цветовой палитре                            |
//+------------------------------------------------------------------+
bool CColorPicker::OnClickPalette(const string clicked_object)
  {
//--- Выйти, если имя объекта не совпадает
   if(clicked_object!=m_canvas.Name())
      return(false);
//--- Установим цвет и всплывающую подсказку в соответствующий образец (маркер)
   m_picked_color=m_hover_color;
   m_picked.Color(m_picked_color);
   m_picked.BackColor(m_picked_color);
   m_picked.Tooltip(::ColorToString(m_picked_color));
//--- Рассчитаем и установим компоненты цвета относительно выделенной радио-кнопки
   SetComponents();
   return(true);
  }

  • Метод CColorPicker::OnClickRadioButton() — обработка нажатия на радио-кнопке. Здесь сначала нужно пройти две проверки: (1) по идентификатору элемента и (2) по отображаемому тексту радио-кнопки. Если проверки пройдены, то цветовая палитра перерисовывается относительно выделенного компонента цветовой модели, которой он принадлежит.

//+------------------------------------------------------------------+
//| Обработка нажатия на радио-кнопке                                |
//+------------------------------------------------------------------+
bool CColorPicker::OnClickRadioButton(const long id,const int button_index,const string button_text)
  {
//--- Выйти, если идентификаторы не совпадают
   if(id!=CElement::Id())
      return(false);
//--- Выйти, если текст радио-кнопки не совпадает
   if(button_text!=m_radio_buttons.SelectedButtonText())
      return(false);
//--- Обновить палитру с учётом последних изменений
   DrawPalette(button_index);
   return(true);
  }

  • Метод CColorPicker::OnEndEdit() — обработка ввода нового значения в поле ввода. Здесь достаточно только одной проверки — по идентификатору элемента, после прохождения которой осуществляется расчёт компонентов всех цветовых моделей относительно той, радио-кнопка компонента которой сейчас выделена. 

//+------------------------------------------------------------------+
//| Обработка ввода нового значения в поле ввода                     |
//+------------------------------------------------------------------+
bool CColorPicker::OnEndEdit(const long id,const int button_index)
  {
//--- Выйти, если идентификаторы не совпадают
   if(id!=CElement::Id())
      return(false);
//--- Рассчитаем и установим компоненты цвета для всех цветовых моделей 
   SetComponents(button_index,false);
   return(true);
  }

  • Метод CColorPicker::OnClickButtonOK() — обработка нажатия на кнопке 'OK'. Это не окончательная версия метода, и далее в статье в него будет внесено небольшое дополнение. Единственное, что сейчас нужно знать, — то, что при нажатии на кнопку выбранный цвет сохраняется как текущий.  

//+------------------------------------------------------------------+
//| Обработка нажатия на кнопке 'OK'                                 |
//+------------------------------------------------------------------+
bool CColorPicker::OnClickButtonOK(const string clicked_object)
  {
//--- Выйти, если имя объекта не совпадает
   if(clicked_object!=m_button_ok.Text())
      return(false);
//--- Сохранить выбранный цвет
   m_current_color=m_picked_color;
   m_current.BackColor(m_current_color);
   m_current.Tooltip(::ColorToString(m_current_color));
   return(true);
  }

  • Метод CColorPicker::OnClickButtonCancel() — обработка нажатия на кнопке 'Cancel'. В этом методе только одна проверка по имени объекта. Затем, если форма, к которой присоединён элемент, имеет тип «диалоговое окно», то оно закрывается

//+------------------------------------------------------------------+
//| Обработка нажатия на кнопке 'Cancel'                             |
//+------------------------------------------------------------------+
bool CColorPicker::OnClickButtonCancel(const string clicked_object)
  {
//--- Выйти, если имя объекта не совпадает
   if(clicked_object!=m_button_cancel.Text())
      return(false);
//--- Закроем окно, если оно диалоговое
   if(m_wnd.WindowType()==W_DIALOG)
      m_wnd.CloseDialogBox();
//---
   return(true);
  }

Всего в обработчике событий цветовой палитры CColorPicker::OnEvent() будет шесть блоков. Каждый метод из списка выше будет вызываться по приходу предназначенного для него идентификатора события. Полный код обработчика событий элемента можно подробнее изучить в листинге кода ниже:

//+------------------------------------------------------------------+
//| Обработчик события графика                                       |
//+------------------------------------------------------------------+
void CColorPicker::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_canvas.MouseFocus(x>m_canvas.X() && x<m_canvas.X2()-1 && y>m_canvas.Y() && y<m_canvas.Y2()-1);
      //--- Получение цвета под курсором мыши
      if(OnHoverColor(x,y))
         return;
      //---
      return;
     }
//--- Обработка события нажатия левой кнопки мыши на объекте
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Если нажали на палитре
      if(OnClickPalette(sparam))
         return;
      //---
      return;
     }
//--- Обработка ввода значения в поле ввода
   if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
     {
      //--- Проверка ввода нового значения
      if(OnEndEdit(lparam,(int)dparam))
         return;
      //---
      return;
     }
//--- Обработка нажатия на элементе
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      //--- Если нажали на радио-кнопке
      if(OnClickRadioButton(lparam,(int)dparam,sparam))
         return;
      //---
      return;
     }
//--- Обработка нажатия на переключателях полей ввода
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC || id==CHARTEVENT_CUSTOM+ON_CLICK_DEC)
     {
      //--- Проверка ввода нового значения
      if(OnEndEdit(lparam,(int)dparam))
         return;
      //---
      return;
     }
//--- Обработка нажатия на кнопке элемента
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     {
      //--- Выйти, если идентификаторы не совпадают
      if(lparam!=CElement::Id())
         return;
      //--- Если нажали на кнопке "OK"
      if(OnClickButtonOK(sparam))
         return;
      //--- Если нажали на кнопке "CANCEL"
      if(OnClickButtonCancel(sparam))
         return;
      //---
      return;
     }
  }

Во многих элементах разрабатываемой библиотеки есть метод FastSwitching(). Обычно он используется для быстрой перемотки значений в полях ввода, прокрутки списков или таблиц. Однако здесь он нужен для перерисовки цветовой палитры, когда активирована перемотка того или иного счётчика поля ввода компонента. С кодом метода CColorPicker::FastSwitching() можно ознакомиться в приложенных к статье файлах.

 

 

Кнопка для вызова цветовой панели

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

  1. Фон элемента
  2. Текстовая метка с описанием
  3. Индикатор выбранного цвета
  4. Фон кнопки
  5. Описание выбранного цвета в формате RGB

 Рис. 3. Составные части кнопки для вызова цветовой палитры.

Рис. 3. Составные части кнопки для вызова цветовой палитры.


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

Нам нужно связать цветовую палитру с кнопкой для её вызова. Сделаем это через указатель кнопки, который будет храниться в классе CColorPicker. Для этого подключим файл ColorButton.mqh к файлу ColorPicker.mqh и объявим экземпляр класса CColorButton, в котором будет сохраняться указатель на кнопку для вызова цветовой палитры.

//+------------------------------------------------------------------+
//|                                                  ColorPicker.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
#include "SpinEdit.mqh"
#include "SimpleButton.mqh"
#include "RadioButtons.mqh"
#include "ColorButton.mqh"
//+------------------------------------------------------------------+
//| Класс для создания цветовой палитры для выбора цвета             |
//+------------------------------------------------------------------+
class CColorPicker : public CElement
  {
private:
   //--- Указатель на кнопку, вызывающую элемент для выбора цвета
   CColorButton     *m_color_button;
  };

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

class CColorPicker : public CElement
  {
public:
   //--- Сохраняет указатель на кнопку, вызывающую цветовую палитру
   void              ColorButtonPointer(CColorButton &object);
  };
//+------------------------------------------------------------------+
//| Сохраняет указатель на кнопку, вызывающую цветовую палитру и      |
//| открывает окно, к которому палитра присоединена                  |
//+------------------------------------------------------------------+
void CColorPicker::ColorButtonPointer(CColorButton &object)
  {
//--- Сохранить указатель на кнопку
   m_color_button=::GetPointer(object);
//--- Установим цвет переданной кнопки всем маркерам палитры
   CurrentColor(object.CurrentColor());
//--- Откроем окно, к которому присоединена палитра
   m_wnd.Show();
  }

Кроме этого, нам понадобятся методы для установки и получения цвета кнопки. Установленный цвет будет отображаться на маркере (индикаторе) кнопки, а в качестве дополнительной информации в содержании текста кнопки отображается строковое представление цвета в RGB-формате.

class CColorButton : public CElement
  {
public:
   //--- Возвращает/устанавливает текущий цвет параметра
   color             CurrentColor(void)                 const { return(m_current_color);       }
   void              CurrentColor(const color clr);
  };
//+------------------------------------------------------------------+
//| Изменяет текущий цвет параметра                                  |
//+------------------------------------------------------------------+
void CColorButton::CurrentColor(const color clr)
  {
   m_current_color=clr;
   m_button_icon.BackColor(clr);
   m_button_label.Description(::ColorToString(clr));
  }

И ещё одно небольшое дополнение добавляется в метод CColorPicker::OnClickButtonOK(). Если указатель на кнопку установлен, то:

  • кнопке устанавливается выбранный на палитре цвет;
  • окно, к которому присоединена цветовая палитра, закрывается;
  • генерируется сообщение о том, что в палитре выбран новый цвет. Здесь понадобится новый идентификатор события ON_CHANGE_COLOR, находящийся в файле Defines.mqh. Также в этом сообщении будет содержаться (1) идентификатор элемента, (2) индекс элемента и (3) текст кнопки, которая вызвала цветовую палитру. Таким образом, в обработчике пользовательского класса можно будет понять, к какой кнопке относится это сообщение, что позволит правильно обработать событие;
  • указатель на кнопку обнуляется. 

Если же указателя на кнопку нет, то разработчику MQL-приложения в журнал терминала будет выведено сообщение с подсказкой.  

//+------------------------------------------------------------------+
//| Обработка нажатия на кнопке 'OK'                                 |
//+------------------------------------------------------------------+
bool CColorPicker::OnClickButtonOK(const string clicked_object)
  {
//--- Выйти, если имя объекта не совпадает
   if(clicked_object!=m_button_ok.Text())
      return(false);
//--- Сохранить выбранный цвет
   m_current_color=m_picked_color;
   m_current.BackColor(m_current_color);
   m_current.Tooltip(::ColorToString(m_current_color));
//--- Если есть указатель кнопки вызова окна для выбора цвета
   if(::CheckPointer(m_color_button)!=POINTER_INVALID)
     {
      //--- Установим кнопке выбранный цвет
      m_color_button.CurrentColor(m_current_color);
      //--- Закроем окно
      m_wnd.CloseDialogBox();
      //--- Отправим сообщение об этом
      ::EventChartCustom(m_chart_id,ON_CHANGE_COLOR,CElement::Id(),CElement::Index(),m_color_button.LabelText());
      //--- Обнулим указатель
      m_color_button=NULL;
     }
   else
     {
      //--- Если указателя нет и окно диалоговое,
      //    вывести сообщение, что нет указателя на кнопку для вызова элемента
      if(m_wnd.WindowType()==W_DIALOG)
         ::Print(__FUNCTION__," > Невалидный указатель вызывающего элемента (CColorButton).");
     }
//---
   return(true);
  }

Теперь у нас всё готово для того, чтобы протестировать цветовую палитру. 

 

Тест элементов

Для теста может быть использован любой эксперт из предыдущей статьи. Сделаем копию и оставим в нём только главное меню и статусную строку. В главном окне (W_MAIN) графического интерфейса создадим пять кнопок для вызова диалогового окна (W_DIALOG) с цветовой палитрой. Другими словами, достаточно создать одну цветовую палитру на всё MQL-приложение. Каждый раз при нажатии на кнопку вызова диалогового окна с цветовой палитрой будет вызываться одно и то же окно. Но указатель кнопки в момент вызова нужно передавать в класс CColorPicker самостоятельно. Далее будет показано, как это должно быть реализовано в пользовательском классе приложения.

В пользовательском классе CProgram нужно объявить экземпляры классов для создания ещё одного окна (CWindow), пяти кнопок для вызова цветовой палитры (CColorButton) и цветовую палитру (CColorPicker), а также методы для их создания с отступами от крайней точки формы.

class CProgram : public CWndEvents
  {
private:
   //--- Форма 2 - окно с цветовой палитрой для выбора цвета
   CWindow           m_window2;
   //--- Кнопки для вызова окна с цветовой палитрой
   CColorButton      m_color_button1;
   CColorButton      m_color_button2;
   CColorButton      m_color_button3;
   CColorButton      m_color_button4;
   CColorButton      m_color_button5;
   //--- Цветовая палитра
   CColorPicker      m_color_picker;
   //---
private:
   //--- Форма 2
   bool              CreateWindow2(const string text);
   //--- Кнопки для вызова цветовой палитры
#define COLORBUTTON1_GAP_X    (7)
#define COLORBUTTON1_GAP_Y    (50)
   bool              CreateColorButton1(const string text);
#define COLORBUTTON2_GAP_X    (7)
#define COLORBUTTON2_GAP_Y    (75)
   bool              CreateColorButton2(const string text);
#define COLORBUTTON3_GAP_X    (7)
#define COLORBUTTON3_GAP_Y    (100)
   bool              CreateColorButton3(const string text);
#define COLORBUTTON4_GAP_X    (7)
#define COLORBUTTON4_GAP_Y    (125)
   bool              CreateColorButton4(const string text);
#define COLORBUTTON5_GAP_X    (7)
#define COLORBUTTON5_GAP_Y    (150)
   bool              CreateColorButton5(const string text);
   //--- Цветовая палитра
#define COLORPICKER_GAP_X     (1)
#define COLORPICKER_GAP_Y     (20)
   bool              CreateColorPicker(void);
  };

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

//+------------------------------------------------------------------+
//| Создаёт кнопку для вызова цветовой палитры 1                     |
//+------------------------------------------------------------------+
bool CProgram::CreateColorButton1(const string text)
  {
//--- Сохраним указатель на окно
   m_color_button1.WindowPointer(m_window1);
//--- Координаты
   int x=m_window1.X()+COLORBUTTON1_GAP_X;
   int y=m_window1.Y()+COLORBUTTON1_GAP_Y;
//--- Установим свойства перед созданием
   m_color_button1.XSize(195);
   m_color_button1.YSize(18);
   m_color_button1.ButtonXSize(100);
   m_color_button1.ButtonYSize(18);
   m_color_button1.AreaColor(clrWhiteSmoke);
   m_color_button1.LabelColor(clrBlack);
   m_color_button1.BackColor(C'220,220,220');
   m_color_button1.BorderColor(clrSilver);
   m_color_button1.CurrentColor(clrRed);
//--- Создать элемент
   if(!m_color_button1.CreateColorButton(m_chart_id,m_subwin,text,x,y))
      return(false);
//--- Добавим указатель на элемент в базу
   CWndContainer::AddToElementsArray(0,m_color_button1);
   return(true);
  }

Код метода создания формы диалогового окна для цветовой палитры отличается от главного окна только тем, что нужно указать тип окна (W_DIALOG). Кроме этого, установим для этого окна уникальную картинку указывающую на его назначение. Все изображения приложены в архиве в конце статьи. 

//+------------------------------------------------------------------+
//| Создаёт форму 2 для цветовой палитры                             |
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\color_picker.bmp"
//---
bool CProgram::CreateWindow2(const string caption_text)
  {
//--- Сохраним указатель на окно
   CWndContainer::AddWindow(m_window2);
//--- Координаты
   int x=(m_window2.X()>0) ? m_window2.X() : 30;
   int y=(m_window2.Y()>0) ? m_window2.Y() : 30;
//--- Свойства
   m_window2.Movable(true);
   m_window2.XSize(350);
   m_window2.YSize(286);
   m_window2.WindowType(W_DIALOG);
   m_window2.WindowBgColor(clrWhiteSmoke);
   m_window2.WindowBorderColor(clrLightSteelBlue);
   m_window2.CaptionBgColor(clrLightSteelBlue);
   m_window2.CaptionBgColorHover(clrLightSteelBlue);
   m_window2.IconFile("Images\\EasyAndFastGUI\\Icons\\bmp16\\color_picker.bmp");
//--- Создание формы
   if(!m_window2.CreateWindow(m_chart_id,m_subwin,caption_text,x,y))
      return(false);
//---
   return(true);
  }

В листинге ниже представлен код метода CProgram::CreateColorPicker() для создания цветовой палитры. Обязательно нужно сохранить указатель на диалоговое окно, к которому будем присоединять элемент. При добавлении указателя элемента в базу элементов нужно передать индекс окна, к которому элемент присоединён. В данном случае индекс диалогового окна [1].

//+------------------------------------------------------------------+
//| Создаёт цветовую палитру для выбора цвета                        |
//+------------------------------------------------------------------+
bool CProgram::CreateColorPicker(void)
  {
//--- Сохраним указатель на окно
   m_color_picker.WindowPointer(m_window2);
//--- Координаты
   int x=m_window2.X()+COLORPICKER_GAP_X;
   int y=m_window2.Y()+COLORPICKER_GAP_Y;
//--- Создание элемента
   if(!m_color_picker.CreateColorPicker(m_chart_id,m_subwin,x,y))
      return(false);
//--- Добавим указатель на элемент в базу
   CWndContainer::AddToElementsArray(1,m_color_picker);
   return(true);
  }

Нужно самостоятельно позаботиться о том, чтобы при нажатии на кнопку её указатель передавался цветовой палитре. Это можно сделать в обработчике событий пользовательского класса CProgram::OnEvent(). При нажатии на кнопку генерируется сообщение с идентификатором события ON_CLICK_BUTTON. В сообщении также содержится текст описания кнопки, по которому будем определять, какой именно объект кнопки типа CColorButton нужно передать цветовой палитре. Сразу же после передачи объекта кнопки откроется окно с цветовой палитрой, и во всех её маркерах будет отображаться цвет кнопки, объект которого только что был передан. В листинге кода ниже это продемонстрировано:

//+------------------------------------------------------------------+
//| Обработчик событий                                               |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Событие нажатия на кнопке
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     {
      //--- Если нажали на первую кнопку
      if(sparam==m_color_button1.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button1);
         return;
        }
      //--- Если нажали на вторую кнопку
      if(sparam==m_color_button2.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button2);
         return;
        }
      //--- Если нажали на третью кнопку
      if(sparam==m_color_button3.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button3);
         return;
        }
      //--- Если нажали на четвёртую кнопку
      if(sparam==m_color_button4.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button4);
         return;
        }
      //--- Если нажали на пятую кнопку
      if(sparam==m_color_button5.LabelText())
        {
         m_color_picker.ColorButtonPointer(m_color_button5);
         return;
        }
     }
  }

Уже после того, как выбор цвета подтвержден нажатием кнопки "ОК" на цветовой палитре, сообщение с идентификатором  ON_CHANGE_COLOR  будет обработано так, как показано в следующем листинге кода.

void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Событие изменения цвета посредством цветовой палитры
   if(id==CHARTEVENT_CUSTOM+ON_CHANGE_COLOR)
     {
      //---Если идентификаторы элементов совпадают
      if(lparam==m_color_picker.Id())
        {
         //--- Если ответ от первой кнопки
         if(sparam==m_color_button1.LabelText())
           {
            //--- Изменить цвет объекта, который относится к первой кнопке...
            return;
           }
         //--- Если ответ от второй кнопки
         if(sparam==m_color_button2.LabelText())
           {
            //--- Изменить цвет объекта, который относится ко второй кнопке...
            return;
           }
         //--- Если ответ от третьей кнопки
         if(sparam==m_color_button3.LabelText())
           {
            //--- Изменить цвет объекта, который относится к третьей кнопке...
            return;
           }
         //--- Если ответ от четвёртой кнопки
         if(sparam==m_color_button4.LabelText())
           {
            //--- Изменить цвет объекта, который относится к четвёртой кнопке...
            return;
           }
         //--- Если ответ от пятой кнопки
         if(sparam==m_color_button5.LabelText())
           {
            //--- Изменить цвет объекта, который относится к пятой кнопке...
            return;
           }
        }
      return;
     }
  }

Скомпилируйте программу и загрузите её на график в терминале. Результат показан на скриншоте ниже:

 Рис. 4. Тест кнопок для вызова цветовой палитры.

Рис. 4. Тест кнопок для вызова цветовой палитры.

Нажав на кнопку для вызова цветовой палитры из пяти представленных на главном окне, откроется окно для выбора цвета (Color picker), как показано на следующем скриншоте:

 Рис. 5. Тест элемента «Цветовая палитра для выбора цвета».

Рис. 5. Тест элемента «Цветовая палитра для выбора цвета».

Теперь всё работает так, как задумывалось. 

 


Заключение

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

В следующей статье будет представлено описание классов кода таких элементов, как «Индикатор выполнения» и «Линейный график».

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

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


Прикрепленные файлы |
Последние комментарии | Перейти к обсуждению на форуме трейдеров (11)
Artyom Trishkin
Artyom Trishkin | 14 июл. 2016 в 15:35
Реter Konow:

Не совсем понял необходимость использования цветовой палитры в пользовательском приложении.

Зачем она нужна?

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

В остальном, смысл применения цветовой палитры для меня не ясен. Другое дело, если менются скины приложения или темы...

Это вам, одиночке, пытающемуся создать визуальную студию, непонятны аспекты и области применения цветовой палитры, а нам, простым смертным, уже приходилось разрабатывать себе колорпикеры и применять их в своих разработках. Теперь вот будет в одной библиотеке.
Реter Konow
Реter Konow | 14 июл. 2016 в 15:51
Artyom Trishkin:
Это вам, одиночке, пытающемуся создать визуальную студию, непонятны аспекты и области применения цветовой палитры, а нам, простым смертным, уже приходилось разрабатывать себе колорпикеры и применять их в своих разработках. Теперь вот будет в одной библиотеке.
Ну, если Вам ясна необходимость применения колорпикера в приложении и нетрудно привести пример, буду благодарен.
Реter Konow
Реter Konow | 14 июл. 2016 в 16:22

Конечно, можно постараться и найти применение этому инструменту в mql приложениях, но по настоящему его использование имеет смысл только в визуальной студии.

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

Если все разработчики скоординируют свою работу, то возможно, совместными усилиями что то может получится.

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

Кажется, идея конструктивная и многообещающая.)


P.S. Если проект совместного создания визуальной студии разработчиками будет начат, скоординирован и возглавлен, то обязательно присоединюсь к общей работе.

Andrey Khatimlianskii
Andrey Khatimlianskii | 14 июл. 2016 в 23:52
Реter Konow:
Ну, если Вам ясна необходимость применения колорпикера в приложении и нетрудно привести пример, буду благодарен.
Элементарно: для выбора цвета создаваемых приложением значков или линий в процессе работы. Зачем перезагружать программу, чтобы просто поменять цвет создаваемых объектов?
Artyom Trishkin
Artyom Trishkin | 15 июл. 2016 в 00:09
Andrey Khatimlianskii:
Элементарно: для выбора цвета создаваемых приложением значков или линий в процессе работы. Зачем перезагружать программу, чтобы просто поменять цвет создаваемых объектов?

Андрей, ну вот зачем? :)))

Можно было предоставить человеку свободу для полёта мысли

Какие проверки должен пройти торговый робот перед публикацией в Маркете Какие проверки должен пройти торговый робот перед публикацией в Маркете
Все продукты Маркета перед публикацией проходят обязательную предварительную проверку для обеспечения единого стандарта качества. В этой статье мы расскажем о наиболее частых ошибках, которые допускают разработчики в своих технических индикаторах и торговых роботах. А также покажем как самостоятельно проверить свой продукт перед отправкой в Маркет.
Работа с сокетами в MQL, или Как стать провайдером сигналов Работа с сокетами в MQL, или Как стать провайдером сигналов
Сокеты… Что вообще сейчас в нашем информационном мире может без них существовать? Впервые появившиеся в 1982 г. и практически не изменившиеся до настоящего времени, они исправно работают на нас каждую секунду. Это основа сети, нервные окончания нашей Matrix, в которой мы живем.
Графические интерфейсы IX: Элементы "Индикатор выполнения" и "Линейный график" (Глава 2) Графические интерфейсы IX: Элементы "Индикатор выполнения" и "Линейный график" (Глава 2)
Вторая глава девятой части серии будет посвящена элементам «Индикатор выполнения» и «Линейный график». Как всегда, будут показаны подробные примеры того, как можно использовать эти элементы в своих MQL-приложениях.
Графические интерфейсы VIII: Элемент "Файловый навигатор" (Глава 3) Графические интерфейсы VIII: Элемент "Файловый навигатор" (Глава 3)
В предыдущих главах восьмой части серии наша библиотека пополнилась несколькими классами для создания указателей для курсора мыши, календарей и древовидных списков. В настоящей статье рассмотрим элемент «Файловый навигатор», который тоже можно будет использовать в качестве части графического интерфейса MQL-приложения.