Обсуждение статьи "Графические интерфейсы X: Элемент "Стандартный график" (build 4)" - страница 2
Вы упускаете торговые возможности:
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Регистрация
Вход
Вы принимаете политику сайта и условия использования
Если у вас нет учетной записи, зарегистрируйтесь
Анатолий, подскажи в чём причина ошибки
До этого обновления всё работало прекрасно. Сейчас при построении таблицы 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.
Что касается оптимизации, то я ещё не все варианты исчерпал. Ещё есть что оптимизировать и есть понимание как.