2016.10.19 03:09:04.993 TestTable (EURUSD,H1) invalid pointer access in 'Scrolls.mqh' (698,10)
До этого обновления всё работало прекрасно. Сейчас при построении таблицы CTable выскакивает эта ошибка.
Подскажи пожалуйста где не так стало - уже каждую строчку принтовал - интерфейс строится, но после где-то спотыкается, и ... ошибка.
Файл с примером в архиве.
Забыл внести исправление, как это было сделано ранее в классе CCanvasTable.
В классе CTable нужно заменить текущие версии методов CreateScrollV() и CreateScrollH() на представленные в листинге ниже:
//+------------------------------------------------------------------+ //| Создаёт вертикальную полосу прокрутки | //+------------------------------------------------------------------+ bool CTable::CreateScrollV(void) { //--- Сохранить указатель формы m_scrollv.WindowPointer(m_wnd); //--- Координаты int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth(); int y=CElement::Y(); //--- Установим размеры m_scrollv.Id(CElement::Id()); m_scrollv.IsDropdown(CElement::IsDropdown()); m_scrollv.XSize(m_scrollv.ScrollWidth()); m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size); m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side); m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side); //--- Создание полосы прокрутки if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total)) return(false); //--- Скрыть, если сейчас не нужна if(m_rows_total<=m_visible_rows_total) m_scrollv.Hide(); //--- return(true); } //+------------------------------------------------------------------+ //| Создаёт горизонтальную полосу прокрутки | //+------------------------------------------------------------------+ bool CTable::CreateScrollH(void) { //--- Сохранить указатель формы m_scrollh.WindowPointer(m_wnd); //--- Координаты int x=CElement::X(); int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth(); //--- Установим размеры m_scrollh.Id(CElement::Id()); m_scrollh.IsDropdown(CElement::IsDropdown()); m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize()); m_scrollh.YSize(m_scrollh.ScrollWidth()); m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side); m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side); //--- Создание полосы прокрутки if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total)) return(false); //--- Скрыть, если сейчас не нужна if(m_columns_total<=m_visible_columns_total) m_scrollh.Hide(); //--- return(true); }
//---
Аналогичные изменения нужно внести в классе CLabelsTable. Исправления будут в следующем обновлении.
Забыл внести исправление, как это было сделано ранее в классе CCanvasTable.
В классе CTable нужно заменить текущие версии методов CreateScrollV() и CreateScrollH() на представленные в листинге ниже:
//+------------------------------------------------------------------+ //| Создаёт вертикальную полосу прокрутки | //+------------------------------------------------------------------+ bool CTable::CreateScrollV(void) { //--- Сохранить указатель формы m_scrollv.WindowPointer(m_wnd); //--- Координаты int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth(); int y=CElement::Y(); //--- Установим размеры m_scrollv.Id(CElement::Id()); m_scrollv.IsDropdown(CElement::IsDropdown()); m_scrollv.XSize(m_scrollv.ScrollWidth()); m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size); m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side); m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side); //--- Создание полосы прокрутки if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total)) return(false); //--- Скрыть, если сейчас не нужна if(m_rows_total<=m_visible_rows_total) m_scrollv.Hide(); //--- return(true); } //+------------------------------------------------------------------+ //| Создаёт горизонтальную полосу прокрутки | //+------------------------------------------------------------------+ bool CTable::CreateScrollH(void) { //--- Сохранить указатель формы m_scrollh.WindowPointer(m_wnd); //--- Координаты int x=CElement::X(); int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth(); //--- Установим размеры m_scrollh.Id(CElement::Id()); m_scrollh.IsDropdown(CElement::IsDropdown()); m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize()); m_scrollh.YSize(m_scrollh.ScrollWidth()); m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side); m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side); //--- Создание полосы прокрутки if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total)) return(false); //--- Скрыть, если сейчас не нужна if(m_columns_total<=m_visible_columns_total) m_scrollh.Hide(); //--- return(true); }
//---
Аналогичные изменения нужно внести в классе CLabelsTable. Исправления будут в следующем обновлении.
Анатолий, изменения внесены. Берём пример из \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, правим таблицу в Program.mqh так, чтобы количество строк совпадало с видимым количеством строк, или количество столбцов совпадало с видимым количеством столбцов, или и то, и другое чтобы совпадало. Например, так:
//+------------------------------------------------------------------+ //| Создаёт таблицу | //+------------------------------------------------------------------+ bool CProgram::CreateTable(void) { #define COLUMNS1_TOTAL (6) #define ROWS1_TOTAL (15) //--- Сохраним указатель на форму m_table.WindowPointer(m_window1); //--- Координаты int x=m_window1.X()+TABLE1_GAP_X; int y=m_window1.Y()+TABLE1_GAP_Y; //--- Количество видимых столбцов и рядов intvisible_columns_total =6; intvisible_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); } //+------------------------------------------------------------------+
Компилируем, запускаем пример, щёлкаем по самой нижней строке таблицы (всё нормально), а потом ещё раз щёлкаем по ней же. На втором щелчке выскакивает ошибка:
2016.10.24 03:37:16.407 ChartWindow02 (USDCHF,H1) array out of range in 'Table.mqh' (1091,86)
Анатолий, изменения внесены. Берём пример из \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, правим таблицу в Program.mqh так, чтобы количество строк совпадало с видимым количеством строк, или количество столбцов совпадало с видимым количеством столбцов, или и то, и другое чтобы совпадало. Например, так:
...
Компилируем, запускаем пример, щёлкаем по самой нижней строке таблицы (всё нормально), а потом ещё раз щёлкаем по ней же. На втором щелчке выскакивает ошибка:
2016.10.24 03:37:16.407 ChartWindow02 (USDCHF,H1) array out of range in 'Table.mqh' (1091,86)
Что делать, и как быть?
В классах CScrollHи CScrollV в методах ScrollBarControl() нужно добавить дополнительную проверку на видимость элемента так, как это показано в листинге ниже:
//+------------------------------------------------------------------+ //| Управление скроллом | //+------------------------------------------------------------------+ bool CScrollH::ScrollBarControl(constint x,constint y,constbool mouse_state) { //--- Выйти, если нет указателя на форму if(::CheckPointer(m_wnd)==POINTER_INVALID) return(false); //--- Выйти, если форма заблокирована другим элементом if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id()) return(false); //--- Выйти, если элемент скрыт if(!CElement::IsVisible()) return(false); //--- Проверка фокуса над ползунком m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() && y>m_thumb.Y() && y<m_thumb.Y2()); //--- Проверим и запомним состояние кнопки мыши CScroll::CheckMouseButtonState(mouse_state); //--- Изменим цвет полосы прокрутки списка CScroll::ChangeObjectsColor(); //--- Если управление передано полосе прокрутки, определим положение ползунка if(CScroll::ScrollState()) { //--- Перемещение ползунка OnDragThumb(x); //--- Изменяет номер позиции ползунка CalculateThumbPos(); return(true); } return(false); }
//---
Исправление будет доступно в следующем обновлении библиотеки.
В классах CScrollH и CScrollV в методах ScrollBarControl() нужно добавить дополнительную проверку на видимость элемента так, как это показано в листинге ниже:
...
Исправление будет доступно в следующем обновлении библиотеки.
Спасибо. Внёс такие изменения: в файле Scrolls.mqh в классах CScrollH и CScrollV добавил строки:
//+------------------------------------------------------------------+ //| Управление ползунком | //+------------------------------------------------------------------+ bool CScrollV::ScrollBarControl(constint x,constint y,constbool mouse_state) { //--- Выйти, если нет указателя на форму if(::CheckPointer(m_wnd)==POINTER_INVALID) return(false); //--- Если форма не заблокирована и идентификаторы совпадают if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id()) return(false); //--- Выйти, если элемент скрыт if(!CElement::IsVisible()) return(false); //--- Проверка фокуса над ползуком m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() && y>m_thumb.Y() && y<m_thumb.Y2()); //--- Проверим и запомним состояние кнопки мыши CScroll::CheckMouseButtonState(mouse_state); //--- Изменим цвет ползунка CScroll::ChangeObjectsColor(); //--- Если управление передано полосе прокрутки, определим положение ползунка if(CScroll::ScrollState()) { //--- Перемещение ползунка OnDragThumb(y); //--- Изменяет номер позиции ползунка CalculateThumbPos(); return(true); } //--- return(false); } //+------------------------------------------------------------------+
//+------------------------------------------------------------------+ //| Управление скроллом | //+------------------------------------------------------------------+ bool CScrollH::ScrollBarControl(constint x,constint y,constbool mouse_state) { //--- Выйти, если нет указателя на форму if(::CheckPointer(m_wnd)==POINTER_INVALID) return(false); if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id()) return(false); //--- Выйти, если элемент скрыт if(!CElement::IsVisible()) return(false); //--- Проверка фокуса над ползуком m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() && y>m_thumb.Y() && y<m_thumb.Y2()); //--- Проверим и запомним состояние кнопки мыши CScroll::CheckMouseButtonState(mouse_state); //--- Изменим цвет полосы прокрутки списка CScroll::ChangeObjectsColor(); //--- Если управление передано полосе прокрутки, определим положение ползунка if(CScroll::ScrollState()) { //--- Перемещение ползунка OnDragThumb(x); //--- Изменяет номер позиции ползунка CalculateThumbPos(); return(true); } return(false); } //+------------------------------------------------------------------+
Компилирую и запускаю тот же проверочный файл из \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, в который внесены изменения в функцию построения таблицы в Program.mqh так, чтобы количество всех столбцов и строк совпадало с количеством видимых столбцов и строк:
//+------------------------------------------------------------------+ //| Создаёт таблицу | //+------------------------------------------------------------------+ bool CProgram::CreateTable(void) { #define COLUMNS1_TOTAL (6) #define ROWS1_TOTAL (15) //--- Сохраним указатель на форму 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); } //+------------------------------------------------------------------+
Компилирую и запускаю ChartWindow02.ex5
Несколько раз щёлкаем по самой нижней строке таблицы и получаем вылет за пределы массива:
2016.10.25 01:39:22.899 ChartWindow02 (USDCHF,H1) array out of range in 'Table.mqh' (1096,86)
А у меня после внесённых изменений больше не воспроизводится. Возможно, я какие-то ещё изменения вносил, но уже не помню. Не отмечаю у себя историю мелких правок.
На всякий случай, попробуй ещё методы CScroll::Show() и CScroll::Hide() заменить вот этими версиями, если отличаются:
//+------------------------------------------------------------------+ //| Показывает пункт меню | //+------------------------------------------------------------------+ void CScroll::Show(void) { //--- Выйдем, если количество элементов списка не больше количества видимой части списка if(m_items_total<=m_visible_items_total) return; //--- m_area.Timeframes(OBJ_ALL_PERIODS); m_bg.Timeframes(OBJ_ALL_PERIODS); m_inc.Timeframes(OBJ_ALL_PERIODS); m_dec.Timeframes(OBJ_ALL_PERIODS); m_thumb.Timeframes(OBJ_ALL_PERIODS); //--- Обновить положение объектов Moving(m_wnd.X(),m_wnd.Y(),true); //--- Состояние видимости CElement::IsVisible(true); } //+------------------------------------------------------------------+ //| Скрывает пункт меню | //+------------------------------------------------------------------+ void CScroll::Hide(void) { m_area.Timeframes(OBJ_NO_PERIODS); m_bg.Timeframes(OBJ_NO_PERIODS); m_inc.Timeframes(OBJ_NO_PERIODS); m_dec.Timeframes(OBJ_NO_PERIODS); m_thumb.Timeframes(OBJ_NO_PERIODS); //--- Состояние видимости CElement::IsVisible(false); }
//---
Если не поможет, то придётся подождать следующего обновления.
А у меня после внесённых изменений больше не воспроизводится. Возможно, я какие-то ещё изменения вносил, но уже не помню. Не отмечаю у себя историю мелких правок.
На всякий случай, попробуй ещё методы CScroll::Show() и CScroll::Hide() заменить вот этими версиями, если отличаются:
//+------------------------------------------------------------------+ //| Показывает пункт меню | //+------------------------------------------------------------------+ void CScroll::Show(void) { //--- Выйдем, если количество элементов списка не больше количества видимой части списка if(m_items_total<=m_visible_items_total) return; //--- m_area.Timeframes(OBJ_ALL_PERIODS); m_bg.Timeframes(OBJ_ALL_PERIODS); m_inc.Timeframes(OBJ_ALL_PERIODS); m_dec.Timeframes(OBJ_ALL_PERIODS); m_thumb.Timeframes(OBJ_ALL_PERIODS); //--- Обновить положение объектов Moving(m_wnd.X(),m_wnd.Y(),true); //--- Состояние видимости CElement::IsVisible(true); } //+------------------------------------------------------------------+ //| Скрывает пункт меню | //+------------------------------------------------------------------+ void CScroll::Hide(void) { m_area.Timeframes(OBJ_NO_PERIODS); m_bg.Timeframes(OBJ_NO_PERIODS); m_inc.Timeframes(OBJ_NO_PERIODS); m_dec.Timeframes(OBJ_NO_PERIODS); m_thumb.Timeframes(OBJ_NO_PERIODS); //--- Состояние видимости CElement::IsVisible(false); }
//---
Если не поможет, то придётся подождать следующего обновления.
Благодарю, вродь помогло. Отсутствовали строки о состоянии видимости в Show():
//--- Состояние видимости CElement::IsVisible(true);
и в Hide():
//--- Состояние видимости CElement::IsVisible(false);
Интерактивность элементов интерфейса реализованная через таймер странное решение. - Почему она должна реализовываться через (или с помощью) таймера? - Конечно, это будет потреблять много ресурсов.
Для управления состояниями элементов управления вообще не нужен таймер.
1. Записывайте текущие координаты всех элементов в массиве (карте). Вносите коррективы в координаты местоположения всех объектов формы при перемещении окна.
2. Сделайте функцию нахождения элементов по координатам (локализатор). Функция будет делать цикл по записанным текущим координатам элементов и находить тот элемент, который сейчас находится под курсором.
3. Вызывайте локализатор из события "CHARTEVENT_MOUSE_MOVE" (на событие движения курсора).
4. Возвращаемое от локализатора имя объекта передавайте в функцию интерактивности, в которой к объекту будет применятся функция ObjectSetInteger(), которая будет заставлять менять его цвет.
Как видите, в этой схеме нет таймера, а значит нет и лишнего потребления ресурсов.
Интерактивность элементов интерфейса реализованная через таймер странное решение. - Почему она должна реализовываться через (или с помощью) таймера? - Конечно, это будет потреблять много ресурсов.
...
Как видите, в этой схеме нет таймера, а значит нет и лишнего потребления ресурсов.
Вы ошибаетесь. Достаточно подробно уже ответил в комментариях выше, зачем это было сделано именно так.
Сейчас это не потребляет много ресурсов (теперь и в Windows 10 тоже). Вы статью читали (и комментарии тоже) ?
//---
P.S. Кстати, потребление ресурсов процессора в разных терминалах (MT4/MT5) и версиях ОС (Windows) сильно отличается при равных условиях. В Windows 7 терминал MetaTrader 4 показывал себя существенно лучше, чем MetaTrader 5. К сожалению не смогу сейчас привести цифры, так как уже полностью перешёл на Windows 10.
Что касается оптимизации, то я ещё не все варианты исчерпал. Ещё есть что оптимизировать и есть понимание как.
Анатолий, подскажи в чём причина ошибки
До этого обновления всё работало прекрасно. Сейчас при построении таблицы CTable выскакивает эта ошибка.
Подскажи пожалуйста где не так стало - уже каждую строчку принтовал - интерфейс строится, но после где-то спотыкается, и ... ошибка.
Файл с примером в архиве.
Забыл внести исправление, как это было сделано ранее в классе CCanvasTable.
В классе CTable нужно заменить текущие версии методов CreateScrollV() и CreateScrollH() на представленные в листинге ниже:
//| Создаёт вертикальную полосу прокрутки |
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
{
//--- Сохранить указатель формы
m_scrollv.WindowPointer(m_wnd);
//--- Координаты
int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
int y=CElement::Y();
//--- Установим размеры
m_scrollv.Id(CElement::Id());
m_scrollv.IsDropdown(CElement::IsDropdown());
m_scrollv.XSize(m_scrollv.ScrollWidth());
m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size);
m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side);
m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Создание полосы прокрутки
if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
return(false);
//--- Скрыть, если сейчас не нужна
if(m_rows_total<=m_visible_rows_total)
m_scrollv.Hide();
//---
return(true);
}
//+------------------------------------------------------------------+
//| Создаёт горизонтальную полосу прокрутки |
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
{
//--- Сохранить указатель формы
m_scrollh.WindowPointer(m_wnd);
//--- Координаты
int x=CElement::X();
int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth();
//--- Установим размеры
m_scrollh.Id(CElement::Id());
m_scrollh.IsDropdown(CElement::IsDropdown());
m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize());
m_scrollh.YSize(m_scrollh.ScrollWidth());
m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side);
m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Создание полосы прокрутки
if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
return(false);
//--- Скрыть, если сейчас не нужна
if(m_columns_total<=m_visible_columns_total)
m_scrollh.Hide();
//---
return(true);
}
//---
Аналогичные изменения нужно внести в классе CLabelsTable. Исправления будут в следующем обновлении.
Забыл внести исправление, как это было сделано ранее в классе CCanvasTable.
В классе CTable нужно заменить текущие версии методов CreateScrollV() и CreateScrollH() на представленные в листинге ниже:
...
//---
Аналогичные изменения нужно внести в классе CLabelsTable. Исправления будут в следующем обновлении.
Забыл внести исправление, как это было сделано ранее в классе CCanvasTable.
В классе CTable нужно заменить текущие версии методов CreateScrollV() и CreateScrollH() на представленные в листинге ниже:
//| Создаёт вертикальную полосу прокрутки |
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
{
//--- Сохранить указатель формы
m_scrollv.WindowPointer(m_wnd);
//--- Координаты
int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
int y=CElement::Y();
//--- Установим размеры
m_scrollv.Id(CElement::Id());
m_scrollv.IsDropdown(CElement::IsDropdown());
m_scrollv.XSize(m_scrollv.ScrollWidth());
m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size);
m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side);
m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Создание полосы прокрутки
if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
return(false);
//--- Скрыть, если сейчас не нужна
if(m_rows_total<=m_visible_rows_total)
m_scrollv.Hide();
//---
return(true);
}
//+------------------------------------------------------------------+
//| Создаёт горизонтальную полосу прокрутки |
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
{
//--- Сохранить указатель формы
m_scrollh.WindowPointer(m_wnd);
//--- Координаты
int x=CElement::X();
int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth();
//--- Установим размеры
m_scrollh.Id(CElement::Id());
m_scrollh.IsDropdown(CElement::IsDropdown());
m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize());
m_scrollh.YSize(m_scrollh.ScrollWidth());
m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side);
m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Создание полосы прокрутки
if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
return(false);
//--- Скрыть, если сейчас не нужна
if(m_columns_total<=m_visible_columns_total)
m_scrollh.Hide();
//---
return(true);
}
//---
Аналогичные изменения нужно внести в классе CLabelsTable. Исправления будут в следующем обновлении.
Анатолий, изменения внесены. Берём пример из \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, правим таблицу в Program.mqh так, чтобы количество строк совпадало с видимым количеством строк, или количество столбцов совпадало с видимым количеством столбцов, или и то, и другое чтобы совпадало. Например, так:
//| Создаёт таблицу |
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
{
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL (15)
//--- Сохраним указатель на форму
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);
}
//+------------------------------------------------------------------+
Компилируем, запускаем пример, щёлкаем по самой нижней строке таблицы (всё нормально), а потом ещё раз щёлкаем по ней же. На втором щелчке выскакивает ошибка:
Что делать, и как быть?
Анатолий, изменения внесены. Берём пример из \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, правим таблицу в Program.mqh так, чтобы количество строк совпадало с видимым количеством строк, или количество столбцов совпадало с видимым количеством столбцов, или и то, и другое чтобы совпадало. Например, так:
...
Компилируем, запускаем пример, щёлкаем по самой нижней строке таблицы (всё нормально), а потом ещё раз щёлкаем по ней же. На втором щелчке выскакивает ошибка:
Что делать, и как быть?
В классах CScrollH и CScrollV в методах ScrollBarControl() нужно добавить дополнительную проверку на видимость элемента так, как это показано в листинге ниже:
//| Управление скроллом |
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
{
//--- Выйти, если нет указателя на форму
if(::CheckPointer(m_wnd)==POINTER_INVALID)
return(false);
//--- Выйти, если форма заблокирована другим элементом
if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
return(false);
//--- Выйти, если элемент скрыт
if(!CElement::IsVisible())
return(false);
//--- Проверка фокуса над ползунком
m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
y>m_thumb.Y() && y<m_thumb.Y2());
//--- Проверим и запомним состояние кнопки мыши
CScroll::CheckMouseButtonState(mouse_state);
//--- Изменим цвет полосы прокрутки списка
CScroll::ChangeObjectsColor();
//--- Если управление передано полосе прокрутки, определим положение ползунка
if(CScroll::ScrollState())
{
//--- Перемещение ползунка
OnDragThumb(x);
//--- Изменяет номер позиции ползунка
CalculateThumbPos();
return(true);
}
return(false);
}
//---
Исправление будет доступно в следующем обновлении библиотеки.
В классах CScrollH и CScrollV в методах ScrollBarControl() нужно добавить дополнительную проверку на видимость элемента так, как это показано в листинге ниже:
...
Исправление будет доступно в следующем обновлении библиотеки.
Спасибо. Внёс такие изменения: в файле Scrolls.mqh в классах CScrollH и CScrollV добавил строки:
//| Управление ползунком |
//+------------------------------------------------------------------+
bool CScrollV::ScrollBarControl(const int x,const int y,const bool mouse_state)
{
//--- Выйти, если нет указателя на форму
if(::CheckPointer(m_wnd)==POINTER_INVALID)
return(false);
//--- Если форма не заблокирована и идентификаторы совпадают
if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
return(false);
//--- Выйти, если элемент скрыт
if(!CElement::IsVisible())
return(false);
//--- Проверка фокуса над ползуком
m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
y>m_thumb.Y() && y<m_thumb.Y2());
//--- Проверим и запомним состояние кнопки мыши
CScroll::CheckMouseButtonState(mouse_state);
//--- Изменим цвет ползунка
CScroll::ChangeObjectsColor();
//--- Если управление передано полосе прокрутки, определим положение ползунка
if(CScroll::ScrollState())
{
//--- Перемещение ползунка
OnDragThumb(y);
//--- Изменяет номер позиции ползунка
CalculateThumbPos();
return(true);
}
//---
return(false);
}
//+------------------------------------------------------------------+
//| Управление скроллом |
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
{
//--- Выйти, если нет указателя на форму
if(::CheckPointer(m_wnd)==POINTER_INVALID)
return(false);
if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
return(false);
//--- Выйти, если элемент скрыт
if(!CElement::IsVisible())
return(false);
//--- Проверка фокуса над ползуком
m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
y>m_thumb.Y() && y<m_thumb.Y2());
//--- Проверим и запомним состояние кнопки мыши
CScroll::CheckMouseButtonState(mouse_state);
//--- Изменим цвет полосы прокрутки списка
CScroll::ChangeObjectsColor();
//--- Если управление передано полосе прокрутки, определим положение ползунка
if(CScroll::ScrollState())
{
//--- Перемещение ползунка
OnDragThumb(x);
//--- Изменяет номер позиции ползунка
CalculateThumbPos();
return(true);
}
return(false);
}
//+------------------------------------------------------------------+
Компилирую и запускаю тот же проверочный файл из \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, в который внесены изменения в функцию построения таблицы в Program.mqh так, чтобы количество всех столбцов и строк совпадало с количеством видимых столбцов и строк:
//| Создаёт таблицу |
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
{
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL (15)
//--- Сохраним указатель на форму
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);
}
//+------------------------------------------------------------------+
Компилирую и запускаю ChartWindow02.ex5
Несколько раз щёлкаем по самой нижней строке таблицы и получаем вылет за пределы массива:
...
Получается, что ничего не изменилось?А у меня после внесённых изменений больше не воспроизводится. Возможно, я какие-то ещё изменения вносил, но уже не помню. Не отмечаю у себя историю мелких правок.
На всякий случай, попробуй ещё методы CScroll::Show() и CScroll::Hide() заменить вот этими версиями, если отличаются:
//| Показывает пункт меню |
//+------------------------------------------------------------------+
void CScroll::Show(void)
{
//--- Выйдем, если количество элементов списка не больше количества видимой части списка
if(m_items_total<=m_visible_items_total)
return;
//---
m_area.Timeframes(OBJ_ALL_PERIODS);
m_bg.Timeframes(OBJ_ALL_PERIODS);
m_inc.Timeframes(OBJ_ALL_PERIODS);
m_dec.Timeframes(OBJ_ALL_PERIODS);
m_thumb.Timeframes(OBJ_ALL_PERIODS);
//--- Обновить положение объектов
Moving(m_wnd.X(),m_wnd.Y(),true);
//--- Состояние видимости
CElement::IsVisible(true);
}
//+------------------------------------------------------------------+
//| Скрывает пункт меню |
//+------------------------------------------------------------------+
void CScroll::Hide(void)
{
m_area.Timeframes(OBJ_NO_PERIODS);
m_bg.Timeframes(OBJ_NO_PERIODS);
m_inc.Timeframes(OBJ_NO_PERIODS);
m_dec.Timeframes(OBJ_NO_PERIODS);
m_thumb.Timeframes(OBJ_NO_PERIODS);
//--- Состояние видимости
CElement::IsVisible(false);
}
//---
Если не поможет, то придётся подождать следующего обновления.
А у меня после внесённых изменений больше не воспроизводится. Возможно, я какие-то ещё изменения вносил, но уже не помню. Не отмечаю у себя историю мелких правок.
На всякий случай, попробуй ещё методы CScroll::Show() и CScroll::Hide() заменить вот этими версиями, если отличаются:
//| Показывает пункт меню |
//+------------------------------------------------------------------+
void CScroll::Show(void)
{
//--- Выйдем, если количество элементов списка не больше количества видимой части списка
if(m_items_total<=m_visible_items_total)
return;
//---
m_area.Timeframes(OBJ_ALL_PERIODS);
m_bg.Timeframes(OBJ_ALL_PERIODS);
m_inc.Timeframes(OBJ_ALL_PERIODS);
m_dec.Timeframes(OBJ_ALL_PERIODS);
m_thumb.Timeframes(OBJ_ALL_PERIODS);
//--- Обновить положение объектов
Moving(m_wnd.X(),m_wnd.Y(),true);
//--- Состояние видимости
CElement::IsVisible(true);
}
//+------------------------------------------------------------------+
//| Скрывает пункт меню |
//+------------------------------------------------------------------+
void CScroll::Hide(void)
{
m_area.Timeframes(OBJ_NO_PERIODS);
m_bg.Timeframes(OBJ_NO_PERIODS);
m_inc.Timeframes(OBJ_NO_PERIODS);
m_dec.Timeframes(OBJ_NO_PERIODS);
m_thumb.Timeframes(OBJ_NO_PERIODS);
//--- Состояние видимости
CElement::IsVisible(false);
}
//---
Если не поможет, то придётся подождать следующего обновления.
Благодарю, вродь помогло. Отсутствовали строки о состоянии видимости в Show():
CElement::IsVisible(true);
и в Hide():
CElement::IsVisible(false);
Благодарю, вродь помогло. Отсутствовали строки о состоянии видимости в Show():
CElement::IsVisible(true);
и в Hide():
CElement::IsVisible(false);
Ещё одна поправка нужна. Видимость нужно устанавливать перед обновлением положения элемента. Вот так:
//--- Состояние видимости
CElement::IsVisible(true);
//--- Обновить положение объектов
Moving(m_wnd.X(),m_wnd.Y(),true);
...
Интерактивность элементов интерфейса реализованная через таймер странное решение. - Почему она должна реализовываться через (или с помощью) таймера? - Конечно, это будет потреблять много ресурсов.
Для управления состояниями элементов управления вообще не нужен таймер.
1. Записывайте текущие координаты всех элементов в массиве (карте). Вносите коррективы в координаты местоположения всех объектов формы при перемещении окна.
2. Сделайте функцию нахождения элементов по координатам (локализатор). Функция будет делать цикл по записанным текущим координатам элементов и находить тот элемент, который сейчас находится под курсором.
3. Вызывайте локализатор из события "CHARTEVENT_MOUSE_MOVE" (на событие движения курсора).
4. Возвращаемое от локализатора имя объекта передавайте в функцию интерактивности, в которой к объекту будет применятся функция ObjectSetInteger(), которая будет заставлять менять его цвет.
Как видите, в этой схеме нет таймера, а значит нет и лишнего потребления ресурсов.
Интерактивность элементов интерфейса реализованная через таймер странное решение. - Почему она должна реализовываться через (или с помощью) таймера? - Конечно, это будет потреблять много ресурсов.
...
Как видите, в этой схеме нет таймера, а значит нет и лишнего потребления ресурсов.
Вы ошибаетесь. Достаточно подробно уже ответил в комментариях выше, зачем это было сделано именно так.
Сейчас это не потребляет много ресурсов (теперь и в Windows 10 тоже). Вы статью читали (и комментарии тоже) ?
//---
P.S. Кстати, потребление ресурсов процессора в разных терминалах (MT4/MT5) и версиях ОС (Windows) сильно отличается при равных условиях. В Windows 7 терминал MetaTrader 4 показывал себя существенно лучше, чем MetaTrader 5. К сожалению не смогу сейчас привести цифры, так как уже полностью перешёл на Windows 10.
Что касается оптимизации, то я ещё не все варианты исчерпал. Ещё есть что оптимизировать и есть понимание как.