Bibliotecas: EasyAndFastGUI - biblioteca para criar interfaces gráficas do usuário - página 11

 
Anatoli Kazharski:

Inicialmente, simplesmente não havia essa tarefa de que, após a criação da GUI, era necessário mover os elementos. Tudo foi baseado na ideia de que cada elemento já tinha todo o comportamento necessário implementado.

Perguntas contrárias: Por que você precisa mover elementos? O que você quer fazer? Que comportamento você deseja obter ao interagir com a GUI?

Para saber se algo vai quebrar, você precisa testar todos os elementos após cada alteração nas classes de base. Já é difícil dizer isso imediatamente. Já faz algum tempo que não estou pesquisando a fundo.

Crie uma GUI de teste com todos os elementos da biblioteca e teste-os após as alterações.

Por exemplo, listas expansíveis. Quando você clica, alguns dos elementos ficam ocultos, e tudo o que está abaixo é puxado para cima. E vice-versa.

Testar a GUI é uma boa ideia, vou ter que tentar criá-la :)

A propósito, no mesmo CElement::Moving.

//--- Se o vínculo estiver à direita
   if(m_anchor_right_window_side)
     {
      //--- Salvando coordenadas em campos de elementos
      CElementBase::X(m_main.X2()-XGap());
      //--- Salvando coordenadas em campos de objetos
      m_canvas.X(m_main.X2()-m_canvas.XGap());
     }
   else
     {
      CElementBase::X(m_main.X()+XGap());
      m_canvas.X(m_main.X()+m_canvas.XGap());
     }
//--- Se o vínculo for de baixo para cima
   if(m_anchor_bottom_window_side)
     {
      CElementBase::Y(m_main.Y2()-YGap());
      m_canvas.Y(m_main.Y2()-m_canvas.YGap());
     }
   else
     {
      CElementBase::Y(m_main.Y()+YGap());
      m_canvas.Y(m_main.Y()+m_canvas.YGap());
     }

Se houver um vínculo, o elemento se moverá junto com a tela. Portanto, teoricamente, nada deve quebrar :)

 

Alguém já tentou criar uma caixa de combinação usando essa biblioteca para alterar os elementos nela? ????? Share Como você faz isso?

Eu crio uma caixa de combinação e tudo funciona. Em seguida, eu a preencho com elementos usando a seguinte função:

void CPresenter::setCombobox(CComboBox *cb_ptr,CArrayString &arr)
  {
   CListView *lv_ptr=cb_ptr.GetListViewPointer();
   lv_ptr.Clear(true);
   
   cb_ptr.ItemsTotal(arr.Total());
   for(int i=0;i<arr.Total();i++)
      cb_ptr.SetValue(i,arr[i]);
   lv_ptr.SelectItem(0,true);
   cb_ptr.SelectItem(0);
   cb_ptr.Update(true);
   cb_ptr.GetButtonPointer().Update(true);
  }

Tudo funciona. Depois que seleciono na combobox preenchida - por exemplo, o terceiro valor - e clico no botão, o resultado é uma série de ações que resultam no transbordamento da combobox. E eu a preencho novamente com um valor (por exemplo, inicialmente havia 20 itens nela, mas depois de clicar no botão, resta apenas um item!)

E aqui vem um erro interessante - depois que tudo é sobrescrito (usando a função acima) - tento abrir a caixa de combinação, mas não consigo, porque o erro Array out of range!
O erro ocorre no método:
void CListView::RedrawItemsByMode(const bool is_selected_item=false).

Na linha 1364. Como descobri pesquisando, isso ocorre porque:
1) ao selecionar o terceiro item da lista (antes de pressionar o botão) - a variável
m_prev_item_index_focus é preenchida com um índice igual a 3.

Em seguida, esse índice é passado por meio da variável prev_item_index para a matriz
indexes

na linha 1357. O resultado disso - na linha 1364 - é a seleção de um valor da matriz
m_items

no índice #2 (índice correspondente ao último elemento selecionado), enquanto a matriz (m_items) tem apenas um valor no índice #0.

Estou pesquisando pelo segundo dia e ainda não consegui encontrar o local onde o valor da variável
m_prev_item_index_focus seria redefinido para zero.

Logicamente, ele deveria ser limpo no método Clear da classe CListView, que usei para limpar todos os itens, mas infelizmente não consegui encontrar esse método....


Em relação a todas as perguntas acima:
1) É um bug na biblioteca ou estou atualizando os valores incorretamente?
2) Qual é a melhor maneira de contornar esse problema?

 
O código mínimo reproduzível para minha pergunta:

//+------------------------------------------------------------------+
//|TestCombobox.mq5
//| Copyright 2018, MetaQuotes Software Corp.
//| https://www.mql5.com
//+------------------------------------------------------------------+

#include <EasyAndFastGUI\WndEvents.mqh>
#include <Arrays/ArrayString.mqh>
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CWindowManager : public CWndEvents
  {
public:
   void              OnDeinitEvent(const int reason){CWndEvents::Destroy();};
   //--- Manipulador de eventos do Graph
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);//

   //--- Cria a GUI do programa
   bool              CreateGUI(void);

private:
   CComboBox         m_cb;
   CButton           m_btn;

   void              Btn_Click(int id,long lparam);

   bool              CreateComboBox(const string comboBox_name,
                                    const string &items_text[],
                                    const int x_gap,
                                    const int y_gap,
                                    const int x_size,
                                    const int y_size,
                                    CComboBox &comboBox_link,
                                    int x_ButtonSize=0);
   bool              CreateButton(const string text,
                                  const int x_gap,
                                  const int y_gap,
                                  const int x_size,
                                  const int y_size,
                                  CButton &btn_link);
   bool              CreateWindow(const string text);

   void              setCombobox(CComboBox *cb_ptr,CArrayString &arr);
   //--- Janela principal
   CWindow           m_window;
   //--- ID e número da janela do gráfico
   long              m_chart_id;
   int               m_subwin;
  };

CWindowManager _window;
//+------------------------------------------------------------------+
//| Função de inicialização de especialista|
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!_window.CreateGUI())
     {
      Print(__FUNCTION__," > Falha ao criar uma GUI!");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Função de desinicialização de especialista|
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   _window.OnDeinitEvent(reason);
  }
//+------------------------------------------------------------------+
//| Função de tique de especialista|
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   _window.ChartEvent(id,lparam,dparam,sparam);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void CWindowManager::setCombobox(CComboBox *cb_ptr,CArrayString &arr)
  {
   CListView *lv_ptr=cb_ptr.GetListViewPointer();

   lv_ptr.Clear(true);
   cb_ptr.ItemsTotal(arr.Total());
   for(int i=0;i<arr.Total();i++)
      cb_ptr.SetValue(i,arr[i]);
   lv_ptr.SelectItem(0,true);
   cb_ptr.SelectItem(0);
   cb_ptr.Update(true);
   cb_ptr.GetButtonPointer().Update(true);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateWindow(const string text)
  {
//--- Adicione o ponteiro da janela à matriz de janelas
   CWndContainer::AddWindow(m_window);
//--- Coordenadas
   int x=(m_window.X()>0) ? m_window.X() : 1;
   int y=(m_window.Y()>0) ? m_window.Y() : 1;
//--- Propriedades
   m_window.XSize(300);
   m_window.YSize(300);
   m_window.Alpha(200);
   m_window.IconXGap(3);
   m_window.IconYGap(2);
   m_window.IsMovable(true);
   m_window.ResizeMode(false);
   m_window.CloseButtonIsUsed(true);
   m_window.FullscreenButtonIsUsed(false);
   m_window.CollapseButtonIsUsed(true);
   m_window.TooltipsButtonIsUsed(false);
   m_window.RollUpSubwindowMode(true,true);
   m_window.TransparentOnlyCaption(true);

//--- Definir dicas de ferramentas
   m_window.GetCloseButtonPointer().Tooltip("Close");
   m_window.GetCollapseButtonPointer().Tooltip("Collapse/Expand");
//--- Criação de formulário
   if(!m_window.CreateWindow(m_chart_id,m_subwin,text,x,y))
      return(false);
//---
   return(true);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateButton(const string text,
                                  const int x_gap,
                                  const int y_gap,
                                  const int x_size,
                                  const int y_size,
                                  CButton &btn_link)
  {
//--- Salvar o ponteiro para o elemento principal
   btn_link.MainPointer(m_window);
//--- Propriedades
   btn_link.XSize(x_size);
   btn_link.YSize(y_size);
   btn_link.IconXGap(3);
   btn_link.IconYGap(3);
   btn_link.IsCenterText(true);
//--- Criar um controle
   if(!btn_link.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Adicione um ponteiro ao elemento na base
   CWndContainer::AddToElementsArray(0,btn_link);
   return(true);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateComboBox(const string comboBox_name,
                                    const string &items_text[],
                                    const int x_gap,
                                    const int y_gap,
                                    const int x_size,
                                    const int y_size,
                                    CComboBox &comboBox_link,
                                    int x_lableXSize)
  {
//--- Salvar o ponteiro para o elemento principal
   comboBox_link.MainPointer(m_window);

   if(x_lableXSize==0)
      x_lableXSize=x_size;

   int items_total=ArraySize(items_text);

//--- Definir propriedades antes da criação
   comboBox_link.XSize(x_size);
   comboBox_link.YSize(y_size);
   comboBox_link.ItemsTotal(items_total);
   comboBox_link.AnchorRightWindowSide(false);
   comboBox_link.GetButtonPointer().YSize(y_size);

   if(StringCompare(comboBox_name,"")==0)
     {
      comboBox_link.GetButtonPointer().XSize(x_size);
      comboBox_link.GetButtonPointer().AnchorRightWindowSide(true);
     }
   else
     {
      comboBox_link.GetButtonPointer().XSize(x_lableXSize);
      comboBox_link.GetButtonPointer().AnchorRightWindowSide(false);
     }

//--- Salvar os valores dos itens na lista da caixa de combinação
   for(int i=0;i<items_total;i++)
      comboBox_link.SetValue(i,items_text[i]);

//--- Obter o ponteiro da lista
   CListView *lv=comboBox_link.GetListViewPointer();

//--- Definir propriedades da lista
   lv.YSize((int)MathMin(items_total*y_size,150));
   lv.LightsHover(true);
   lv.SelectItem(lv.SelectedItemIndex()==WRONG_VALUE ? 0 : lv.SelectedItemIndex());

//--- Criar um controle
   if(!comboBox_link.CreateComboBox(comboBox_name,x_gap,y_gap))
      return false;

   CWndContainer::AddToElementsArray(0,comboBox_link);
   return true;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateGUI(void)
  {
   if(!CreateWindow("Combobox Bug ???? "))
      return(false);
   string cb_arr[20];
   for(int i=0;i<20;i++)
      cb_arr[i]=IntegerToString(i+1);
   if(!CreateComboBox("",cb_arr,100,100,100,20,m_cb))
      return false;
   if(!CreateButton("Action",100,130,50,20,m_btn))
      return false;

// Mostrar janela
   CWndEvents::CompletedGUI();
   return true;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void CWindowManager::Btn_Click(int id,long lparam)
  {
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_btn.Id())
     {
      CArrayString s;
      s.Add("new value");
      setCombobox(&m_cb,s);
     }
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void CWindowManager::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   Btn_Click(id,lparam);
  }
//+------------------------------------------------------------------+



Até agora, todas as soluções que encontrei se resumem a editar o código da biblioteca (adicionando novas 3 linhas de código) - mas não gosto da ideia de ajustar o código de outra pessoa...

 
Andrey Azatskiy:
Código mínimo reproduzível para minha pergunta:

...

Até agora, todas as soluções que encontrei se resumem à edição do código da biblioteca (adição de novas 3 linhas de código), mas não gosto da ideia de ajustar o código de outra pessoa...

Obrigado pela mensagem.

Tente fazer uma pequena adição ao método da classe CListView. Você precisa zerar os campos auxiliares, conforme indicado abaixo:

//+------------------------------------------------------------------+
//| Limpa a lista (exclui todos os itens)
//+------------------------------------------------------------------+
void CListView::Clear(const bool redraw=false)
  {
//--- Redefinir os campos auxiliares para zero
   m_item_index_focus      =WRONG_VALUE;
   m_prev_selected_item    =WRONG_VALUE;
   m_prev_item_index_focus =WRONG_VALUE;
//--- Definir o tamanho como zero
   ListSize(0);
//--- Calcular e definir novos tamanhos de lista
   RecalculateAndResizeList(redraw);
  }
 
Anatoli Kazharski:

Obrigado pela mensagem.

Tente fazer uma pequena adição ao método da classe CListView. Você precisa zerar os campos auxiliares, conforme indicado abaixo:

Obrigado por sua resposta.

 
Anatoli Kazharski:

Que tal um repositório no bitbucket e aceitar commits de usuários ativos da biblioteca?

Juntos, terminaremos o projeto mais rápido ;)

 

Você pode me dizer como lidar corretamente com o botão de fechar a janela?

O problema é o seguinte: coloco um Expert Advisor (por exemplo, ExampleEAF.ex5) e meu indicador em uma janela separada sob o gráfico (o código mínimo exibe apenas uma janela vazia). Em seguida, clico no botão fechar janela em qualquer um desses aplicativos e ambos são fechados (removidos do gráfico).

Esse comportamento não é totalmente correto. Existe alguma maneira de distinguir eventos para diferentes aplicativos que trabalham simultaneamente no mesmo gráfico? Há uma suspeita de que outros eventos também possam se sobrepor.

 
Andrey Khatimlianskii:

Que tal um repositório no bitbucket e aceitar commits de usuários ativos da biblioteca?

Juntos, terminaremos o projeto mais rápido ;)

Já me deram acesso. Tenho dúvidas sobre muitas das edições.

Não há justificativa para essas ou aquelas alterações. É mais fácil discutir isso aqui no fórum.

Se alguma alteração for feita, é necessário dar exemplos e resultados de testes com a explicação de por que ela será melhor.

 
dmyger:

Você pode me dizer como lidar corretamente com o botão de fechar a janela?

O problema é o seguinte: coloco um Expert Advisor (por exemplo, ExampleEAF.ex5) e meu indicador em uma janela separada sob o gráfico (o código mínimo exibe apenas uma janela vazia). Em seguida, clico no botão fechar janela em qualquer um desses aplicativos e ambos são fechados (removidos do gráfico).

Esse não é o comportamento correto. Existe alguma maneira de distinguir eventos para diferentes aplicativos que trabalham simultaneamente no mesmo gráfico? Suspeito que outros eventos também possam se sobrepor.

Vou testá-lo quando tiver tempo e relatarei o resultado aqui.

 

Andrey Khatimlianskii:

Как на счет репозитория на битбакете и принятия коммитов от активных пользователей библиотеки?

Вместе быстрее допилим ;)

Anatoli Kazharski:

...

Se alguma alteração for feita, é necessário dar exemplos e resultados de testes com uma explicação de por que seria melhor.

Pelo menos de forma breve. Por exemplo:

Correções na classe CListView. No método Clear(), precisamos zerar alguns campos auxiliares para evitar que outros métodos da classe saiam da matriz.