Librerías: EasyAndFastGUI - librería para crear interfaces gráficas - página 11

 
Anatoli Kazharski:

Inicialmente simplemente no existía la tarea de que después de crear la GUI fuera necesario mover elementos. Todo se basaba en la idea, cuando cada elemento ya tenía todo el comportamiento necesario implementado.

Contra preguntas: ¿Por qué es necesario mover elementos? ¿Qué se quiere hacer? ¿Qué comportamiento al interactuar con la GUI quieres obtener?

Para entender si algo se romperá, necesitas probar todos los elementos después de cada cambio en las clases base. Ya es difícil decirlo de entrada. Hace tiempo que no miro en profundidad.

Crea una GUI de prueba con todos los elementos de la librería y pruébalos después de los cambios.

Por ejemplo, las listas expandibles. Cuando haces clic, algunos de los elementos se ocultan, todo lo de abajo se despliega. Y viceversa.

La GUI de prueba es una buena idea, tendré que intentar hacerla :)

Por cierto, en el mismo CElement::Moving.

//--- Si el enlace está a la derecha
   if(m_anchor_right_window_side)
     {
      //--- Guardar coordenadas en campos de elementos
      CElementBase::X(m_main.X2()-XGap());
      //--- Guardar coordenadas en campos de objeto
      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());
     }
//--- Si el enlace es desde abajo
   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());
     }

Si hay un binding, el elemento se mueve junto con el canvas. Así que teóricamente nada debe romper :)

 

¿Alguien ha intentado crear un combobox utilizando esa biblioteca - para cambiar los elementos en ella ????? Share ¿Cómo se hace?

Creo un combobox, todo funciona. Luego lo relleno con elementos usando la siguiente función:

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);
  }

Todo funciona. Después selecciono en el combobox rellenado - por ejemplo, el tercer valor. y hago clic en el botón, el resultado es una serie de acciones que resultan en el desbordamiento del combobox. Y lo vuelvo a llenar con un valor (por ejemplo, inicialmente había 20 elementos en él, ¡después de hacer clic en el botón sólo queda un elemento!)

Y aquí viene un error interesante - después de sobreescribir todo (usando la función anterior) - intento abrir el cuadro combinado, pero no puedo hacerlo, ¡porque el error Array out of range!
El error ocurre en el método:
void CListView::RedrawItemsByMode(const bool is_selected_item=false).

En la línea 1364. Según he averiguado investigando, ocurre porque :
1) al seleccionar el tercer elemento de la lista (antes de pulsar el botón) - la variable
m_prev_item_index_focus se rellena con un índice igual a 3. Luego este índice se pasa a través de m_prev_item_index_focus.

Luego este índice se pasa a través de la variable prev_item_index al array
indexes

en la línea 1357. El resultado -en la línea 1364- es la selección de un valor de la matriz
m_items

en el índice #2 (el índice correspondiente al último elemento seleccionado), mientras que el array (m_items) sólo tiene un valor en el índice #0.

Estoy indagando por segundo día y todavía no he podido encontrar el lugar donde el valor de la variable
m_prev_item_index_focus se pondría a cero.

Lógicamente, debería borrarse en el método Clear de la clase CListView, que utilicé para borrar todos los elementos allí, pero desafortunadamente no pude encontrar tal método allí....


En relación con todas las preguntas anteriores:
1) ¿Es un error en la biblioteca, o estoy actualizando los valores incorrectamente?
2) ¿Cuál es la mejor manera de solucionar este problema?

 
El código mínimo reproducible para mi pregunta:

//+------------------------------------------------------------------+
//|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();};
   //--- Controlador de eventos gráficos
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);//

   //--- Crea la interfaz gráfica del 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);
   //--- Ventana principal
   CWindow           m_window;
   //--- ID y número de la ventana del gráfico
   long              m_chart_id;
   int               m_subwin;
  };

CWindowManager _window;
//+------------------------------------------------------------------+
//| Función de inicialización experta|
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!_window.CreateGUI())
     {
      Print(__FUNCTION__,"> ¡Fallo al crear una interfaz gráfica de usuario!");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Función de desinicialización experta|
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   _window.OnDeinitEvent(reason);
  }
//+------------------------------------------------------------------+
//| Función tick experto|
//+------------------------------------------------------------------+
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)
  {
//--- Añade el puntero de la ventana al array de ventanas
   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;
//--- Propiedades
   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);

//--- Establecer información sobre herramientas
   m_window.GetCloseButtonPointer().Tooltip("Close");
   m_window.GetCollapseButtonPointer().Tooltip("Collapse/Expand");
//--- Creación del formulario
   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)
  {
//--- Guardar el puntero al elemento principal
   btn_link.MainPointer(m_window);
//--- Propiedades
   btn_link.XSize(x_size);
   btn_link.YSize(y_size);
   btn_link.IconXGap(3);
   btn_link.IconYGap(3);
   btn_link.IsCenterText(true);
//--- Crear un control
   if(!btn_link.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Añade un puntero al elemento en la 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)
  {
//--- Guardar el puntero al elemento principal
   comboBox_link.MainPointer(m_window);

   if(x_lableXSize==0)
      x_lableXSize=x_size;

   int items_total=ArraySize(items_text);

//--- Establecer propiedades antes de la creación
   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);
     }

//--- Guardar los valores de los elementos en la lista del cuadro combinado
   for(int i=0;i<items_total;i++)
      comboBox_link.SetValue(i,items_text[i]);

//--- Obtener el puntero de la lista
   CListView *lv=comboBox_link.GetListViewPointer();

//--- Establecer las propiedades de la lista
   lv.YSize((int)MathMin(items_total*y_size,150));
   lv.LightsHover(true);
   lv.SelectItem(lv.SelectedItemIndex()==WRONG_VALUE ? 0 : lv.SelectedItemIndex());

//--- Crear un control
   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 ventana
   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);
  }
//+------------------------------------------------------------------+



Hasta ahora todas las soluciones que he encontrado se reducen a editar el código de la biblioteca (añadiendo nuevas 3 líneas de código) - pero no me gusta la idea de retocar el código de otra persona...

 
Andrey Azatskiy:
Código mínimo reproducible para mi pregunta:

...

Hasta ahora todas las soluciones que he encontrado se reducen a editar el código de la biblioteca (añadiendo nuevas 3 líneas de código) - pero no me gusta la idea de retocar el código de otra persona...

Gracias por el mensaje.

Intenta hacer una pequeña adición al método de la clase CListView. Tienes que poner a cero los campos auxiliares como se indica a continuación:

//+------------------------------------------------------------------+
//| Limpia la lista (borra todos los elementos)
//+------------------------------------------------------------------+
void CListView::Clear(const bool redraw=false)
  {
//--- Poner a cero los campos auxiliares
   m_item_index_focus      =WRONG_VALUE;
   m_prev_selected_item    =WRONG_VALUE;
   m_prev_item_index_focus =WRONG_VALUE;
//--- Poner el tamaño a cero
   ListSize(0);
//--- Calcular y establecer nuevos tamaños de lista
   RecalculateAndResizeList(redraw);
  }
 
Anatoli Kazharski:

Gracias por el mensaje.

Intente hacer una pequeña adición al método de la clase CListView. Es necesario poner a cero los campos auxiliares como se indica a continuación:

Gracias por su respuesta.

 
Anatoli Kazharski:

¿Qué tal un repositorio en bitbucket y aceptar commits de usuarios activos de la biblioteca?

Lo terminaremos más rápido juntos ;)

 

¿Puede decirme cómo manejar correctamente el botón de cierre de la ventana?

El problema es el siguiente: coloco un Asesor Experto (por ejemplo, ExampleEAF.ex5) y mi indicador en una ventana separada debajo del gráfico (el código mínimo sólo muestra una ventana vacía). Luego hago clic en el botón de cerrar ventana en cualquiera de estas aplicaciones y ambas se cierran (se eliminan del gráfico).

Este comportamiento no es del todo correcto. ¿Hay alguna forma de distinguir los eventos de las distintas aplicaciones que trabajan simultáneamente en el mismo gráfico? Existe la sospecha de que otros eventos puedan solaparse también.

 
Andrey Khatimlianskii:

¿Qué tal un repositorio en bitbucket y aceptar commits de usuarios activos de la biblioteca?

Lo terminaremos más rápido juntos ;)

Ya me han dado acceso. Tengo dudas sobre muchas de las ediciones.

No hay justificación para estos o aquellos cambios. Es más fácil discutirlo aquí en el foro.

Si se hacen cambios, es necesario dar ejemplos y resultados de pruebas con la explicación de por qué será mejor.

 
dmyger:

¿Puede decirme cómo manejar correctamente el botón de cierre de la ventana?

El problema es el siguiente: coloco un Asesor Experto (por ejemplo, ExampleEAF.ex5) y mi indicador en una ventana separada debajo del gráfico (el código mínimo sólo muestra una ventana vacía). Luego hago clic en el botón de cerrar ventana en cualquiera de estas aplicaciones y ambas se cierran (se quitan del gráfico).

Este comportamiento no es del todo correcto. ¿Hay alguna forma de distinguir los eventos de las distintas aplicaciones que trabajan simultáneamente en el mismo gráfico? Sospecho que también pueden solaparse otros eventos.

Lo probaré cuando tenga tiempo e informaré del resultado aquí.

 

Andrey Khatimlianskii:

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

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

Anatoli Kazharski:

...

Si se hace algún cambio, es necesario dar ejemplos y resultados de pruebas con una explicación de por qué sería mejor.

Al menos brevemente. Por ejemplo:

Correcciones en la clase CListView. En el método Clear() necesitamos poner a cero algunos campos auxiliares para evitar que otros métodos de la clase se salgan del array.