Descargar MetaTrader 5

Interfaces gráficas VI: Controles "Slider" y "Slider doble" (Capítulo 2)

30 junio 2016, 14:29
Anatoli Kazharski
0
633

Í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 el artículo anterior nuestra librería ha sido completada con cuatro controles que se encuentran con bastante frecuencia en las interfaces gráficas: se trata de “checkbox”, “campo de edición”, “campo de edición con checkbox” y “combobox con checkbox”. El segundo capítulo de la sexta parte estará dedicado a los controles como Slider y Slider doble.


Control “Slider”

Un slider es una variante del control tipo “campo de edición”, que contiene un rango limitado con valores máximos y mínimos. A diferencia del control “campo de edición”, que hemos considerado antes, el slider no tiene botones conmutadores para cambiar el valor en el campo de edición. En vez de eso, aquí se utiliza una banda y un deslizador que se mueve en sus límites. Este control conviene para los casos cuando no es necesario indicar un valor preciso. Es decir, será suficiente especificar un valor aproximado dentro de un rango conocido. A pesar de eso, se guarda la posibilidad de introducir un valor con precisión en el campo de edición.

Vamos a utilizar seis objetos gráficos para diseñar este control. Son los siguientes:

  1. Fondo
  2. Título (etiqueta de texto)
  3. Campo de edición
  4. Banda del slider
  5. Deslizador del slider
  6. Indicador del slider

 

Fig. 1. Partes integrantes del control “Slider”.


Ahora vamos a ver cómo está organizada la clase de este control.

 


Desarrollo de la clase para la creación del control “Slider”

Creamos el archivo Slider.mqh y lo incluimos en el archivo WndContainer.mqh:

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

En el archivo Slider.mqh, creamos la clase CSlider con el conjunto estándar de los métodos que deben estar presentes en cada control de nuestra librería. Aparte de los archivos de inclusión Element.mqh y Window.mqh, vamos a incluir también el archivo SeparateLine.mqh con la clase CSeparateLine para crear una línea separadora. Antes, ya hemos considerado esta clase (CSeparateLine) en el artículo Interfaces gráficas II: Controles “Línea separadora” y “Menú contextual” (Capítulo 2), por eso no vamos a volver a analizarla al detalle. Lo único que quiero recordar es que si el alto se establece más de dos píxeles, entre dos líneas trazadas aparece un espacio vacío. Visualmente, eso parece a una cavidad que nos va muy bien para la creación de la banda del slider (raja o ranura) dentro de la cual va a desplazarse el deslizador.

//+------------------------------------------------------------------+
//|                                                       Slider.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
#include "SeparateLine.mqh"
//+------------------------------------------------------------------+
//| Clase para crear el slider con el campo de edición                        |
//+------------------------------------------------------------------+
class CSlider : public CElement
  {
private:
   //--- Puntero al formulario al que está adjuntado el control
   CWindow          *m_wnd;
public:
                     CSlider(void);
                    ~CSlider(void);
   //---
public:
   //--- Guarda el puntero del formulario
   void              WindowPointer(CWindow &object)                 { m_wnd=::GetPointer(object);         }
   //---
public:
   //--- Manejador de eventos del gráfico
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Temporizador
   virtual void      OnEventTimer(void);
   //--- Desplazamiento del control
   virtual void      Moving(const int x,const int y);
   //--- (1) Mostrar, (2) ocultar, (3) resetear, (4) eliminar
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- (1) Establecer, (2) resetear las prioridades para el clic izquierdo del ratón
   virtual void      SetZorders(void);
   virtual void      ResetZorders(void);
   //--- Resetear el color
   virtual void      ResetColors(void);
  };

Vamos a dar al usuario de la librería la posibilidad de configurar las propiedades de todos los objetos que van a formar parte del control “Slider”. Son las siguientes propiedade:

  • Color del fondo del control
  • Texto de la descripción del slider
  • Colores de las etiquetas de texto en diferentes estados
  • Valor actual en el campo de edición
  • Tamaños del campo de edición
  • Colores del campo de edición en diferentes estados
  • Colores del texto del campo de edición en diferentes estados
  • Colores del marco del campo de edición en diferentes estados
  • Tamaño de la ranura por el eje Y (alto)
  • Colores de las líneas de la ranura
  • Colores del indicador del slider en diferentes estados
  • Tamaños del deslizador del slider
  • Colores del deslizador del slider
  • Prioridades para el clic izquierdo del ratón

El código de abajo contiene los campos y los métodos de la clase de las propiedades de los objetos del control mencionadas:

class CSlider : public CElement
  {
private:
   //Color del fondo general
   color             m_area_color;
   //--- Texto para la descripción del slider
   string            m_label_text;
   //--- Colores de la etiqueta de texto en diferentes estados
   color             m_label_color;
   color             m_label_color_hover;
   color             m_label_color_locked;
   color             m_label_color_array[];
   //--- Tamaños del campo de edición
   int               m_edit_x_size;
   int               m_edit_y_size;
   //--- Colores del campo de edición en diferentes estados
   color             m_edit_color;
   color             m_edit_color_locked;
   //--- Colores del texto del campo de edición en diferentes estados
   color             m_edit_text_color;
   color             m_edit_text_color_locked;
   //--- Colores del marco 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[];
   //--- Tamaño de la ranura
   int               m_slot_y_size;
   //--- Colores de la ranura
   color             m_slot_line_dark_color;
   color             m_slot_line_light_color;
   //--- Colores del indicador en diferentes estados
   color             m_slot_indicator_color;
   color             m_slot_indicator_color_locked;
   //--- Tamaños del deslizador del slider
   int               m_thumb_x_size;
   int               m_thumb_y_size;
   //--- Colores del deslizador del slider
   color             m_thumb_color;
   color             m_thumb_color_hover;
   color             m_thumb_color_locked;
   color             m_thumb_color_pressed;
   //--- Prioridades para el clic izquierdo del ratón
   int               m_zorder;
   int               m_area_zorder;
   int               m_edit_zorder;
   //---
public:
   //--- (1) Color del fondo, (2) colores de la etiqueta de texto
   void              AreaColor(const color clr)                     { m_area_color=clr;                   }
   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;           }
   //--- Tamaños del (1) campo de edición y de (2) la ranura
   void              EditXSize(const int x_size)                    { m_edit_x_size=x_size;               }
   void              EditYSize(const int y_size)                    { m_edit_y_size=y_size;               }
   void              SlotYSize(const int y_size)                    { m_slot_y_size=y_size;               }
   //--- 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;       }
   //--- Colores del marco 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;     }
   //--- Color (1) oscuro y (2) claro de la línea separadora (de la ranura)
   void              SlotLineDarkColor(const color clr)             { m_slot_line_dark_color=clr;         }
   void              SlotLineLightColor(const color clr)            { m_slot_line_light_color=clr;        }
   //--- Colores del indicador del slider en diferentes estados
   void              SlotIndicatorColor(const color clr)            { m_slot_indicator_color=clr;         }
   void              SlotIndicatorColorLocked(const color clr)      { m_slot_indicator_color_locked=clr;  }
   //--- Tamaños del deslizador del slider
   void              ThumbXSize(const int x_size)                   { m_thumb_x_size=x_size;              }
   void              ThumbYSize(const int y_size)                   { m_thumb_y_size=y_size;              }
   //--- Colores del deslizador del slider
   void              ThumbColor(const color clr)                    { m_thumb_color=clr;                  }
   void              ThumbColorHover(const color clr)               { m_thumb_color_hover=clr;            }
   void              ThumbColorLocked(const color clr)              { m_thumb_color_locked=clr;           }
   void              ThumbColorPressed(const color clr)             { m_thumb_color_pressed=clr;          }
  };

Las propiedades desde la lista anterior se refieren principalmente al color y tamaños de los objetos del control. Las propiedades que se refieren al valor y al rango en el campo de edición del slider mostraremos en un grupo separado. Éstas son las siguientes: 

  • Valor mínimo
  • Valor máximo
  • Paso para el cambio del valor en el campo de edición
  • Modo de alineación del texto
  • Número de dígitos después de la coma
class CSlider : public CElement
  {
private:
   //--- Valor (1) mínimo y (2) máximo, (3) paso para el cambio del valor
   double            m_min_value;
   double            m_max_value;
   double            m_step_value;
   //--- Número de dígitos después de la coma
   int               m_digits;
   //--- Modo de alineación del texto
   ENUM_ALIGN_MODE   m_align_mode;
   //---
public:
   //--- Valor mínimo
   double            MinValue(void)                           const { return(m_min_value);                }
   void              MinValue(const double value)                   { m_min_value=value;                  }
   //--- Valor máximo
   double            MaxValue(void)                           const { return(m_max_value);                }
   void              MaxValue(const double value)                   { m_max_value=value;                  }
   //--- Paso del cambio del valor
   double            StepValue(void)                          const { return(m_step_value);               }
   void              StepValue(const double value)                  { m_step_value=(value<=0)? 1 : value; }
   //--- (1) Número de dígitos después de la coma, (2) modo de alineación del texto
   void              SetDigits(const int digits)                    { m_digits=::fabs(digits);            }
   void              AlignMode(ENUM_ALIGN_MODE mode)                { m_align_mode=mode;                  }
  };

Para obtener el valor actual, así como para ajustar y establecer un valor nuevo en el campo de edición, van a utilizarse los métodos CSlider::GetValue(), CSlider::SetValue() y CSlider::ChangeValue():

class CSlider : public CElement
  {
private:
   //--- Valor actual en el campo de edición
   double            m_edit_value;
   //---
public:
   //--- Devolver y establecer el valor del campo de edición
   double            GetValue(void)                           const { return(m_edit_value);               }
   bool              SetValue(const double value);
   //--- Cambio del valor en el campo de edición
   void              ChangeValue(const double value);
  };
//+------------------------------------------------------------------+
//| Establecer el valor actual                                       |
//+------------------------------------------------------------------+
bool CSlider::SetValue(const double value)
  {
//--- Para la corrección
   double corrected_value=0.0;
//--- Corregimos tomando en cuenta el paso
   corrected_value=::MathRound(value/m_step_value)*m_step_value;
//--- Comprobación del mínimo/máximo
   if(corrected_value<=m_min_value)
      corrected_value=m_min_value;
   if(corrected_value>=m_max_value)
      corrected_value=m_max_value;
//--- Si el valor ha sido cambiado
   if(m_edit_value!=corrected_value)
     {
      m_edit_value=corrected_value;
      return(true);
     }
//--- Valor sin cambios
   return(false);
  }
//+------------------------------------------------------------------+
//| Cambio del valor en el campo de edición                                  |
//+------------------------------------------------------------------+
void CSlider::ChangeValue(const double value)
  {
//--- Comprobamos, ajustamos y guardamos el valor nuevo
   SetValue(value);
//--- Establecemos el valor nuevo en el campo de edición
   m_edit.Description(::DoubleToString(GetValue(),m_digits));
  }

Cuando el deslizador se mueve, el valor en el campo de edición debe calcularse en relación a la coordenada X. Si el valor se introduce en el campo de edición manualmente, la coordenada X del deslizador debe calcularse en relación al nuevo valor en el campo de edición. En otras palabras, a la hora de desarrollar el control hay que prever la posibilidad de conversiones inversas de los valores de estas variables. 

Para el cálculo correcto, vamos a necesitar campos auxiliares (variables) de la clase que van a utilizarse en los cálculos. Los valores de estas variables deben calcularse sólo una vez, inmediatamente después de la creación del control. Abajo se muestran las descripciones de estas variables:

  • Número de píxeles en el área de trabajo (m_pixels_total).
  • Número de pasos en el rango de valores del área de trabajo (m_value_steps_total).
  • Tamaño del paso respecto al ancho del área de trabajo (m_position_step).

Para el cálculo de los valores de estas variables escribiremos el método CSlider::CalculateCoefficients():

class CSlider : public CElement
  {
private:
   //--- Número de píxeles en el área de trabajo
   int               m_pixels_total;
   //--- Número de pasos en el rango de valores del área de trabajo
   int               m_value_steps_total;
   //--- Tamaño del paso respecto al ancho del área de trabajo
   double            m_position_step;
   //---
private:
   //--- Cálculo de valores (pasos y coeficientes)
   bool              CalculateCoefficients(void);
  };
//+------------------------------------------------------------------+
//| Cálculo de valores (pasos y coeficientes)                            |
//+------------------------------------------------------------------+
bool CSlider::CalculateCoefficients(void)
  {
//--- Salir si el ancho del control es menos que el ancho del deslizador del slider
   if(CElement::XSize()<m_thumb_x_size)
      return(false);
//--- Número de píxeles en el área de trabajo
   m_pixels_total=CElement::XSize()-m_thumb_x_size;
//--- Número de pasos en el rango de valores del área de trabajo
   m_value_steps_total=int((m_max_value-m_min_value)/m_step_value);
//--- Tamaño del paso respecto al ancho del área de trabajo
   m_position_step=m_step_value*(double(m_value_steps_total)/double(m_pixels_total));
   return(true);
  }

Ahora podemos utilizar los valores de las variables arriba mencionadas para el cálculo de la coordenada X del deslizador en relación al valor en el campo de edición, y viceversa. Para eso escribiremos dos métodos separados: CSlider::CalculateThumbX() y CSlider::CalculateThumbPos().

En el método CSlider::CalculateThumbX(), primero se calculan los valores de la variable local auxiliar (neg_range) para la corrección, en caso si el valor del límite mínimo es negativo. Luego se calcula la coordenada X para el deslizador del slider. Después de eso, si la banda del slider ha sido excedida, el valor se ajusta. Al final del método, al deslizador del slider se le asigna un valor nuevo de la coordenada X y el margen desde el punto extremos del formulario al que está adjuntado el control vuelve a calcularse.

Al principio del método CSlider::CalculateThumbPos(), obtenemos la posición del deslizador del slider en el rango de valores. Luego, se realiza la corrección en caso si el valor del límite mínimo es negativo y el valor de la variable m_current_pos_x es correcto. Luego, si el área de trabajo ha sido excedida, se realiza la corrección correspondiente del valor.

class CSlider : public CElement
  {
private:
   //--- Posición actual del deslizador del slider: (1) valor, (2) voordinada X
   double            m_current_pos;
   double            m_current_pos_x;
   //---
private:
   //--- Cálculo de la coordenada X del deslizador del slider
   void              CalculateThumbX(void);
   //--- Cambia la posición del slider en relación al valor actual
   void              CalculateThumbPos(void);
  };
//+------------------------------------------------------------------+
//| Cálculo de la coordenada X del deslizador del slider                            |
//+------------------------------------------------------------------+
void CSlider::CalculateThumbX(void)
  {
//--- Ajuste tomando en cuenta que el valor mínimo puede ser negativo
   double neg_range=(m_min_value<0)? ::fabs(m_min_value/m_position_step) : 0;
//--- Calculamos la coordenada X del deslizador del slider
   m_current_pos_x=m_area.X()+(m_edit_value/m_position_step)+neg_range;
//--- Si salimos fuera del área de trabajo hacia la izquierda
   if(m_current_pos_x<m_area.X())
      m_current_pos_x=m_area.X();
//--- Si salimos fuera del área de trabajo hacia la derecha
   if(m_current_pos_x+m_thumb.XSize()>m_area.X2())
      m_current_pos_x=m_area.X2()-m_thumb.XSize();
//--- Guardamos y establecemos la nueva coordenada X
   m_thumb.X(int(m_current_pos_x));
   m_thumb.X_Distance(int(m_current_pos_x));
   m_thumb.XGap(m_thumb.X()-m_wnd.X());
  }
//+------------------------------------------------------------------+
//| Cálculo de la posición del deslizador del slider en el rango de valores            |
//+------------------------------------------------------------------+
void CSlider::CalculateThumbPos(void)
  {
//--- Obtenemos el número de la posición del deslizador del slider
   m_current_pos=(m_thumb.X()-m_area.X())*m_position_step;
//--- Ajuste tomando en cuenta que el valor mínimo puede ser negativo
   if(m_min_value<0 && m_current_pos_x!=WRONG_VALUE)
      m_current_pos+=int(m_min_value);
//--- Comprobar la superación del rango del área de trabajo hacia la derecha/izquierda
   if(m_thumb.X2()>=m_area.X2())
      m_current_pos=int(m_max_value);
   if(m_thumb.X()<=m_area.X())
      m_current_pos=int(m_min_value);
  }

Durante el desplazamiento del deslizador del slider, hay que calcular y actualizar el ancho del indicador del slider. El lado derecho del indicador tiene que “estar anclado” al deslizador. Para eso escribiremos el método CSlider::UpdateIndicator():

class CSlider : public CElement
  {
private:
   //--- Actualización del indicador del slider
   void              UpdateIndicator(void);
  };
//+------------------------------------------------------------------+
//| Actualización del indicador del slider                                   |
//+------------------------------------------------------------------+
void CSlider::UpdateIndicator(void)
  {
//--- Calculamos el tamaño
   int x_size=m_thumb.X()-m_indicator.X();
//--- Corrección en caso de valores inadmisibles
   if(x_size<=0)
      x_size=1;
//--- Establecer el tamaño nuevo
   m_indicator.X_Size(x_size);
  }

Para crear el control “Slider”, vamos a necesitar seis métodos privados (private) y un método principal público (public):

class CSlider : public CElement
  {
public:
   //--- Métodos para crear el control
   bool              CreateSlider(const long chart_id,const int subwin,const string text,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateLabel(void);
   bool              CreateEdit(void);
   bool              CreateSlot(void);
   bool              CreateIndicator(void);
   bool              CreateThumb(void);
  };

Aquí vamos a mostrar sólo el código del método CSlider::CreateThumb(), porque todos los métodos para los cálculos considerados anteriormente van a llamarse precisamente en este método por primera vez. Todos los demás métodos de la creación de los objetos del control no tienen nada distinto de los que hemos hablado antes en otros artículos de la serie.

//+------------------------------------------------------------------+
//| Crea el deslizador del slider                                        |
//+------------------------------------------------------------------+
bool CSlider::CreateThumb(void)
  {
//--- Formación del nombre del objeto
   string name=CElement::ProgramName()+"_slider_thumb_"+(string)CElement::Id();
//--- Coordenadas
   int x=CElement::X();
   int y=m_slot.Y()-((m_thumb_y_size-m_slot_y_size)/2);
//--- Establecemos el objeto
   if(!m_thumb.Create(m_chart_id,name,m_subwin,x,y,m_thumb_x_size,m_thumb_y_size))
      return(false);
//--- Establecemos las propiedades
   m_thumb.Color(m_thumb_color);
   m_thumb.BackColor(m_thumb_color);
   m_thumb.BorderType(BORDER_FLAT);
   m_thumb.Corner(m_corner);
   m_thumb.Selectable(false);
   m_thumb.Z_Order(m_zorder);
   m_thumb.Tooltip("\n");
//--- Guardamos los tamaños (en el objeto)
   m_thumb.XSize(m_thumb.X_Size());
   m_thumb.YSize(m_thumb.Y_Size());
//--- Guardamos las coordenadas
   m_thumb.X(x);
   m_thumb.Y(y);
//--- Márgenes desde el punto extremo
   m_thumb.XGap(x-m_wnd.X());
   m_thumb.YGap(y-m_wnd.Y());
//--- Cálculo de valores de las variables auxiliares
   CalculateCoefficients();
//--- Cálculo de la coordenada X del deslizador en relación al valor actual en el campo de edición
   CalculateThumbX();
//--- Cálculo de la posición del deslizador del slider en el rango de valores
   CalculateThumbPos();
//--- Обновляем индикатор слайдера
   UpdateIndicator();
//--- Guardamos el puntero del objeto
   CElement::AddToArray(m_thumb);
   return(true);
  }

Los métodos para el desplazamiento del deslizador del slider prácticamente no se diferencian en nada de los métodos homónimos en las clases CScroll и CScrollH, que han sido considerados detalladamente en el artículo Interfaces gráficas V: Barra de desplazamiento vertical y horizontal (Capítulo 1). Por eso, no vamos a mostrar su código aquí. Nos limitaremos sólo con su declaración el cuerpo de la clase CSlider

class CSlider : public CElement
  {
private:
  //--- Estado del botón del ratón (pulsado/suelto)
   ENUM_THUMB_MOUSE_STATE m_clamping_area_mouse;
   //--- Para identificar el modo de desplazamiento del deslizador del slider
   bool              m_slider_thumb_state;
   //--- Variables relacionadas con el desplazamiento del deslizador
   int               m_slider_size_fixing;
   int               m_slider_point_fixing;
   //---
private:
   //--- Proceso del desplazamiento del deslizador del slider
   void              OnDragThumb(const int x);
   //--- Actualización de la posición del deslizador del slider
   void              UpdateThumb(const int new_x_point);
   //--- Comprueba el estado del botón del ratón
   void              CheckMouseButtonState(void);
   //--- Poner a cero las variables relacionadas con el desplazamiento del deslizador del slider
   void              ZeroThumbVariables(void);
  };

Para el procesamiento de la entrada del valor en el campo de edición, vamos a crear el método CSlider::OnEndEdit() que va a llamarse en el manejador de eventos del control CSlider::OnEvent(). 

En el inicio del método CSlider::OnEndEdit() se comprueba por el nombre del objeto si ha sido introducido algún valor en el campo de este slider. Luego obtenemos el valor actual en el campo de edición. A continuación, se realiza la comprobación y la corrección obligatoria de la entrada del valor inaceptable, se calcula la coordenada X del deslizador del slider y la posición en el rango de valores. Después de eso se actualiza el indicador del slider, y al final del método hay que enviar el mensaje con (1) el identificador del evento personalizado ON_END_EDIT, (2) identificador del control, (3) índice del control y (4) la descripción de la etiqueta de texto. 

class CSlider : public CElement
  {
private:
   //--- Procesamiento de la entrada del valor en el campo de edición
   bool              OnEndEdit(const string object_name);
  };
//+------------------------------------------------------------------+
//| Procesamiento de la entrada del valor en el campo de edición                            |
//+------------------------------------------------------------------+
bool CSlider::OnEndEdit(const string object_name)
  {
//--- Salimos si el nombre del objeto no coincide
   if(object_name!=m_edit.Name())
      return(false);
//--- Obtenemos el valor recién introducido
   double entered_value=::StringToDouble(m_edit.Description());
//--- Comprobamos, ajustamos y guardamos el valor nuevo
   ChangeValue(entered_value);
//--- Cálculo de la coordenada X del deslizador
   CalculateThumbX();
//--- Calculamos la posición dentro del rango de valores
   CalculateThumbPos();
//--- Actualizamos el indicador del slider
   UpdateIndicator();
//--- Enviamos el mensaje sobre ello
   ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
   return(true);
  }

Hay que enviar el mismo mensaje personalizado después de finalizar el desplazamiento del deslizador para cambiar el valor en el campo de edición. El mejor método para eso es CSlider::ZeroThumbVariables() que se invoca dentro del método CSlider::CheckMouseButtonState(), donde se monitorea el área del clic izquierdo del ratón. Todo está organizado de tal manera que la llamada al método CSlider::ZeroThumbVariables() ya supone que el botón izquierdo está suelto. Si antes de eso ya estaba pulsado sobre el área del deslizador, eso significa que el desplazamiento del deslizador ya está finalizado y ahora se puede enviar el mensaje sobre el hecho de que el valor en el campo de edición ha sido cambiado.

//+------------------------------------------------------------------+
//| Poner a cero las variables relacionadas con el desplazamiento de la barra de desplazamiento   |
//+------------------------------------------------------------------+
void CSlider::ZeroThumbVariables(void)
  {
//--- Si hemos entrado aquí, significa que el botón izquierdo del ratón está suelto.
//    Si el botón izquierdo ha sido pulsado sobre el deslizador del slider...
   if(m_clamping_area_mouse==THUMB_PRESSED_INSIDE)
     {
      //--- ... enviamos el mensaje que el cambio del valor en el campo de edición mediante el deslizador ha sido finalizado
      ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
     }
//---
   m_slider_size_fixing  =0;
   m_clamping_area_mouse =THUMB_NOT_PRESSED;
//--- Si el identificador del control coincide con el identificador activador,
    //--- desbloqueamos el formulario y reseteamos el identificador del elemento activo
   if(CElement::Id()==m_wnd.IdActivatedElement())
     {
      m_wnd.IsLocked(false);
      m_wnd.IdActivatedElement(WRONG_VALUE);
     }
  }

En este caso, el código completo del manejador CSlider::OnEvent() será el siguiente:

//+------------------------------------------------------------------+
//| Manejador del evento del gráfico                                       |
//+------------------------------------------------------------------+
void CSlider::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;
       //--- Coordenadas y el estado del botón izquierdo del ratón
      int x=(int)lparam;
      int y=(int)dparam;
      m_mouse_state=(bool)int(sparam);
      //--- Comprobación del foco sobre los controles
      CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2());
      m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() && 
                         y>m_thumb.Y() && y<m_thumb.Y2());
      //--- Salir si el control está bloqueado
      if(!m_slider_state)
         return;
      //--- Comprobamos y recordamos el estado del botón del ratón
      CheckMouseButtonState();
      //--- Cambiamos el color del deslizador
      ChangeThumbColor();
      //--- Si el control se pasa a la banda del slider, determinamos su posición
      if(m_clamping_area_mouse==THUMB_PRESSED_INSIDE)
        {
         //--- Desplazamiento del deslizador del slider
         OnDragThumb(x);
        //--- Cálculo de la posición del deslizador del slider en el rango de valores
         CalculateThumbPos();
         //--- Establecer el valor nuevo en el campo de edición
         ChangeValue(m_current_pos);
        //--- Actualizamos el indicador del slider
         UpdateIndicator();
         return;
        }
     }
//--- Procesamiento del evento del cambio del valor en el campo de edición
   if(id==CHARTEVENT_OBJECT_ENDEDIT)
     {
       //--- Procesamiento de la entrada del valor
      if(OnEndEdit(sparam))
         return;
     }
  }

Todos los métodos para la creación y el manejo del control de la interfaz “Slider” están implementados. Ahora vamos a probarlo en la aplicación MQL que hemos utilizado en el artículo anterior.

 


Prueba del control “Slider”

En el artículo anterior, en la aplicación de prueba hemos creado cuatro casillas de verificación (checkbox) que controlan la disponibilidad de otros controles. Ahora vamos a añadir el control “Slider” y otro (quinto) checkbox para controlar su disponibilidad. Para eso, declaramos las instancias de las clases CCheckBox y CSlider en la clase personalizada CProgram, aí como los métodos con las márgenes desde el punto extremo del formulario al que van a adjuntarse estos controles.

//+------------------------------------------------------------------+
//| Clase para crear la aplicación                                     |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
  //--- Casillas de verificación (checkbox)
   CCheckBox         m_checkbox5;
   //--- Sliders
   CSlider           m_slider1;
   //---
private:
  //--- Casillas de verificación (checkbox)
#define CHECKBOX5_GAP_X       (7)
#define CHECKBOX5_GAP_Y       (200)
   bool              CreateCheckBox5(const string text);
   //--- Sliders
#define SLIDER1_GAP_X         (32)
#define SLIDER1_GAP_Y         (225)
   bool              CreateSlider1(const string text);
  };

El código para la creación de los checkboxs ya ha sido considerado en el artículo anterior, por eso pasaremos directamente al método de la creación del control “Slider” CProgram::CreateSlider1(). Usamos los métodos CSlider::MinValue() y CSlider::MaxValue() para establecer el rango de valores de -1 a 1. Establecemos el paso con la precisión de 8 dígitos (0,00000001). La disponibilidad del control va a depender del estado actual del quinto checkbox

//+------------------------------------------------------------------+
//| Crea el slider 1                                                 |
//+------------------------------------------------------------------+
bool CProgram::CreateSlider1(const string text)
  {
//--- Guardamos el puntero a la ventana
   m_slider1.WindowPointer(m_window1);
//--- Coordenadas
   int x=m_window1.X()+SLIDER1_GAP_X;
   int y=m_window1.Y()+SLIDER1_GAP_Y;
//--- Valor
   double v=(m_slider1.GetValue()==WRONG_VALUE) ? 0.84615385 : m_slider1.GetValue();
//--- Establecemos las propiedades antes de la creación
   m_slider1.XSize(264);
   m_slider1.YSize(40);
   m_slider1.EditXSize(87);
   m_slider1.MaxValue(1);
   m_slider1.StepValue(0.00000001);
   m_slider1.MinValue(-1);
   m_slider1.SetDigits(8);
   m_slider1.SetValue(v);
   m_slider1.AreaColor(clrWhiteSmoke);
   m_slider1.LabelColor(clrBlack);
   m_slider1.LabelColorLocked(clrSilver);
   m_slider1.EditColorLocked(clrWhiteSmoke);
   m_slider1.EditBorderColor(clrSilver);
   m_slider1.EditBorderColorLocked(clrSilver);
   m_slider1.EditTextColorLocked(clrSilver);
   m_slider1.SlotLineDarkColor(clrSilver);
   m_slider1.SlotLineLightColor(clrWhite);
   m_slider1.SlotYSize(4);
   m_slider1.ThumbColorLocked(clrLightGray);
   m_slider1.ThumbColorPressed(clrSilver);
   m_slider1.SlotIndicatorColor(C'85,170,255');
   m_slider1.SlotIndicatorColorLocked(clrLightGray);
//--- Creamos el control
   if(!m_slider1.CreateSlider(m_chart_id,m_subwin,text,x,y))
      return(false);
La disponibilidad va a depender del estado actual del quinto checkbox
   m_slider1.SliderState(m_checkbox5.CheckButtonState());
//--- Añadimos el objeto al array común de los grupos de objetos
   CWndContainer::AddToElementsArray(0,m_slider1);
   return(true);
  }

La llamada a los nuevos métodos de creación de los controles debe realizarse en el método principal de creación de la interfaz gráfica. En el código de abajo se muestra la versión reducida de este método:

//+------------------------------------------------------------------+
//| Crea el panel de trading                                          |
//+------------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Creación del formulario 1 para los controles
//--- Creación de controles:
//    Menú principal
//--- Menús contextuales
//--- Creación de la barra de estado
//--- Checkboxs
   if(!CreateCheckBox5("Checkbox 5"))
      return(false);
//--- Sliders
   if(!CreateSlider1("Slider 1:"))
      return(false);
//--- Redibujar el gráfico
   m_chart.Redraw();
   return(true);
  }

Nosotros vamos a monitorear el cambio del estado del quinto checkbox para el control de la disponibilidad del slider en el manejador de eventos de la aplicación CProgram::OnEvent(). El evento con el identificador personalizado ON_END_EDIT va a indicar cuando se cambia el valor en el campo de edición.

//+------------------------------------------------------------------+
//| Manejador de eventos                                               |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Evento del clic en la etiqueta de texto
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Si el clic ha sido en el quinto checkbox
      if(lparam==m_checkbox5.Id())
        {
        //--- Establecer el estado para el primer slider
         m_slider1.SliderState(m_checkbox5.CheckButtonState());
        }
     }
 //--- Evento del fin de la entrada del valor en el campo de edición
   if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
  }

Ahora se puede compilar el programa y cargarlo en el gráfico. Por favor, intente interactuar con los controles de la interfaz gráfica. Si ha hecho todo bien, en el gráfico aparece el resultado que se muestra a continuación:

 Fig. 2. Prueba del control “Slider”.

Fig. 2. Prueba del control “Slider”. 

 


Control “Slider doble”

El control “Slider doble” se diferencia del slider común en que permite seleccionar el rango de valores dentro del rango establecido por el usuario. Para eso en la banda del slider hay dos deslizadores. El deslizador izquierdo puede desplazarse desde el lado izquierdo de la banda del slider hasta el deslizador derecho. El deslizador derecho, respectivamente, puede desplazarse desde el lado derecho de la banda del slider hasta el deslizador izquierdo. Además. aquí hay dos campos de edición en los que se muestran los valores respecto a las posiciones de los deslizadores en la banda del slider. Usted puede introducir los valores en estos campos manualmente, al mismo tiempo van a cambiarse las posiciones de los deslizadores.

Este control va a componerse de ocho objetos primitivos. Son los siguientes:

  1. Fondo
  2. Título (etiqueta de texto)
  3. Campo de edición izquierdo
  4. Campo de edición derecho
  5. Banda del slider
  6. Deslizador izquierdo del slider
  7. Deslizador dereho del slider
  8. Indicador del slider


Fig. 3. Partes integrantes del control “Slider doble”.


A continuación vamos a ver cómo está organizado el control “Slider doble” y en qué se diferencia del slider habitual.

 


Desarrollo de la clase para la creación del control “Slider doble”

Incluimos el archivo DualSlider.mqh con la clase del control (CDualSlider) en el archivo WndContainer.mqh:

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

En cuanto a las propiedades del control, la clase CDualSlider es la copia absoluta de la clase CSlider. La diferencia consiste en que era necesario implementar los campos y los métodos separados para el campo de edición izquierdo y derecho y para los deslizadores del slider. Los cambios y las deferencias en estos métodos son insignificantes, por eso no vamos a presentar su código aquí. Se puede verlos en los archivos adjuntos al artículo.

class CDualSlider : public CElement
  {
private:
   //--- Valores actuales en los campos de edición (izquierdo y derecho)
   double            m_left_edit_value;
   double            m_right_edit_value;
   //--- Posición actual de los deslizadores del slider (izquierdo y derecho)
   double            m_left_current_pos;
   double            m_left_current_pos_x;
   double            m_right_current_pos;
   double            m_right_current_pos_x;
   //--- Estado del botón del ratón (pulsado/suelto) para los deslizadores del slider (izquierdo y derecho)
   ENUM_THUMB_MOUSE_STATE m_clamping_mouse_left_thumb;
   ENUM_THUMB_MOUSE_STATE m_clamping_mouse_right_thumb;
   //---
public:
   //--- Devolver y establecer el valor en los campos de edición (izquierdo y derecho)
   double            GetLeftValue(void)                       const { return(m_left_edit_value);          }
   double            GetRightValue(void)                      const { return(m_right_edit_value);         }
   bool              SetLeftValue(double value);
   bool              SetRightValue(double value);
   //--- Cambio del valor en los campos de edición (izquierdo y derecho)
   void              ChangeLeftValue(const double value);
   void              ChangeRightValue(const double value);
   //---
private:
   //--- Proceso del desplazamiento del deslizador del slider (izquierdo y derecho)
   void              OnDragLeftThumb(const int x);
   void              OnDragRightThumb(const int x);
   //--- Actualización de la posición del deslizador del slider (izquierdo y derecho)
   void              UpdateLeftThumb(const int new_x_point);
   void              UpdateRightThumb(const int new_x_point);
   //--- Comprueba el estado del botón del ratón sobre el deslizador del slider
   void              CheckMouseOnLeftThumb(void);
   void              CheckMouseOnRightThumb(void);
   //--- Cálculo de la coordenada X del deslizador del slider (izquierdo y derecho)
   void              CalculateLeftThumbX(void);
   void              CalculateRightThumbX(void);
   //--- Cambia la posición del deslizador izquierdo respecto al valor(izquierdo y derecho)
   void              CalculateLeftThumbPos(void);
   void              CalculateRightThumbPos(void);
  };

Vamos a mostrar aquí el código de los métodos donde se consideran sólo dos campos de edición y dos deslizadores del slider. Por ejemplo, el método CDualSlider::OnEndEdit():

class CDualSlider : public CElement
  {
private:
   //--- Procesamiento de la entrada del valor en el campo de edición
   bool              OnEndEdit(const string object_name);
  };
//+------------------------------------------------------------------+
//| Fin de la entrada del valos                                         |
//+------------------------------------------------------------------+
bool CDualSlider::OnEndEdit(const string object_name)
  {
//--- Si el valor se introduce en el campo izquierdo
   if(object_name==m_left_edit.Name())
     {
      //--- Obtenemos el valor recién introducido
      double entered_value=::StringToDouble(m_left_edit.Description());
      //--- Comprobamos, ajustamos y guardamos el valor nuevo
      ChangeLeftValue(entered_value);
       //--- Cálculo de la coordenada X del deslizador
      CalculateLeftThumbX();
       //--- Actualización de la posición del deslizador del slider
      UpdateLeftThumb(m_left_thumb.X());
      //--- Calculamos la posición dentro del rango de valores
      CalculateLeftThumbPos();
      //--- Comprobamos, ajustamos y guardamos el valor nuevo
      ChangeLeftValue(m_left_current_pos);
      //--- Actualizamos el indicador del slider
      UpdateIndicator();
      //--- Enviamos el mensaje sobre ello
      ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
      return(true);
     }
//--- Si el valor se introduce en el campo derecho
   if(object_name==m_right_edit.Name())
     {
      //--- Obtenemos el valor recién introducido
      double entered_value=::StringToDouble(m_right_edit.Description());
      //--- Comprobamos, ajustamos y guardamos el valor nuevo
      ChangeRightValue(entered_value);
       //--- Cálculo de la coordenada X del deslizador
      CalculateRightThumbX();
       //--- Actualización de la posición del deslizador del slider
      UpdateRightThumb(m_right_thumb.X());
      //--- Calculamos la posición dentro del rango de valores
      CalculateRightThumbPos();
      //--- Comprobamos, ajustamos y guardamos el valor nuevo
      ChangeRightValue(m_right_current_pos);
      //--- Actualizamos el indicador del slider
      UpdateIndicator();
      //--- Enviamos el mensaje sobre ello
      ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description());
      return(true);
     }
//---
   return(false);
  }

Lo mismo se refiere al desplazamiento del deslizador izquierdo y derecho. Para cada uno de ellos, en el manejador de eventos CDualSlider::OnEvent() hay sus comprobaciones y bloques del código: 

//+------------------------------------------------------------------+
//| Manejador del evento del gráfico                                       |
//+------------------------------------------------------------------+
void CDualSlider::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;
       //--- Coordenadas y el estado del botón izquierdo del ratón
      int x=(int)lparam;
      int y=(int)dparam;
      m_mouse_state=(bool)int(sparam);
      //--- Comprobación del foco sobre los controles
      CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2());
      m_left_thumb.MouseFocus(x>m_left_thumb.X() && x<m_left_thumb.X2() && 
                              y>m_left_thumb.Y() && y<m_left_thumb.Y2());
      m_right_thumb.MouseFocus(x>m_right_thumb.X() && x<m_right_thumb.X2() && 
                               y>m_right_thumb.Y() && y<m_right_thumb.Y2());
      //--- Salir si el control está bloqueado
      if(!m_slider_state)
         return;
      //--- Comprobamos y recordamos el estado del botón del ratón
      CheckMouseOnLeftThumb();
      CheckMouseOnRightThumb();
      //--- Cambiamos el color del deslizador
      ChangeThumbColor();
      //--- Si el control se pasa a la banda del slider (deslizador izquierdo)
      if(m_clamping_mouse_left_thumb==THUMB_PRESSED_INSIDE)
        {
         //--- Desplazamiento del deslizador del slider
         OnDragLeftThumb(x);
        //--- Cálculo de la posición del deslizador del slider en el rango de valores
         CalculateLeftThumbPos();
         //--- Establecer el valor nuevo en el campo de edición
         ChangeLeftValue(m_left_current_pos);
        //--- Actualizamos el indicador del slider
         UpdateIndicator();
         return;
        }
      //--- Si el control se pasa a la barra de desplazamiento (deslizador derecho)
      if(m_clamping_mouse_right_thumb==THUMB_PRESSED_INSIDE)
        {
         //--- Desplazamiento del deslizador del slider
         OnDragRightThumb(x);
        //--- Cálculo de la posición del deslizador del slider en el rango de valores
         CalculateRightThumbPos();
         //--- Establecer el valor nuevo en el campo de edición
         ChangeRightValue(m_right_current_pos);
        //--- Actualizamos el indicador del slider
         UpdateIndicator();
         return;
        }
     }
  }

Para analizar al detalle el código de la clase CDualSlider, por favor, descargue los archivos adjuntos. 

 


Prueba del control “Slider doble”

Añadimos un control “Slider doble” a la interfaz gráfica de la aplicación de prueba. En la clase personalizada de la aplicación CProgram, hay que declarar la instancia de su clase (CDualSlider) y el método con las márgenes desde el punto extremo del formulario:

//+------------------------------------------------------------------+
//| Clase para crear la aplicación                                     |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
   //--- Sliders
   CDualSlider       m_dual_slider1;
   //---
private:
   //--- Sliders
#define DUALSLIDER1_GAP_X     (32)
#define DUALSLIDER1_GAP_Y     (275)
   bool              CreateDualSlider1(const string text);
  };

Abajo se muestra el código del método CProgram::CreateDualSlider1(). Establecemos el rango de valores de -2000 a 1000. La disponibilidad del control va a depender del estado actual del quinto checkbox, como en el caso del slider simple que ha sido creado en este artículo.

//+------------------------------------------------------------------+
//| Crea el slider doble 1                                         |
//+------------------------------------------------------------------+
bool CProgram::CreateDualSlider1(const string text)
  {
//--- Guardamos el puntero a la ventana
   m_dual_slider1.WindowPointer(m_window1);
//--- Coordenadas
   int x=m_window1.X()+DUALSLIDER1_GAP_X;
   int y=m_window1.Y()+DUALSLIDER1_GAP_Y;
//--- Valores
   double v1=(m_dual_slider1.GetLeftValue()==WRONG_VALUE) ? 0 : m_dual_slider1.GetLeftValue();
   double v2=(m_dual_slider1.GetRightValue()==WRONG_VALUE) ? 500 : m_dual_slider1.GetRightValue();
//--- Establecemos las propiedades antes de la creación
   m_dual_slider1.XSize(264);
   m_dual_slider1.YSize(40);
   m_dual_slider1.EditXSize(87);
   m_dual_slider1.MaxValue(1000);
   m_dual_slider1.StepValue(1);
   m_dual_slider1.MinValue(-2000);
   m_dual_slider1.SetDigits(0);
   m_dual_slider1.SetLeftValue(v1);
   m_dual_slider1.SetRightValue(v2);
   m_dual_slider1.AreaColor(clrWhiteSmoke);
   m_dual_slider1.LabelColor(clrBlack);
   m_dual_slider1.LabelColorLocked(clrSilver);
   m_dual_slider1.EditColorLocked(clrWhiteSmoke);
   m_dual_slider1.EditBorderColor(clrSilver);
   m_dual_slider1.EditBorderColorLocked(clrSilver);
   m_dual_slider1.EditTextColorLocked(clrSilver);
   m_dual_slider1.SlotLineDarkColor(clrSilver);
   m_dual_slider1.SlotLineLightColor(clrWhite);
   m_dual_slider1.SlotYSize(4);
   m_dual_slider1.ThumbColorLocked(clrLightGray);
   m_dual_slider1.ThumbColorPressed(clrSilver);
   m_dual_slider1.SlotIndicatorColor(C'85,170,255');
   m_dual_slider1.SlotIndicatorColorLocked(clrLightGray);
//--- Creamos el control
   if(!m_dual_slider1.CreateSlider(m_chart_id,m_subwin,text,x,y))
      return(false);
La disponibilidad va a depender del estado actual del quinto checkbox
   m_dual_slider1.SliderState(m_checkbox5.CheckButtonState());
//--- Añadimos el objeto al array común de los grupos de objetos
   CWndContainer::AddToElementsArray(0,m_dual_slider1);
   return(true);
  }

No olvidamos colocar la llamada al método del control nuevo en el método principal de la creación de la interfaz gráfica, tal como se muestra en la versión reducida del código de abajo. 

//+------------------------------------------------------------------+
//| Crea el panel de trading                                          |
//+------------------------------------------------------------------+
bool CProgram::CreateTradePanel(void)
  {
//--- Creación del formulario 1 para los controles
//--- Creación de controles:
//    Menú principal
//--- Menús contextuales
//--- Creación de la barra de estado
//--- Checkboxs
//--- Sliders
   if(!CreateDualSlider1("Dual Slider 1:"))
      return(false);
//--- Redibujar el gráfico
   m_chart.Redraw();
   return(true);
  }

Ahora dos controles van a depender del estado actual del quinto checkbox:slider simple y slider doble.

//+------------------------------------------------------------------+
//| Manejador de eventos                                               |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Evento del clic en la etiqueta de texto
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Si el clic ha sido en el quinto checkbox
      if(lparam==m_checkbox5.Id())
        {
        //--- Establecer el estado para los sliders
         m_slider1.SliderState(m_checkbox5.CheckButtonState());
         m_dual_slider1.SliderState(m_checkbox5.CheckButtonState());
        }
     }
 //--- Evento del fin de la entrada del valor en el campo de edición
   if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
     {
      ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
  }

Nos queda compilar el programa y cargarlo en el gráfico. En la captura de pantalla de abajo se puede ver el resultado de nuestro trabajo:

 Fig. 4. Prueba del control “Slider doble”.

Fig. 4. Prueba del control “Slider doble”.

 


Conclusión

En la sexta parte de la serie hemos analizado seis controles:

  • Casilla de verificación (checkbox)
  • Campo de edición
  • Campo de edición con checkbox
  • Lista combinada (combobox) con casilla de verificación (checkbox)
  • Slider
  • Slider doble

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

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

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


En la siguiente (séptima) parte de la serie, vamos a enriquecer nuestra librería con tablas y pestañas.

Más abajo puede descargar el material de la sexta parte de la serie para poder probar cómo funciona todo eso. 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 listados más abajo, o bien hacer su pregunta en los comentarios para el artículo.

Lista de artículos (capítulos) de la sexta parte:


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

Archivos adjuntos |
Experto comercial universal: trabajando con órdenes pendientes y cobertura (parte 5) Experto comercial universal: trabajando con órdenes pendientes y cobertura (parte 5)

Este artículo continúa la presentación a los lectores del motor comercial CStrategy. A petición de multitud de usuarios, se han añadido funciones de trabajo con órdenes pendientes al motor comercial. Asimismo, las últimas versiones de MetaTrader 5 han comenzado a dar soporte a cuentas con cobertura. Ahora CStrategy también da soporte a las mismas. En el artículo se da una descripción detallada de un algoritmo para trabajar con órdenes pendientes, así como de los principios de funcionamiento de CStrategy con las cuentas con cobertura.

Interfaces gráficas VI: Controles "Casilla de verificación", "Campo de edición" y sus tipos combinados (Capítulo 1) Interfaces gráficas VI: Controles "Casilla de verificación", "Campo de edición" y sus tipos combinados (Capítulo 1)

Este artículo empieza la sexta parte de la serie sobre el desarrollo de la librería para la creación de las interfaces gráficas en los terminales MetaTrader. En el primer capítulo hablaremos sobre los siguientes controles: “casilla de verificación”, “campo de edición” y los tipos combinados de estos controles.

Experto comercial universal: Trabajando con trailing-stops personalizados (parte 6) Experto comercial universal: Trabajando con trailing-stops personalizados (parte 6)

La sexta parte del artículo sobre el experto comercial universal describe el funcionamiento de los trailing-stops. Después de leerlo, usted aprenderá cómo usar normas unificadas para crear su propio módulo de trailing-stop y conectarlo al motor comercial de tal forma que el control de la posición realizado por este suceda automáticamente.

Optimización propia de EA: algoritmos genéticos y evolutivos Optimización propia de EA: algoritmos genéticos y evolutivos

Este artículo cubre los principales principios establecidos en los algoritmos evolutivos, su variedad y características. Llevamos a cabo un experimento con un simple Asesor Experto utilizado como ejemplo para mostrar cómo nuestro sistema de trading se beneficia de la optimización. Consideramos los programas de software que implementan genética, evolutivos y de otros tipos de optimización y proporcionar ejemplos de aplicación cuando se optimiza un sistema predictor y los parámetros del sistema de trading.