Скачать MetaTrader 5

Изучаем класс CCanvas. Реализация прозрачности графических объектов

12 февраля 2015, 10:14
Vladimir Karputov
32
3 302

Оглавление


Введение

Рисовать в терминале MetaTrader 5 несложно, нужно знать только несколько нюансов. Например, как устроен сам экран терминала. Точнее, нас будет интересовать, каким образом происходит вывод графики на экран терминала. Ведь на экране сам график может отображаться на заднем фоне, а может отображаться и на переднем плане. От такого расположения будет зависеть вывод цвета на экран. Некоторые графические объекты при выводе на экран могут изменять цвет в области пересечения.

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

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


1. Прозрачность (альфа-канал)

Мы живем в трехмерном мире и воспринимаем все предметы вокруг нас объемными. Объем окружающих нас предметов мы привыкли видеть или даже ощущать. В трехмерном мире мы можем различать, какой из объектов расположен ближе или дальше от нас.

При этом некоторые предметы могут быть полупрозрачными. Для примера возьмем прозрачный стеклянный стакан с налитой в него полупрозрачной жидкостью на синем фоне. Через стакан с жидкостью просматривается задний синий фон. Причем от степени прозрачности жидкости зависит детализация фона.


Рис. 1. Привычный взгляд на объем

Рис. 1. Привычный взгляд на объем


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

При отображении изображения на компьютерном мониторе все иначе – пиксельная матрица мониторов двухмерная: изображение, отображаемое матрицей, имеет высоту и ширину, но не имеет третьего параметра – глубины. Именно поэтому нет возможности располагать пиксели один над другим – как бы имитировать ситуацию: нижний пиксель – это желтый фон, верхний пиксель – полупрозрачный стакан. Любое изображение трехмерного и реалистичного объекта на мониторе – это иллюзия, которая достигается игрой цвета и тени.

Рассмотрим пример изображения, которое можно разделить на два слоя: нижний слой – это синий фон и верхний слой - стакан с непрозрачной жидкостью. Как это выглядит на мониторе:


Рис. 2. Непрозрачный стакан

Рис. 2. Непрозрачный стакан


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


2. ARGB-представление цвета

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

ARGB представление цвета – это 4 байтовый тип uint, в котором записаны по порядку следующие значения: альфа-канал, красный, зеленый, голубой. То есть, для придания прозрачности к цвету в формате RGB добавляют дополнительный байт со значением прозрачности - альфа-канал.

Рис. 3. ARGB

Рис. 3. ARG

Значение альфа-канала задается значением от 0 (цвет накладываемого пикселя из верхнего слоя совсем не меняет отображения нижележащего пикселя нижнего слоя) до 255 (цвет накладывается полностью и перекрывает собой цвет нижележащего пикселя). Прозрачность цвета в процентном выражении вычисляется по формуле:

формула 1.1

То есть, чем меньше значение альфа-канала, тем более прозрачен цвет. Значит, если известна прозрачность, которую мы хотим достичь, то значение alpha можно рассчитать так:

формула 1.2

Для преобразования цвета в ARGB представление служит функция ColorToARGB(цвет, alpha).


3. Схема рисования объектов в терминале

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

3.1. График на заднем плане

Проверить эту настройку можно так: правый клик мышкой на графике, дальше выбрать в выпадающем меню пункт "Свойства..." и перейти на вкладку "Общие".


Рис. 4. График на заднем плане

Рис. 4. График на заднем плане


Окно графика в терминале состоит из четырех слоев. На двух крайних слоях ("Задний план" и "Передний план") можно рисовать:

Рис. 5. Схема окна графика

Рис. 5. Схема окна графика


На заднем плане (фоне) и на переднем плане графические объекты при рисовании накладываются друг на друга в соответствии с временем своего создания.

То есть, в самом низу на слое "Задний план" и на слое "Передний план" будут находится самые "старые" графические объекты. Поверх будут накладываться более "молодые" графические объекты.


Рис. 6. Расположение объектов в зависимости от времени создания

Рис. 6. Расположение объектов в зависимости от времени создания


Не все графические объекты могут накладываться полностью, без перекрашивания в местах (или областях) пересечения с нижележащими графическими объектами.

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

Идентификатор Объект Описание В месте пересечения с нижележащим объектом
 OBJ_VLINE vertical_line  Вертикальная линия  Не перекрашивает
 OBJ_HLINE horizonal_line  Горизонтальная линия Не перекрашивает
 OBJ_TREND  trend_line  Трендовая линия Не перекрашивает
 OBJ_TRENDBYANGLE trend_line)by_angle   Трендовая линия по углу  Не перекрашивает
 OBJ_CYCLES  cycle_lines  Циклические линии Не перекрашивает
 OBJ_ARROWED_LINE  arrowed_line  Объект "Линия со стрелкой" Не перекрашивает
 OBJ_CHANNEL  equidistance_channel  Равноудаленный канал Не перекрашивает
 OBJ_STDDEVCHANNEL  stddeviation_channel  Канал стандартного отклонения  Не перекрашивает
 OBJ_REGRESSION  regression_channel  Канал на линейной регрессии Не перекрашивает
 OBJ_PITCHFORK  andrewspitchfork  Вилы Эндрюса Не перекрашивает
 OBJ_GANNLINE  gann_line  Линия Ганна Не перекрашивает
 OBJ_GANNFAN  gann_fan  Веер Ганна Не перекрашивает
 OBJ_GANNGRID  gann_grid  Сетка Ганна Не перекрашивает
 OBJ_FIBO  fibonacci_levels  Уровни Фибоначчи Не перекрашивает
 OBJ_FIBOTIMES  fibonacci_time_zones   Временные зоны Фибоначчи Не перекрашивает
 OBJ_FIBOFAN  fibo_fan  Веер Фибоначчи Не перекрашивает
 OBJ_FIBOARC fibo_arc  Дуги Фибоначчи Не перекрашивает
 OBJ_FIBOCHANNEL  fibo_channel  Канал Фибоначчи Не перекрашивает
 OBJ_EXPANSION  fibo_expansion  Расширение Фибоначчи Не перекрашивает
 OBJ_ELLIOTWAVE5  elliot_impuls  5-волновка Эллиота Не перекрашивает
 OBJ_ELLIOTWAVE3  elliot_correction  3-волновка Эллиота Не перекрашивает
 OBJ_RECTANGLE  rectangle  Прямоугольник Без заливки не перекрашивает,
с заливкой перекрашивает
 OBJ_TRIANGLE  triangle  Треугольник Без заливки не перекрашивает,
с заливкой перекрашивает
 OBJ_ELLIPSE  ellipse  Эллипс Без заливки не перекрашивает,
с заливкой перекрашивает
 OBJ_ARROW_THUMB_UP  THUMB_UP  Знак "Хорошо" (большой палец вверх) Не перекрашивает
 OBJ_ARROW_THUMB_DOWN  THUMB_DOWN  Знак "Плохо" (большой палец вниз) Не перекрашивает
 OBJ_ARROW_UP  arrow_up  Знак "Стрелка вверх" Не перекрашивает
 OBJ_ARROW_DOWN  arrow_down  Знак "Стрелка вниз" Не перекрашивает
 OBJ_ARROW_STOP  stop_signal  Знак "Стоп" Не перекрашивает
 OBJ_ARROW_CHECK  check_signal  Знак "Птичка" (галка) Не перекрашивает
 OBJ_ARROW_LEFT_PRICE  left_price_label  Левая ценовая метка Не перекрашивает
 OBJ_ARROW_RIGHT_PRICE right_price_label   Правая ценовая метка Не перекрашивает
 OBJ_ARROW_BUY  buy_sign_icon  Знак "Buy" Не перекрашивает
 OBJ_ARROW_SELL sell_sign_icon   Знак "Sell" Не перекрашивает
 OBJ_ARROW  arrow_symbol  Объект "Стрелка" Не перекрашивает
 OBJ_TEXT text_object   Объект "Текст" Не перекрашивает
 OBJ_LABEL  label_object  Объект "Текстовая метка" Не перекрашивает
 OBJ_BUTTON  button_object  Объект "Кнопка" Не перекрашивает
 OBJ_CHART chart_object   Объект "График" Не перекрашивает
 OBJ_BITMAP  picture_object  Объект "Рисунок Не перекрашивает
 OBJ_BITMAP_LABEL  bitmap_object  Объект "Графическая метка" Не перекрашивает
 OBJ_EDIT  edit_object  Объект "Поле ввода" Не перекрашивает
 OBJ_EVENT  obj_event  Объект "Событие", соответствующий событию в экономическом календаре Не перекрашивает
 OBJ_RECTANGLE_LABEL  rectangle_label  Объект "Прямоугольная метка"для создания и оформления пользовательского графического интерфейса  Не перекрашивает

Табл. 1. Наложение и прозрачность графических объектов


На примере трех объектов типа OBJ_RECTANGLE (прямоугольники) рассмотрим алгоритм перекрашивания в местах пересечения объектов, которые перекрашиваются (файл xor.mq5).

Скрипт (файл xor.mq5) устанавливает белый цвет фона (0xFFFFFF) и рисует прямоугольники №1 и №2 синим цветом (0x0000FF) с заливкой, прямоугольник №3 отображается красным цветом (0xFF0000) с заливкой.


Рис. 7. Перекрашивание. График на заднем плане

Рис. 7. Перекрашивание. График на заднем плане


На рисунке получились две области пересечения, в которых цвет был перекрашен:

  1. Область №1 – результирующий цвет (0x000000) полностью прозрачный, поэтому в области №1 видно неперекрашенные фон и график;
  2. Область №2 – результирующий цвет (0x00FF00).

Графические объекты типа прямоугольников при пересечении перекрашиваются по алгоритму Побитовая операция ИЛИ.


Для рис. 6 ниже дан пример перекрашивания цветов для обоих областей:

Литеральное представление Целочисленное представление Бинарное представление Примечание
C’0,0,255’ 0x0000FF 0000 0000 0000 0000 1111 1111 Синий цвет


XOR
C’0,0,225’ 0x0000FF 0000 0000 0000 0000 1111 1111 Синий цвет


=
C’0,0,0’ 0x000000 0000 0000 0000 0000 0000 0000 Прозрачный


XOR
C’255,255,255’ 0xFFFFFF 1111 1111 1111 1111 1111 1111 Белый цвет (фон)


=
C’255,255,255’ 0xFFFFFF 1111 1111 1111 1111 1111 1111 Белый цвет

Табл. 2. Побитовое исключающее ИЛИ для Синий + Синий + Белый


Литеральное представление Целочисленное представление Бинарное представление Примечание
C’0,0,255’ 0x0000FF 0000 0000 0000 0000 1111 1111 Синий цвет


XOR
C’255,0,0’ 0xFF0000 1111 1111 0000 0000 0000 0000 Красный цвет


=
С’255,0,255’ 0xFF00FF 1111 1111 0000 0000 1111 1111


XOR
C’255,255,255’ 0xFFFFFF 1111 1111 1111 1111 1111 1111 Белый цвет (фон)


=
С’0,255,0’ 0x00FF00 0000 0000 1111 1111 0000 0000

Табл. 3. Побитовое исключающее ИЛИ для Синий + Красный + Белый


3.2. График на переднем плане

Когда для графика включена настройка "График сверху", расположение слоев окна графика отличается от расположения, при котором график находится на заднем плане:


Рис. 8. Схема окна графика. График сверху

Рис. 8. Схема окна графика. График сверху


Когда включена настройка для графика "График сверху" два слоя для рисования "Передний план" и "Задний план" соединяются в один общий слой. Этот общий слой находится в самом низу под слоями с барами и сеткой.


3.3. Перекрашивание для "График сверху"

Как и для рис. 7, рассмотрим алгоритм перекрашивания в местах пересечения объектов, которые перекрашиваются (файл xor.mq5).


Скрипт (файл xor.mq5) устанавливает белый цвет фона (0xFFFFFF) и рисует прямоугольники №1 и №2 синим цветом (0x0000FF) с заливкой, прямоугольник №3 рисуется красным цветом (0xFF0000) с заливкой.


Рис. 9. Перекрашивание. График на переднем плане

Рис. 9. Перекрашивание. График на переднем плане

Если сравнить рис. 7 и рис. 9, то видно, что области пересечения перекрашиваются одинаково.


4. Смешивание цветов. Результирующий цвет

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

Пусть на белом фоне (это фон графика в цветовой схеме "Black On White") мы хотим нарисовать на канвасе красный цвет c альфа-каналом, равным 128. В формате ARGB этот цвет будет иметь запись 0x80FF0000. Для расчета результирующего цвета нужно рассчитать цвет каждого из каналов (Red, Green, Blue).

Формула расчета результирующего цвета при наложении цвета с альфа-каналом, нормализованным к единице:

формула 1.3

где:

  • result - результирующее значение интенсивности цветового канала. Если полученное значение больше 255, то возвращается 255.
  • background - значение цветового канала фона.
  • foreground - значение цветового канала налагаемой картинки.
  • alpha - значение альфа-канала, нормализованное к единице.

Рассчитаем результирующий цвет согласно формуле (1.3):

Альфа-канал Альфа-канал, нормализован к "1" R G B Примечание


255 255 255 Белый цвет
128 0,5 255 0 0 Красный с альфа-каналом 128


255*(1-0.5)+255*0.5=255 255*(1-0.5)+0*0.5=127 255*(1-0.5)+0*0.5=127

Табл. 4. Результаты расчета по формуле (1.3)

В результате на мониторе получится следующий цвет:

Рис. 10. Итоговый цвет

Рис. 10. Итоговый цвет

4.1. Способы обработки цвета. ENUM_COLOR_FORMAT

При создании канваса можно задать один из трех способов обработки цвета (ENUM_COLOR_FORMAT):


Идентификатор Описание
COLOR_FORMAT_XRGB_NOALPHA Компонента альфа-канала игнорируется
COLOR_FORMAT_ARGB_RAW Компоненты цвета не обрабатываются терминалом (должны быть корректно заданы пользователем)
COLOR_FORMAT_ARGB_NORMALIZE Компоненты цвета обрабатываются терминалом

Табл. 5. Способы обработки цвета при создании канваса

COLOR_FORMAT_ARGB_NORMALIZE позволяет получать более красивую картинку за счет учета правильного наложения компонентов RGB. Расчет результирующего цвета при наложении цвета с альфа-каналом происходит по формуле (1.3).

COLOR_FORMAT_ARGB_RAW не производит контроль над переполнением RGB компонентов цветов и поэтому COLOR_FORMAT_ARGB_RAW более быстрый метод по сравнению с COLOR_FORMAT_ARGB_NORMALIZE.

Формула расчета результирующего цвета при наложении цвета с альфа-каналом, нормализованном к единице, для метода COLOR_FORMAT_ARGB_RAW:

формула 1.4

где:

  • result - результирующее значение интенсивности цветового канала. Если полученное значение больше 255, то возвращается 255.
  • background - значение цветового канала фона.
  • foreground - значение цветового канала налагаемой картинки.
  • alpha - значение альфа-канала, нормализованное к единице.

5. Иллюзия прозрачности

Теперь можно приступить к практической реализации прозрачности.

На графике рисуем несколько прямоугольников с заливкой (скрипт "xor.mq5"). Для наглядности иллюстрации разницы методов обработки цвета поверх графика накладываем по горизонтали три канваса без их взаимного перекрытия.

Первый имеет метод обработки COLOR_FORMAT_XRGB_NOALPHA, второй - COLOR_FORMAT_ARGB_RAW и третий - COLOR_FORMAT_ARGB_NORMALIZE. Затем постепенно меняем прозрачность от 255 (полная непрозрачность) до 0 (полная прозрачность). Назовем наш скрипт "Illusion.mq5".

Видео работы скрипта "Illusion.mq5":


Рис. 11. Работа скрипта illusion.mq5


5.1. Создание скрипта "Illusion.mq5"

Добавленные или измененные участки кода будут выделяться цветом.

Пока еще пустой шаблон скрипта:

//+------------------------------------------------------------------+
//|                                                     Illusion.mq5 |
//|                              Copyright © 2015, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2015, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.0"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
  }

Добавим описание скрипта, возможность вводить параметры при запуске скрипта и подключим класс CCanvas - класс, благодаря которому мы и будем рисовать:

#property version   "1.0"
#property description "The illusion of transparency"
//--- show the window of input parameters when launching the script
#property script_show_inputs
#include <Canvas\Canvas.mqh>

Для работы скрипта нужны будут несколько переменных - высота и ширина графика, высота и ширина канваса, а также вспомогательные переменные для рисования координат канваса:

#include <Canvas\Canvas.mqh>

//+------------------------------------------------------------------+
//| inputs                                                           |
//+------------------------------------------------------------------+
input color colr=clrRed;
input color clr_Circle=clrBlue;
//--- variable width and height of the chart.
int            ChartWidth=-1;
int            ChartHeight=-1;
//---
uchar alpha=0;                //alpha channel managing color transparency
int   can_width,can_height;   //width and height of the canvas
int   can_x1,can_y1,can_x2,can_y2,can_y3,can_x3;   //coordinates
Для получения ширины и высоты графика воспользуемся стандартными функциями:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
  }

//+------------------------------------------------------------------+
//| Chart property width                                             |
//+------------------------------------------------------------------+
int ChartWidthInPixels(const long chart_ID=0)
  {
//--- prepare the variable to get the property value
   long result=-1;
//--- reset the error value
   ResetLastError();
//--- receive the property value
   if(!ChartGetInteger(chart_ID,CHART_WIDTH_IN_PIXELS,0,result))
     {
      //--- display the error message in Experts journal
      Print(__FUNCTION__+", Error Code = ",GetLastError());
     }
//--- return the value of the chart property
   return((int)result);
  }
//+------------------------------------------------------------------+
//| Chart property height                                            |
//+------------------------------------------------------------------+
int ChartHeightInPixelsGet(const long chart_ID=0,const int sub_window=0)
  {
//--- prepare the variable to get the property value
   long result=-1;
//--- reset the error value
   ResetLastError();
//--- receive the property value
   if(!ChartGetInteger(chart_ID,CHART_HEIGHT_IN_PIXELS,sub_window,result))
     {
      //--- display the error message in Experts journal
      Print(__FUNCTION__+", Error Code = ",GetLastError());
     }
//--- return the value of the chart property
   return((int)result);
  }

Переходим непосредственно в OnStart().

Для наглядности на рис. 12 приведена схема расположения канвасов на графике, а также обозначение вспомогательных переменных для координат канвасов:


Рис. 12. Координаты на графике

Рис. 12. Координаты на графике


Получим высоту и ширину графика, а также рассчитаем вспомогательные переменные для координат канвасов:

void OnStart()
  {
//--- width and height of the chart
   ChartWidth=ChartWidthInPixels();
   ChartHeight=ChartHeightInPixelsGet()-50;
//---
   can_width=ChartWidth/3;   can_height=ChartHeight;
   can_x1=0;            can_y1=0;
   can_x2=can_width;    can_y2=0;
   can_x3=can_width*2;  can_y3=0;
  }

Имея рассчитанные ширину и высоту канваса, а также вспомогательные координаты можно приступить к рисованию.

Дальше изменим тип void функции OnStart() на int и нарисуем на первом канвасе закрашенный прямоугольник, текст с названием метода обработки цвета на данном канвасе и закрашенную окружность:

int OnStart()
  {
//--- width and height of the chart
   ChartWidth=ChartWidthInPixels();
   ChartHeight=ChartHeightInPixelsGet()-50;
//---
   can_width=ChartWidth/3;   can_height=ChartHeight;
   can_x1=0;            can_y1=0;
   can_x2=can_width;    can_y2=0;
   can_x3=can_width*2;  can_y3=0;
//--- create canvas COLOR_FORMAT_XRGB_NOALPHA
   CCanvas canvas_XRGB_NOALPHA,canvas_ARGB_RAW,canvas_XARGB_NORMALIZE;
   if(!canvas_XRGB_NOALPHA.CreateBitmapLabel("canvas_XRGB_NOALPHA",can_x1,can_y1,can_width-1,can_height,COLOR_FORMAT_XRGB_NOALPHA))
     {
      Print("Error creating canvas: ",GetLastError());
      return(-1);
     }
   canvas_XRGB_NOALPHA.Erase(ColorToARGB(colr,alpha));
   canvas_XRGB_NOALPHA.TextOut((can_width)/2,can_height/2,"canvas_XRGB_NOALPHA",ColorToARGB(clrBlue,255),TA_CENTER|TA_VCENTER);
   canvas_XRGB_NOALPHA.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255));
   canvas_XRGB_NOALPHA.Update();
   return(0);
  }

Остановлюсь подробнее на последнем вставленном коде.

canvas_XRGB_NOALPHA.CreateBitmapLabel("canvas_XRGB_NOALPHA",can_x1,can_y1,can_width-1,can_height,COLOR_FORMAT_XRGB_NOALPHA)

canvas_XRGB_NOALPHA.CreateBitmapLabel - Здесь мы создали графический ресурс, привязанный к объекту чарта.

Первый канвас создан с режимом обработки изображения COLOR_FORMAT_XRGB_NOALPHA - компонента альфа-канала при рисовании будут игнорироваться.

canvas_XRGB_NOALPHA.Erase(ColorToARGB(colr,alpha));

Заполняем весь канвас цветом в формате ARGB c прозрачностью alpha.

Так как для данного канваса задан режим обработки изображений COLOR_FORMAT_XRGB_NOALPHA - канвас будет заполнен цветом без учета альфа-канала.

canvas_XRGB_NOALPHA.TextOut((can_width)/2,can_height/2,"canvas_XRGB_NOALPHA",ColorToARGB(clrBlue,255),TA_CENTER|TA_VCENTER);

Выводим текст - тип обработки изображения для данного канваса. Цвет текста в формате ARGB и альфа-каналом равным 255, то есть цвет выводимого текста полностью непрозрачен.

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

canvas_XRGB_NOALPHA.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255));

Рисуем закрашенный круг. Круг будет рисоваться поверх цвета, которым мы заполнили канвас (canvas_XRGB_NOALPHA.Erase(ColorToARGB(colr,alpha));).

Это сделано для демонстрации того, что нарисованная на канвасе фигура (или область/точка) полностью стирает под собой нижележащий рисунок на канвасе. То есть, никакого перекрашивания на канвасе не будет, т.к. последний вывод рисунка стирает полностью область под собой.

canvas_XRGB_NOALPHA.Update();

Если мы хотим, чтобы все нарисованное отобразилось на экране, нужно обновить экран.

Аналогично рисуются остальные два канваса: второй канвас с режимом отображения COLOR_FORMAT_ARGB_RAW и третий канвас с режимом отображения COLOR_FORMAT_ARGB_NORMALIZE:

   canvas_XRGB_NOALPHA.Update();

//--- create canvas COLOR_FORMAT_ARGB_RAW
   if(!canvas_ARGB_RAW.CreateBitmapLabel("canvas_ARGB_RAW",can_x2,can_y2,can_width-1,can_height,COLOR_FORMAT_ARGB_RAW))
     {
      Print("Error creating canvas: ",GetLastError());
      return(-1);
     }
   canvas_ARGB_RAW.Erase(ColorToARGB(colr,alpha)); //clrNONE,0));
   canvas_ARGB_RAW.TextOut((can_width)/2,can_height/2,"canvas_ARGB_RAW",ColorToARGB(clrBlue,255),TA_CENTER|TA_VCENTER);
   canvas_ARGB_RAW.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255));
   canvas_ARGB_RAW.Update();

//--- create canvas COLOR_FORMAT_ARGB_NORMALIZE
   if(!canvas_XARGB_NORMALIZE.CreateBitmapLabel("canvas_XARGB_NORMALIZE",can_x3,can_y3,can_width-1,can_height,COLOR_FORMAT_ARGB_NORMALIZE))
     {
      Print("Error creating canvas: ",GetLastError());
      return(-1);
     }
   canvas_XARGB_NORMALIZE.Erase(ColorToARGB(colr,alpha));
   canvas_XARGB_NORMALIZE.TextOut((can_width)/2,can_height/2,"canvas_XARGB_NORMALIZE",ColorToARGB(clrBlue,255),TA_CENTER|TA_VCENTER);
   canvas_XARGB_NORMALIZE.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255));
   canvas_XARGB_NORMALIZE.Update();
   return(0);
  }

Канвасы и графика внутри канвасов нарисованы.

Теперь сделаем цикл, в котором будет изменяться прозрачность всего канваса:

   canvas_XARGB_NORMALIZE.FillCircle((can_width)/2,can_height/2+50,25,ColorToARGB(clr_Circle,255));
   canvas_XARGB_NORMALIZE.Update();
   //--- transparent from 255 to 0
   uchar transparent;
   for(transparent=255;transparent>0;transparent--)
     {
      canvas_XRGB_NOALPHA.TransparentLevelSet(transparent);
      canvas_XRGB_NOALPHA.Update();
      canvas_ARGB_RAW.TransparentLevelSet(transparent);
      canvas_ARGB_RAW.Update();
      canvas_XARGB_NORMALIZE.TransparentLevelSet(transparent);
      canvas_XARGB_NORMALIZE.Update();
      Sleep(50);
     }
   canvas_XRGB_NOALPHA.TransparentLevelSet(transparent);
   canvas_XRGB_NOALPHA.Update();
   canvas_ARGB_RAW.TransparentLevelSet(transparent);
   canvas_ARGB_RAW.Update();
   canvas_XARGB_NORMALIZE.TransparentLevelSet(transparent);
   canvas_XARGB_NORMALIZE.Update();
   Sleep(6000);
   return(0);
  }

Изменение прозрачности для всего канваса выполняется с помощью строчек вида:

.TransparentLevelSet(transparent)

После окончания рисования нужно убрать за собой - удалить графические ресурсы.

Так как мы создавали графический ресурс с привязкой к объекту чарта (метод CreateBitmapLabel), то удаление ресурса выполним с помощью метода Destroy() - заодно удалится и объект чарта (Bitmap Label):

   canvas_XARGB_NORMALIZE.Update();
   Sleep(6000);
   //--- finish
   canvas_XRGB_NOALPHA.Destroy();
   canvas_ARGB_RAW.Destroy();
   canvas_XARGB_NORMALIZE.Destroy();
   return(0);
  }

Скрипт, плавно изменяющий прозрачность работает.

Отмечу, что отличие режимов отображения COLOR_FORMAT_ARGB_RAW и COLOR_FORMAT_ARGB_NORMALIZE особенно хорошо видно, если скрипт запустить сначала на белом фоне графика, а потом на черном фоне.


Заключение

В статье были рассмотрены основы работы со цветом, мы узнали, как рисовать в окне графика. Также рассмотрели основы работы с классом CCanvas Стандартной библиотеки, узнали про формат представления цвета с прозрачностью ARGB.

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


Прикрепленные файлы |
xor.mq5 (6.99 KB)
Illusion.mq5 (5.88 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (32)
Artyom Trishkin
Artyom Trishkin | 30 май 2016 в 16:57
Karputov Vladimir:
"Time[]", "Close[]" - mistake. There are no such variables in MQL5!
MQL4 ;)
Vladimir Karputov
Vladimir Karputov | 30 май 2016 в 17:21
Artyom Trishkin:
MQL4 ;)

Я не приветствую MQL4. Все примеры только на MQL5.

//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                              Copyright © 2016, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2016, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.00"
#include <Canvas\Canvas.mqh>
CCanvas     m_canvas;           // the canvas object
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   datetime arr_time[];
   double   arr_open[];
   double   arr_close[];
   if(CopyTime(Symbol(),Period(),0,2,arr_time)==-1)
      return;
   if(CopyClose(Symbol(),Period(),0,2,arr_close)==-1)
      return;
   if(CopyOpen(Symbol(),Period(),0,2,arr_open)==-1)
      return;
   int x1,y1,x2,y2;
   if(!ChartTimePriceToXY(0,0,arr_time[0],arr_open[0],x1,y1))
      Print("Error ",GetLastError());
   if(!ChartTimePriceToXY(0,0,arr_time[1],arr_close[0],x2,y2))
      Print("Error ",GetLastError());
//x1 = Time[1];
//y1 = Open[1];
//x2 = Time[0];
//y2 = Close[1];
   Print("arr_time[0]=",arr_time[0],", arr_open[0]=",arr_open[0]);
   m_canvas.CreateBitmapLabel("COLOR_FORMAT_ARGB_NORMALIZE",x1,y1,MathAbs(x2-x1),MathAbs(y2-y1),COLOR_FORMAT_ARGB_NORMALIZE);
   m_canvas.Erase(ColorToARGB(clrBlue,200));
   m_canvas.Update();
   Sleep(10000);
   m_canvas.Destroy();
  }
//+------------------------------------------------------------------+
//| Gets the width of chart (in pixels)                              |
//+------------------------------------------------------------------+
int ChartWidthInPixels(const long chart_ID=0)
  {
//--- prepare the variable to get the property value
   long result=-1;
//--- reset the error value
   ResetLastError();
//--- receive the property value
   if(!ChartGetInteger(chart_ID,CHART_WIDTH_IN_PIXELS,0,result))
     {
      //--- display the error message in Experts journal
      Print(__FUNCTION__+", Error Code = ",GetLastError());
     }
//--- return the value of the chart property
   return((int)result);
  }
//+------------------------------------------------------------------+
//| Gets the height of chart (in pixels)                             |
//+------------------------------------------------------------------+
int ChartHeightInPixelsGet(const long chart_ID=0,const int sub_window=0)
  {
//--- prepare the variable to get the property value
   long result=-1;
//--- reset the error value
   ResetLastError();
//--- receive the property value
   if(!ChartGetInteger(chart_ID,CHART_HEIGHT_IN_PIXELS,sub_window,result))
     {
      //--- display the error message in Experts journal
      Print(__FUNCTION__+", Error Code = ",GetLastError());
     }
//--- return the value of the chart property
   return((int)result);
  }
//+------------------------------------------------------------------+

 

И результат работы скрипта:

результат 

Dennis Kirichenko
Dennis Kirichenko | 16 окт 2016 в 17:17

Владимир, вопрос к Вам как к спецу.

Есть панель в виде холста. А потом на графике рисуются трендовые линии. Как их спрятать за холст?

Скриншоты торговой платформы MetaTrader

RTS Splice, H1, 2016.10.16

АО &#39;&#39;Открытие Брокер&#39;&#39;, MetaTrader 5, Demo

RTS Splice, H1, 2016.10.16, АО &#39;&#39;Открытие Брокер&#39;&#39;, MetaTrader 5, Demo


Vladimir Karputov
Vladimir Karputov | 16 окт 2016 в 18:03
Dennis Kirichenko:

Владимир, вопрос к Вам как к спецу.

Есть панель в виде холста. А потом на графике рисуются трендовые линии. Как их спрятать за холст?


Например уничтожить панель и нарисовать заново...
Dennis Kirichenko
Dennis Kirichenko | 17 окт 2016 в 00:50
Ага, спасибо. Пока придумал просто объекты помещать на задний план...
Рецепты MQL5 - ОСО-ордера Рецепты MQL5 - ОСО-ордера

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

Разнонаправленная торговля и хеджирование позиций в MetaTrader 5 с помощью API HedgeTerminal, часть 2 Разнонаправленная торговля и хеджирование позиций в MetaTrader 5 с помощью API HedgeTerminal, часть 2

Статья описывает новый подход в вопросах хеджирования позиций и ставит точку в спорах между пользователями платформ MetaTrader 4 и MetaTrader 5 в этом вопросе. Она является продолжением первой части: "Разнонаправленная торговля и хеджирование позиций в MetaTrader 5 с помощью панели API HedgeTerminal". Во второй части описывается интеграция пользовательских экспертов с HedgeTerminalAPI - специальной библиотекой виртуализации, позволяющей торговать разнонаправлено, находясь в комфортном программном окружении, позволяющем легко и просто управлять своими позициями.

Рецепты MQL5 - Реализуем ассоциативный массив или словарь для быстрого доступа к данным Рецепты MQL5 - Реализуем ассоциативный массив или словарь для быстрого доступа к данным

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

Создание интерактивного приложения для отображения RSS-каналов в MetaTrader 5 Создание интерактивного приложения для отображения RSS-каналов в MetaTrader 5

В данной статье рассматривается создание приложения, отображающего RSS-каналы. Мы также рассмотрим аспекты применения Стандартной библиотеки при создании интерактивных программ для MetaTrader 5.