Discussão do artigo "Interfaces Gráficas X: Os Controles Horário, Lista de Caixas de Seleção e Tabela Ordenada (build 6)" - página 2

 

No entanto, parece-me que as alterações recentes relacionadas à especificação de coordenadas por deslocamento a partir da borda do formulário não são muito amigáveis para o usuário final. Se antes o usuário podia usar com segurança duas opções para especificar o local de um objeto na janela, agora uma delas se tornou mais complicada. As coisas desmoronaram assim em toda a tela.

  1. Anteriormente, o usuário podia especificar a coordenada x,y do objeto como um deslocamento de qualquer borda da forma de janela. Para fazer isso, bastava especificar a coordenada inicial dessa janela mais/menos o deslocamento em pixels. Agora, o usuário é forçado a começar somente a partir da borda esquerda do formulário, reduzindo as possibilidades de especificar a coordenada exata ou o deslocamento da coordenada em pixels de qualquer borda do formulário ou objeto.
  2. Se antes o usuário podia, sem questionar o tamanho do objeto a partir do qual calcula o deslocamento, colocar calmamente um novo objeto com um deslocamento do tamanho necessário de qualquer borda do objeto pai, agora ele será forçado a recalcular as coordenadas do novo objeto toda vez que alterar o tamanho do objeto a partir do qual o novo objeto é construído com um deslocamento.
    Exemplo:
    Botão1 - sua coordenada x está a 4 pixels de distância da borda esquerda da janela do formulário. Ela é definida da seguinte forma: x=m_window.X()+4; O tamanho do botão1 é de 43 pixels de largura. Sua borda direita pode ser obtida da seguinte forma: m_butt1.X2();
    Botão2 - sua coordenada está a 2 pixels de distância da borda direita do botão1. Ele é definido da seguinte forma: x=m_butt1.X2()+2; O tamanho do botão2 é de 24 pixels de largura. Sua borda direita pode ser obtida da seguinte forma: m_butt2.X2();
    Botão3 - sua coordenada está a 4 pixels de distância da borda direita do botão2. Ele é definido da seguinte forma: x=m_butt2.X2()+4; O tamanho do botão3 é de 18 pixels de largura. Sua borda direita pode ser obtida da seguinte forma: m_butt3.X2();
    A barra de separação vertical está a 4 pixels da borda direita do botão3: x=m_butt3.X2()+4;
    Portanto, podemos alterar facilmente o tamanho de qualquer um dos três botões, e todos eles estarão localizados no deslocamento que definimos, e a barra de separação estará perfeitamente posicionada no deslocamento que precisamos do botão3.
  3. Agora vamos ver o que temos de fazer ao criar a interface de acordo com as novas regras:
    Button1: x_gap1=4;
    Button2: x_gap2=4+m_butt1.XSize()+2;
    Button3: x_gap3=4+m_butt1.XSize()+2+m_butt2.XSize()+4;
    R-Strip: x_gap4=4+m_butt1.XSize()+2+m_butt2.XSize()+4+m_butt3.XSize()+4;
    Aqui é sugerido especificar a coordenada X2() em vez de especificar os tamanhos dos objetos, mas esse não é o caso - tudo desmorona de uma só vez (eu, por exemplo, quebrei a cabeça ao adivinhar que Y2() não aponta para o local correto da coordenada Y).

Vejamos: eu defini as coordenadas do menu com um recuo de 1 pixel na horizontal e com um recuo do tamanho do "cabeçalho" da janela principal. A altura do menu é de 18 pixels.

//--- Criando o menu da janela principal
   x=m_window_main.X()+1;
   y=m_window_main.Y()+m_window_main.CaptionHeight();
   h=18;

O menu está em seu lugar:


Agora preciso colocar a tabela deslocada da borda inferior do menu. Se o CaptionHeight() da janela do formulário for de 18 pixels e a altura do menu também for de 18 pixels, o deslocamento vertical da tabela deverá ser de 36 pixels. Há duas opções: ou nos sentamos com uma calculadora e calculamos todos os deslocamentos necessários (e os recalculamos novamente no caso de ajustes subsequentes com alterações de tamanho) ou tentamos obtê-los. Escolhemos a segunda opção, é claro, e tentamos: para a tabela, o y_gap deve ser igual à altura do título da janela principal mais a altura do menu: m_window_main.CaptionHeight()+m_menu_main.YSize();

   //--- Tabela de lista de caracteres
   x=2;
   y=m_window_main.CaptionHeight()+m_menu_main.YSize()+1;
   w=140;

Compilar, obter:


A guia está no lugar. Mas. O valor Y2() do menu, nesse caso, não deveria coincidir com o valor que calculamos? Afinal, é mais conveniente não coletar os tamanhos de todos os objetos que se seguem uns aos outros, mas apenas obter suas coordenadas, certo? Vamos tentar: altere o cálculo da coordenada para sua obtenção:

   //--- Tabela de lista de caracteres
   x=2;
   //y=m_window_main.CaptionHeight()+m_menu_main.YSize()+1;
   y=m_menu_main.Y2()+1;
   w=140;

Compile, get:


Y2() não deveria retornar o mesmo Y2 que calculamos anteriormente? m_window_main.CaptionHeight()+m_menu_main.YSize()+1;

Agora não especificamos coordenadas com deslocamento a partir de qualquer borda da janela, mas apenas deslocamento, e apenas a partir do topo ou da esquerda. Bom. Remova da coordenada Y2() obtida a coordenada Y() da parte superior da janela do formulário para obter o valor do deslocamento a partir da parte superior da janela do formulário:

   //--- Tabela de lista de caracteres
   x=2;
   //y=m_window_main.CaptionHeight()+m_menu_main.YSize()+1;
   y=m_menu_main.Y2()-m_window_main.Y()+1;
   w=140;

Compile e obtenha o que deseja:


Então, para vinte objetos que estão a dois pixels de distância um do outro, devemos sempre adicionar seus tamanhos mais o deslocamento um do outro para obter o deslocamento correto para o último objeto? Afinal, Y2() do décimo nono objeto (a partir do qual era possível construir o vigésimo objeto apenas adicionando um deslocamento de dois pontos) agora não nos dá um ponto de partida e não retorna o que é esperado.... e temos que somar os tamanhos de todos os objetos para obter o deslocamento necessário ou, para cada objeto antes de sua criação, temos que calcular seu deslocamento com base em sua coordenada Y2() e na coordenada Y() inicial da janela do formulário.

Não estou entendendo. Anatoly, por favor, me dê uma solução. O que estou fazendo de errado? Por que é assim? Por que você acha que agora está mais amigável? Se antes você podia simplesmente especificar o deslocamento de qualquer borda da janela do formulário, de qualquer objeto nessa janela ou até mesmo da borda do gráfico em geral para criar o objeto necessário, agora você tem que fazer uma dança de pandeiro para calcular suas coordenadas antes de criá-lo? É melhor e mais conveniente escrever mais código e cálculos diferentes?

Entendo que você é o autor e sabe o que é melhor. Mesmo assim, você permite que outras pessoas o utilizem. Eu (apenas minha opinião) acho que essa inovação acabou sendo a única decisão ruim de apresentá-la como uma atualização - ela se tornou pior. Ele não tinha mais os recursos fáceis de criação de interface que tinha antes.

Peço desculpas se o ofendi (antigamente, os mensageiros com más notícias tinham suas cabeças cortadas).

 
Artyom Trishkin:

...

Desculpe-me se o ofendi.

Responderei um pouco mais tarde, mas, antes disso, gostaria de esclarecer o que você quer dizer com essa frase em relação a mim. O que são "más notícias" e quem é um "mensageiro" nesse contexto? :)

 
Anatoli Kazharski:

Responderei um pouco mais tarde, mas, antes disso, gostaria de esclarecer o que você quis dizer com essa frase sobre mim. O que são "más notícias" e quem é um "mensageiro" nesse contexto? :)

:)

Chamei de "más notícias" minha atitude em relação à inovação de que não é mais possível usar qualquer coordenada arbitrária como ponto de referência da coordenada do objeto, mas apenas as bordas esquerda e superior do formulário (adicionei um recálculo das coordenadas no local - cálculos desnecessários).... E o mensageiro sou eu, é claro, já que não gostei e disse isso :)

 
Artyom Trishkin:

:)

A má notícia é que chamei minha atitude para a inovação de que agora não é possível tomar qualquer coordenada arbitrária como ponto de referência de coordenadas do objeto, mas apenas as bordas esquerda e superior do formulário (adicionei um recálculo de coordenadas em cálculos locais - desnecessários).... Bem, o mensageiro sou eu, é claro, já que não gostei e disse isso :)

Então, aí está. Muito bom. Porque eu achei que tinha entendido errado. )

Aqui está minha resposta:

Artyom Trishkin:

No entanto, acho que as alterações recentes relacionadas à especificação de coordenadas por deslocamento da borda do formulário não são muito amigáveis para o usuário final. Se antes o usuário podia usar com segurança duas opções para especificar o local do objeto na janela, agora uma delas se tornou mais complicada. Já aconteceu de as coisas desmoronarem e se dividirem por toda a tela dessa forma.

...

Agora vamos ver o que temos de fazer ao criar a interface de acordo com as novas regras:

Button1: x_gap1=4;
Button2: x_gap2=4+m_butt1.XSize()+2;
Button3: x_gap3=4+m_butt1.XSize()+2+m_butt2.XSize()+4;
R Strip: x_gap4=4+m_butt1.XSize()+2+m_butt2.XSize()+4+m_butt3.XSize()+4;

...

Em vez de especificar os tamanhos dos objetos, você ficaria tentado a especificar a coordenada X2() deles, mas esse não é o caso - tudo desmorona de uma vez (eu, por exemplo, quebrei a cabeça até perceber que Y2() não aponta para o local correto da coordenada Y).

É muito simples. Anteriormente, você tinha que passar coordenadas absolutas para os métodos de criação de elementos. Elas tinham de ser calculadas em relação ao ponto mais à esquerda do formulário ao qual o elemento está anexado.

Aqui está um exemplo do que tivemos de fazer anteriormente:

//+------------------------------------------------------------------+
//|| Cria um botão|
//+------------------------------------------------------------------+
bool CProgram::CreateSimpleButton(const int x_gap,const int y_gap,const string button_text)
  {
//--- Salvar o ponteiro no formulário
   m_simple_button.WindowPointer(m_window);
//--- Coordenadas
   int x=m_window.X()+x_gap;
   int y=m_window.Y()+y_gap;

//--- Definir propriedades antes da criação
   m_simple_button.ButtonXSize(100);
//--- Criando um botão
   if(!m_simple_button.CreateSimpleButton(m_chart_id,m_subwin,button_text,x,y))
      return(false);
//--- Adicione um ponteiro ao elemento na base
   CWndContainer::AddToElementsArray(0,m_simple_button);
   return(true);
  }

//---

Agora você não precisa calcular nada, pois basta passar as coordenadas relativas.

Um exemplo do que precisa ser feito agora:

//+------------------------------------------------------------------+
//|| Cria um botão|
//+------------------------------------------------------------------+
bool CProgram::CreateSimpleButton(const int x_gap,const int y_gap,const string button_text)
  {
//--- Passar o objeto do painel
   m_simple_button.WindowPointer(m_window);
//--- Definir propriedades antes da criação
   m_simple_button.ButtonXSize(100);
//--- Criando um botão
   if(!m_simple_button.CreateSimpleButton(m_chart_id,m_subwin,button_text,x_gap,y_gap))
      return(false);
//--- Adicione um ponteiro ao elemento na base
   CWndContainer::AddToElementsArray(0,m_simple_button);
   return(true);
  }

//---

Nos seus exemplos acima, você está calculando coordenadas absolutas. Decisão estúpida seguida de conclusões erradas colocadas apressadamente em público.

Os métodos CElement ::X(), CElement ::X2(), CElement ::Y() e CElement::Y2() retornam coordenadas absolutas das bordas do elemento. E foi fácil entender isso apenas com a saída desses valores para o registro do terminal, se houver alguma dúvida.

Abaixo está um exemplo de cálculo da indentação( coordenadarelativa ) em relação a algum elemento. Há dois botões. A coordenada X (relativa) do segundo botão é calculada em relação à borda direita do primeiro botão.

//+------------------------------------------------------------------+
//|| Cria a GUI do programa
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
  {
//--- Criando um painel
   if(!CreateWindow("EXPERT PANEL"))
      return(false);
   if(!CreateSimpleButton1(7,25,"BUTTON 1"))
      return(false);
   if(!CreateSimpleButton2(m_simple_button1.X2()-m_window.X()+5,25,"BUTTON 2"))
      return(false);
//---
   return(true);
  }

//---

Como resultado, o segundo botão será definido com um recuo de 5 pixels da borda direita do primeiro botão:

//---

Ao alterar a largura ou a coordenada X do primeiro botão, a posição do segundo botão será ajustada automaticamente.

Portanto, os cálculos desnecessários estão apenas em seu exemplo citado acima.

 
Anatoli Kazharski:

//+------------------------------------------------------------------+
//|| Cria a GUI do programa
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
  {
//--- Criando um painel
   if(!CreateWindow("EXPERT PANEL"))
      return(false);
   if(!CreateSimpleButton1(7,25,"BUTTON 1"))
      return(false);
   if(!CreateSimpleButton2(m_simple_button1.X2()-m_window.X()+5,25,"BUTTON 2"))
      return(false);
//---
   return(true);
  }

//---

Como resultado, o segundo botão será definido com um recuo de 5 pixels a partir da borda direita do primeiro botão:

//---

Ao alterar a largura ou a coordenada X do primeiro botão, a posição do segundo botão será ajustada automaticamente.

Portanto, os cálculos extras estão apenas em seu exemplo citado acima.

Aqui... Isso não ficou muito claro:

if(!CreateSimpleButton2(m_simple_button1.X2()-m_window.X()+5,25,"BUTTON 2"))

Tenho que colocar esse recálculo em minhas funções para não escrever esse recálculo em todos os lugares ao especificar as coordenadas de um objeto recém-criado, mas para continuar escrevendo como era antes - é mais claro ver a relação de um objeto com outro. É uma questão de gosto e preferências de cada um, é claro...

A propósito, o navegador de arquivos não funciona mesmo quando se especificam as coordenadas, como você disse. Mas talvez seja apenas eu. Vou procurar o motivo.

Capturas de tela da plataforma de negociação MetaTrader

EURUSD, D1, 2016.12.12

MetaQuotes Software Corp., MetaTrader 5, Demonstração

EURUSD, D1, 2016.12.12, MetaQuotes Software Corp., MetaTrader 5, Demonstração


 

Anatoly, parece que você esqueceu de editar o FileNavigator.mqh no arquivo

//+------------------------------------------------------------------+
//| Cria uma lista em árvore|
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\folder_w10.bmp"
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\text_file_w10.bmp"
//---
bool CFileNavigator::CreateTreeView(void)
  {
//--- Salvar o ponteiro da janela
   m_treeview.WindowPointer(m_wnd);
//--- Definir propriedades
   m_treeview.Id(CElement::Id());
   m_treeview.ResizeListAreaMode(true);
   m_treeview.TreeViewAreaWidth(m_treeview_area_width);
   m_treeview.ContentAreaWidth(m_content_area_width);
   m_treeview.AutoXResizeMode(CElement::AutoXResizeMode());
   m_treeview.AutoXResizeRightOffset(CElement::AutoXResizeRightOffset());
   m_treeview.AnchorRightWindowSide(m_anchor_right_window_side);
   m_treeview.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Formam matrizes da lista de árvores
   int items_total=::ArraySize(m_g_item_text);
   for(int i=0; i<items_total; i++)
     {
      //--- Definir a imagem para o item (pasta/arquivo)
      string icon_path=(m_g_is_folder[i])? m_folder_icon : m_file_icon;
      //--- Se for uma pasta, exclua o último caractere ('\') da string
      if(m_g_is_folder[i])
         m_g_item_text[i]=::StringSubstr(m_g_item_text[i],0,::StringLen(m_g_item_text[i])-1);
      //--- Adicionar um item à lista da árvore
      m_treeview.AddItem(i,m_g_prev_node_list_index[i],m_g_item_text[i],icon_path,m_g_item_index[i],
                         m_g_node_level[i],m_g_prev_node_item_index[i],m_g_items_total[i],m_g_folders_total[i],false,m_g_is_folder[i]);
     }
//--- Criar uma lista em árvore
   if(!m_treeview.CreateTreeView(m_chart_id,m_subwin,m_x-1,m_y+m_address_bar_y_size-1))
      return(false);
//--- Salvar as dimensões do navegador
   CElement::XSize(m_treeview.XSize());
   CElement::YSize(m_treeview.YSize()+m_address_bar_y_size);
   return(true);
  }
//+------------------------------------------------------------------+

É aqui que você precisa adicioná-lo:

//--- Criar uma lista em árvore
   if(!m_treeview.CreateTreeView(m_chart_id,m_subwin,m_x-m_wnd.X()-1,m_y-m_wnd.Y()+m_address_bar_y_size-1))
      return(false);
 
Artyom Trishkin:

...

A propósito, o navegador de arquivos trava mesmo ao especificar as coordenadas, como você disse. Mas talvez seja só eu. Fui procurar o motivo.

Não consegui reproduzi-lo:

 
Anatoli Kazharski:

Eu mesmo não o reproduzi:

Verifique o arquivo FileNavigator.mqh na atualização mais recente.
 
Artyom Trishkin:
Verifique o FileNavigator.mqh na atualização mais recente.
Essa é a mais recente.
 
Anatoli Kazharski:
Esse é o mais recente.

Quero dizer, no site, no artigo - talvez haja um antigo pregado nas atualizações. Peguei o arquivo da atualização mais recente, baixado do site na parte inferior do artigo a partir do zip.

Aqui, fiz as correções conforme escrevi acima: