English Русский 中文 Deutsch 日本語 Português
Interfaces gráficas X: Campo de edición del texto, slider de imágenes y controles simples (build 5)

Interfaces gráficas X: Campo de edición del texto, slider de imágenes y controles simples (build 5)

MetaTrader 5Ejemplos | 5 diciembre 2016, 11:36
1 086 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 los artículos de cada parte se puede encontrar la lista de los capítulos con los enlaces, así como 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.

En este artículo vamos a analizar los controles nuevos, tales como: «Campo de edición del texto», «Slider de imágenes», así como veremos los controles simples adicionales, «Etiqueta de texto» e «Imagen» que también pueden ser útiles en diferentes situaciones. La librería sigue desarrollándose, y además de la aparición de controles nuevos, se van mejorando los que ya han sido creados anteriormente. Puesto que muchos usuarios ya utilizan esta librería en su trabajo, ellos envían diferentes observaciones y proposiciones. Muchas de sus observaciones han sido implementadas en la versión nueva de la librería. Además, algunos de los algoritmos han sido optimizados. Eso ha reducido aún más el consumo de los recursos de la CPU. Para más información sobre todo eso, lea a continuación.

 

Control «Campo de edición del texto»

Hasta ahora ya teníamos el control «Campo de edición» (clase CSpinEdit) en nuestra librería, pero servía sólo para la introducción de valores numéricos. Completaremos la librería con un control más, que nos permitirá introducir cualquier texto en el campo. El control «Campo de edición del texto» puede ser necesario en diferentes situaciones. Por ejemplo, se puede crear la búsqueda de una línea en los archivos del «entorno protegido» (file sandbox) del terminal. Otra opción de su uso es proporcionar al usuario final de la aplicación MQL la posibilidad de introducir por sí mismo el array de símbolos para el trading. En total, puede ser cualquier tipo de datos necesarios para el trabajo.

Vamos a nombrar todos los componentes que van a formar parte del control «Campo de edición del texto»:

  1. Fondo
  2. Icono
  3. Descripción
  4. Campo de edición

 

Fig. 1. Partes integrantes del control «Campo de edición del texto».


Vamos a ver con más detalles cómo está organizada la clase de este control.

 

Clase para crear el control «Campo de edición del texto»

Creamos el archivo TextEdit.mqh con la clase CTextEdit con los métodos estándar para todos los controles, y lo incluimos en el motor de la librería (archivo WndContainer.mqh). Abajo se listan las propiedades que estarán disponibles para la configuración personalizada del control.

  • Color del fondo del control
  • Iconos del control para el estado activo y bloqueado
  • Márgenes del icono por dos ejes (x, y)
  • Texto de la descripción del control
  • Márgenes de la etiqueta de texto por dos ejes (x, y)
  • Color del texto en diferentes estados del control
  • Tamaños del campo de edición
  • Márgenes del campo de edición por dos ejes (x, y)
  • Color del campo de edición y del texto en diferentes estados
  • Alineación del texto dentro del campo de edición (a la izquierda/a la derecha/centrado);
  • Modo de visualización del puntero para seleccionar el texto
  • Modo para resetear el valor en el campo de edición
//+------------------------------------------------------------------+
//| Clase para crear el control Campo de edición del texto                         |
//+------------------------------------------------------------------+
class CTextEdit : public CElement
  {
private:
   //--- Color del fondo del control
   color             m_area_color;
   //--- Iconos del control en el estado activo y bloqueado
   string            m_icon_file_on;
   string            m_icon_file_off;
   //--- Márgenes del icono
   int               m_icon_x_gap;
   int               m_icon_y_gap;
   //--- Texto de descripción del campo de edición
   string            m_label_text;
   //--- Márgenes de la etiqueta de texto
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Colores del texto en diferentes estados
   color             m_label_color;
   color             m_label_color_hover;
   color             m_label_color_locked;
   color             m_label_color_array[];
   //--- Valor actual en el campo de edición
   string            m_edit_value;
   //--- Tamaños del campo de edición
   int               m_edit_x_size;
   int               m_edit_y_size;
   //--- Márgenes del campo de edición
   int               m_edit_x_gap;
   int               m_edit_y_gap;
   //--- Colores del campo de edición y del texto dentro en diferentes estados
   color             m_edit_color;
   color             m_edit_color_locked;
   color             m_edit_text_color;
   color             m_edit_text_color_locked;
   color             m_edit_text_color_highlight;
   //--- Colores del borde del campo de edición en diferentes estados
   color             m_edit_border_color;
   color             m_edit_border_color_hover;
   color             m_edit_border_color_locked;
   color             m_edit_border_color_array[];
   //--- Modo para resetear el valor (línea vacía)
   bool              m_reset_mode;
   //--- Modo de visualización del puntero para seleccionar el texto
   bool              m_show_text_pointer_mode;
   //--- Modo de alineación del texto
   ENUM_ALIGN_MODE   m_align_mode;
   //---
public:
   //--- Márgenes del icono
   void              IconXGap(const int x_gap)                      { m_icon_x_gap=x_gap;                 }
   void              IconYGap(const int y_gap)                      { m_icon_y_gap=y_gap;                 }
   //--- (1) Color del fondo, (2) texto de la descripción del campo de edición, (3) márgenes de la etiqueta de texto
   void              AreaColor(const color clr)                     { m_area_color=clr;                   }
   string            LabelText(void)                          const { return(m_label.Description());      }
   void              LabelText(const string text)                   { m_label.Description(text);          }
   void              LabelXGap(const int x_gap)                     { m_label_x_gap=x_gap;                }
   void              LabelYGap(const int y_gap)                     { m_label_y_gap=y_gap;                }
   //--- Colores de la etiqueta de texto en diferentes estados
   void              LabelColor(const color clr)                    { m_label_color=clr;                  }
   void              LabelColorHover(const color clr)               { m_label_color_hover=clr;            }
   void              LabelColorLocked(const color clr)              { m_label_color_locked=clr;           }
   //--- (1) Tamaños del campo de edición, (2) margen del campo de edición desde el borde derecho
   void              EditXSize(const int x_size)                    { m_edit_x_size=x_size;               }
   void              EditYSize(const int y_size)                    { m_edit_y_size=y_size;               }
   //--- Márgenes del campo de edición
   void              EditXGap(const int x_gap)                      { m_edit_x_gap=x_gap;                 }
   void              EditYGap(const int y_gap)                      { m_edit_y_gap=y_gap;                 }
   //--- Colores del campo de edición en diferentes estados
   void              EditColor(const color clr)                     { m_edit_color=clr;                   }
   void              EditColorLocked(const color clr)               { m_edit_color_locked=clr;            }
   //--- Colores del texto del campo de edición en diferentes estados
   void              EditTextColor(const color clr)                 { m_edit_text_color=clr;              }
   void              EditTextColorLocked(const color clr)           { m_edit_text_color_locked=clr;       }
   void              EditTextColorHighlight(const color clr)        { m_edit_text_color_highlight=clr;    }
   //--- Colores del borde del campo de edición en diferentes estados
   void              EditBorderColor(const color clr)               { m_edit_border_color=clr;            }
   void              EditBorderColorHover(const color clr)          { m_edit_border_color_hover=clr;      }
   void              EditBorderColorLocked(const color clr)         { m_edit_border_color_locked=clr;     }
   //--- (1) Modo del reseteo al pulsar en la etiqueta de texto, (2) modo de visualización del puntero de selección del texto
   bool              ResetMode(void)                                { return(m_reset_mode);               }
   void              ResetMode(const bool mode)                     { m_reset_mode=mode;                  }
   void              ShowTextPointerMode(const bool mode)           { m_show_text_pointer_mode=mode;      }
   //--- Modo de alineación del texto
   void              AlignMode(ENUM_ALIGN_MODE mode)                { m_align_mode=mode;                  }
   //--- Establecer los iconos para el control en el estado activo y bloqueado
   void              IconFileOn(const string file_path);
   void              IconFileOff(const string file_path);
  };

El modo del visualización del puntero para seleccionar el texto significa que cuando situamos el cursor sobre el campo de edición éste va a completarse con un icono que indica que aquí podemos introducir el texto. Para que eso funcione, ha sido añadido un identificador más (MP_TEXT_SELECT) a la enumeración ENUM_MOUSE_POINTER.

//+------------------------------------------------------------------+
//| Enumeración de los tipos de punteros                                    |
//+------------------------------------------------------------------+
enum ENUM_MOUSE_POINTER
  {
   MP_CUSTOM      =0,
   MP_X_RESIZE    =1,
   MP_Y_RESIZE    =2,
   MP_XY1_RESIZE  =3,
   MP_XY2_RESIZE  =4,
   MP_X_SCROLL    =5,
   MP_Y_SCROLL    =6,
   MP_TEXT_SELECT =7
  };

La adición correspondiente ha sido introducida en la clase CPointer (véase el código de abajo). La imagen para el icono del puntero de selección del texto va adjunta al final del artículo .

//+------------------------------------------------------------------+
//|                                                      Pointer.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
//--- Recursos
...
#resource "\\Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp"

//+------------------------------------------------------------------+
//| Establecimiento de imágenes para el puntero según el tipo del puntero               |
//+------------------------------------------------------------------+
void CPointer::SetPointerBmp(void)
  {
   switch(m_type)
     {
      case MP_X_RESIZE :
         m_file_on  ="Images\\EasyAndFastGUI\\Controls\\pointer_x_rs_blue.bmp";
         m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_x_rs.bmp";
         break;
      case MP_Y_RESIZE :
         m_file_on  ="Images\\EasyAndFastGUI\\Controls\\pointer_y_rs_blue.bmp";
         m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_y_rs.bmp";
         break;
      case MP_XY1_RESIZE :
         m_file_on  ="Images\\EasyAndFastGUI\\Controls\\pointer_xy1_rs_blue.bmp";
         m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_xy1_rs.bmp";
         break;
      case MP_XY2_RESIZE :
         m_file_on  ="Images\\EasyAndFastGUI\\Controls\\pointer_xy2_rs_blue.bmp";
         m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_xy2_rs.bmp";
         break;
      case MP_X_SCROLL :
         m_file_on  ="Images\\EasyAndFastGUI\\Controls\\pointer_x_scroll_blue.bmp";
         m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_x_scroll.bmp";
         break;
      case MP_Y_SCROLL :
         m_file_on  ="Images\\EasyAndFastGUI\\Controls\\pointer_y_scroll_blue.bmp";
         m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_y_scroll.bmp";
         break;
      case MP_TEXT_SELECT :
         m_file_on  ="Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp";
         m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp";
         break;

     }
//--- Si se indica el tipo personalizado (MP_CUSTOM)
   if(m_file_on=="" || m_file_off=="")
      ::Print(__FUNCTION__," > Para el puntero del cursor hay que establecer ambas imágenes!");
  }

Para crear el elemento «Campo de edición del texto», vamos a necesitar cinco métodos privados (private) y un método público (public): 

class CTextEdit : public CElement
  {
private:
   //--- Objetos para crear el campo de edición
   CRectLabel        m_area;
   CBmpLabel         m_icon;
   CLabel            m_label;
   CEdit             m_edit;
   CPointer          m_text_select;
   //---
public:
   //--- Métodos para crear el campo de edición
   bool              CreateTextEdit(const long chart_id,const int subwin,const string label_text,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateIcon(void);
   bool              CreateLabel(void);
   bool              CreateEdit(void);
   bool              CreateTextSelectPointer(void);
  };


Por lo demás, la clase CTextEdit no tiene nada más de lo que no hemos hablado en los artículos anteriores de esta serie. Por eso, Usted puede conocer sus posibilidades por sí mismo. La versión actual del control «Campo de edición del texto» tiene limitación de 63 caracteres.  

 

Control «Slider de imágenes»

El «Slider de imágenes» pertenece a los elementos informativos de la interfaz gráfica. Puede ser usado para crear la guía de usuario breve en la que de forma ilustrativa se muestran diversas situaciones en los gráficos de precios o descripciones breves sobre el uso de uno u otro control de la la interfaz gráfica en una aplicación MQL. 

Vamos a nombrar todos los componentes que van a formar parte del control «Slider de imágenes»:

  1. Fondo
  2. Botones del cambio consecutivo de imágenes
  3. Grupo de botones de opción (radio buttons)
  4. Grupo de imágenes relacionado con el grupo de botones de opción


 

Fig. 2. Partes integrantes del control “Slider de imágenes”.

 

Clase para crear el control «Slider de imágenes»

En el directorio que contiene todos los demás archivos de los controles de la librería se crea el archivo PicturesSlider.mqh con los métodos estándar que están incluidos en los demás controles, e incluimos este archivo en el archivo WndContainer.mqh. Abajo se listan las propiedades del control que estarán disponibles para la configuración personalizada del control.

  • Color del fondo del control
  • Color del borde del fondo del control
  • Margen para las imágenes por el eje Y
  • Márgenes para los botones del cambio consecutivo de imágenes por dos ejes (x, y)
  • Márgenes para los botones de opción por dos ejes (x, y)
  • Margen entre los botones de opción
//+------------------------------------------------------------------+
//| Clase para la creación del slider de imágenes                             |
//+------------------------------------------------------------------+
class CPicturesSlider : public CElement
  {
private:
   //--- Color del fondo y del borde del control
   color             m_area_color;
   color             m_area_border_color;
   //--- Margen para las imágenes por el eje Y
   int               m_pictures_y_gap;
   //--- Márgenes para los botones
   int               m_arrows_x_gap;
   int               m_arrows_y_gap;
   //--- Márgenes para los botones de opción
   int               m_radio_buttons_x_gap;
   int               m_radio_buttons_y_gap;
   int               m_radio_buttons_x_offset;
   //---
public:
   //--- (1) Color del fondo y (2) borde del fondo
   void              AreaColor(const color clr)              { m_area_color=clr;                      }
   void              AreaBorderColor(const color clr)        { m_area_border_color=clr;               }
   //--- Márgenes para los botones de flechas
   void              ArrowsXGap(const int x_gap)             { m_arrows_x_gap=x_gap;                  }
   void              ArrowsYGap(const int y_gap)             { m_arrows_y_gap=y_gap;                  }
   //--- Margen para las imágenes por el eje Y
   void              PictureYGap(const int y_gap)            { m_pictures_y_gap=y_gap;                }
   //--- (1) Márgenes de los botones de opción, (2) distancia entre los botones de opción
   void              RadioButtonsXGap(const int x_gap)       { m_radio_buttons_x_gap=x_gap;           }
   void              RadioButtonsYGap(const int y_gap)       { m_radio_buttons_y_gap=y_gap;           }
   void              RadioButtonsXOffset(const int x_offset) { m_radio_buttons_x_offset=x_offset;     }
  };

 Para crear el elemento «Slider de imágenes», vamos a necesitar cinco métodos privados (private) y un método público (public):

class CPicturesSlider : public CElement
  {
private:
   //--- Objetos para crear el control
   CRectLabel        m_area;
   CBmpLabel         m_pictures[];
   CRadioButtons     m_radio_buttons;
   CIconButton       m_left_arrow;
   CIconButton       m_right_arrow;
   //---
public:
   //--- Métodos para crear el slider de imágenes
   bool              CreatePicturesSlider(const long chart_id,const int subwin,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreatePictures(void);
   bool              CreateRadioButtons(void);
   bool              CreateLeftArrow(void);
   bool              CreateRightArrow(void);
  };

El ancho del control va a calcularse automáticamente a base de los parámetros establecidos por el usuario. A estos parámetros les pertenece el margen del grupo de los botones de opción desde el borde izquierdo del control, respecto al cual también se calcula la coordenada para el botón conmutador derecho del slider de imágenes. El alto del control también depende del tamaño de las imágenes. Se supone que el tamaño de las imágenes va a ser el mismo, por eso en los cálculos se utilizan las dimensiones de la primera imagen del grupo.

Antes de llamar al método principal de la creación del control, hay que añadir las imágenes al array usando el método CPicturesSlider::AddPicture(). Si no enviamos la ruta hacia la imagen como el único argumento de este método, va a aplicarse la ruta por defecto

//+------------------------------------------------------------------+
//|                                               PicturesSlider.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
...
//--- Imagen predefinida
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp"
//+------------------------------------------------------------------+
//| Clase para crear el slider de imágenes                             |
//+------------------------------------------------------------------+
class CPicturesSlider : public CElement
  {
private:
   //--- Array de imágenes (ruta hacia las imágenes)
   string            m_file_path[];
   //--- Ruta hacia la imagen por defecto
   string            m_default_path;
   //---
public:
   //--- Añade la imagen
   void              AddPicture(const string file_path="");
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CPicturesSlider::CPicturesSlider(void) : m_default_path("Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp"),
                                         m_area_color(clrNONE),
                                         m_area_border_color(clrNONE),
                                         m_arrows_x_gap(2),
                                         m_arrows_y_gap(2),
                                         m_radio_button_width(12),
                                         m_radio_buttons_x_gap(25),
                                         m_radio_buttons_y_gap(1),
                                         m_radio_buttons_x_offset(20),
                                         m_pictures_y_gap(25)
  {
//--- Guardamos el nombre de la clase del control en la clase base
   CElement::ClassName(CLASS_NAME);
//--- Establecemos las prioridades para el clic izquierdo del ratón
   m_zorder=0;
  }
//+------------------------------------------------------------------+
//| Añade la imagen                                               |
//+------------------------------------------------------------------+
void CPicturesSlider::AddPicture(const string file_path="")
  {
//--- Aumentamos el tamaño del array a un elemento
   int array_size=::ArraySize(m_pictures);
   int new_size=array_size+1;
   ::ArrayResize(m_pictures,new_size);
   ::ArrayResize(m_file_path,new_size);
//--- Guardamos los valores de los parámetros enviados
   m_file_path[array_size]=(file_path=="")? m_default_path : file_path;
  }

Para mostrar la imagen del grupo, hay que usar el método CPicturesSlider::SelectPicture(). Este método va a invocarse cuando se pulsan los botones de conmutación y los botones de opción, en el manejador de la clase CPicturesSlider.  

class CPicturesSlider : public CElement
  {
public:
   //--- Cambia la imagen según el índice especificado
   void              SelectPicture(const uint index);
  };
//+------------------------------------------------------------------+
//| Indica qué imagen debe visualizarse                   |
//+------------------------------------------------------------------+
void CPicturesSlider::SelectPicture(const uint index)
  {
//--- Obtenemos el número de imágenes
   uint pictures_total=PicturesTotal();
//--- Si en el grupo no hay imágenes, avisar sobre ello
   if(pictures_total<1)
     {
      ::Print(__FUNCTION__," > La llamada a este método debe realizarse, "
              "cuando en el grupo hay por lo menos una imagen! Utilice el método CPicturesSlider::AddPicture()");
      return;
     }
//--- Corregir el valor del índice si supera el rango
   uint correct_index=(index>=pictures_total)? pictures_total-1 : index;
//--- Seleccionar el botón de opción según este índice
   m_radio_buttons.SelectRadioButton(correct_index);
//--- Cambiar de la imagen
   for(uint i=0; i<pictures_total; i++)
     {
      if(i==correct_index)
         m_pictures[i].Timeframes(OBJ_ALL_PERIODS);
      else
         m_pictures[i].Timeframes(OBJ_NO_PERIODS);
     }
  }

Cuando se pulsan los botones para la conmutación consecutiva de las imágenes, en el manejador del control se llaman a los métodos CPicturesSlider::OnClickLeftArrow() y CPicturesSlider::OnClickRightArrow(). Abajo se muestra el código del método para el botón izquierdo. En caso de necesidad, los eventos del clic en los botones del slider de imágenes se puede seguir en la clase personalizada de la aplicación MQL. 

class CPicturesSlider : public CElement
  {
public:
private:
   //--- Procesamiento del clic en el botón izquierdo
   bool              OnClickLeftArrow(const string clicked_object);
   //--- Procesamiento del clic en el botón derecho
   bool              OnClickRightArrow(const string clicked_object);
  };
//+------------------------------------------------------------------+
//| Clic en el botón izquierdo                                          |
//+------------------------------------------------------------------+
bool CPicturesSlider::OnClickLeftArrow(const string clicked_object)
  {
//--- Salimos si el clic no ha sido hecho en el botón
   if(::StringFind(clicked_object,CElement::ProgramName()+"_icon_button_",0)<0)
      return(false);
//--- Obtenemos el identificador del control desde el nombre del objeto
   int id=CElement::IdFromObjectName(clicked_object);
//--- Obtenemos el índice del control desde el nombre del objeto
   int index=CElement::IndexFromObjectName(clicked_object);
//--- Salir si los identificadores de controles no coinciden
   if(id!=CElement::Id())
      return(false);
//--- Salir si los índices de controles no coinciden
   if(index!=0)
      return(false);
//--- Obtenemos el índice actual del botón de opción seleccionado
   int selected_radio_button=m_radio_buttons.SelectedButtonIndex();
//--- Cambio de la imagen
   SelectPicture(--selected_radio_button);
//--- Enviamos el mensaje sobre ello
   ::EventChartCustom(m_chart_id,ON_CLICK_BUTTON,CElement::Id(),CElement::Index(),"");
   return(true);
  }

Abajo se muestra el código reducido del manejador de eventos del slider de imágenes. Se ve que aquí mismo se controla el clic en los botones de opción del slider. Se puede comprender que el clic ha sido hecho en el botón de opción en el grupo local gracias al identificador del control que coincide con el identificador del slider de imágenes

//+------------------------------------------------------------------+
//| Manejador de eventos                                               |
//+------------------------------------------------------------------+
void CPicturesSlider::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Procesamiento del evento del desplazamiento del cursor

//--- Procesamiento del evento del clic en el botón de opción
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      //--- Si es el botón de opción del slider, cambiar de la imagen
      if(lparam==CElement::Id())
         SelectPicture(m_radio_buttons.SelectedButtonIndex());
      //---
      return;
     }
//--- Procesamiento del evento del clic izquierdo en el objeto
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Si se pulsa el botón con flecha del slider, cambiar de la imagen
      if(OnClickLeftArrow(sparam))
         return;
      if(OnClickRightArrow(sparam))
         return;
      //---
      return;
     }
  }

 

Controles «Etiqueta de texto» e «Imagen»

Como adición, en la librería han sido incluidas dos clases nuevas, CTextLabel y CPicture, para la creación de los controles simples de la interfaz, «Etiqueta de texto» e «Imagen». Se puede utilizarlos como objetos separados, es decir sin vinculación estricta a algún otro control. Su contenido es muy simple. En la clase CPicture, el usuario puede modificar sólo una propiedad, es la ruta hacia la imagen. Para eso se utiliza el método CPicture::Path(). Si la ruta no está especificada, se usará la imagen predefinida. La imagen se puede cambar en cualquier momento con medios del programa después de la creación de la la interfaz gráfica de la aplicación MQL.

//+------------------------------------------------------------------+
//|                                                      Picture.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
//--- Recursos
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp"
//+------------------------------------------------------------------+
//| Clase para crear la imagen                                      |
//+------------------------------------------------------------------+
class CPicture : public CElement
  {
private:
   //--- Ruta hacia la imagen
   string            m_path;
   //---
public:
   //--- Devuelve/establece la ruta hacia la imagen
   string            Path(void)               const { return(m_path);             }
   void              Path(const string path);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CPicture::CPicture(void) : m_path("Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp")

  {
//--- Guardamos el nombre de la clase del control en la clase base
   CElement::ClassName(CLASS_NAME);
//--- Establecemos las prioridades para el clic izquierdo del ratón
   m_zorder=0;
  }
//+------------------------------------------------------------------+
//| Establecimiento de la imagen                                               |
//+------------------------------------------------------------------+
void CPicture::Path(const string path)
  {
   m_path=path;
   m_picture.BmpFileOn("::"+path);
   m_picture.BmpFileOff("::"+path);
  }

Lo que se refiere al control «Etiqueta de texto», aquí también todo es muy sencillo y el usuario puede establecer solamente cuatro propiedades:

  • Texto de la etiqueta
  • Color del texto
  • Fuente
  • Tamaño de la fuente
//+------------------------------------------------------------------+
//| Clase para crear el la etiqueta de texto                              |
//+------------------------------------------------------------------+
class CTextLabel : public CElement
  {
public:
   //--- Devuelve/establece el texto de la etiqueta
   string            LabelText(void)             const { return(m_label.Description()); }
   void              LabelText(const string text)      { m_label.Description(text);     }
   //--- Establecimiento del (1) color, (2) fuente y (3) tamaño de la fuente de la etiqueta de texto
   void              LabelColor(const color clr)       { m_label.Color(clr);            }
   void              LabelFont(const string font)      { m_label.Font(font);            }
   void              LabelFontSize(const int size)     { m_label.FontSize(size);        }
  };

 

Clase CFonts para trabajar con las fuentes

Para que la selección de las fuentes sea más fácil, ha sido escrita la clase adicional CFonts. En esta clase hay 187 fuentes disponibles. Son las fuentes de sistema del terminal cuya lista seguramente ya haya visto en los ajustes de algunos objetos gráficos.

 Fig. 3. Fuentes de sistema del terminal.

Fig. 3. Fuentes de sistema del terminal.


El archivo con las fuentes (Fonts.mqh) se ubica en el directorio "MetaTrader 5\MQL5\Include\EasyAndFastGUI\Fonts.mqh" y para el acceso completo en el esquema de la librería está incluido en el archivo Objects.mqh:

//+------------------------------------------------------------------+
//|                                                      Objects.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Enums.mqh"
#include "Defines.mqh"
#include "..\Fonts.mqh"
#include "..\Canvas\Charts\LineChart.mqh"
#include <ChartObjects\ChartObjectSubChart.mqh>
#include <ChartObjects\ChartObjectsBmpControls.mqh>
#include <ChartObjects\ChartObjectsTxtControls.mqh>

En la clase CFonts hay solamente dos métodos públicos para obtener el tamaño del array de las fuentes y para obtener el nombre de la fuente por el índice. El array de las fuentes se inicializa en el constructor de la clase

//+------------------------------------------------------------------+
//|                                                        Fonts.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Clase para trabajar con la fuente                                       |
//+------------------------------------------------------------------+
class CFonts
  {
private:
   //--- Array de las fuentes
   string            m_fonts[];
   //---
public:
                     CFonts(void);
                    ~CFonts(void);
   //--- Devuelve el número de las fuentes
   int               FontsTotal(void) const { return(::ArraySize(m_fonts)); }
   //--- Devuelve la fuente por el índice
   string            FontsByIndex(const uint index);
   //---
private:
   //--- Inicialización del array de las fuentes
   void              InitializeFontsArray(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CFonts::CFonts(void)
  {
//--- Inicialización del array de las fuentes
   InitializeFontsArray();
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CFonts::~CFonts(void)
  {
   ::ArrayFree(m_fonts);
  }

Cuando se llama al método CFonts::FontsByIndex() se realiza la corrección que impide la salida fuera de los límites del array:

//+------------------------------------------------------------------+
//| Devuelve la fuente por el índice                                      |
//+------------------------------------------------------------------+
string CFonts::FontsByIndex(const uint index)
  {
//--- Tamaño del array
   uint array_size=FontsTotal();
//--- Corrección en caso de salir fuera del rango
   uint i=(index>=array_size)? array_size-1 : index;
//--- Devolver la fuente
   return(m_fonts[i]);
  }

 

Lista de actualizaciones adicionales de la librería

1. Ha sido corregida la visualización incorrecta de las descripciones emergentes (tooltip) en las ventanas de diálogo. Ahora el estatus del botón de las tooltips en la ventana principal es válido para todas las demás ventanas de la interfaz gráfica cuando este botón se pulsa. Al hacer clic en el botón, se genera el mensaje con el identificador nuevo del evento ON_WINDOW_TOOLTIPS (ver archivo Defines.mqh).

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
...
#define ON_WINDOW_TOOLTIPS         (29) // Clic en el botón «Descripción emergente»

Por lo tanto, ha sido añadido el método OnClickTooltipsButton() a la clase CWindow para el procesamiento del clic en el botón de tooltips: 

//+------------------------------------------------------------------+
//| Clase de creación del formulario para los controles                    |
//+------------------------------------------------------------------+
class CWindow : public CElement
  {
private:
   //--- Procesamiento del clic en el botón «Descripciones emergentes»
   bool              OnClickTooltipsButton(const string clicked_object);
  };
//+------------------------------------------------------------------+
//| Manejador de eventos del gráfico                                       |
//+------------------------------------------------------------------+
void CWindow::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Procesamiento del evento del clic en el objeto
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
       //--- Si el clic en el botón «Descripciones emergentes»
      if(OnClickTooltipsButton(sparam))
         return;
     }
  }
//+------------------------------------------------------------------+
//| Procesamiento del clic en el botón «Descripciones emergentes»              |
//+------------------------------------------------------------------+
bool CWindow::OnClickTooltipsButton(const string clicked_object)
  {
//--- Este botón no es necesario si la ventana es de diálogo
   if(m_window_type==W_DIALOG)
      return(false);
//--- Salimos si el clic no ha sido hecho en el botón de opción
   if(::StringFind(clicked_object,CElement::ProgramName()+"_window_tooltip_",0)<0)
      return(false);
//--- Obtenemos el identificador del control desde el nombre del objeto
   int id=CElement::IdFromObjectName(clicked_object);
//--- Salir si los identificadores de controles no coinciden
   if(id!=CElement::Id())
      return(false);
//--- Recordamos el estado en el campo de la clase
   m_tooltips_button_state=m_button_tooltip.State();
//--- Enviamos el mensaje sobre ello
   ::EventChartCustom(m_chart_id,ON_WINDOW_TOOLTIPS,CElement::Id(),CElement::Index(),"");
   return(true);
  }

Para que todo eso funcione en el motor de la librería (clase CWndEvents), ha sido añadido el método OnWindowTooltips() para el procesamiento de eventos con el identificador ON_WINDOW_TOOLTIPS

class CWndEvents : public CWndContainer
  {
private:
   //--- Activar/desactivar descripciones emergentes
   bool              OnWindowTooltips(void);
  };
//+------------------------------------------------------------------+
//| 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
//--- Si hay señal para cambiar el tamaño de los controles por el eje X
//--- Si hay señal para cambiar el tamaño de los controles por el eje Y
//--- Si hay la señal para activar/desactivar descripciones emergentes
   if(OnWindowTooltips())
      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 controles 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
  }
//+------------------------------------------------------------------+
//| Evento ON_WINDOW_TOOLTIPS                                       |
//+------------------------------------------------------------------+
bool CWndEvents::OnWindowTooltips(void)
  {
//--- Si hay la señal para «Activar/desactivar descripciones emergentes»
   if(m_id!=CHARTEVENT_CUSTOM+ON_WINDOW_TOOLTIPS)
      return(false);
//--- Si los identificadores de la ventana coinciden
   if(m_lparam!=m_windows[0].Id())
      return(true);
//--- Sincronizar el modo de las descripciones emergentes entre todas las ventanas
   int windows_total=WindowsTotal();
   for(int w=0; w<windows_total; w++)
     {
      if(w>0)
         m_windows[w].TooltipButtonState(m_windows[0].TooltipButtonState());
     }
//---
   return(true);
  }

2. Ha sido añadida la posibilidad de editar el texto en la descripción de los siguientes controles tras su creación: 

 

Fig. 4. Lista de controles con la posibilidad de editar el texto después de la creación.


3. En todos los controles donde eso podía ser necesario ahora se puede establecer la imagen (ver la tabla de abajo). Aparte de eso, ha sido añadida la posibilidad de modificar las imágenes de los controles ya después de su creación:


 

Fig. 5. Lista de controles con la posibilidad de cambiar la imagen después de la creación.

 

Para cambiar la imagen en todos los controles listados más arriba, existen los métodos IconFileOn() y IconFileOff().


4. Ha sido añadida la posibilidad de manejar mediante pprogramación todos los tipos de botones y pestañas (pulsada/suelta) después de su creación. A continuación, se muestran los controles a los que se refiere esta adición:

 

Fig. 6. Lista de controles con la posibilidad de cambiar el estado (pulsado/suelto) después de la creación.


5. Ha sido optimizado el algoritmo para resaltar los elementos al situar el cursor en los siguientes controles:

 

Fig. 7. Controles con la optimización del algoritmo del resalto de los elementos del control.

 

Antes, en las listas de los elementos de los controles de la tabla de arriba, el programa repasaba todos los elementos comprobando la posición del cursor sobre ellos. De esta manera, el elemento debajo del cursor se resaltaba con otro color, y para los demás se establecía el color predefinido. Pero este método requiere muchos recursos, por eso aquí era necesario realizar la optimización. Ahora en vez del ciclo por el array de los elementos en el cambio del color participan sólo dos elementos. La búsqueda en el ciclo se realiza solamente cuando ha sido notado el cambio al otro elemento, es decir cuando se cambia el foco. 

A continuación veremos cómo eso ha sido implementado en la clase CListView. Para implementar todo eso, fue necesario añadir (1) el campo de la clase m_prev_item_index_focus para guardar el índice del último elemento en el foco, (2) el método CListView::CheckItemFocus() para comprobar el foco sobre el elemento y (3) cambiar el algoritmo en el método CListView::ChangeItemsColor().  

//+------------------------------------------------------------------+
//| Clase para crear la lista                                        |
//+------------------------------------------------------------------+
class CListView : public CElement
  {
private:
   //--- Para determinar el momento del cambio del cursor desde un elemento al otro
   int               m_prev_item_index_focus;
   //---
private:
   //--- Cambio del color de los elementos de la lista al situar el cursor encima
   void              ChangeItemsColor(void);
   //--- Comprobación del foco de la línea de la lista al situar el cursor encima
   void              CheckItemFocus(void);
  };

El método CListView::CheckItemFocus() es llamado sólo si el cursor ha entrado en la zona del control (en este caso se trata de la lista – CListView), así como cuando se realiza el paso del cursor desde un elemento al otro (véase el código de abajo). En cuanto el elemento encima del cual se sitúa el cursor se encuentre, su índice se guarda

//+------------------------------------------------------------------+
//| Comprobación del foco de la línea de la lista al situar el cursor encima              |
//+------------------------------------------------------------------+
void CListView::CheckItemFocus(void)
  {
//--- Obtenemos la posición actual del deslizador de la barra de desplazamiento
   int v=m_scrollv.CurrentPos();
//--- Buscamos el elemento sobre el que se sitúa el cursor y lo resaltamos
   for(int i=0; i<m_visible_items_total; i++)
     {
      //--- Aumentamos el contador si estamos dentro del diapasón de la lista
      if(v>=0 && v<m_items_total)
         v++;
      //--- Omitimos el elemento seleccionado
      if(m_selected_item_index==v-1)
        {
         m_items[i].BackColor(m_item_color_selected);
         m_items[i].Color(m_item_text_color_selected);
         continue;
        }
      //--- Si el cursor se encuentra sobre este elemento, lo resaltamos
      if(m_mouse.X()>m_items[i].X() && m_mouse.X()<m_items[i].X2() &&
         m_mouse.Y()>m_items[i].Y() && m_mouse.Y()<m_items[i].Y2())
        {
         m_items[i].BackColor(m_item_color_hover);
         m_items[i].Color(m_item_text_color_hover);
         //--- Recordar el elemento
         m_prev_item_index_focus=i;
         break;
        }
     }
  }

La llamada al método CListView::CheckItemFocus() se realiza dentro del método CListView::ChangeItemsColor() en los casos como ha sido descrito en el párrafo anterior (véase el código de abajo):

//+------------------------------------------------------------------+
//| Cambio del color de la línea de la lista al situar el cursor encima              |
//+------------------------------------------------------------------+
void CListView::ChangeItemsColor(void)
  {
//--- Salimos si el resalto está desactivado al apuntar con el cursor o el srolling está activo
   if(!m_lights_hover || m_scrollv.ScrollState())
      return;
//--- Salimos si el control no es desplegable y el formulario está bloqueado
   if(!CElement::IsDropdown() && m_wnd.IsLocked())
      return;
//--- Si hemos entrado en la lista de nuevo
   if(m_prev_item_index_focus==WRONG_VALUE)
     {
      //--- Comprobación del foco en el elemento actual
      CheckItemFocus();
     }
   else
     {
      //--- Comprobamos el foco en la fila actual
      int i=m_prev_item_index_focus;
      bool condition=m_mouse.X()>m_items[i].X() && m_mouse.X()<m_items[i].X2() &&
                     m_mouse.Y()>m_items[i].Y() && m_mouse.Y()<m_items[i].Y2();
      //--- Si es el paso al siguiente elemento
      if(!condition)
        {
         //--- Resetear el color del elemento anterior
         m_items[i].BackColor(m_item_color);
         m_items[i].Color(m_item_text_color);
         m_prev_item_index_focus=WRONG_VALUE;
        //--- Comprobación del foco en el elemento actual
         CheckItemFocus();
        }
     }
  }

En el manejador de eventos CListView::OnEvent() lla llamada al método CListView::ChangeItemsColor() se realiza sólo si el cursor se encuentra dentro del área del control. En cuanto el cursor salga fuera del área del control, se establecen los colores por defecto y se resetea el valor del índice del control. Abajo se muestra la versión reducida del manejador de eventos. 

//+------------------------------------------------------------------+
//| Manejador de eventos                                               |
//+------------------------------------------------------------------+
void CListView::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
      //--- Salir si los números de las subventanas no coinciden
      //--- Comprobación del foco sobre los controles
      //--- Si es la lista desplegable y el botón del ratón está pulsado
      //--- Desplazamos la lista si el manejo del deslizador está activado

      //--- Resetear los colores del control si no se encuentra en el foco
      if(!CElement::MouseFocus())
        {
        //--- Si ya hay un elemento en el foco
         if(m_prev_item_index_focus!=WRONG_VALUE)
           {
             //--- Resetear los colores de la lista
            ResetColors();
            m_prev_item_index_focus=WRONG_VALUE;
           }
         return;
        }
      //--- Cambia el color de las líneas de la lista al situar el cursor encima
      ChangeItemsColor();
      return;
     }
  }

El mismo principio ha sido implementado en las clases CTable, CCalendar y CTreeView, pero con algunas diferencias debidas a las particularidades de cada control.

6. Al pulsar el botón tipo CIconButton en modo doble (cuando el botón no se suelta tras la pulsación), aparece otra imagen, si ha sido establecida Para establecer la imagen para el botón pulsado, se puede usar los métodos CIconButton::IconFilePressedOn() y CIconButton::IconFilePressedOff()

//+------------------------------------------------------------------+
//| Clase para crear un botón con imagen                            |
//+------------------------------------------------------------------+
class CIconButton : public CElement
  {
private:
   //--- Iconos del botón en el estado activo, bloqueado y pulsado
   string            m_icon_file_on;
   string            m_icon_file_off;
   string            m_icon_file_pressed_on;
   string            m_icon_file_pressed_off;

   //---
public:
   //--- Establecer los iconos para el botón en el estado pulsado, activo y bloqueado
   void              IconFileOn(const string file_path);
   void              IconFileOff(const string file_path);
   void              IconFilePressedOn(const string file_path);
   void              IconFilePressedOff(const string file_path);

  };
//+------------------------------------------------------------------+
//| Establecer la imagen para el estado pulsado «Activado»             |
//+------------------------------------------------------------------+
void CIconButton::IconFilePressedOn(const string file_path)
  {
//--- Salir si el modo «Dos estados» está desactivado
   if(!m_two_state)
      return;
//--- Guardar la ruta hacia la imagen
   m_icon_file_pressed_on=file_path;
//--- Establecer si el botón está pulsado
   if(m_button.State())
      m_icon.BmpFileOn("::"+file_path);
  }
//+------------------------------------------------------------------+
//| Establecer la imagen para el estado pulsado «Desactivado»             |
//+------------------------------------------------------------------+
void CIconButton::IconFilePressedOff(const string file_path)
  {
//--- Salir si el modo «Dos estados» está desactivado
   if(!m_two_state)
      return;
//--- Guardar la ruta hacia la imagen
   m_icon_file_pressed_off=file_path;
//--- Establecer si el botón está pulsado
   if(m_button.State())
      m_icon.BmpFileOff("::"+file_path);
  }

7. Ha sido añadida la posibilidad de seleccionar una fila en la tabla (CTable) de forma programada. Para eso se utiliza el método CTable::SelectRow(). La indicación del índice de una fila seleccionada quita la selección.

//+------------------------------------------------------------------+
//| Clase par crear la tabla de los campos de edición                        |
//+------------------------------------------------------------------+
class CTable : public CElement
  {
public:
   //--- Selección de la fila especificada
   void              SelectRow(const uint row_index);
  };
//+------------------------------------------------------------------+
//| Selección de la fila especificada                                |
//+------------------------------------------------------------------+
void CTable::SelectRow(const uint row_index)
  {
//--- Corrección en caso de salir fuera del diapasón
   uint index=(row_index>=(uint)m_rows_total)? m_rows_total-1 : row_index;
//--- Si está fila ya está seleccionada, quitamos la selección
   bool is_selected=(index==m_selected_item);
//--- Guardamos el índice de la fila
   m_selected_item=(is_selected)? WRONG_VALUE : (int)index;
//--- Guardamos la línea de la celda
   m_selected_item_text=(is_selected)? "" : m_vcolumns[0].m_vrows[index];
//--- Formar la línea con los parámetros de la celda
   string cell_params=string(0)+"_"+string(index)+"_"+m_vcolumns[0].m_vrows[index];
//--- Resetear el foco
   m_prev_item_index_focus=WRONG_VALUE;
//--- Actualiza la tabla
   UpdateTable();
//--- Resalto de la fila seleccionada
   HighlightSelectedItem();
  }

8. Ha sido solucionado el problema de la visualización de los controles de la pestaña seleccionada del control tipo CIconTabs. Este problema surgía al abrir y maximizar el formulario con este tipo de pestañas. 

 

Aplicación para la prueba del control

Vamos a escribir la aplicación de prueba en el que Ud. podrá probar todos los controles nuevos y practicar con ellos activando sus diferentes modos. Vamos a crear el control «Pestañas» (clase CTabs) que va a contener cuatro pestañas con el siguiente contenido:

1. La primera pestaña:

  • La barra de progreso (CProgressBar).
  • Campo de edición del texto (CTextEdit).
  • Combobox con lista desplegable (CCombobox).
  • Campo de edición para valores numéricos (CSpinEdit).
  • Botón para abrir la paleta de colores (CColorButton).
  • Etiqueta de texto (CTextLabel).

Establecemos un icono para todos los controles, salvo la etiqueta de texto. Hagamos que los controles «Barra de progreso» y «Campo de edición del texto» cambien la descripción del control dentro de unos determinados intervalos de tiempo para demostrar que esta posibilidad existe. Colocaremos los nombres de todas las fuentes de la clase CFonts en la lista del combobox. Configuraremos el modelo de eventos de la aplicación MQL de prueba de tal manera que la selección de la fuente desde la lista del combobox se visualice en la etiqueta de texto. De la misma manera, el campo de edición numérico para el cambio del tamaño de la fuente y la selección del color en la paleta serán vinculados con la etiqueta de texto.

Entonces, el manejador de eventos para la gestión de los parámetros del control «Etiqueta de texto» tendrá el siguiente aspecto:

//+------------------------------------------------------------------+
//| Manejador de eventos del gráfico                                       |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Evento de la selección en la lista
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM)
     {
      //--- Si los identificadores de los controles coinciden
      if(lparam==m_combobox1.Id())
        {
         //--- Cambiar la fuente
         m_text_label1.LabelFont(m_combobox1.ButtonText());
        }
      //---
      return;
     }
//--- Evento del clic en los botones del campo de edición
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC ||
      id==CHARTEVENT_CUSTOM+ON_CLICK_DEC)
     {
      //--- Si los identificadores de los controles coinciden
      if(lparam==m_spin_edit1.Id())
        {
         //--- Cambiar el tamaño de la fuente
         m_text_label1.LabelFontSize(int(m_spin_edit1.GetValue()));
        }
      //---
      return;
     }
//--- Evento del cambio del color a través de la paleta de colores
   if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
     {
      //--- Si los identificadores de los controles coinciden
      if(lparam==m_spin_edit1.Id())
        {
         //--- Cambiar el tamaño de la fuente
         m_text_label1.LabelFontSize(int(m_spin_edit1.GetValue()));
        }
      //---
      return;
     }
//--- Evento del cambio del color a través de la paleta de colores
   if(id==CHARTEVENT_CUSTOM+ON_CHANGE_COLOR)
     {
      //--- Si los identificadores de los controles coinciden
      if(lparam==m_color_picker.Id())
        {
         //--- Si es la respuesta del primer botón
         if(sparam==m_color_button1.LabelText())
           {
            //--- Cambiar el color del objeto
            m_text_label1.LabelColor(m_color_button1.CurrentColor());
            return;
           }
        }
      return;
     }
//--- Evento del clic en el botón
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     {
      //--- Si ha sido pulsado el primer botón para abrir la paleta de colores
      if(sparam==m_color_button1.LabelText())
        {
         //--- Pasar el puntero del botón, lo que abrirá automáticamente la ventana con la paleta de colores
         m_color_picker.ColorButtonPointer(m_color_button1);
         return;
        }
      //---
      return;
     }
  }

En la captura de abajo se muestra cómo al final se puede configurar la visualización del texto mediante la interfaz gráfica desarrollada con esta librería:

Fig. 8. Grupo de controles en la primera pestaña. 

Fig. 8. Grupo de controles en la primera pestaña.


2. En la segunda pestaña colocaremos el único control, «Slider de imágenes» (clase CPicturesSlider). Vamos a añadir sólo tres imágenes por defecto para que Usted pueda probar rápidamente este control personalmente. Para el trabajo correcto del este control, por favor, prepare las imágenes del mismo tamaño.

Fig. 9. «Slider de imágenes» en la segunda pestaña. 

Fig. 9. «Slider de imágenes» en la segunda pestaña.


Para el cambio automático de imágenes, utilice el método CPicturesSlider::SelectPicture().


3. La tercera pestaña tendrá la tabla tipo CTable. Para la selección automática de una fila utilice el método CTable::SelectRow(). 

 Fig. 10. Control «Tabla» en la tercera pestaña.

Fig. 10 Control «Tabla» en la tercera pestaña.


4. Colocaremos tres controles en la cuarta pestaña: (1) calendario, (2) lista desplegable y (3) el botón con dos imágenes diferentes para el estado pulsado/suelto.

Fig. 11. Grupo de controles de la cuarta pestaña. 

Fig. 11. Grupo de controles de la cuarta pestaña.

 

Puede descargar esta aplicación de prueba al final del artículo para estudiarla más detalladamente. 


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. 12. Estructura de la librería en la fase actual del desarrollo.

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


La siguiente versión de la librería será ampliada con los controles adicionales. Además, vamos a mejorar y completar los controles ya existentes con nuevas posibilidades.

Si le surgen algunas preguntas sobre el uso del material de estos archivos, puede dirigirse a la descripción detallada del proceso de desarrollo de la librería en uno de los artículos de esta serie, o bien hacer su pregunta en los comentarios para el artículo. 

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

Archivos adjuntos |
Sistema comercial 'Turtle Soup' y su modificación 'Turtle Soup Plus One' Sistema comercial 'Turtle Soup' y su modificación 'Turtle Soup Plus One'
En este artículo han sido formalizadas y programadas las reglas de las estrategias comerciales llamadas «Turtle Soup» y «Turtle Soup Plus One» del libro titulado «Street Smarts: High Probability Short-Term Trading Strategies», escrito por Linda Raschke y Laurence Connors. Las estrategias descritas en este libro recibieron bastante amplia acogida, pero es importante comprender que sus autores las ideaban basándose en el comportamiento del mercado de hace 15-20 años.
Principios de programación en MQL5: Variables globales del terminal  MetaTrader 5 Principios de programación en MQL5: Variables globales del terminal MetaTrader 5
Las variables globales del terminal es un medio imprescindible durante la programación de los Asesores Expertos complejos y seguros. Después de aprender a trabajar con las variables globales, ya no podrá imaginar la creación de los asesores expertos en MQL5 sin usarlas.
Estrategia de trading '80-20' Estrategia de trading '80-20'
En este artículo se describe la creación de las herramientas (indicador y Asesor Experto) para el análisis de la estrategia comercial '80-20'. Las reglas de esta Estrategia Comercial han sido tomadas del libro titulado «Street Smarts: High Probability Short-Term Trading Strategies» escrito por Linda Raschke y Laurence Connors. Las reglas han sido formalizadas en el lenguaje MQL5, y el indicador y el Asesor Experto diseñados a base de esta estrategia han sido probados en el historial actual del mercado.
Asesor experto multiplataforma: Órdenes Asesor experto multiplataforma: Órdenes
MetaTrader 4 y MetaTrader 5 usan reglas diferentes en el procesamiento de solicitudes comerciales. En este artículo se discutirá la posibilidad de usar un objeto de clase para representar las operaciones procesadas por el servidor, para que en lo sucesivo el asesor pueda trabajar con ellas independientemente de la versión de la plataforma comercial y del modo ejecutado.