Обсуждение статьи "Графические интерфейсы X: Элемент "Стандартный график" (build 4)"

 

Опубликована статья Графические интерфейсы X: Элемент "Стандартный график" (build 4):

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

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

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

Автор: Anatoli Kazharski

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

Для прокрутки OBJ_CHART зачем использовать таймер? Да и для взаимодействия с интерфейсом - аналогичный вопрос. Ведь, вроде, всегда должно хватать событий от мыши.

 
fxsaber:

Для прокрутки OBJ_CHART зачем использовать таймер? Да и для взаимодействия с интерфейсом - аналогичный вопрос. Ведь, вроде, всегда должно хватать событий от мыши.

То, что Вы процитировали, относится не к OBJ_CHART, а к таймеру движка библиотеки в целом. Поэтому решение этой задачи было вынесено в отдельный раздел статьи "Оптимизация таймера и обработчика событий движка библиотеки", как дополнение к основной теме.

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

//--- 

P.S. А прокрутка OBJ_CHART, как раз осуществляется по событию перемещения курсора мыши - CHARTEVENT_MOUSE_MOVE. В листинге ниже код обработчика (сокращённая версия) событий элемента "Стандартный график" (класс CStandardChart):

//+------------------------------------------------------------------+
//| Обработка событий                                                |
//+------------------------------------------------------------------+
void CStandardChart::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Обработка события перемещения курсора
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Выйти, если элемент скрыт
      if(!CElement::IsVisible())
         return;
      //--- Выйти, если в режиме изменения размера подокна
      if(CheckDragBorderWindowMode())
         return;
      //--- Выйти, если номера подокон не совпадают
      if(CElement::m_subwin!=CElement::m_mouse.SubWindowNumber())
         return;
      //--- Выйти, если форма заблокирована другим элементом
      if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
         return;
      //--- Проверка фокуса
      CElement::MouseFocus(m_mouse.X()>X() && m_mouse.X()<X2() && m_mouse.Y()>Y() && m_mouse.Y()<Y2());
      //--- Если есть фокус
      if(CElement::MouseFocus())
         //--- Горизонтальная прокрутка графика
         HorizontalScroll();
      //--- Если фокуса нет и левая кнопка мыши отжата
      else if(!m_mouse.LeftButtonState())
        {
         //--- Скрыть указатель горизонтальной прокрутки
         m_x_scroll.Hide();
         //--- Разблокировать форму
         if(m_wnd.IdActivatedElement()==CElement::Id())
           {
            m_wnd.IsLocked(false);
            m_wnd.IdActivatedElement(WRONG_VALUE);
           }
        }
      //---
      return;
     }
//...
  }
 
Anatoli Kazharski:

По таймеру организовано изменение цвета элементов управления по наведению курсора мыши

Почему здесь мышью обойтись не вышло?
 
fxsaber:
Почему здесь мышью обойтись не вышло?

Потому что предусмотрено плавное изменение цвета (кол-во шагов устанавливает пользователь). 

Это относится и к прокрутке списков. Если использовать метод, как это реализовано в СБ, то будет рваная (неравномерная) прокрутка.

 
Anatoli Kazharski:

Потому что предусмотрено плавное изменение цвета (кол-во шагов устанавливает пользователь). 

Это относится и к прокрутке списков. Если использовать метод, как это реализовано в СБ, то будет рваная (неравномерная) прокрутка.

Почему тогда для OBJ_CHART рваной не выходит?
 
fxsaber:
Почему тогда для OBJ_CHART рваной не выходит?

В каком случае (относительно тестового эксперта из статьи) ? 

  1. В случае, когда осуществляется прокрутка через календарь?
  2. В случае прокрутки вручную по событию CHARTEVENT_MOUSE_MOVE в обработчике событий элемента (CStandardChart?

Если первое, то прокрутка графика осуществляется по таймеру, так как прокрутка календаря осуществляется по таймеру. То есть генерация события изменения даты в календаре (ON_CHANGE_DATE) осуществляется по таймеру с интервалом 16 мс.

Если второе, то сдвиг рассчитывается и не всегда равен 1 бару. Поэтому это только кажется, что прокрутка вручную по событию CHARTEVENT_MOUSE_MOVE плавная. 

 
Anatoli Kazharski:

Если второе, то сдвиг рассчитывается и не всегда равен 1 бару. Поэтому это только кажется, что прокрутка вручную по событию CHARTEVENT_MOUSE_MOVE плавная. 

Понял, спасибо!

 
Спасибо Вам за статью. Ждал. Не разочарован.)
 

Анатолий, подскажи в чём причина ошибки

2016.10.19 03:09:04.993 TestTable (EURUSD,H1)   invalid pointer access in 'Scrolls.mqh' (698,10)

До этого обновления всё работало прекрасно. Сейчас при построении таблицы CTable выскакивает эта ошибка.

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

Файл с примером в архиве.

Файлы:
TestTable.zip  734 kb
 

Нашёл.

Берём твой пример из \MQL4\Experts\Article07\TestLibrary02\TestLibrary02.mq4

Из твоего примера, указанного выше:

Делаем одинаковыми количество столбцов и количество видимых столбцов, компилируем, запускаем, и получаем ошибку.

//+------------------------------------------------------------------+
//| Создаёт таблицу                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
  {
//#define COLUMNS1_TOTAL (100)
//#define ROWS1_TOTAL    (1000)
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL    (1000)
//--- Сохраним указатель на форму
   m_table.WindowPointer(m_window1);
//--- Координаты
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- Количество видимых столбцов и рядов
   int visible_columns_total =6;
   int visible_rows_total    =15;
//--- Установим свойства перед созданием
   m_table.XSize(600);
   m_table.RowYSize(20);
   m_table.FixFirstRow(true);
   m_table.FixFirstColumn(true);
   m_table.LightsHover(true);
   m_table.SelectableRow(true);
   m_table.TextAlign(ALIGN_CENTER);
   m_table.HeadersColor(C'255,244,213');
   m_table.HeadersTextColor(clrBlack);
   m_table.CellColorHover(clrGold);
   m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- Создадим элемент управления
   if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- Заполним таблицу:
//    Первая ячейка пустая
   m_table.SetValue(0,0,"-");
//--- Заголовки для столбцов
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//--- Заголовки для рядов, способ выравнивания текста - справа
   for(int c=0; c<1; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,"PARAMETER "+string(r));
         m_table.TextAlign(c,r,ALIGN_RIGHT);
        }
     }
//--- Данные и форматирование таблицы (цвет фона и цвет ячеек)
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,string(c)+":"+string(r));
         m_table.TextColor(c,r,(c%2==0)? clrRed : clrRoyalBlue);
         m_table.CellColor(c,r,(r%2==0)? clrWhiteSmoke : clrWhite);
        }
     }
//--- Обновить таблицу для отображения изменений
   m_table.UpdateTable();
//--- Добавим объект в общий массив групп объектов
   CWndContainer::AddToElementsArray(0,m_table);
   return(true);
  }
//+------------------------------------------------------------------+
Собственно, если сделать одинаковыми так же значения количества рядов и количество видимых рядов, то та же ошибка.
Причина обращения: