English Русский 中文 Deutsch 日本語 Português
Interfaces gráficas X: Actualizaciones para la librería Easy And Fast (build 2)

Interfaces gráficas X: Actualizaciones para la librería Easy And Fast (build 2)

MetaTrader 5Ejemplos | 26 agosto 2016, 14:06
1 464 0
Anatoli Kazharski
Anatoli Kazharski

Índice

Introducción

El primer artículo de la serie nos cuenta con más detalles para qué sirve esta librería: Interfaces gráficas I: Preparación de la estructura de la librería (Capítulo 1). Al final de cada artículo de la serie se muestra la lista completa de los capítulos con los enlaces. Además, se puede descargar la versión completa de la librería en la fase actual del desarrollo del proyecto. Es necesario colocar los ficheros en los mismos directorios, tal como están ubicados en el archivo.

Desde la publicación del anterior artículo de esta serie, la librería Easy And Fast ha adquirido nuevas posibilidades. Ha sido hecha la optimización parcial del esquema y del código de la librería, eso ha reducido un poco el consumo de recursos de la CPU. Algunos métodos que se repiten con frecuencia en muchas clases de los controles han sido traspasados a la clase base CElement. Además, han sido introducidas pequeñas mejoras visuales y han sido corregidos algunos errores. El presente artículo cuenta con más detalles sobre todo eso.

 

Lista de actualizaciones

1. El esquema de colores predefinido ha sido modificado. Ahora está hecha en tonos claros, lo que se ve igualmente de bien en cualquier fondo de colores del gráfico. Además, el uso del esquema de colores predefinido da la posibilidad de especificar el número mínimo de propiedades a la hora de escribir los métodos para la creación de los controles en la clase de usuario. 

A continuación, se muestran las capturas de pantalla con los ejemplos de la interfaz gráfica de la aplicación MQL sobre el fondo claro y oscuro:

 Fig. 1. Ejemplo de la interfaz gráfica con el esquema de colores predefinido sobre el fondo claro.

Fig. 1. Ejemplo de la interfaz gráfica con el esquema de colores predefinido sobre el fondo claro.


 Fig. 2. Ejemplo de la interfaz gráfica con el esquema de colores predefinido sobre el fondo oscuro.

Fig. 2. Ejemplo de la interfaz gráfica con el esquema de colores predefinido sobre el fondo oscuro.


 

2. Ha sido implementada la primera versión de la clase CMouse para almacenar los parámetros del ratón y del cursor del ratón. Analizaremos esta clase más detalladamente. 

La clase CMouse se encuentra en el archivo Mouse.mqh, que se ubica en el mismo directorio que todos los archivos de la librería: “<catálogo del terminal>\MQLX\Include\EasyAndFastGUI\Controls ”. Aquí vamos a necesitar la instancia de la clase CChart de la librería estándar. De esta clase se cogerá el método CChart::SubwindowY() para calcular la coordenada Yrespecto a la subventana en la que se encuentra el cursor del ratón en el momentos actual. La vinculación al gráfico se realiza en el constructor de la clase, y la desvinculación, en el destructor.

De aquí mismo la clase CChart estará disponible para todas las clases principales de la librería, por eso en el esquema han sido introducidas las modificaciones correspondientes. 

//+------------------------------------------------------------------+
//|                                                        Mouse.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Charts\Chart.mqh>
//+------------------------------------------------------------------+
//| Clase para obtener los parámetros del ratón                              |
//+------------------------------------------------------------------+
class CMouse
  {
private:
   //--- Instancia de la clase para controlar el gráfico
   CChart            m_chart;
   //---
public:
                     CMouse(void);
                    ~CMouse(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMouse::CMouse(void)
  {
//--- Obtenemos ID del gráfico actual
   m_chart.Attach();
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMouse::~CMouse(void)
  {
//--- Desvincularse del gráfico
   m_chart.Detach();
  }

Abajo se muestra la lista de los parámetros del ratón y del cursor que serán necesarios para el trabajo prácticamente en todas las clases de la librería.

  • Coordenadas actuales del cursor.
  • Número de la subventana en la que se encuentra el cursor del ratón actualmente.
  • Hora respecto a la coordenada X del cursor en el gráfico.
  • Nivel respecto a la coordenada Y del cursor en el gráfico.
  • Estado del botón izquierdo del ratón (pulsado/suelto).

Los campos y los métodos para guardar y obtener los valores de estos parámetros han sido implementados en el cuerpo de la clase CMouse

class CMouse
  {
private:
   //--- Coordenadas
   int               m_x;
   int               m_y;
   //--- Número de la ventana en la que se encuentra el cursor
   int               m_subwin;
   //--- Tiempo correspondiente a la coordenada X
   datetime          m_time;
   //--- Nivel (precio) correspondiente a la coordenada Y
   double            m_level;
   //--- Estado del botón izquierdo del ratón (pulsado/suelto)
   bool              m_left_button_state;
   //---
public:
   //--- Devuelve coordenadas
   int               X(void)               const { return(m_x);                 }
   int               Y(void)               const { return(m_y);                 }
   //--- (1) Devuelve el número de la ventana en la que se encuentra el cursor, (2) tiempo correspondiente a la coordenada X
       //--- (3) nivel (precio) correspondiente a la coordenada Y
   int               SubWindowNumber(void) const { return(m_subwin);            }
   datetime          Time(void)            const { return(m_time);              }
   double            Level(void)           const { return(m_level);             }
   //--- Devuelve el estado del botón izquierdo del ratón (pulsado/suelto)
   bool              LeftButtonState(void) const { return(m_left_button_state); }
  };

Claro que no se puede pasar sin el manejador de eventos en el que va a monitorearse la llegada del evento con el identificador CHARTEVENT_MOUSE_MOVE. Los campos de la clase CMouse se llenan en el bloque del procesamiento de este evento. Ya conocemos este código: antes lo hemos visto prácticamente en todos los manejadores de eventos de los controles. Ahora va a estar presente únicamente en la clase CMouse, lo que ha hecho que el código de las clases de los controles sea más claro y comprensible. Aparte de eso, la obtención de los valores de los parámetros del ratón y del cursor ahora se realiza sólo una vez durante el ciclo entero del repaso de todos los controles. Eso ha reducido el consumo de los recursos del procesador.  

class CMouse
  {
   Manejador de eventos
   void              OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
  };
//+------------------------------------------------------------------+
//| Procesamiento de eventos del desplazamiento del cursor del ratón                       |
//+------------------------------------------------------------------+
void CMouse::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Procesamiento del evento del desplazamiento del cursor
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
       //--- Coordenadas y el estado del botón izquierdo del ratón
      m_x                 =(int)lparam;
      m_y                 =(int)dparam;
      m_left_button_state =(bool)int(sparam);
      //--- Obtenemos la posición del cursor
      if(!::ChartXYToTimePrice(0,m_x,m_y,m_subwin,m_time,m_level))
         return;
      //--- Obtenemos la coordenada relativa Y
      if(m_subwin>0)
         m_y=m_y-m_chart.SubwindowY(m_subwin);
     }
  }

La instancia de la clase CMouse ha sido declarada en la clase base del motor de la librería (CWndContainer):

//+------------------------------------------------------------------+
//| Clase para almacenar todos los objetos de la interfaz                      |
//+------------------------------------------------------------------+
class CWndContainer
  {
protected:
   //--- Instancia de la clase para obtener los parámetros del ratón
   CMouse            m_mouse;
  };

En la clase base de los controles CElement también ha sido declarada la instancia de la clase CMouse para almacenar el puntero al objeto de este tipo, que a su vez ha sido declarado en la clase CWndContainer. Además, aquí hay métodos que permiten guardar y obtener el puntero. 

//+------------------------------------------------------------------+
//| Clase base del control                                |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- Instancia de la clase para obtener los parámetros del ratón
   CMouse           *m_mouse;
   //---
public:
   //--- (1) Guarda y (2) devuelve el puntero del ratón
   void              MousePointer(CMouse &object)                   { m_mouse=::GetPointer(object);       }
   CMouse           *MousePointer(void)                       const { return(::GetPointer(m_mouse));      }
  };

El puntero al objeto CMouse se pasa automáticamente a todos los controles durante la creación de la interfaz gráfica de la librería. Para eso en el método CWndContainer::AddToObjectsArray(), donde los punteros de todos los objetos gráficos que forman parte de los controles llegan al array común, hay que pasar el objeto CMouse, tal como se muestra en el código de abajo. 

//+------------------------------------------------------------------+
//| Añade los punteros de objetos del control al array común             |
//+------------------------------------------------------------------+
template<typename T>
void CWndContainer::AddToObjectsArray(const int window_index,T &object)
  {
   int total=object.ObjectsElementTotal();
   for(int i=0; i<total; i++)
      AddToArray(window_index,object.Object(i));
//--- Guardamos el puntero del ratón en la clase base del control
   object.MousePointer(m_mouse);
  }

Ahora en cada clase del control hay acceso a los parámetros del ratón y del cursor que se guardan en el único objeto de la librería. Para obtener nuevos valores, en el manejador de eventos ChartEvent() de la clase CWndEvents hay que llamar al manejador del objeto CMouse, pasándole los parámetros actuales del evento. Puesto que esta llamada se hace antes del ciclo del procesamiento de eventos de todos los controles, los valores actuales de los parámetros del ratón y cursor estarán disponibles para todos los controles, sin necesidad de realizar de nuevo la conversión de tipos, asignación de los valores a los campos de la clase y cálculo respecto a la coordenada Y.

//+------------------------------------------------------------------+
//| Manejo de eventos del programa                                      |
//+------------------------------------------------------------------+
void CWndEvents::ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Si el array está vacío, salimos
 //--- Inicialización de los campos de los parámetros de eventos

//--- Obtenemos los parámetros del ratón
   m_mouse.OnEvent(id,lparam,dparam,sparam);

//--- Eventos personalizados
//| Comprobación de los eventos de los controles de la interfaz
//--- Evento de desplazamiento del ratón
//--- Evento del cambio de propiedades del gráfico
  }

Como ejemplo, mostraremos aquí una parte del código del manejador del control «Botón simple» (CSimpleButton). Abajo se muestra la versión reducida del método CSimpleButton::OnEvent(). Las cadenas con las llamadas a los métodos del objeto CMouse para obtener el (1) número de la subventana en la que se encuentra el cursor, (2) las coordenadas del cursor y (3) el estado del botón izquierdo del ratón están marcadas en amarillo.  

//+------------------------------------------------------------------+
//| Procesamiento de eventos                                                |
//+------------------------------------------------------------------+
void CSimpleButton::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Procesamiento del evento del desplazamiento del cursor
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Salir si el control está ocultado
      if(!CElement::IsVisible())
         return;
      //--- Salir si el formulario está bloqueado
      if(m_wnd.IsLocked())
         return;
      //--- Salir si los números de las subventanas no coinciden
      if(CElement::m_subwin!=CElement::m_mouse.SubWindowNumber())
         return;
      //--- Salir si el botón está bloqueado
      if(!m_button_state)
         return;
      //--- Definimos el foco
      CElement::MouseFocus(CElement::m_mouse.X()>X() && CElement::m_mouse.X()<X2() && 
                           CElement::m_mouse.Y()>Y() && CElement::m_mouse.Y()<Y2());
      //--- Salir si el botón del ratón está suelto
      if(!CElement::m_mouse.LeftButtonState())
         return;
      //--- 
      ...
      return;
     }
//...
  }

Las correcciones correspondientes han sido introducidas en todas las clases de los controles de la librería.  


3. Antes en muchas clases de los controles de la librería, se repetían los métodos para la obtención del identificador e índice del control desde el nombre de los objetos gráficos del control. Ahora, estos métodos han sido traspasados a la clase base CElement para evitar las repeticiones.  

//+------------------------------------------------------------------+
//| Clase base del control                                |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- Obtener el identificador desde el nombre del botón
   int               IdFromObjectName(const string object_name);
   //--- Obtener el índice desde el nombre del elemento del menú
   int               IndexFromObjectName(const string object_name);
  };

 

4. Han sido añadidos los métodos en la clase CWindow para habilitar el botón de minimizar/maximizar la ventana y para posicionar la etiqueta de texto del encabezado.  

//+------------------------------------------------------------------+
//| Clase de creación del formulario para los controles                    |
//+------------------------------------------------------------------+
class CWindow : public CElement
  {
private:
   //--- Márgenes de la etiqueta de texto del encabezado
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Presencia del botón para minimizar/maximizar la ventana
   bool              m_roll_button;
   //---
public:
   //--- Márgenes de la etiqueta de texto
   void              LabelXGap(const int x_gap)                              { m_label_x_gap=x_gap;                }
   void              LabelYGap(const int y_gap)                              { m_label_y_gap=y_gap;                }
   //--- Usar el botón de ayudas
   void              UseRollButton(void)                                     { m_roll_button=true;                 }
  };

 

5. A la clase CElement ha sido añadido el método CheckWindowPointer() para comprobar la presencia del puntero de la ventana (CWindow). Usando el método de sistema CheckPointer(), a este método hay que pasarle el tipo del puntero para comprobar que sea correcto. Antes, el mismo código se repetía en todas las clases de los controles en el método principal de la creación del control antes de su creación. El método CElement::CheckWindowPointer() facilita este proceso, reduce el volumen del código y lo hace más universal. 

//+------------------------------------------------------------------+
//| Clase base del control                                |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- Comprobación de la presencia del puntero al formulario
   bool              CheckWindowPointer(ENUM_POINTER_TYPE pointer_type);
  };
//+------------------------------------------------------------------+
//| Comprobación de la presencia del puntero al formulario                              |
//+------------------------------------------------------------------+
bool CElement::CheckWindowPointer(ENUM_POINTER_TYPE pointer_type)
  {
//--- Si no hay puntero al formulario
   if(pointer_type==POINTER_INVALID)
     {
      //--- Crear mensaje
      string message=__FUNCTION__+" > Antes de crear el control, hay que pasar el puntero al formulario: "+ClassName()+"::WindowPointer(CWindow &object)";
      //--- Mostrar el mensaje en el registro del terminal
      ::Print(message);
      //--- Interrumpir la construcción de la interfaz gráfica de la aplicación
      return(false);
     }
//--- Enviar el indicio de la presencia del puntero
   return(true);
  }

Ahora para comprobar la presencia del puntero al formulario al que debe adjuntarse el control, será suficiente llamar al método CElement::CheckWindowPointer(), tal como se muestra en el código de abajo, tomando de ejemplo la creación del botón simple en la clase CSimpleButton. Las modificaciones correspondientes han sido introducidas en todas las clases de los controles de la librería. 

//+------------------------------------------------------------------+
//| Crea el control «Botón simple»                                 |
//+------------------------------------------------------------------+
bool CSimpleButton::CreateSimpleButton(const long chart_id,const int subwin,const string button_text,const int x,const int y)
  {
//--- Salir si no hay puntero al formulario
   if(!CElement::CheckWindowPointer(::CheckPointer(m_wnd)))
      return(false);
//--- Inicialización de variables
   m_id          =m_wnd.LastId()+1;
   m_chart_id    =chart_id;
   m_subwin      =subwin;
   m_x           =x;
   m_y           =y;
   m_button_text =button_text;
//--- Márgenes desde el punto extremo
   CElement::XGap(m_x-m_wnd.X());
   CElement::YGap(m_y-m_wnd.Y());
//--- Crear el botón
   if(!CreateButton())
      return(false);
//--- Ocultar el elemento si es la ventana de diálogo o está minimizada
   if(m_wnd.WindowType()==W_DIALOG || m_wnd.IsMinimized())
      Hide();
//---
   return(true);
  }

 

6. A la clase base CElement ha sido añadido el modo para el cambio automático del ancho de los controles si se ha cambiado el ancho del formulario al que está adjuntado el control. Para establecer este modo, se utiliza el método CElement::AutoXResizeMode(). Ahora, el borde derecho del control en este modo estará anclado al borde derecho del formulario. Además, ha sido añadido el método CElement::AutoXResizeRightOffset() para establecer y obtener el margen (en píxeles) desde el borde derecho del formulario. 

//+------------------------------------------------------------------+
//| Clase base del control                                |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- Modo del cambio automático del ancho del control
   bool              m_auto_xresize_mode;
   //--- Margen desde el borde derecho en modo del cambio automático del ancho del control
   int               m_auto_xresize_right_offset;
   //---
public:
   //--- (1) Modo del cambio automático del ancho del control, (2) obtener/establecer el margen desde el borde derecho del formulario
   bool              AutoXResizeMode(void)                    const { return(m_auto_xresize_mode);         }
   void              AutoXResizeMode(const bool flag)               { m_auto_xresize_mode=flag;            }
   int               AutoXResizeRightOffset(void)             const { return(m_auto_xresize_right_offset); }
   void              AutoXResizeRightOffset(const int offset)       { m_auto_xresize_right_offset=offset;  }
  };

Por defecto, el modo de anclaje del borde derecho del control al borde derecho del formulario está desactivado (false), y el margen es igual a 0. La inicialización se realiza en el constructor de la clase CElement (véase el código de abajo).

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CElement::CElement(void) : m_auto_xresize_mode(false),
                           m_auto_xresize_right_offset(0)
  {
  }

Antes, en la clase CWindow ya ha sido creado el método CWindow::ChangeWindowWidth() para el cambio del ancho del formulario. Ahora, si el modo está activado, el ancho del formulario se cambia automáticamente sólo si la interfaz gráfica está implementada en la subventana del indicador. Es decir, cuando se cambia el ancho de la ventana del gráfico, se corrige el ancho del formulario según el evento CHARTEVENT_CHART_CHANGE en el manejador de eventos del formulario. 

//--- Evento del cambio de propiedades del gráfico
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- Si el botón está suelto
      if(m_clamping_area_mouse==NOT_PRESSED)
        {
         //--- Obtenemos las dimensiones de la ventana del gráfico
         SetWindowProperties();
         //--- Corrección de coordenadas
         UpdateWindowXY(m_x,m_y);
        }
      //--- Cambiar el tamaño si el modo está activado
      if(CElement::AutoXResizeMode())
         ChangeWindowWidth(m_chart.WidthInPixels()-2);
      //---
      return;
     }

A la lista de los identificadores de eventos de la librería ha sido añadido uno más: ON_WINDOW_CHANGE_SIZE. Este identificador va a utilizarse para generar el mensaje sobre el cambio del tamaño del formulario. 

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
...
//--- Identificadores de eventos
#define ON_WINDOW_CHANGE_SIZE     (3)  // Cambio del tamaño de la ventana
...

Por consecuente, al método CWindow::ChangeWindowWidth() ha sido añadida la generación de este mensaje. Abajo se muestra la versión reducida de este método: 

//+------------------------------------------------------------------+
//| Cambia el ancho de la ventana                                             |
//+------------------------------------------------------------------+
void CWindow::ChangeWindowWidth(const int width)
  {
//--- Si el ancho no ha cambiado, salimos
//--- Actualizamos el ancho para el fondo y encabezamiento
//--- Actualizamos las coordenadas y sangrías para todos los botones:
//    Botón de cierre
//--- Botón para maximizar
//--- Botón para minimizar
//--- Botón “Ayudas emergentes” (si está activado)

//--- Mensaje sobre el cambio de los tamaños de la ventana
   ::EventChartCustom(m_chart_id,ON_WINDOW_CHANGE_SIZE,(long)CElement::Id(),0,””);
  }

El procesamiento de este mensaje se realiza en el motor de la librería (clase CWndEvents). En la clase base de los controles CElement ha sido añadido el método virtual ChangeWidthByRightWindowSide(), y en muchas clases derivadas (donde es necesario cambiar el ancho del control), su implementación única.  

//+------------------------------------------------------------------+
//| Clase base del control                                |
//+------------------------------------------------------------------+
class CElement
  {
public:
   //--- Cambiar el ancho por el lado derecho de la ventana
   virtual void      ChangeWidthByRightWindowSide(void) {}
  };

De esta manera, cuando llega el evento ON_WINDOW_CHANGE_SIZE en la clase CWndEvents se puede cambiar el ancho para los controles que tienen activado el modo correspondiente. Para eso ha sido implementado el método CWndEvents::OnWindowChangeSize(). 

//+------------------------------------------------------------------+
//| Clase para procesar los eventos                                      |
//+------------------------------------------------------------------+
class CWndEvents : public CWndContainer
  {
private:
   //--- Procesamiento del cambio del tamaño de la ventana
   bool              OnWindowChangeSize(void);
  };
//+------------------------------------------------------------------+
//| Evento ON_WINDOW_CHANGE_SIZE                                    |
//+------------------------------------------------------------------+
bool CWndEvents::OnWindowChangeSize(void)
  {
//--- Hay señal «Cambiar el tamaño de los controles»
   if(m_id!=CHARTEVENT_CUSTOM+ON_WINDOW_CHANGE_SIZE)
      return(false);
//--- Índice de la ventana activa
   int awi=m_active_window_index;
//--- Si los identificadores de la ventana coinciden
   if(m_lparam!=m_windows[awi].Id())
      return(true);
//--- Cambiar el ancho de todos los controles, excepto el formulario
   int elements_total=CWndContainer::ElementsTotal(awi);
   for(int e=0; e<elements_total; e++)
     {
      if(m_wnd[awi].m_elements[e].ClassName()=="CWindow")
         continue;
      //---
      if(m_wnd[awi].m_elements[e].AutoXResizeMode())
         m_wnd[awi].m_elements[e].ChangeWidthByRightWindowSide();
     }
//---
   return(true);
  }

La llamada a este método se realiza en el método principal del procesamiento de eventos de la librería CWndEvents::ChartEventCustom(): .

//+------------------------------------------------------------------+
//| Evento CHARTEVENT_CUSTOM                                        |
//+------------------------------------------------------------------+
void CWndEvents::ChartEventCustom(void)
  {
//--- Si hay la señal para minimizar el formulario
//--- Si hay la señal para maximizar el formulario

//--- Hay señal para cambiar el tamaño de los controles
   if(OnWindowChangeSize())
      return;

//--- Si hay señal para ocultar los menús contextuales desde el elemento iniciador
//--- Si hay señal para cerrar todos los menús contextuales
//--- Si hay la señal para abrir la ventana de diálogo
//--- Si hay la señal para cerrar la ventana de diálogo
//--- Si hay señal para resetear el color de los elementos en el formulario especificado
//--- Si hay señal para resetear las prioridades para el clic izquierdo del ratón
//--- Si hay señal para recuperar las prioridades para el clic izquierdo del ratón
  }

Para este momento, los métodos únicos ChangeWidthByRightWindowSide() para el cambio del ancho del control respecto al ancho del formulario al que pertenecen existen sólo en las siguientes clases:

  • CTabs – pestañas simples.
  • CIconTabs – pestañas con imágenes.
  • CStatusBar – barra de estado.
  • CMenuBar – menú principal.
  • CLabelsTable – tabla de las etiquetas de texto.
  • CTable – tabla a base de los campos de edición.
  • CCanvasTable – tabla dibujada.
  • CProgressBar – indicador de progreso.
  • CTreeView – lista jerárquica.
  • CFileNavigator – explorador de archivos.
  • CLineGraph – gráfico lineal.

Como ejemplo, abajo se muestra el código de este método para el control tipo CLabelsTable

//+------------------------------------------------------------------+
//| Cambiar el ancho por el lado derecho del formulario                            |
//+------------------------------------------------------------------+
void CLabelsTable::ChangeWidthByRightWindowSide(void)
  {
//--- Coordenadas
   int x=0;
//--- Tamaños
   int x_size=0;
//--- Calcular y establecer nuevo tamaño para el fondo de la tabla
   x_size=m_wnd.X2()-m_area.X()-m_auto_xresize_right_offset;
   CElement::XSize(x_size);
   m_area.XSize(x_size);
   m_area.X_Size(x_size);
//--- Calcular y establecer nueva coordenada para la barra vertical de desplazamiento
   x=m_area.X2()-m_scrollv.ScrollWidth();
   m_scrollv.XDistance(x);
//--- Calcular y modificar el ancho de la barra de desplazamiento horizontal
   x_size=CElement::XSize()-m_scrollh.ScrollWidth()+1;
   m_scrollh.ChangeXSize(x_size);
//--- Actualizar la posición de los objetos
   Moving(m_wnd.X(),m_wnd.Y());
  }


7. Ha sido añadida la posibilidad de conmutar las pestañas ya después de su creación. Para eso en las clases CTabs y CIconTabs ha sido implementado el método SelectTab(). Como ejemplo, en el código de abajo se muestra el método desde la clase CTabs:

//+------------------------------------------------------------------+
//| Clase para crear las pestañas                                      |
//+------------------------------------------------------------------+
class CTabs : public CElement
  {
public:
   //--- Selecciona la pestaña especificada
   void              SelectTab(const int index);
  };
//+------------------------------------------------------------------+
//| Selecciona la pestaña                                                 |
//+------------------------------------------------------------------+
void CTabs::SelectTab(const int index)
  {
   for(int i=0; i<m_tabs_total; i++)
     {
      //--- Si esta pestaña está seleccionada
      if(index==i)
        {
         //--- Coordenadas
         int x=0;
         int y=0;
         //--- Tamaños
         int x_size=0;
         int y_size=0;
         //--- Guardar el índice de la pestaña seleccionada
         SelectedTab(index);
         //--- Establecer los colores
         m_tabs[i].Color(m_tab_text_color_selected);
         m_tabs[i].BackColor(m_tab_color_selected);
        //--- Cálculo respecto al posicionamiento de las pestañas
         CalculatingPatch(x,y,x_size,y_size);
         //--- Actualizar valores
         m_patch.X_Size(x_size);
         m_patch.Y_Size(y_size);
         m_patch.XGap(x-m_wnd.X());
         m_patch.YGap(y-m_wnd.Y());
        //--- Actualizar la posición de los objetos
         Moving(m_wnd.X(),m_wnd.Y());
        }
      else
        {
         //--- Establecer el color para las pestañas no activas
         m_tabs[i].Color(m_tab_text_color);
         m_tabs[i].BackColor(m_tab_color);
        }
     }
//--- Mostrar los controles sólo de la pestaña seleccionada
   ShowTabElements();
  }

 

8. En la tabla de los campos de edición (CTable), se puede quitar la selección de la fila haciendo doble clic en ella.

9. Al hacer clic en la celda de la tabla (CTable), si el modo de la edición de celdas está desactivado, en el evento generado en el parámetro string (sparam) se envía la cadena en el formato «columna_fila_texto».

10. Ha sido corregida la enumeración y los métodos para determinar el área de presión del botón del ratón. Ahora se utiliza una enumeración ENUM_MOUSE_STATE para determinar el área de presión del botón izquierdo del ratón en todos los controles.

11. Han sido renombrados algunos archivos con imágenes que se utilizan en la librería como recursos debido a la limitación de la longitud del nombre en los programas tipo «Indicador».

12. Además, han sido introducidas pequeñas mejoras visuales y han sido corregidos algunos errores. Algunos errores tenían lugar sólo en MetaTrader 4


Aplicación para la prueba de actualizaciones

Vamos a escribir la aplicación para que Usted pueda probar todas las actualizaciones mencionadas en el apartado anterior y asegurarse de que todo funcione de forma correcta. Hagamos dos versiones de esta aplicación: «Asesor Experto» e «Indicador». Colocaremos la interfaz gráfica del indicador en la subventana del gráfico para poder probar el modo del cambio automático del ancho de la ventana según el ancho de la ventana del gráfico, así como de los controles que van a ajustar su ancho respecto a la ventana a la que están adjuntados. 

Para realizar el testeo completo, incluiremos en la interfaz gráfica todos los tipos de controles que existen en la librería para este momento. Para que la interfaz del programa sea compacta al máximo y no ocupe demasiado sitio en el gráfico, colocaremos los controles en diferentes pestañas (CTabs). Puesto que la lista de los controles se hace bastante grande, sería conveniente colocar la implementación de los métodos para su creación en un archivo separado. Vamos a darle el nombre MainWindow.mqh. Va a guardarse en la misma carpeta donde se guardan los demás archivos del proyecto. Habrá que incluirlo justamente después del cuerpo de la clase de usuario, tal como se muestra en el código de abajo:

//+------------------------------------------------------------------+
//|                                                      Program.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <EasyAndFastGUI\Controls\WndEvents.mqh>
//+------------------------------------------------------------------+
//| Clase para crear la aplicación                                     |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {

//...

  };
//+------------------------------------------------------------------+
//| Creación de controles                                    |
//+------------------------------------------------------------------+
#include "MainWindow.mqh"

Para que la vinculación entre los archivos funcione bien, hay que incluir el archivo Program.mqh en el archivo MainWindow.mqh

//+------------------------------------------------------------------+
//|                                                   MainWindow.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Program.mqh"

En el archivo Program.mqh, tiene sentido dejar sólo el archivo principal para la creación de la interfaz gráfica, en el que se invocan todos los métodos de creación de los controles. 

Pues bien, empezamos. En las interfaces gráficas de las aplicaciones de prueba habrá ocho pestañas en total. En las capturas de pantalla de abajo se muestra la posición de los controles en estas pestañas. La primera pestaña contiene todos los tipos de botones (inclusive grupos de botones) y la lista con la barra de desplazamiento vertical. El botón «Simple Button 3» es de dos modos. Si lo activamos, aparecerá el elemento «Indicador de progreso» en el que vamos a imitar algún proceso para los fines de demostración. 

 Fig. 3. Grupo de controles de la interfaz gráfica de la primera pestaña.

Fig. 3. Grupo de controles de la interfaz gráfica de la primera pestaña.


En la captura de abajo se muestra que cuando el botón «Simple Button 3» se encuentra en el estado activado, en la barra de estado se muestra el indicador de progreso:

 Fig. 4. Demostración del control “Indicador de progreso”.

Fig. 4. Demostración del control “Indicador de progreso”.


En la segunda, tercera y la cuarta pestañas se encuentran las tablas de diferentes tipos:

 Fig. 5. Grupo de controles de la interfaz gráfica de la segunda pestaña.

Fig. 5. Grupo de controles de la interfaz gráfica de la segunda pestaña.

 

 Fig. 6. Grupo de controles de la interfaz gráfica de la tercera pestaña.

Fig. 6. Grupo de controles de la interfaz gráfica de la tercera pestaña.

 

Fig. 7. Grupo de controles de la interfaz gráfica de la cuarta pestaña. 

Fig. 7. Grupo de controles de la interfaz gráfica de la cuarta pestaña.


En la quinta pestaña se encuentra el elemento «Gráfico lineal». Los métodos para trabajar con este elemento han sido declarados e implementados en la clase CProgram. Las series aleatorias se generan en el temporizador CProgram::OnTimerEvent() cada 300 milisegundos:

 Fig. 8. Grupo de controles de la interfaz gráfica de la quinta pestaña.

Fig. 8. Grupo de controles de la interfaz gráfica de la quinta pestaña.


En la sexta y la séptima pestañas se encuentra la lista jerárquica y explorador de archivos, así como diferentes tipos de combobox, campos de edición y checkbox.

 Fig. 9. Grupo de controles de la interfaz gráfica de la sexta pestaña.

Fig. 9. Grupo de controles de la interfaz gráfica de la sexta pestaña.

 

Fig. 10. Grupo de controles de la interfaz gráfica de la séptima pestaña. 

Fig. 10 Grupo de controles de la interfaz gráfica de la séptima pestaña.


A la octava pestaña le pertenecen los siguientes controles: «Calendario», «Calendario desplegable», «Slider», «Slider doble», «Barra separadora» y «Botón para abrir la paleta de colores»:

 Fig. 11. Grupo de controles de la interfaz gráfica de la octava pestaña.

Fig. 11. Grupo de controles de la interfaz gráfica de la octava pestaña.


Si hace falta que la ventana con la paleta de colores se cree en la ventana principal del gráfico, hay que indicar el índice cero en el método de creación, tanto para el formulario, como para los controles que estarán adjuntados a este formulario. En este caso, tenemos adjuntado al gráfico sólo un control: «Paleta de colores». En la captura de pantalla de abajo se muestra el resultado final:

 Fig. 12. Demostración del control «Paleta de colores» en la ventana principal del gráfico.

Fig. 12 Demostración del control «Paleta de colores» en la ventana principal del gráfico.


Como ya hemos dicho antes, hemos creado una aplicación más para la prueba (Asesor Experto) con la misma interfaz gráfica:

 Fig. 13. Prueba de la aplicación tipo «Asesor Experto».

Fig. 13 Prueba de la aplicación tipo «Asesor Experto».


Ambos tipos de aplicaciones (EA e Indicador) han sido implementados para dos plataformas: MetaTrader 4 y MetaTrader 5. Puede descargar todos los archivos para las pruebas al final del artículo.

 

 


Conclusión

En esta fase del desarrollo de la librería para la creación de las interfaces gráficas, su esquema general tiene el siguiente aspecto.

 Fig. 14. Estructura de la librería en la fase actual del desarrollo.

Fig. 14 Estructura de la librería en la fase actual del desarrollo.


Muchas correcciones y actualizaciones han sido realizadas por las peticiones de los usuarios interesados. Si le falta algo o durante la creación de su aplicación ha encontrado algún error referente a esta librería, por favor, avíseme sobre ello en los comentarios para el artículo o mediante un mensaje privado. Le contestaré sin falta. En este momento ya se realiza el trabajo con la siguiente versión de la librería (build 3). Tendrá muchas posibilidades adicionales que llevarán a la librería a un nuevo nivel. 

Aparte de las aplicaciones de prueba que han sido consideradas en este artículo, en los archivos de abajo se puede descargar las versiones actualizadas de los EAs e indicadores de todos los artículos anteriores de la serie.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/2634

Archivos adjuntos |
Red neuronal profunda con Stacked RBM. Auto-aprendizaje, auto-control Red neuronal profunda con Stacked RBM. Auto-aprendizaje, auto-control
El artículo es la continuación de artículos anteriores sobre neuroredes profundas y elección de predictores. En este veremos las particularidades de una neurored iniciada con Stacked RBM, así como su implementación en el paquete "darch".
Interfaces gráficas IX: Elementos "Indicador de progreso" y "Gráfico lineal" (Capítulo 2) Interfaces gráficas IX: Elementos "Indicador de progreso" y "Gráfico lineal" (Capítulo 2)
El segundo capítulo de la novena parte de la serie estará dedicada a los elementos «Indicador de progreso» y «Gráfico lineal». Como siempre mostraremos los ejemplos detallados de cómo puede usar estos elementos en sus aplicaciones MQL.
Cómo desarrollar y depurar rápidamente cualquier estrategia de scalping en MetaTrader 5 Cómo desarrollar y depurar rápidamente cualquier estrategia de scalping en MetaTrader 5
Los sistemas automáticos de scalping se consideran por derecho propio la cima del trading automático, y precisamente por ello, son a la vez los más complejos a la hora de escribir el código. En este artículo vamos a mostrar cómo se pueden construir estrategias basadas en el análisis de ticks entrantes con la ayuda de los recursos de depuración incorporados y de la simulación visual. Para desarrollar las reglas de entrada y salida con frecuencia se necesitan años de comercio manual. Pero con la ayuda de MetaTrader 5 usted podrá comprobar cualquier estrategia similar en la historia real.
Asesor experto multiplataforma: Introducción Asesor experto multiplataforma: Introducción
En este artículo se describe con detalle un método para desarrollar de forma rápida y sencilla un asesor experto multiplataforma. El método propuesto aúna funciones comunes para ambas versiones en una clase y desarrolla la implementación para las funciones incompatibles en las clases heredadas.