Вывод сообщений в окно графика

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

void Comment(argument, ...)

Функция выводит сообщение, составленное из всех переданных аргументов, в левый верхний угол графика. Сообщение остается там, пока эта или какая-либо другая программа не удалит его или не заменит другим.

Окно может содержать только один комментарий: при каждом вызове Comment прежнее содержимое (если оно было) заменяется на новое.

Чтобы очистить комментарий, достаточно вызвать функцию с пустой строкой: Comment("").

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

Общая длина выводимого сообщения ограничена 2045 символами. В случае превышения лимита конец строки будет обрезан.

Текущее содержимое комментария является одним из строковых свойств графика, которые можно узнать с помощью вызова функции ChartGetString(NULL, CHART_COMMENT). Об этом и других свойствах графиков (не только строковых) мы поговорим в отдельной главе.

Так же как и в функциях Print, PrintFormat, Alert, строковые аргументы могут содержать символ перевода строки ('\n' или '\r\n'), в результате чего сообщение будет разделено на соответствующее количество строк. Для Comment это единственная возможность показать многострочное сообщение. Если для получения того же эффекта с помощью функций печати и сигналов можно вызвать их несколько раз, то с Comment так сделать нельзя, поскольку каждый вызов заменит старую строку на новую.

Пример работы функции Comment приведен на изображении окна со скриптом приветствия из первой главы, в разделе Вывод данных.

Дополнительно разработаем класс и упрощенные функции для вывода многострочных комментариев на основе кольцевого буфера заданного размера. Тестовый скрипт (OutputComment.mq5) и заголовочный файл с кодом класса (Comments.mqh) прилагаются к книге.

class Comments
{
   const int capacity// максимальное количество строк
   const bool reverse// порядок отображения (новые наверху, если true)
   string lines[];     // текстовый буфер
   int cursor;         // куда помещаем следующую строку
   int size;           // актуальное количество сохраненных строк
   
public:
   Comments(const int limit = N_LINESconst bool r = false):
      capacity(limit), reverse(r), cursor(0), size(0)
   {
      ArrayResize(linescapacity);
   }
   
   void add(const string line);
   void clear();
};

Основную работу выполняет метод add.

void Comments::add(const string line)
{
   ...
   // если переданный текст содержит несколько строк,
   // разбиваем его на элементы по символу перевода строк
   string inputs[];
   const int n = StringSplit(line, '\n', inputs);
   
   // добавляем все новые элементы в кольцевой буфер
   // перезаписывая по курсору самые старые записи
   // курсор увеличивается по модулю емкости (сброс на 0 по переполнению)
   for(int i = 0i < n; ++i)
   {
      lines[cursor] = inputs[reverse ? n - i - 1 : i];
      cursor = (cursor + 1) % capacity;
      if(size < capacitysize++;
   }
   // объединяем все текстовые записи в прямом или обратном порядке
   // склеивая символами перевода строки   
   string result = "";
   for(int i = 0k = size == capacity ? cursor % capacity : 0;
      i < size; ++ik = ++k % capacity)
   {
      if(reverse)
      {
         result = lines[k] + "\n" + result;
      }
      else
      {
         result += lines[k] + "\n";
      }
   }
   
   // выводим результат
   Comment(result);
}

При необходимости комментарий и текстовый буфер можно очистить методом clear или вызвав add(NULL).

void Comments::clear()
{
   Comment("");
   cursor = 0;
   size = 0;
}

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

Comments c(30/*capacity*/true/*order*/);
   
void function()
{
   ...
   c.add("123");
}

Но для упрощения генерации комментариев в привычном функциональном стиле, по аналогии с функцией Comment, реализована пара вспомогательных функций.

void MultiComment(const string line = NULL)
{
   static Comments com(N_LINEStrue);
   com.add(line);
}
 
void ChronoComment(const string line = NULL)
{
   static Comments com(N_LINESfalse);
   com.add(line);
}

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

Количество строк буфера равно по умолчанию N_LINES (10). Если определить этот макрос с другим значением до включения заголовочного файла, он изменит размер.

Тестовый скрипт содержит цикл, в котором периодически генерируются сообщения.

void OnStart()
{
   for(int i = 0i < 50 && !IsStopped(); ++i)
   {
      if((i + 1) % 10 == 0MultiComment();
      MultiComment("Line " + (string)i + ((i % 3 == 0) ? "\n  (details)" : ""));
      Sleep(1000);
   }
   MultiComment();
}

На каждой десятой итерации комментарий очищается. На каждой третьей — создается сообщение из двух строк (на остальных — из одной). Задержка в 1 секунду позволяет рассмотреть динамику в действии.

Вот пример окна во время работы скрипта (в режиме "новые сообщения наверху").

Многострочные комментарии на графике

Многострочные комментарии на графике

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