Discussão do artigo "Interfaces gráficas X: Seleção de texto na caixa de texto multilinha (build 13)" - página 11

 
Konstantin:
Ou seja, nessa classe, o método CreateTabs é fundamental para a criação de guias? Ao alterar o número de guias, seria correto usar o método Delete e depois usar o método CreateTabs? Ou é necessário especificar todas as propriedades novamente após o método Delete, como na criação inicial?

Sim. Especificamos as propriedades primeiro e depois criamos o item.

No momento, não há mecanismo para a exclusão correta de elementos em tempo de execução. Eles permanecerão na lista geral de elementos. Mas tente como você descreveu em sua pergunta. Ainda não testei essa forma.

 
Anatoli Kazharski:

Sim. Primeiro especificamos as propriedades e depois criamos o elemento.

No momento, não há mecanismo para a exclusão correta de elementos em tempo de execução. Eles permanecerão na lista geral de elementos. Mas tente como você descreveu em sua pergunta. Ainda não testei essa forma.

))) Já estou testando, se tudo ocorrer corretamente, publicarei um exemplo.
 

É assim que funciona:

#ifndef __TBLTABS_MQH__
#define __TBLTABS_MQH__

#include "..\\..\\..\\v1.00\\lib\\define.mqh"

#include <Arrays\List.mqh>
#include <EasyAndFastGUI\WndEvents.mqh>

//+------------------------------------------------------------------+
class CTblTabs
  {
private:
   int      m_x;
   int      m_y;
   long     m_chart_id;
   int      m_subwin;
   string   m_text[];
   int      m_width[];
   CTabs    m_tabs;
   CWindow  *m_form;

public:
                     CTblTabs(void);
                    ~CTblTabs(void);
   bool              Create(CWindow &a_form,const long a_chart_id,const int a_subwin,     // criação de objeto
                              const int a_x,const int a_y);
   void              OnLinkProgram(CList &a_pair);                                        // comunicação com o programa
   CTabs*            GetTbl(void) { return &m_tabs; }

private:
   void              UpdateTabs(CList &a_pair,CTabs &a_tabs,string &a_text[],int &a_width[]);   // atualizar valores da tabela
   bool              ReInit(CWindow &a_form,CList &a_pair,CTabs &a_tabs,string &a_text[],       // reinicialização das guias do objeto
                              int &a_width[],const long a_chart_id,const int a_subwin,const int a_x,const int a_y);
  };
//+------------------------------------------------------------------+
/*!
 \brief Designer
*/
CTblTabs::CTblTabs(void) : m_x(0), m_y(0), m_chart_id(0), m_subwin(0), m_form(NULL) { }
/*!
 \brief Destructor
*/
CTblTabs::~CTblTabs(void) {
   m_form = NULL;
}
/*!
 \brief Criando um objeto
 \param CWindow &a_form - objeto de formulário
 \param const long a_chart_id - ID do gráfico
 \param const int a_subwin - subjanela do gráfico
 \param const int a_x - coordenada X
 \param const int a_y - coordenada Y
 \return true se bem-sucedido, caso contrário false
*/
bool CTblTabs::Create(CWindow &a_form,const long a_chart_id,const int a_subwin,const int a_x,const int a_y) {
   m_x = a_x;
   m_y = a_y;
   m_chart_id = a_chart_id;
   m_subwin   = a_subwin;
   m_form     = &a_form;

   //--- matrizes com texto e largura para as guias
   //::ArrayResize(m_text, 1);
   //m_text[0] = "NULL_NULL";
   //::ArrayResize(m_width, 1);
   //m_width[0] = 65;

   m_tabs.WindowPointer(a_form);       // salvar o ponteiro no formulário

   //--- coordenadas
   int _x = a_form.X() + m_x;
   int _y = a_form.Y() + m_y;

   //--- dimensões
   m_tabs.XSize(400);
   m_tabs.YSize(200);

   //--- propriedades
   m_tabs.TabYSize(20);
   m_tabs.PositionMode(TABS_TOP);
   m_tabs.AutoXResizeMode(true);
   m_tabs.AutoYResizeMode(true);
   m_tabs.AutoXResizeRightOffset(200);
   m_tabs.AutoYResizeBottomOffset(23);
   m_tabs.TabBorderColor(clrLightSteelBlue);
   m_tabs.SelectedTab((m_tabs.SelectedTab() == WRONG_VALUE) ? 0 : m_tabs.SelectedTab());


   //--- adicionar guias com as propriedades especificadas
   //for(int i = 0, _size = ArraySize(m_text); i < _size; ++i)
   // m_tabs.AddTab(m_text[i], m_width[i]);

   //--- criar um controle
   //if(!m_tabs.CreateTabs(a_chart_id, a_subwin, _x, _y))
   //   return false;

//---
   return true;
}
/*!
 \brief Conexão com o programa
 \param CList &a_pair - ponteiro para a lista de pares de negociação com sinais
*/
void CTblTabs::OnLinkProgram(CList &a_pair) {
   if(a_pair.Total() != m_tabs.TabsTotal())
      this.ReInit(m_form, a_pair, m_tabs, m_text, m_width, m_chart_id, m_subwin, m_x, m_y);
   else
      this.UpdateTabs(a_pair, m_tabs, m_text, m_width);
}
//+------------------------------------------------------------------+
/*!
 \brief Atualizar valores da guia
 \param CList &a_pair - ponteiro para a lista de pares de negociação com sinais
 \param CTabs &a_tabs - objeto de tabela
 \param string &a_text[] - matriz com o nome das guias
 \param int &a_width[] - matriz com o tamanho da largura das guias
*/
void CTblTabs::UpdateTabs(CList &a_pair,CTabs &a_tabs,string &a_text[],int &a_width[]) {
   int _total = a_tabs.TabsTotal();
   //--- decompor os dados em uma tabela
   int _count = 0;
   for(CWrapUnitPair *_unit = a_pair.GetFirstNode(); _unit != NULL; _count++, _unit = a_pair.GetNextNode())
      a_tabs.Text(_count, _unit.data_tt[0].ticker + " " + _unit.data_tt[1].ticker);

}
/*!
 \brief Reinicialização de abas de objetos
 \param CWindow &a_form - objeto de formulário
 \param CList &a_pair - ponteiro para a lista de pares de negociação com sinais
 \param CTabs &a_tabs - objeto de tabela
 \param string &a_text[] - matriz com o nome das guias
 \param int &a_width[] - matriz com o tamanho da largura das guias
 \param const long a_chart_id - ID do gráfico
 \param const int a_subwin - subjanela do gráfico
 \param const int a_x - coordenada X
 \param const int a_y - coordenada Y
 \return true if successful, otherwise false
*/
bool CTblTabs::ReInit(CWindow &a_form,CList &a_pair,CTabs &a_tabs,string &a_text[],int &a_width[],const long a_chart_id,
                                                                                  const int a_subwin,
                                                                                  const int a_x,
                                                                                  const int a_y) {

   a_tabs.Delete();     // limpar as guias do objeto

   //--- reinicializar matrizes de valores
   int _total = a_pair.Total();
   ::ArrayResize(a_text, _total);
   ::ArrayResize(a_width, _total);

   //--- preencher as matrizes com os nomes das guias
   int _count = 0;
   for(CWrapUnitPair *_unit = a_pair.GetFirstNode(); _unit != NULL; _count++, _unit = a_pair.GetNextNode()) {
      a_text[_count]  = _unit.data_tt[0].ticker + " " + _unit.data_tt[1].ticker;
      a_width[_count] = 65;
   }

   //--- adicionar guias com as propriedades especificadas
   for(int i = 0, _size = ArraySize(m_text); i < _size; ++i)
      a_tabs.AddTab(a_text[i], a_width[i]);

   //--- coordenadas
   int _x = a_form.X() + a_x;
   int _y = a_form.Y() + a_y;

   //--- criar um controle
   if(!a_tabs.CreateTabs(a_chart_id, a_subwin, _x, _y))
      return false;
//---
   return true;
}
//+------------------------------------------------------------------+

#endif // __TBLTABS_MQH__

Eu destaquei em cores o que não é mais necessário no método de criação de classe, pois é essencialmente usado no método ReInit.

Todos os mecanismos de evento e interação são descritos na classe de formulário principal do programa.


 
Konstantin:

é assim que funciona:

Obrigado pelo exemplo. Interessante.

 
Anatoli Kazharski:

Obrigado pelo exemplo. Interessante.


Encontrei um erro: se não houver abas, ao alterar o tamanho do gráfico (formulário), o programa falha com o erro array out of range em 'Tabs.mqh' (821,21)

 
Konstantin:

Encontrei um erro: se não houver abas, ao alterar o tamanho do gráfico (formulário), o programa falha com o erro array out of range em 'Tabs.mqh' (821,21).

Haverá uma correção na próxima atualização.
 

Ao criar objetos (elementos de formulário), o método CWndContainer::AddToElementsArray(0, m_object); é usado. Existe algum mecanismo para remover corretamente um determinado objeto desse contêiner?

Isso é necessário ao criar/excluir gráficos, ao usar o mecanismo acima para adicionar/excluir guias.

 
Konstantin:

Ao criar objetos (elementos de formulário), o método CWndContainer::AddToElementsArray(0, m_object); é usado. Existe algum mecanismo para remover corretamente um determinado objeto desse contêiner?

Isso é necessário ao criar/excluir gráficos, ao usar o mecanismo acima para adicionar/excluir guias.

Isso ainda não foi implementado.

 
Anatoli Kazharski:

Isso ainda não foi implementado.

Seria mais lógico fazer a exclusão a pedido do usuário da classe, porque trabalhar com objetos em dinâmica anima mais a interface. Para a minha tarefa, inserirei o número de gráficos pelo número de pares de tickers, mas como tenho 702 pares de tickers com base em 27 tickers, não é difícil calcular quais serão os freios se você for para outro mercado em que haja muito mais tickers ))

A propósito, também verificarei quanta memória será consumida por esse número de pares de tíquetes))

 

Ao executar a tarefa de adicionar/remover abas dinamicamente e adicionar/remover gráficos à matriz de abas, deparei-me com o problema da impossibilidade de obter o nome das abas na classe CTabs. Nesse sentido, sugiro que o desenvolvedor complemente essa classe com um método para obter o nome da guia:

   //--- Define (1) o texto (nome da guia) para o índice especificado (2) получает текст (имя вкладки) по указанному индексу
   void              Text(const uint index,const string text);                     // esse método é
   string            Text(const uint index) { return m_tab[index].text; }  // isso não é suficiente
A adição desse método é necessária devido ao fato de que, mesmo herdando da classe CTabs para complementar os métodos ausentes, será impossível implementar o método sobrecarregado Text, pois o objeto m_tab[] está na área protegida da classe. E editar a classe para se adequar a si mesmo viola o princípio da OOP.