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

Vladimir Karputov | 12 февраля, 2015

Оглавление


Введение

Рисовать в терминале 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  Вертикальная линия  Не перекрашивает
 OBJ_HLINE  Горизонтальная линия Не перекрашивает
 OBJ_TREND    Трендовая линия Не перекрашивает
 OBJ_TRENDBYANGLE    Трендовая линия по углу  Не перекрашивает
 OBJ_CYCLES    Циклические линии Не перекрашивает
 OBJ_ARROWED_LINE    Объект "Линия со стрелкой" Не перекрашивает
 OBJ_CHANNEL    Равноудаленный канал Не перекрашивает
 OBJ_STDDEVCHANNEL    Канал стандартного отклонения  Не перекрашивает
 OBJ_REGRESSION    Канал на линейной регрессии Не перекрашивает
 OBJ_PITCHFORK    Вилы Эндрюса Не перекрашивает
 OBJ_GANNLINE    Линия Ганна Не перекрашивает
 OBJ_GANNFAN    Веер Ганна Не перекрашивает
 OBJ_GANNGRID    Сетка Ганна Не перекрашивает
 OBJ_FIBO    Уровни Фибоначчи Не перекрашивает
 OBJ_FIBOTIMES     Временные зоны Фибоначчи Не перекрашивает
 OBJ_FIBOFAN    Веер Фибоначчи Не перекрашивает
 OBJ_FIBOARC  Дуги Фибоначчи Не перекрашивает
 OBJ_FIBOCHANNEL    Канал Фибоначчи Не перекрашивает
 OBJ_EXPANSION    Расширение Фибоначчи Не перекрашивает
 OBJ_ELLIOTWAVE5    5-волновка Эллиота Не перекрашивает
 OBJ_ELLIOTWAVE3    3-волновка Эллиота Не перекрашивает
 OBJ_RECTANGLE    Прямоугольник Без заливки не перекрашивает,
с заливкой перекрашивает
 OBJ_TRIANGLE    Треугольник Без заливки не перекрашивает,
с заливкой перекрашивает
 OBJ_ELLIPSE    Эллипс Без заливки не перекрашивает,
с заливкой перекрашивает
 OBJ_ARROW_THUMB_UP    Знак "Хорошо" (большой палец вверх) Не перекрашивает
 OBJ_ARROW_THUMB_DOWN    Знак "Плохо" (большой палец вниз) Не перекрашивает
 OBJ_ARROW_UP    Знак "Стрелка вверх" Не перекрашивает
 OBJ_ARROW_DOWN    Знак "Стрелка вниз" Не перекрашивает
 OBJ_ARROW_STOP    Знак "Стоп" Не перекрашивает
 OBJ_ARROW_CHECK    Знак "Птичка" (галка) Не перекрашивает
 OBJ_ARROW_LEFT_PRICE    Левая ценовая метка Не перекрашивает
 OBJ_ARROW_RIGHT_PRICE    Правая ценовая метка Не перекрашивает
 OBJ_ARROW_BUY    Знак "Buy" Не перекрашивает
 OBJ_ARROW_SELL    Знак "Sell" Не перекрашивает
 OBJ_ARROW    Объект "Стрелка" Не перекрашивает
 OBJ_TEXT    Объект "Текст" Не перекрашивает
 OBJ_LABEL    Объект "Текстовая метка" Не перекрашивает
 OBJ_BUTTON    Объект "Кнопка" Не перекрашивает
 OBJ_CHART    Объект "График" Не перекрашивает
 OBJ_BITMAP    Объект "Рисунок Не перекрашивает
 OBJ_BITMAP_LABEL    Объект "Графическая метка" Не перекрашивает
 OBJ_EDIT    Объект "Поле ввода" Не перекрашивает
 OBJ_EVENT    Объект "Событие", соответствующий событию в экономическом календаре Не перекрашивает
 OBJ_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

где:

Рассчитаем результирующий цвет согласно формуле (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

где:


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. Еще раз хочу остановиться на прозрачности: именно частичная прозрачность придает наиболее красивую форму для окантовок графических объектов. В силу двухмерности мониторов прозрачность в графике – это иллюзия, достигаемая обработкой накладываемого пискеля.