Discussão do artigo "Interfaces Gráficas X: O Controle Gráfico Padrão (build 4)" - página 2

 
Artyom Trishkin:

Anatoly, diga-me qual é a causa do erro

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

Tudo funcionava bem antes dessa atualização. Agora, ao criar a tabela CTable, esse erro aparece.

Por favor, diga-me onde está o erro - já imprimi todas as linhas - a interface é criada, mas depois de algum tempo ela tropeça e .... erro.

Arquivo com um exemplo no arquivo.

Esqueci de fazer uma correção, pois ela foi feita anteriormente na classe CCanvasTable.

Na classe CTable, você precisa substituir as versões atuais dos métodos CreateScrollV() e CreateScrollH() pelos métodos mostrados na listagem abaixo:

//+------------------------------------------------------------------+
//|| Cria uma barra de rolagem vertical
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
  {
//--- Salvar o ponteiro do formulário
   m_scrollv.WindowPointer(m_wnd);
//--- Coordenadas
   int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
   int y=CElement::Y();
//--- Definir dimensões
   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);
//--- Criando uma barra de rolagem
   if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
      return(false);
//--- Ocultar se não for necessário agora
   if(m_rows_total<=m_visible_rows_total)
      m_scrollv.Hide();
//---
   return(true);
  }
//+------------------------------------------------------------------+
//|| Cria uma barra de rolagem horizontal
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
  {
//--- Salvar o ponteiro do formulário
   m_scrollh.WindowPointer(m_wnd);
//--- Coordenadas
   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();
//--- Definir dimensões
   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);
//--- Criando uma barra de rolagem
   if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
      return(false);
//--- Ocultar se não for necessário agora
   if(m_columns_total<=m_visible_columns_total)
      m_scrollh.Hide();
//---
   return(true);
  }


//---

Mudanças semelhantes precisam ser feitas na classe CLabelsTable. As correções estarão na próxima atualização.

 
Anatoli Kazharski:

Esqueci de fazer uma correção, pois ela foi feita anteriormente na classe CCanvasTable.

Na classe CTable, você precisa substituir as versões atuais dos métodos CreateScrollV() e CreateScrollH() pelos métodos mostrados na listagem abaixo:

...
//---

Mudanças semelhantes precisam ser feitas na classe CLabelsTable. As correções estarão na próxima atualização.

О! Obrigado!
 
Anatoli Kazharski:

Esqueci de fazer uma correção, pois ela foi feita anteriormente na classe CCanvasTable.

Na classe CTable, você precisa substituir as versões atuais dos métodos CreateScrollV() e CreateScrollH() pelos métodos mostrados na listagem abaixo:

//+------------------------------------------------------------------+
//|| Cria uma barra de rolagem vertical
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
  {
//--- Salvar o ponteiro do formulário
   m_scrollv.WindowPointer(m_wnd);
//--- Coordenadas
   int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
   int y=CElement::Y();
//--- Definir dimensões
   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);
//--- Criando uma barra de rolagem
   if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
      return(false);
//--- Ocultar se não for necessário agora
   if(m_rows_total<=m_visible_rows_total)
      m_scrollv.Hide();
//---
   return(true);
  }
//+------------------------------------------------------------------+
//|| Cria uma barra de rolagem horizontal
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
  {
//--- Salvar o ponteiro do formulário
   m_scrollh.WindowPointer(m_wnd);
//--- Coordenadas
   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();
//--- Definir dimensões
   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);
//--- Criando uma barra de rolagem
   if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
      return(false);
//--- Ocultar se não for necessário agora
   if(m_columns_total<=m_visible_columns_total)
      m_scrollh.Hide();
//---
   return(true);
  }


//---

Mudanças semelhantes precisam ser feitas na classe CLabelsTable. As correções estarão na próxima atualização.

Anatoly, as alterações foram feitas. Pegue o exemplo de MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, corrija a tabela em Program.mqh para que o número de linhas coincida com o número visível de linhas, ou o número de colunas coincida com o número visível de colunas, ou ambos. Por exemplo:

//+------------------------------------------------------------------+
//|| Cria uma tabela|
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
  {
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL    (15)
//--- Salvar o ponteiro no formulário
   m_table.WindowPointer(m_window1);
//--- Coordenadas
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- Número de colunas e linhas visíveis
   int visible_columns_total =6;
   int visible_rows_total    =15;
//--- Definir propriedades antes da criação
   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);
//--- Criar um controle
   if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- Vamos preencher a tabela:
// A primeira célula está vazia
   m_table.SetValue(0,0,"-");
//--- Títulos para colunas
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//--- Cabeçalhos para linhas, método de alinhamento de texto - à direita
   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);
        }
     }
//--- Formatação de dados e tabelas (cor de fundo e cor da célula)
   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);
        }
     }
//--- Atualize a tabela para mostrar as alterações
   m_table.UpdateTable();
//--- Adicione o objeto à matriz comum de grupos de objetos
   CWndContainer::AddToElementsArray(0,m_table);
   return(true);
  }
//+------------------------------------------------------------------+

Compile, execute o exemplo, clique na linha mais baixa da tabela (tudo está bem) e, em seguida, clique nela novamente. No segundo clique, aparece um erro:

2016.10.24 03:37:16.407 ChartWindow02 (USDCHF,H1)       array out of range in 'Table.mqh' (1091,86)

O que fazer e o que fazer?

 
Artyom Trishkin:

Anatoly, as alterações foram feitas. Pegue o exemplo de MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, corrija a tabela em Program.mqh para que o número de linhas coincida com o número visível de linhas, ou o número de colunas coincida com o número visível de colunas, ou ambos. Por exemplo, assim:

...

Compile, execute o exemplo, clique na linha mais baixa da tabela (tudo está bem) e, em seguida, clique nela novamente. Um erro aparece no segundo clique:

2016.10.24 03:37:16.407 ChartWindow02 (USDCHF,H1)       array out of range in 'Table.mqh' (1091,86)

O que fazer e o que fazer?

Nas classes CScrollH e CScrollV , nos métodos ScrollBarControl(), você precisa adicionar uma verificação adicional da visibilidade do elemento, conforme mostrado na listagem abaixo:

//+------------------------------------------------------------------+
//| Controle de rolagem|
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- Sair se não houver ponteiro para o formulário
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
      return(false);
//--- Sair se o formulário estiver bloqueado por outro elemento
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return(false);
//--- Sair se o item estiver oculto
   if(!CElement::IsVisible())
     return(false);

//--- Verificando o foco sobre o controle deslizante
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- Verificar e lembrar o estado do botão do mouse
   CScroll::CheckMouseButtonState(mouse_state);
//--- Alterar a cor da barra de rolagem da lista
   CScroll::ChangeObjectsColor();
//--- Se o controle for passado para a barra de rolagem, defina a posição do controle deslizante
   if(CScroll::ScrollState())
     {
      //--- Movendo o controle deslizante
      OnDragThumb(x);
      //--- Altera o número da posição do controle deslizante
      CalculateThumbPos();
      return(true);
     }
   return(false);
  }

//---

A correção estará disponível na próxima atualização da biblioteca.

 
Anatoli Kazharski:

Nas classes CScrollH e CScrollV , nos métodos ScrollBarControl(), precisamos adicionar uma verificação adicional da visibilidade do elemento, conforme mostrado na listagem abaixo:

...

A correção estará disponível na próxima atualização da biblioteca.

Obrigado. Fiz as seguintes alterações: no arquivo Scrolls.mqh, nas classes CScrollH e CScrollV, adicionei linhas:

//+------------------------------------------------------------------+
//| Controle deslizante|
//+------------------------------------------------------------------+
bool CScrollV::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- Sair se não houver ponteiro para o formulário
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
      return(false);
//--- Se o formulário não estiver bloqueado e os identificadores corresponderem
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return(false);
//--- Sair se o item estiver oculto
   if(!CElement::IsVisible())
     return(false);

//--- Verificando o foco sobre o controle deslizante
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- Verificar e lembrar o estado do botão do mouse
   CScroll::CheckMouseButtonState(mouse_state);
//--- Alterar a cor do controle deslizante
   CScroll::ChangeObjectsColor();
//--- Se o controle for passado para a barra de rolagem, defina a posição do controle deslizante
   if(CScroll::ScrollState())
     {
      //--- Movendo o controle deslizante
      OnDragThumb(y);
      //--- Altera o número da posição do controle deslizante
      CalculateThumbPos();
      return(true);
     }
//---
   return(false);
  }
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| Controle de rolagem|
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- Sair se não houver ponteiro para o formulário
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
      return(false);
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return(false);
//--- Sair se o item estiver oculto
   if(!CElement::IsVisible())
     return(false);

//--- Verificando o foco sobre o controle deslizante
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- Verificar e lembrar o estado do botão do mouse
   CScroll::CheckMouseButtonState(mouse_state);
//--- Alterar a cor da barra de rolagem da lista
   CScroll::ChangeObjectsColor();
//--- Se o controle for passado para a barra de rolagem, defina a posição do controle deslizante
   if(CScroll::ScrollState())
     {
      //--- Movendo o controle deslizante
      OnDragThumb(x);
      //--- Altera o número da posição do controle deslizante
      CalculateThumbPos();
      return(true);
     }
   return(false);
  }
//+------------------------------------------------------------------+

Compilei e executei o mesmo arquivo de teste de \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02 .mq5, no qual alterei a função de criação de tabela em Program.mqh para que o número de todas as colunas e linhas coincidisse com o número de colunas e linhas visíveis:

//+------------------------------------------------------------------+
//|| Cria uma tabela|
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
  {
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL    (15)
//--- Salvar o ponteiro no formulário
   m_table.WindowPointer(m_window1);
//--- Coordenadas
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- Número de colunas e linhas visíveis
   int visible_columns_total =6;
   int visible_rows_total    =15;
//--- Definir propriedades antes da criação
   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);
//--- Criar um controle
   if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- Vamos preencher a tabela:
// A primeira célula está vazia
   m_table.SetValue(0,0,"-");
//--- Títulos para colunas
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//--- Cabeçalhos para linhas, o método de alinhamento de texto é alinhado à direita
   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);
        }
     }
//--- Formatação de dados e tabelas (cor de fundo e cor da célula)
   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);
        }
     }
//--- Atualize a tabela para mostrar as alterações
   m_table.UpdateTable();
//--- Adicione o objeto à matriz comum de grupos de objetos
   CWndContainer::AddToElementsArray(0,m_table);
   return(true);
  }
//+------------------------------------------------------------------+

Compilar e executar o ChartWindow02.ex5

Várias vezes clicamos na linha mais baixa da tabela e obtemos um voo fora da matriz:

2016.10.25 01:39:22.899 ChartWindow02 (USDCHF,H1)       array out of range in 'Table.mqh' (1096,86)
Parece que nada mudou?
 
Artyom Trishkin:

...

Então nada mudou?

Depois das alterações que fiz, ele não funciona mais. Talvez eu tenha feito outras alterações, mas não me lembro. Não tenho um histórico de pequenas edições.

Por via das dúvidas, tente substituir os métodos CScroll::Show() e CScroll::Hide() por estas versões, se forem diferentes:

//+------------------------------------------------------------------+
//| Mostra o item de menu|
//+------------------------------------------------------------------+
void CScroll::Show(void)
  {
//--- Sair se o número de itens da lista não for maior que o número da parte visível da lista
   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);
//--- Atualizar a posição dos objetos
   Moving(m_wnd.X(),m_wnd.Y(),true);
//--- Status de visibilidade
   CElement::IsVisible(true);
  }
//+------------------------------------------------------------------+
//| Oculta o item de menu|
//+------------------------------------------------------------------+
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);
//--- Status de visibilidade
   CElement::IsVisible(false);
  }


//---

Se isso não ajudar, você terá que aguardar a próxima atualização.

 
Anatoli Kazharski:

Mas depois das alterações que fiz, ele não é mais reproduzido. Talvez eu tenha feito outras alterações, mas não me lembro. Não marco o histórico de pequenas edições.

Por via das dúvidas, tente substituir os métodos CScroll::Show() e CScroll::Hide() por estas versões, se forem diferentes:

//+------------------------------------------------------------------+
//| Mostra o item de menu|
//+------------------------------------------------------------------+
void CScroll::Show(void)
  {
//--- Sair se o número de itens da lista não for maior que o número da parte visível da lista
   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);
//--- Atualizar a posição dos objetos
   Moving(m_wnd.X(),m_wnd.Y(),true);
//--- Status de visibilidade
   CElement::IsVisible(true);
  }
//+------------------------------------------------------------------+
//| Oculta o item de menu|
//+------------------------------------------------------------------+
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);
//--- Status de visibilidade
   CElement::IsVisible(false);
  }


//---

Se isso não ajudar, você terá que aguardar a próxima atualização.

Obrigado, parece ter ajudado. Estavam faltando linhas sobre o status de visibilidade em Show():

//--- Status de visibilidade
   CElement::IsVisible(true);

: e Hide():

//--- Status de visibilidade
   CElement::IsVisible(false);
 
Artyom Trishkin:

Obrigado, parece que funcionou. Estavam faltando linhas sobre o status de visibilidade em Show():

//--- Status de visibilidade
   CElement::IsVisible(true);

e Hide():

//--- Status de visibilidade
   CElement::IsVisible(false);

É necessária mais uma correção. A visibilidade deve ser definida antes de atualizar a posição do elemento. Assim:

...
//--- Status de visibilidade
   CElement::IsVisible(true);
//--- Atualizar a posição dos objetos
   Moving(m_wnd.X(),m_wnd.Y(),true);
...
 

A interatividade dos elementos da interface implementada por meio de um cronômetro é uma solução estranha. - Por que ela deveria ser implementada por meio de (ou com) um cronômetro? - É claro que isso consumirá muitos recursos.

Você não precisa de um timer para controlar os estados dos controles.

1. Registre as coordenadas atuais de todos os elementos na matriz (mapa). Faça ajustes nas coordenadas de localização de todos os objetos do formulário à medida que você move a janela.

2. Crie uma função para localizar elementos por coordenadas (localizador). A função percorrerá as coordenadas do elemento atual registrado e encontrará o elemento que está agora sob o cursor.

3. Chame o localizador a partir do evento "CHARTEVENT_MOUSE_MOVE" (no evento de movimento do cursor).

4. Passe o nome do objeto retornado pelo localizador para a função de interatividade, onde a função ObjectSetInteger() será aplicada ao objeto, o que o forçará a mudar de cor.


Como você pode ver, não há cronômetro nesse esquema, portanto, não há consumo desnecessário de recursos.

 
Реter Konow:

A interatividade dos elementos da interface implementada por meio de um cronômetro é uma solução estranha. - Por que ela deveria ser implementada por meio de (ou com) um cronômetro? - É claro que isso consumirá muitos recursos.

...

Como você pode ver, não há nenhum timer nesse esquema, portanto, não há consumo desnecessário de recursos.

Você está errado. Já respondi com detalhes suficientes nos comentários acima por que foi feito dessa forma.

Ele não consome muitos recursos agora (agora também no Windows 10 ). Você leu o artigo (e os comentários também)?

//---

P.S. A propósito, o consumo de recursos da CPU em diferentes terminais (MT4/MT5) e versões do sistema operacional (Windows) é muito diferente em condições iguais. No Windows 7, o terminal MetaTrader 4 se mostrou significativamente melhor do que o MetaTrader 5. Infelizmente, não posso lhe dar os números agora, pois já mudei completamente para o Windows 10.

Quanto à otimização, ainda não esgotei todas as opções. Ainda há algo a ser otimizado e um entendimento de como.