English Русский 中文 Deutsch 日本語 Português
Interfaces gráficas V: Control "Lista combinada" (Capítulo 3)

Interfaces gráficas V: Control "Lista combinada" (Capítulo 3)

MetaTrader 5Ejemplos | 24 junio 2016, 14:30
969 0
Anatoli Kazharski
Anatoli Kazharski

Índice


 

Introducción

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

En dos primeros capítulos de la quinta parte sobre las interfaces gráficas hemos desarrollado las clases para crear la barra de desplazamiento y la lista. Ahí se mostraba cómo incluir la barra de desplazamiento en un control en el que los datos no caben en el área especificada. En este capítulo vamos a hablar de la clase para la creación del control llamado “Lista combinada”. Éste también es un control compuesto que incluye los controles analizados en dos primeros capítulos de la quinta parte.

 


Control “Lista combinada”

La lista combinada o combobox es un control compuesto cuyas partes principales son (1) el botón y (2) la lista. En este caso, la lista es un control desplegable que se abre con un clic en el botón. Después de la selección de un elemento de la lista, su texto se muestra en el botón, mientras que la lista se cierra. Cuando en un programa hay varios parámetros de diversas opciones, los combobox vendrán muy a propósito, ya que permiten crear una interfaz gráfica compacta.

Abajo se muestran los objetos primitivos para componer el control “Combobox”.

  1. Fondo del control
  2. Etiqueta (descripción del control)
  3. Botón
  4. Indicio de lista desplegable


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


A continuación, vamos a analizar el desarrollo de la clase para la creación de este control.

 

 

Desarrollo de la clase para la creación del control

Analizaremos paso a paso todas las fases del desarrollo del control “Combobox” para poder utilizar luego este artículo como ejemplo de creación de propias clases de este tipo. Primero hay que crear el archivo mqh (ComboBox.mqh) e incluir en él todos los archivos necesarios con las clases que serán necesarias para la creación de la lista combinada. En este caso, serán tres archivos con las siguientes clases:

  • CElement — clase base para la creación del control.
  • CWindow — clase del formulario al que va a adjuntarse el control.
  • CListView — clase de la lista cuya visibilidad va a manejarse por Combobox.
//+------------------------------------------------------------------+
//|                                                     ComboBox.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
#include "ListView.mqh"

Luego, en el archivo ComboBox.mqh hay que crear la clase CComboBox y los métodos estándar para cada control de la librería:

//+------------------------------------------------------------------+
//| Clase para crear la lista combinada                       |
//+------------------------------------------------------------------+
class CComboBox : public CElement
  {
private:
   //--- Puntero al formulario al que está adjuntado el control
   CWindow          *m_wnd;
   //---
public:
                     CComboBox(void);
                    ~CComboBox(void);
   //--- 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 color
   virtual void      ResetColors(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CComboBox::CComboBox(void)
  {
//--- Guardamos el nombre de la clase del control en la clase base
   CElement::ClassName(CLASS_NAME);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CComboBox::~CComboBox(void)
  {
  }

Al usuario hay que darle la posibilidad de configurar su propio esquema de colores de la interfaz gráfica. Para eso hay que proporcionar el acceso a los ajustes de las propiedades de objetos de los se compone el control. Abajo se muestran todas las propiedades que se puede ajustar antes de la creación del control:

  • Color del fondo del control
  • Descripción del Combobox (etiqueta de texto)
  • Márgenes para la etiqueta de texto en los ejes X y Y
  • Colores de las etiquetas de texto en diferentes estados
  • Texto del botón (texto del elemento seleccionado en la lista)
  • Tamaño del botón
  • Colores del botón en diferentes estados
  • Colores del marco del botón en diferentes estados
  • Colores del texto del botón en diferentes estados
  • Imágenes para la flecha como indicio de la lista desplegable para el modo activo y bloqueado
  • Márgenes para las imágenes de la flecha en los ejes X y Y

El código de abajo contiene los campos y los métodos para establecer las propiedades mencionadas:

class CComboBox : public CElement
  {
private:
  //--- Propiedades de Combobox
   //    Color del fondo general
   color             m_area_color;
   //--- Texto y márgenes de la etiqueta de texto
   string            m_label_text;
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- Colores de la etiqueta de texto en diferentes estados
   color             m_label_color;
   color             m_label_color_off;
   color             m_label_color_hover;
   color             m_label_color_array[];
   //--- (1) Texto del botón y (2) sus tamaños
   string            m_button_text;
   int               m_button_x_size;
   int               m_button_y_size;
   //--- Colores del botón en diferentes estados
   color             m_button_color;
   color             m_button_color_off;
   color             m_button_color_hover;
   color             m_button_color_pressed;
   color             m_button_color_array[];
   //--- Colores del marco del botón en diferentes estados
   color             m_button_border_color;
   color             m_button_border_color_off;
   //--- Color del texto del botón en diferentes estados
   color             m_button_text_color;
   color             m_button_text_color_off;
   //--- Márgenes del icono
   int               m_drop_arrow_x_gap;
   int               m_drop_arrow_y_gap;
   //Iconos del botón con el menú desplegable en el estado activo y bloqueado
   string            m_drop_arrow_file_on;
   string            m_drop_arrow_file_off;
   //--- Prioridades para el clic izquierdo del ratón
   int               m_area_zorder;
   int               m_button_zorder;
   int               m_zorder;
   //---
public:
   //--- (1) Color del fondo, (2) establece y (3) devuelve el valor de la etiqueta de texto
   void              AreaColor(const color clr)                       { m_area_color=clr;                                }
   void              LabelText(const string label_text)               { m_label_text=label_text;                         }
   string            LabelText(void)                            const { return(m_label_text);                            }
   //--- Márgenes de la etiqueta de texto
   void              LabelXGap(const int x_gap)                       { m_label_x_gap=x_gap;                             }
   void              LabelYGap(const int y_gap)                       { m_label_y_gap=y_gap;                             }
   //--- (1) Devuelve el texto del botón, (2) establecer los tamaños del botón
   string            ButtonText(void)                           const { return(m_button_text);                           }
   void              ButtonXSize(const int x_size)                    { m_button_x_size=x_size;                          }
   void              ButtonYSize(const int y_size)                    { m_button_y_size=y_size;                          }
   //--- (1) Color del fondo, (2) colores de la etiqueta de texto
   void              LabelColor(const color clr)                      { m_label_color=clr;                               }
   void              LabelColorOff(const color clr)                   { m_label_color_off=clr;                           }
   void              LabelColorHover(const color clr)                 { m_label_color_hover=clr;                         }
   //--- Colores del botón
   void              ButtonBackColor(const color clr)                 { m_button_color=clr;                              }
   void              ButtonBackColorOff(const color clr)              { m_button_color_off=clr;                          }
   void              ButtonBackColorHover(const color clr)            { m_button_color_hover=clr;                        }
   void              ButtonBackColorPressed(const color clr)          { m_button_color_pressed=clr;                      }
   //--- Colores del marco del botón
   void              ButtonBorderColor(const color clr)               { m_button_border_color=clr;                       }
   void              ButtonBorderColorOff(const color clr)            { m_button_border_color_off=clr;                   }
   //--- Colores del texto del botón
   void              ButtonTextColor(const color clr)                 { m_button_text_color=clr;                         }
   void              ButtonTextColorOff(const color clr)              { m_button_text_color_off=clr;                     }
   //--- Establecer los iconos para el botón con el menú desplegable en el estado activo y bloqueado
   void              DropArrowFileOn(const string file_path)          { m_drop_arrow_file_on=file_path;                  }
   void              DropArrowFileOff(const string file_path)         { m_drop_arrow_file_off=file_path;                 }
   //--- Márgenes del icono
   void              DropArrowXGap(const int x_gap)                   { m_drop_arrow_x_gap=x_gap;                        }
   void              DropArrowYGap(const int y_gap)                   { m_drop_arrow_y_gap=y_gap;                        }
  };

Los valores predefinidos de las propiedades mencionadas se inicializan en el constructor de la clase: 

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CComboBox::CComboBox(void) : m_area_color(C'15,15,15'),
                             m_label_text("combobox: "),
                             m_label_x_gap(0),
                             m_label_y_gap(2),
                             m_label_color(clrWhite),
                             m_label_color_off(clrGray),
                             m_label_color_hover(C'85,170,255'),
                             m_button_text(""),
                             m_button_y_size(18),
                             m_button_text_color(clrBlack),
                             m_button_text_color_off(clrDarkGray),
                             m_button_color(clrGainsboro),
                             m_button_color_off(clrLightGray),
                             m_button_color_hover(C'193,218,255'),
                             m_button_color_pressed(C'153,178,215'),
                             m_button_border_color(clrWhite),
                             m_button_border_color_off(clrWhite),
                             m_drop_arrow_x_gap(16),
                             m_drop_arrow_y_gap(1),
                             m_drop_arrow_file_on(""),
                             m_drop_arrow_file_off("")
  {
//--- Establecemos las prioridades para el clic izquierdo del ratón
   m_zorder        =0;
   m_area_zorder   =1;
   m_button_zorder =2;
  }

El combobox se crea a través de cinco métodos privados que van a llamarse en en el método público principal CComboBox::CreateComboBox(). Para acceder a los ajustes de las propiedades de la lista y su barra de desplazamiento, vamos a crear los métodos para obtener los punteros a estos controles: 

class CComboBox : public CElement
  {
private:
   //--- Objetos para crear el combobox
   CRectLabel        m_area;
   CLabel            m_label;
   CEdit             m_button;
   CBmpLabel         m_drop_arrow;
   CListView         m_listview;
   //---
public:
   //--- Métodos para crear el combobox
   bool              CreateComboBox(const long chart_id,const int subwin,const int x,const int y);
   //---
private:
   bool              CreateArea(void);
   bool              CreateLabel(void);
   bool              CreateButton(void);
   bool              CreateDropArrow(void);
   bool              CreateList(void);
   //---
public:
   //--- Devuelve los punteros a (1) la lista y a (2) la barra de desplazamiento
   CListView        *GetListViewPointer(void)                         { return(::GetPointer(m_listview));                }
   CScrollV         *GetScrollVPointer(void)                          { return(m_listview.GetScrollVPointer());          }
  };

De los métodos que figuran en el código de arriba, hablaremos más detalladamente sólo del método para la creación de la lista CComboBox::CreateList(). Los demás no tienen nada en particular de lo que no hemos hablado antes en los artículos anteriores de esta parte. Pero antes eso, hay que introducir algunas adiciones en la clase CListView

Cuando una lista es desplegable, eso significa que forma parte de otro control, y en su manejador de eventos puede surgir la necesidad de realizar el seguimiento del foco sobre este control al que está adjuntado. En este caso, se trata del Combobox. Añadimos el campo y el método a la clase CListView para guardar el puntero al combobox al que va a adjuntarse la lista. 

class CListView : public CElement
  {
private:
   //--- Puntero al control que gestiona la visibilidad de la lista
   CElement         *m_combobox;
   //---
public:
   //--- Guarda el puntero al combobox
   void              ComboBoxPointer(CElement &object)                   { m_combobox=::GetPointer(object); }
  };

Si la lista es desplegable, en el método principal (público) de la creación de la lista, agregamos la comprobación de la presencia del puntero. Si durante la creación de la lista resulta que no hay puntero, la creación de la interfaz gráfica será interrumpida, y en el registro aparecerá el mensaje correspondiente.

Abajo se muestra la versión reducida del método CListView::CreateListView(): 

//+------------------------------------------------------------------+
//| Crea la lista                                                  |
//+------------------------------------------------------------------+
bool CListView::CreateListView(const long chart_id,const int window,const int x,const int y)
  {
//--- Salir si no hay puntero al formulario

//--- Si la lista es desplegable, significa que hace falta un puntero al combobox al que será adjuntado
   if(CElement::IsDropdown())
     {
      //--- Salir si no hay puntero al combobox
      if(::CheckPointer(m_combobox)==POINTER_INVALID)
        {
      ::  Print(__FUNCTION__," > Antes de crear la lista desplegable, hay que pasar a la clase "
                 "puntero al combobox: CListView::ComboBoxPointer(CElement &object)");
         return(false);
        }
     }
//--- Inicialización de variables
//--- Márgenes desde el punto extremo
//--- Crear el botón
//--- Ocultar el elemento si es la ventana de diálogo o está minimizada
//---
   return(true);
  }

Ahora volveremos al desarrollo de la clase de la lista combinada (CComboBox). La propiedad que indica que la lista va a ser desplegable tiene que establecerse en la fase inicial, o sea en el constructor de la clase: 

CComboBox::CComboBox(void)
  {
//--- Modo de la lista desplegable
   m_listview.IsDropdown(true);
  }

Durante la creación de la lista, en el principio del método hay que guardar los punteros al formulario y al combobox a los que va a adjuntarse la lista. No olvidemos que el identificador de la lista y del combobox tiene que ser común, porque en este caso es el mismo control. Hya que ocultar la lista después de su creación. 

//+------------------------------------------------------------------+
//| Crea la lista                                                  |
//+------------------------------------------------------------------+
bool CComboBox::CreateList(void)
  {
//--- Guardamos los punteros al formulario y al combobox
   m_listview.WindowPointer(m_wnd);
   m_listview.ComboBoxPointer(this);
//--- Coordenadas
   int x=CElement::X2()-m_button_x_size;
   int y=CElement::Y()+m_button_y_size;
//--- Establecemos las propiedades
   m_listview.Id(CElement::Id());
   m_listview.XSize(m_button_x_size);
//--- Creamos el control
   if(!m_listview.CreateListView(m_chart_id,m_subwin,x,y))
      return(false);
//--- Ocultar lista
   m_listview.Hide();
   return(true);
  }

Para establecer el número de elementos en la lista y llenarla con valores, vamos a añadir los métodos correspondientes a la clase CComboBox :

class CListView : public CElement
  {
public:
   //--- Establecer (1) el tamaño de la lista (número de elementos) y (2) de su parte visible
   void              ItemsTotal(const int items_total)                { m_listview.ListSize(items_total);                }
   void              VisibleItemsTotal(const int visible_items_total) { m_listview.VisibleListSize(visible_items_total); }
   
   //--- Guarda el valor devuelto en la lista según el índice especificado
   void              ValueToList(const int item_index,const string item_text);
  };
//+------------------------------------------------------------------+
//| Guarda el valor devuelto en la lista según el índice especificado     |
//+------------------------------------------------------------------+
void CComboBox::ValueToList(const int item_index,const string item_text)
  {
   m_listview.ValueToList(item_index,item_text);
  }

Para seleccionar (resaltar) un elemento en la lista, vamos a crear el método CComboBox::SelectedItemByIndex(). El índice del elemento a seleccionar es el único argumento que tiene que ser pasado en este método. Luego, el resalto del elemento se hace en el método homónimo de la lista (CListView), en el que el índice se ajusta si el diapasón se excede. Después de eso, el texto del elemento se guarda y se inserta en el botón del combobox. 

class CListView : public CElement
  {
public:
   //--- Resaltar el elemento según el índice especificado
   void              SelectedItemByIndex(const int index);
  };
//+------------------------------------------------------------------+
//| Resaltar el elemento según el índice especificado                           |
//+------------------------------------------------------------------+
void CComboBox::SelectedItemByIndex(const int index)
  {
//--- Seleccionar el elemento de la lista
   m_listview.SelectedItemByIndex(index);
//--- Guardar e insertar el texto en el botón
   m_button_text=m_listview.SelectedItemText();
   m_button.Description(m_listview.SelectedItemText());
  }

Vamos a necesitar un método para bloquear y desbloquear el control, así como para obtener su estado actual. Dependiendo del nuevo estado del control, sus objetos reciben el color correspondiente a este estado. Más tarde mostraremos estos ejemplos. 

class CListView : public CElement
  {
public:
   //--- Obtener y establecer el estado del control
   bool              ComboBoxState(void)                        const { return(m_combobox_state);                        }
   void              ComboBoxState(const bool state);
  };
//+------------------------------------------------------------------+
//| Cambio del estado del combobox                                   |
//+------------------------------------------------------------------+
void CComboBox::ComboBoxState(const bool state)
  {
   m_combobox_state=state;
//--- Establecer los colores para los objetos de acuerdo con el estado actual
   m_label.Color((state)? m_label_color : m_label_color_off);
   m_button.Color((state)? m_button_text_color : m_button_text_color_off);
   m_button.BackColor((state)? m_button_color : m_button_color_off);
   m_button.BorderColor((state)? m_button_border_color : m_button_border_color_off);
   m_drop_arrow.State(state);
  }

Cuando el cursor se sitúa sobre los objetos del control, el cambio de sus colores, usando el método CComboBox::ChangeObjectsColor(), va a realizarse sólo cuando el control está disponible

class CListView : public CElement
  {
public:
   //--- Cambio del color del objeto al situar el cursor sobre él
   void              ChangeObjectsColor(void);
  };
//+------------------------------------------------------------------+
//| Cambio del color del objeto al situar el cursor sobre él                    |
//+------------------------------------------------------------------+
void CComboBox::ChangeObjectsColor(void)
  {
//--- Salir si el control está bloqueado
   if(!m_combobox_state)
      return;
//--- Cambiamos el color de los objetos
   CElement::ChangeObjectColor(m_label.Name(),CElement::MouseFocus(),OBJPROP_COLOR,m_label_color,m_label_color_hover,m_label_color_array);
   CElement::ChangeObjectColor(m_button.Name(),CElement::MouseFocus(),OBJPROP_BGCOLOR,m_button_color,m_button_color_hover,m_button_color_array);
  }

La llamada al método CComboBox::ChangeObjectsColor() debe realizarse en el temporizador del control CComboBox::OnEventTimer(). Adelantándome un poco, quiero mencionar que un Combobox puede formar parte de un control más complicado y desplegable al mismo tiempo. En uno de los siguientes artículos, de ejemplo va a servir el “Calendario desplegable” que va a incluir el Combobox. Por eso, las condiciones para el cambio del color en el temporizador para este control van a formarse de la siguiente manera (véase el código de abajo):

  1. Si el control es desplegable y la lista está oculta.
  2. Si la primera condición no se cumple, comprobamos la disponibilidad del formulario y del propio control. 
//+------------------------------------------------------------------+
//| Temporizador                                                           |
//+------------------------------------------------------------------+
void CComboBox::OnEventTimer(void)
  {
//--- Si el control es desplegable y la lista está oculta
   if(CElement::IsDropdown() && !m_listview.IsVisible())
      ChangeObjectsColor();
   else
     {
      //--- Si el formulario y el control no están bloqueados
      if(!m_wnd.IsLocked() && m_combobox_state)
         ChangeObjectsColor();
     }
  }

Para manejar la visibilidad de la lista del combobox, vamos a crear el método CComboBox::ChangeComboboxListState(). Este método va a cambiar el estado actual del combobox por el contrario. En su principio va a estar la comprobación de la disponibilidad del control. Si el combobox está bloqueado, el programa saldrá del método. Luego, el código se divide en dos ramas:

  1. En caso si la lista ya se encuentra visible, pues aquí será ocultada, y para el botón de combobox se establecerán los colores correspondientes. Después de eso, si el control no es desplegable hay que desbloquear el formulario y resetear el identificador del control activo. 
  2. Si la lista está oculta, hay que mostrarla y establecer el color correspondiente a este estado para el botón del combobox. Al final de la rama hay que bloquear el formulario y guardar el identificador del control activador. 
class CListView : public CElement
  {
public:
   //--- Cambia el estado actual del combobox por el contrario
   void              ChangeComboBoxListState(void);
  };
//+------------------------------------------------------------------+
//| Cambia el estado actual del combobox por el contrario        |
//+------------------------------------------------------------------+
void CComboBox::ChangeComboBoxListState(void)
  {
//--- Salir si el control está bloqueado
   if(!m_combobox_state)
      return;
//--- Si la lista está visible
   if(m_listview.IsVisible())
     {
      //--- Ocultar lista
      m_listview.Hide();
       //--- Establecer los colores
      m_label.Color(m_label_color_hover);
      m_button.BackColor(m_button_color_hover);
      //--- Si el control no es desplegable
      if(!CElement::IsDropdown())
        {
        //--- Desbloquear el formulario
         m_wnd.IsLocked(false);
         m_wnd.IdActivatedElement(WRONG_VALUE);
        }
     }
//--- Si la lista está oculta
   else
     {
      //--- Mostrar la lista
      m_listview.Show();
       //--- Establecer los colores
      m_label.Color(m_label_color_hover);
      m_button.BackColor(m_button_color_pressed);
      //--- Bloquear el formulario
      m_wnd.IsLocked(true);
      m_wnd.IdActivatedElement(CElement::Id());
     }
  }


 


Métodos para procesar los eventos del control

Ahora podemos pasar a la configuración del manejador de eventos del control CComboBox::OnEvent(). Aquí vamos a necesitar dos métodos privados (private) adicionales:

  • CComboBox::OnClickButton() – en este método va a realizar el seguimiento del clic en el botón del combobox.
  • CComboBox::CheckPressedOverButton() – va a realizar aquí el seguimiento del estado del botón izquierdo sobre el botón del combobox.
class CListView : public CElement
  {
private:
   //--- Procesamiento del clic en el botón
   bool              OnClickButton(const string clicked_object);
   //--- Comprobando si el botón izquierdo del ratón está pulsado sobre el botón del combobox
   void              CheckPressedOverButton(void);
  };

El código del método CComboBox::OnClickButton() es muy simple. Va contener sólo la comprobación del nombre del objeto que ha sido pulsado, y la llamada al método CComboBox::ChangeComboBoxListState() discutido anteriormente que debe encargarse de la visibilidad de la lista del combobox (véase el código de abajo). 

//+------------------------------------------------------------------+
//| Clic en el botón del combobox                                    |
//+------------------------------------------------------------------+
bool CComboBox::OnClickButton(const string clicked_object)
  {
//--- Salimos si el nombre del objeto no coincide  
   if(clicked_object!=m_button.Name())
      return(false);
//--- Cambiar el estado de la lista
   ChangeComboboxListState();
   return(true);
  }

Abajo se muestra el código del método CComboBox::CheckPressedOverButton(). En el principio del método se comprueban los formularios disponibles y el identificador del control activador. El programa sale del método si el formulario está bloqueado y los identificadores no coinciden. 

Luego, si no hay foco sobre del control, comprobamos si ha foco sobre la lista, y el estado actual de la barra de desplazamiento. Si resulta que el foco está fuera de la lista o la barra de desplazamiento se encuentra en modo de desplazamiento del deslizador, el programa sale del método. Recordamos que después de que el deslizador haya sido pasado en el modo de desplazamiento, se puede desplazarlo incluso si el cursor sale fuera de los límites del deslizador. Si no se ha cumplido ninguna de estas condiciones, entonces:

(1) la lista se oculta.

(2) se recuperan los colores de los objetos del control,

y al final de este bloque del código, si los identificadores coinciden y el control no es desplegable, (3) hay que desbloquear el formulario. Recordaré que el formulario puede desbloquearse sólo por el control que lo ha bloqueado.

En caso cuando sobre el control hay foco, primero se realiza la comprobación de la visibilidad de la lista. Si la lista está visible, no hay sentido de continuar y el programa sale del método. Si la lista está oculta, entonces se establecen los colores correspondientes dependiendo del foco sobre el botón del combobox. 

//+------------------------------------------------------------------+
//| Comprobando si el botón izquierdo del ratón está pulsado sobre el botón                   |
//+------------------------------------------------------------------+
void CComboBox::CheckPressedOverButton(void)
  {
//--- Salir si el formulario está bloqueado y los identificadores no coinciden
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return;
//--- Si no hay foco
   if(!CElement::MouseFocus())
     {
      //--- Salir si el foco no está sobre la lista o la barra de desplazamiento está activada
      if(m_listview.MouseFocus() || m_listview.ScrollState())
         return;
      //--- Ocultar lista
      m_listview.Hide();
       //--- Recuperar los colores
      ResetColors();
      //--- Si los identificadores coinciden y el control no es desplegable
      if(m_wnd.IdActivatedElement()==CElement::Id() && !CElement::IsDropdown())
        //--- Desbloquear el formulario
         m_wnd.IsLocked(false);
     }
//--- Si hay foco
   else
     {
      //--- Salir si la lista está visible
      if(m_listview.IsVisible())
         return;
      //--- Establecer el color en función del foco
      if(m_button.MouseFocus())
         m_button.BackColor(m_button_color_pressed);
      else
         m_button.BackColor(m_button_color_hover);
     }
  }

La llamada al método CComboBox::OnClickButton() debe ubicarse en el bloque de procesamiento del evento del clic en el objeto gráfico, que puede ser identificado por el identificador CHARTEVENT_OBJECT_CLICK

//+------------------------------------------------------------------+
//| Manejador de eventos                                               |
//+------------------------------------------------------------------+
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Procesamiento del evento del clic izquierdo en el objeto
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Clic en el botón del combobox
      if(OnClickButton(sparam))
         return;
     }
  }

En el bloque del procesamiento del evento del desplazamiento del cursor (CHARTEVENT_MOUSE_MOVE) antes de llamar al método CComboBox::CheckPressedOverButton() hay que comprobar:

  • visibilidad del control;
  • disponibilidad del control;
  • estado del botón izquierdo del ratón. 
//+------------------------------------------------------------------+
//| Manejador de eventos                                               |
//+------------------------------------------------------------------+
void CComboBox::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
      int  x=(int)lparam;
      int  y=(int)dparam;
      //--- Comprobación del foco sobre los controles
      CElement::MouseFocus(x>CElement::X() && x<CElement::X2() && 
                           y>CElement::Y() && y<CElement::Y2());
      m_button.MouseFocus(x>m_button.X() && x<m_button.X2() && 
                          y>m_button.Y() && y<m_button.Y2());
      //--- Salir si el control está bloqueado
      if(!m_combobox_state)
         return;
      //--- Salir si el botón izquierdo del ratón está suelto
      if(sparam=="0")
         return;
       //--- Comprobación del botón izquierdo del ratón pulsado sobre el botón de división
      CheckPressedOverButton();
      return;
     }
  }

En el momento cuando se pulsa uno de los elementos de la lista, se genera el evento de usuario ON_CLICK_LIST_ITEM (véase el código de abajo). Hay que recibir este mensaje en el manejador de eventos del combobox, y si los identificadores de los controles coinciden (es decir el mensaje ha llegado de la lista adjunta a este combobox), entonces guardamos el texto del elemento seleccionado de la lista en el botón, y ocultamos la lista usando el método CComboBox::ChangeComboBoxListState().

Para asegurar la conexión con la aplicación desarrollada, este mensaje con el identificador ON_CLICK_LIST_ITEM se puede recibir en la clase de personalizada CProgram. Pero también se puede enviar el mensaje desde el combobox con el (1) el identificador del evento único para él, (2) identificador del control y (3) descripción del combobox. Para ampliar las posibilidades de identificación de eventos de los controles, vamos a usar esta opción también. Vamos a añadir el identificador único para el control “Lista combinada” al archivo Defines.mqh.

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#define ON_CLICK_COMBOBOX_ITEM    (17) // Selección del elemento en la lista del combobox

En este caso, en el manejador de eventos del control hay que añadir la línea marcada con el color azul en el código de abajo: 

//+------------------------------------------------------------------+
//| Manejador de eventos                                               |
//+------------------------------------------------------------------+
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Procesamiento del evento del clic en un elemento de la lista
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
     {
      //--- Si los identificadores coinciden
      if(lparam==CElement::Id())
        {
        //--- Guardar e insertar el texto en el botón
         m_button_text=m_listview.SelectedItemText();
         m_button.Description(m_listview.SelectedItemText());
         //--- Cambiar el estado de la lista
         ChangeComboBoxListState();
         //--- Enviamos el mensaje sobre ello
         ::EventChartCustom(m_chart_id,ON_CLICK_COMBOBOX_ITEM,CElement::Id(),0,m_label_text);
        }
      //---
      return;
     }
  }

Además, se puede configurar la ocultación de la lista cuando se cambian las propiedades del gráfico. Para eso hay que procesar el evento con el manejador CHARTEVENT_CHART_CHANGE (véase el código de abajo): 

//+------------------------------------------------------------------+
//| Manejador de eventos                                               |
//+------------------------------------------------------------------+
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Procesamiento del evento del cambio de propiedades del gráfico
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- Salir si el control está bloqueado
      if(!m_combobox_state)
         return;
      //--- Ocultar la lista
      m_listview.Hide();
       //--- Recuperar los colores
      ResetColors();
      //--- Desbloquear el formulario
      m_wnd.IsLocked(false);
      m_wnd.IdActivatedElement(WRONG_VALUE);
      return;
     }
  }

La clase para la creación del control “Lista combinada” ya está lista para las pruebas. Pero antes de eso, es necesario conectarla con el motor de la librería para que funcione correctamente. 

 

 


Conexión de la clase del control con el motor de librería

Para conectar el control con el motor de la librería, es necesario realizar unos cuantos simples pasos:

1.Incluir el archivo con la clase del control en el archivo raíz de la librería WndContainer.mqh.

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

2.Si es necesario, crear el array privado para el control y el método para obtener el tamaño de este array. En este caso, el array privado será necesario para las listas desplegables. 

class CWndContainer
  {
protected:
   //--- Estructura de los arrays de controles
   struct WindowElements
     {
      //--- Array común de todos los objetos
      //--- Array común de todos los controles

      //--- Arrays personales de controles:
      //    Array de los menús contextuales
      //Array de los menús principales
      //--- Descripciones emergentes
      //--- Array de las listas desplegables de diferentes tipos
      CElement         *m_drop_lists[];
     };
   //--- Array de los arrays de los controles para cada ventana
   WindowElements    m_wnd[];
   //---
public:
  //--- Número de listas desplegables 
   int               DropListsTotal(const int window_index);
  };
//+------------------------------------------------------------------+
//| Devuelve el número de listas desplegables según el índice especificado de la ventana  |
//+------------------------------------------------------------------+
int CWndContainer::DropListsTotal(const int window_index)
  {
   if(window_index>=::ArraySize(m_wnd))
     {
      ::Print(PREVENTING_OUT_OF_RANGE);
      return(WRONG_VALUE);
     }
//---
   return(::ArraySize(m_wnd[window_index].m_drop_lists));
  }

3.Crear el método privado para añadir los punteros al array privado. En este caso, hay que obtener el puntero a la lista desde el combobox y añadirlo al array privado. Además de eso, hay que añadir los punteros a los objetos de la lista y las barras de desplazamiento de esta lista al array común de los objetos. Para más detalles véase el código del método CWndContainer::AddComboBoxElements() en el código de abajo. 

class CWndContainer
  {
private:
  //--- Guarda los punteros a los controles del menú contextual en la base
  //--- Guarda los punteros a los controles del menú principal en la base
  //--- Guarda los punteros a los elementos del botón de división en la base
  //--- Guarda los punteros a los elementos de las descripciones emergentes en la base
  //--- Guarda los punteros a los objetos de la lista en la base

  //--- Guarda los punteros a los elementos de las listas desplegables en la base
   bool              AddComboBoxElements(const int window_index,CElement &object);
  };
//+------------------------------------------------------------------+
//| Guarda el puntero a la lista desplegable en el array privado   |
//+------------------------------------------------------------------+
bool CWndContainer::AddComboBoxElements(const int window_index,CElement &object)
  {
//--- Salimos si no es una descripción emergente
   if(object.ClassName()!="CComboBox")
      return(false);
//--- Obtenemos el puntero al combobox
   CComboBox *cb=::GetPointer(object);
//---
   for(int i=0; i<2; i++)
     {
       //--- Aumentar el array de controles
      int size=::ArraySize(m_wnd[window_index].m_elements);
      ::ArrayResize(m_wnd[window_index].m_elements,size+1);
      //--- Añadimos la lista a la base
      if(i==0)
        {
         CListView *lv=cb.GetListViewPointer();
         m_wnd[window_index].m_elements[size]=lv;
         AddToObjectsArray(window_index,lv);
         //--- Añadimos el puntero al array privado
         AddToRefArray(lv,m_wnd[window_index].m_drop_lists);
        }
      //--- Añadimos la barra de desplazamiento a la base
      else if(i==1)
        {
         CScrollV *sv=cb.GetScrollVPointer();
         m_wnd[window_index].m_elements[size]=sv;
         AddToObjectsArray(window_index,sv);
        }
     }
//---
   return(true);
  }

4.Y finalmente, si las acciones del tercer punto eran necesarias, no olviden llamar al método CWndContainer::AddComboBoxElements() en el método principal CWndContainer::AddToElementsArray(), donde tienen que ubicarse las llamadas a estos métodos.

//+------------------------------------------------------------------+
//| Añade el puntero al array de controles                           | 
//+------------------------------------------------------------------+
void CWndContainer::AddToElementsArray(const int window_index,CElement &object)
  {
//--- Si en la base no hay formularios para los controles
//--- Si se solicita el formulario que no existe
//--- Añadimos al array común de controles
//--- Añadir los objetos del control al array común de objetos
//--- Recordamos id del último control en todos los formularios
//--- Aumentamos el contador de los identificadores de controles

//--- Guarda los punteros a los objetos del menú contextual en la base
//--- Guarda los punteros a los objetos del menú principal en la base
//--- Guarda los punteros a los objetos del botón de división en la base
//--- Guarda los punteros a los objetos de las descripciones emergentes en la base
//--- Guarda los punteros a los objetos de la lista en la base

//--- Guarda los punteros a los objetos del combobox en la base
   if(AddComboBoxElements(window_index,object))
      return;
  }

Cuando el control es desplegable, durante su uso pueden surgir las situaciones (depende de la posición de este control en el formulario) cuando su área sale fuera los límites del formulario. Para evitar el desplazamiento del gráfico cuando el botón izquierdo del ratón se pulsa sobre el control desplegable, siempre hay que controlar la posición del cursor y desactivar el desplazamiento del gráfico si éste se encuentra sobre uno de estos controles. Para estos propósitos ya hemos escrito el método CWndEvents::SetChartState() en la clase CWndEvents. Ahora hay que completarlo con la comprobación de las listas desplegables. Esta parte está marcada con color amarillo en el código de abajo: 

//+------------------------------------------------------------------+
//| Establece el estado del gráfico                                  |
//+------------------------------------------------------------------+
void CWndEvents::SetChartState(void)
  {
   int awi=m_active_window_index;
//--- Para determinar el estado cuando hay que desactivar la gestión
   bool condition=false;
//--- Comprobamos las ventanas
   int windows_total=CWndContainer::WindowsTotal();
   for(int i=0; i<windows_total; i++)
     {
      //--- Ir al siguiente si este formulario está ocultado
      if(!m_windows[i].IsVisible())
         continue;
      //--- Comprobar condiciones en el manejador interno del formulario
      m_windows[i].OnEvent(m_id,m_lparam,m_dparam,m_sparam);
      //--- Si hay foco, lo anotamos
      if(m_windows[i].MouseFocus())
        {
         condition=true;
         break;
        }
     }
//--- Comprobamos listas desplegables
   if(!condition)
     {
      //--- Obtenemos el número total de listas desplegables 
      int drop_lists_total=CWndContainer::DropListsTotal(awi);
      for(int i=0; i<drop_lists_total; i++)
        {
        //--- Obtenemos el puntero al combobox
         CListView *lv=m_wnd[awi].m_drop_lists[i];
         //--- Si la lista está activada (abierta)
         if(lv.IsVisible())
           {
            //--- Comprobamos el foco sobre la lista y el estado de su barra de desplazamiento
            if(m_wnd[awi].m_drop_lists[i].MouseFocus() || lv.ScrollState())
              {
               condition=true;
               break;
              }
           }
        }
     }
//--- Comprobamos el foco de los menús contextuales
   if(!condition)
     {
      //--- Obtenemos el número total de los menús contextuales desplegables
      int context_menus_total=CWndContainer::ContextMenusTotal(awi);
      for(int i=0; i<context_menus_total; i++)
        {
         //--- Si el foco está sobre el menú contextual
         if(m_wnd[awi].m_context_menus[i].MouseFocus())
           {
            condition=true;
            break;
           }
        }
     }
//--- Establecemos el estado del gráfico en todos los formularios
   for(int i=0; i<windows_total; i++)
      m_windows[i].CustomEventChartState(condition);
  }

Todo está listo para probar el control “Lista combinada”.

 

 

Prueba del control en la interfaz gráfica de la aplicación

Vamos a testear todo lo que hemos implementado en la quinta parte de la serie en la interfaz gráfica de la aplicación. En el artículo anterior, la prueba se ha terminado con tres listas. Vamos a dejarlas, y añadimos cuatro listas combinadas (Combobox) a la interfaz gráfica de la aplicación. Colocaremos dos listas combinadas de tal manera que se pueda probar una posible influencia de las listas desplegables sobre las listas estáticas, que van a encontrarse debajo de ellas. Además de eso, hay que probar cómo trabaja el método CWndEvents::SetChartState(). Por esa razón, colocaremos otros dos combobox de tal manera que, al abrir las listas desplegables, sus áreas salgan de los límites del formulario al que están adjuntadas.

En la clase personalizada (CProgram) de la aplicación de prueba, la clase de la lista combinada ya está disponible a través de las clases base. Creamos cuatro instancias de la clase tipo CComboBox y declaramos cuatro métodos para cada una de ella, indicando las márgenes desde el punto superior izquierdo del formulario (véase el código de abajo).

//+------------------------------------------------------------------+
//| Clase para crear la aplicación                                     |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
  //--- Combobox
   CComboBox         m_combobox1;
   CComboBox         m_combobox2;
   CComboBox         m_combobox3;
   CComboBox         m_combobox4;
   //---
private:
   //--- Combobox 1
#define COMBOBOX1_GAP_X       (7)
#define COMBOBOX1_GAP_Y       (50)
   bool              CreateComboBox1(const string text);
   //--- Combobox 2
#define COMBOBOX2_GAP_X       (160)
#define COMBOBOX2_GAP_Y       (50)
   bool              CreateComboBox2(const string text);
   //--- Combobox 3
#define COMBOBOX3_GAP_X       (7)
#define COMBOBOX3_GAP_Y       (202)
   bool              CreateComboBox3(const string text);
   //--- Combobox 4
#define COMBOBOX4_GAP_X       (160)
#define COMBOBOX4_GAP_Y       (202)
   bool              CreateComboBox4(const string text);
  };

Nosotros vamos a considerar sólo uno de estos métodos, porque se puede decir que son casi idénticos, a excepción de algunas propiedades ajustables. Por ejemplo, vamos a bloquear el cuarto combobox después de su creación. Abajo mostramos la secuencia de acciones principales para crear el control “Combobox”.

  • Guardamos el puntero al formulario en la clase del control.
  • Calculamos las coordenadas.
  • Declaramos e inicializamos inmediatamente el array del texto para los elementos de la lista.
  • Establecemos las propiedades del control. La mayoría de ellas están inicializadas con valores predefinidos. Pero si hace falta, se puede cambiarlos antes de la creación del control.
  • Guardamos los valores de los elementos en la lista combobox.
  • Si es necesario, establecemos las propiedades para la lista y la barra de desplazamiento.
  • Seleccionar un elemento de la lista. Por defecto, queda seleccionado el primer (0) elemento.
  • Creamos el control.
  • Si es necesario, se puede bloquear el control. Como ejemplo, bloqueamos el cuarto combobox en nuestra aplicación de prueba.
  • Al final de todo, hay que pasar el objeto a la clase base para guardar el puntero.

La secuencia de acciones puede ser diferente. Lo importante es mantener la secuencia de sólo tres acciones principales:

  1. Añadir el puntero del formulario a la clase del control. De lo contrario, la creación de la interfaz gráfica será interrumpida. La razón del fallo se puede encontrar en los mensajes del registro.
  2. Creación del control.
  3. Guardamos el puntero del control en la base de objetos.
//+------------------------------------------------------------------+
//| Crea el combobox 1                                             |
//+------------------------------------------------------------------+
bool CProgram::CreateComboBox1(const string text)
  {
//--- Número total de los elementos en la lista
#define ITEMS_TOTAL1 8
//--- Pasar el objeto del formulario
   m_combobox1.WindowPointer(m_window1);
//--- Coordenadas
   int x=m_window1.X()+COMBOBOX1_GAP_X;
   int y=m_window1.Y()+COMBOBOX1_GAP_Y;
//--- Array de valores de elementos en la lista
   string items_text[ITEMS_TOTAL1]={"FALSE","item 1","item 2","item 3","item 4","item 5","item 6","item 7"};
//--- Establecemos las propiedades antes de la creación
   m_combobox1.XSize(140);
   m_combobox1.YSize(18);
   m_combobox1.LabelText(text);
   m_combobox1.ButtonXSize(70);
   m_combobox1.AreaColor(clrWhiteSmoke);
   m_combobox1.LabelColor(clrBlack);
   m_combobox1.LabelColorHover(clrCornflowerBlue);
   m_combobox1.ButtonBackColor(C'206,206,206');
   m_combobox1.ButtonBackColorHover(C'193,218,255');
   m_combobox1.ButtonBorderColor(C'150,170,180');
   m_combobox1.ButtonBorderColorOff(C'178,195,207');
   m_combobox1.ItemsTotal(ITEMS_TOTAL1);
   m_combobox1.VisibleItemsTotal(5);
//--- Guardamos los valores de elementos en la lista de combobox
   for(int i=0; i<ITEMS_TOTAL1; i++)
      m_combobox1.ValueToList(i,items_text[i]);
//--- Obtenemos el puntero de la lista
   CListView *lv=m_combobox1.GetListViewPointer();
//--- Establecemos las propiedades de la lista
   lv.LightsHover(true);
   lv.SelectedItemByIndex(lv.SelectedItemIndex()==WRONG_VALUE ? 2 : lv.SelectedItemIndex());
//--- Creamos el control
   if(!m_combobox1.CreateComboBox(m_chart_id,m_subwin,x,y))
      return(false);
//--- Añadimos el objeto al array común de los grupos de objetos
   CWndContainer::AddToElementsArray(0,m_combobox1);
   return(true);
  }

La llamada a los métodos de la creación de controles debe ubicarse en el método principal de la creación de la interfaz gráfica. En nuestro caso es CProgram::CreateTradePanel(). Abajo se muestra la versión reducida del 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

//--- Comboboxs
   if(!CreateComboBox1("Combobox 1:"))
      return(false);
   if(!CreateComboBox2("Combobox 2:"))
      return(false);
   if(!CreateComboBox3("Combobox 3:"))
      return(false);
   if(!CreateComboBox4("Combobox 4:"))
      return(false);

//--- Listas

//--- Redibujar el gráfico
   m_chart.Redraw();
   return(true);
  }

Añadimos el bloque para identificar los mensajes de los comboboxs con el identificador ON_CLICK_COMBOBOX_ITEM al manejador de eventos de la clase personalizada (CProgram). Hagamos que si llega el mensaje del tercer combobox, entonces dependiendo del elemento seleccionado en su lista, va a cambiarse el estado del cuarto combobox. En este caso, las selección de cualquier elemento a excepción del primero (0) en la lista va a hacer que el cuarto combobox esté disponible. La selección del primer elemento va a bloquearlo. 

//+------------------------------------------------------------------+
//| Manejador de eventos                                               |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Evento de la selección del elemento en el combobox
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM)
     {
      if(sparam==m_combobox1.LabelText())
         ::Print(__FUNCTION__," > Es el mensaje del primer combobox > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      else if(sparam==m_combobox2.LabelText())
         ::Print(__FUNCTION__," > Es el mensaje del segundo combobox > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Procesamos el mensaje del tercer combobox
      else if(sparam==m_combobox3.LabelText())
        {
         ::Print(__FUNCTION__," > Es el mensaje del tercer combobox > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
         //--- Si ha sido seleccionado el valor especificado, bloqueamos el cuarto combobox
         if(m_combobox3.ButtonText()=="FALSE")
            m_combobox4.ComboBoxState(false);
         //--- Si ha sido seleccionado otro valor, activamos el cuarto combobox
         else
            m_combobox4.ComboBoxState(true);
        }
      else if(sparam==m_combobox4.LabelText())
         ::Print(__FUNCTION__," > Es el mensaje del cuarto combobox > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
     }
  }

Si ahora compilamos el programa y los cargamos en el gráfico, obtendremos el siguiente resultado:

 Fig. 2. Prueba del control “Combobox”.

Fig. 2. Prueba del control “Combobox”.

 

Hemos terminado el desarrollo de la clase CComboBox para la creación de las listas combinadas.

 


Conclusión

En este artículo hemos analizado el control compuesto “Lista combinada” o “Combobox”. 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. 3. Estructura de la librería en la fase actual del desarrollo.

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

 

El siguiente artículo abrirá la sexta parte de la serie sobre el desarrollo de la librería para la creación de las interfaces gráficas. En los capítulos de la sexta parte vamos a crear las clases para la creación de los controles tales como: “Casillas de verificación”, “Campos de edición” y sus varios tipos combinados.

Más abajo puede descargar el material de la quinta 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 quinta parte:

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

Archivos adjuntos |
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.
Cómo mejorar el simulador de estrategias para optimizar indicadores usando ejemplos de los mercados de tendencia y flat Cómo mejorar el simulador de estrategias para optimizar indicadores usando ejemplos de los mercados de tendencia y flat
Al comerciar con diferentes estrategias a veces se requiere determinar si el mercado se encuentra en tendencia o en flat. Con este objetivo se desarrollan multitud de indicadores. ¿Pero cómo evaluar si el indicador cumple o no con la tarea indicada? ¿Cómo aclarar cuál es el diapasón medio del estado del flat o de la tendencia para definir nuestros stops y objetivos? En este artículo se propone usar para ello el simulador de estrategias, demostrando al mismo tiempo que no solo sirve para la optimización de robots para determinadas necesidades. Como indicador de prueba vamos a usar a nuestro viejo conocido ADX.
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 V: Control "Lista" (Capítulo 2) Interfaces gráficas V: Control "Lista" (Capítulo 2)
En el primer capítulo de la quinta parte de la serie hemos desarrollado las clases para la creación de los controles como la barra de desplazamiento vertical y horizontal. En este artículo vamos a aplicarlas en la práctica. Esta vez diseñaremos la clase para la creación del control “Lista”, y la barra de desplazamiento vertical será su parte integrante.