
Interfaces gráficas VII: Control "Pestañas" (Capítulo 2)
Índice
- Introducción
- Control “Pestañas”
- Desarrollo de la clase para la creación del control “Pestañas”
- Prueba del control “Pestañas”
- Conclusión
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 el primer capítulo de la séptima parte han sido presentadas tres clases de los controles para la creación de las tablas: tabla de las etiquetas de texto (CLabelsTable), tabla de los campos de edición (CTable) y la tabla dibujada (CCanvasTable). En este artículo (capítulo 2) hablaremos del control “Pestañas”. Habrá dos clases de este control: una clase simple y otra con posibilidades ampliadas.
Control “Pestañas”
Las pestañas sirven para gestionar la visualización de los conjuntos predefinidos de los controles de la interfaz gráfia. En las aplicaciones multifuncionales, a menudo es necesario meter muchos controles en un espacio reducido asignado para la interfaz gráfica. A través de las pestañas, se puede agruparlos por las categorías y activar la visualización del grupo necesario en un momento dado, lo que hace que la interfaz sea mucho más cómoda y más comprensible para el usuario final. Las pestañas externas tienen el aspecto de un grupo de botones con texto (nombre del grupo de controles), pudiendo que sólo una de ellas esté activa.
Vamos a nombrar todas las partes integrantes de este control.
- Fondo o área para colocar el grupo de controles
- Pestañas
Fig. 1. Partes integrantes del control “Pestañas”.
Hagamos que las pestañas se pueda posicionar en cuatro modos (arriba, abajo, a la izquierda y a la derecha) respecto al área donde van a ubicarse los controles.
Desarrollo de la clase para la creación del control “Pestañas”
Creamos el archivo Tabs.mqh y lo incluimos en la librería (archivo WndContainer.mqh):
//+------------------------------------------------------------------+ //| WndContainer.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "Tabs.mqh"
Hay que crear la clase CTabs en el archivo Tabs.mqh. En esta clase, igual que en otras clases de los controles, hay que crear los métodos estándar, así como el método para guardar el puntero al formulario al que será adjuntado este control:
//+------------------------------------------------------------------+ //| Clase para crear las pestañas | //+------------------------------------------------------------------+ class CTabs : public CElement { private: //--- Puntero al formulario al que está adjuntado el control CWindow *m_wnd; //--- public: CTabs(void); ~CTabs(void); //--- (1) Guarda el puntero del formulario, (2) devuelve los punteros a las barras de desplazamiento 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 | //+------------------------------------------------------------------+ CTabs::CTabs(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CTabs::~CTabs(void) { }
Se puede dividir las propiedades de las pestañas en únicas y generales. Vamos a nombrar ambas listas.
Propiedades únicas
- Array de punteros a los controles adjuntos a la pestaña
- Texto
- Ancho
Vamos a crear la estructura TElements para las propiedades únicas, y declaramos el array dinámico con este tipo:
class CTabs : public CElement { private: //--- Estructura de propiedades y arrays de controles adjuntos a cada pestaña struct TElements { CElement *elements[]; string m_text; int m_width; }; TElements m_tab[]; };
Propiedades comunes:
- Modo de posicionar las pestañas
- Color del fondo del área
- Tamaño de las tablas por el eje Y (alto)
- Colores de las pestañas en diferentes estados
- Color del texto de las pestañas en diferentes estados
- Color de los marcos de las pestañas
- Prioridades para el clic izquierdo del ratón
Hay que añadir la enumeración ENUM_TABS_POSITION al archivo Enums.mqh para establecer el modo de posicionamiento de las pestañas:
//+------------------------------------------------------------------+ //| Enumeración del posicionamiento de pestañas | //+------------------------------------------------------------------+ enum ENUM_TABS_POSITION { TABS_TOP =0, TABS_BOTTOM =1, TABS_LEFT =2, TABS_RIGHT =3 };
El código de abajo contiene la declaración de los campos y los métodos para establecer las propiedades:
class CTabs : public CElement { private: //--- Posicionamiento de las pestañas ENUM_TABS_POSITION m_position_mode; //--- Color del fondo del área general int m_area_color; //--- Tamaño de las tablas por el eje Y int m_tab_y_size; //--- Colores de las pestañas en diferentes estados color m_tab_color; color m_tab_color_hover; color m_tab_color_selected; color m_tab_color_array[]; //--- Color del texto de las pestañas en diferentes estados color m_tab_text_color; color m_tab_text_color_selected; //--- Color de los marcos de las pestañas color m_tab_border_color; //--- Prioridades para el clic izquierdo del ratón int m_zorder; int m_tab_zorder; //--- public: //--- (1) Establece/obtiene el posicionamiento de las pestañas (arriba/abajo, a la izquierda/a la derecha), (2) establece el tamaño de las tablas por el eje Y void PositionMode(const ENUM_TABS_POSITION mode) { m_position_mode=mode; } ENUM_TABS_POSITION PositionMode(void) const { return(m_position_mode); } void TabYSize(const int y_size) { m_tab_y_size=y_size; } //--- Color del (1) fondo general, (2) colores de las pestañas en diferentes estados, (3) color de los marcos de las pestañas void AreaColor(const color clr) { m_area_color=clr; } void TabBackColor(const color clr) { m_tab_color=clr; } void TabBackColorHover(const color clr) { m_tab_color_hover=clr; } void TabBackColorSelected(const color clr) { m_tab_color_selected=clr; } void TabBorderColor(const color clr) { m_tab_border_color=clr; } //--- Color del texto de las pestañas en diferentes estados void TabTextColor(const color clr) { m_tab_text_color=clr; } void TabTextColorSelected(const color clr) { m_tab_text_color_selected=clr; } };
Antes de crear el control, primero es necesario añadir la cantidad necesaria de las pestañas indicando el texto a mostrar y el ancho. Para eso escribiremos el método CTabs::AddTab(). Por defecto, los argumentos del método tienen los valores «» (línea vacía) y 50 (ancho).
class CTabs : public CElement { public: //--- Añade la pestaña void AddTab(const string tab_text="",const int tab_width=50); }; //+------------------------------------------------------------------+ //| Añade la pestaña | //+------------------------------------------------------------------+ void CTabs::AddTab(const string tab_text,const int tab_width) { //--- Establecer el tamaño para los arrays de pestañas int array_size=::ArraySize(m_tabs); ::ArrayResize(m_tabs,array_size+1); ::ArrayResize(m_tab,array_size+1); //--- Guardar las propiedades pasadas m_tab[array_size].m_text =tab_text; m_tab[array_size].m_width =tab_width; //--- Guardar el número de pestañas m_tabs_total=array_size+1; }
Si hace falta que después de cargar la aplicación MQL quede seleccionada una determinada pestaña, entonces antes de crear el control, hay que especificar su índice usando el método CTabs::SelectedTab(). Además, vamos a necesitar el método privado CTabs::CheckTabIndex() para comprobar y corregir el índice de la pestaña seleccionada en caso de superar el rango.
class CTabs : public CElement { private: //--- Índice de la pestaña seleccionada int m_selected_tab; //--- public: //--- (1) Guarda y (2) devuelve el índice de la pestaña seleccionada void SelectedTab(const int index) { m_selected_tab=index; } int SelectedTab(void) const { return(m_selected_tab); } //--- private: //--- Comprobación del índice de la pestaña seleccionada void CheckTabIndex(void); }; //+------------------------------------------------------------------+ //| Comprobación del índice de la pestaña seleccionada | //+------------------------------------------------------------------+ void CTabs::CheckTabIndex(void) { //--- Comprobar la superación del rango int array_size=::ArraySize(m_tab); if(m_selected_tab<0) m_selected_tab=0; if(m_selected_tab>=array_size) m_selected_tab=array_size-1; }
Para crear el control vamos a necesitar tres métodos privados (private) y uno público (public ):
class CTabs : public CElement { private: //--- Objetos para crear el control CRectLabel m_main_area; CRectLabel m_tabs_area; CEdit m_tabs[]; //--- public: //--- Métodos para crear las pestañas bool CreateTabs(const long chart_id,const int subwin,const int x,const int y); //--- private: bool CreateMainArea(void); bool CreateTabsArea(void); bool CreateButtons(void); };
Si antes de la creación del control no añadimos ninguna pestaña, al llamar al método público CTabs::CreateTabs(), la creación de la interfaz gráfica será interrumpida y en el registro se mostrará el mensaje:
//--- Si en el grupo no hay pestañas, avisar sobre ello if(m_tabs_total<1) { ::Print(__FUNCTION__," > ¡La llamada a este método debe realizarse " "cuando en el grupo hay por lo menos una pestaña! Utilice el método CTabs::AddTab()"); return(false); }
Dependiendo del modo de posicionamiento seleccionado, la determinación y el cálculo de coordenadas de los objetos del control también va a diferenciarse. Para estos cálculos vamos a necesitar el método CTabs::SumWidthTabs() que devuelve el ancho total de todas las pestañas. En el modo de posicionamiento de la pestañas a la izquierda (TABS_LEFT) y a la derecha (TABS_RIGHT), va a devolverse el ancho de la primera pestaña. Para los modos arriba (TABS_TOP) y abajo (TABS_BOTTOM), el ancho de todas las pestañas se suma.
class CTabs : public CElement { private: //--- Posicionamiento de las pestañas ENUM_TABS_POSITION m_position_mode; //--- private: //--- Ancho de todas las pestañas int SumWidthTabs(void); }; //+------------------------------------------------------------------+ //| Ancho de todas las pestañas | //+------------------------------------------------------------------+ int CTabs::SumWidthTabs(void) { int width=0; //--- Si las pestañas se ubican a la izquierda y a la derecha, devolver el ancho de la primera pestaña if(m_position_mode==TABS_LEFT || m_position_mode==TABS_RIGHT) return(m_tab[0].m_width); //--- Sumamos el ancho de todas las pestañas for(int i=0; i<m_tabs_total; i++) width=width+m_tab[i].m_width; //--- Con solapamiento de un píxel width=width-(m_tabs_total-1); return(width); }
El método CTabs::CreateMainArea() sirve para crear el área donde se ubican los grupos de controles. El cálculo de las coordenadas y tamaños del objeto es el siguiente (versión reducida del método):
//+------------------------------------------------------------------+ //| Crea el fondo general del área | //+------------------------------------------------------------------+ bool CTabs::CreateMainArea(void) { //--- Formación del nombre del objeto string name=CElement::ProgramName()+"_tabs_main_area_"+(string)CElement::Id(); //--- Coordenadas int x=0; int y=0; //--- Tamaños int x_size=0; int y_size=0; //--- Cálculo de las coordenadas y tamaños respecto al posicionamiento de las pestañas switch(m_position_mode) { case TABS_TOP : x =CElement::X(); y =CElement::Y()+m_tab_y_size-1; x_size =CElement::XSize(); y_size =CElement::YSize()-m_tab_y_size; break; case TABS_BOTTOM : x =CElement::X(); y =CElement::Y(); x_size =CElement::XSize(); y_size =CElement::YSize()-m_tab_y_size; break; case TABS_RIGHT : x =CElement::X(); y =CElement::Y(); x_size =CElement::XSize()-SumWidthTabs()+1; y_size =CElement::YSize(); break; case TABS_LEFT : x =CElement::X()+SumWidthTabs()-1; y =CElement::Y(); x_size =CElement::XSize()-SumWidthTabs()+1; y_size =CElement::YSize(); break; } //--- Creación del objeto if(!m_main_area.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size)) return(false); //--- Establecemos las propiedades //--- Márgenes desde el punto extremo //--- Guardamos los tamaños //--- Guardamos las coordenadas //--- Guardamos el puntero del objeto //... return(true); }
A continuación, se muestra el cálculo de las coordenadas y tamaños del fondo de pestañas dependiendo del modo de posicionamiento de pestañas establecido en el método CTabs::CreateTabsArea():
//+------------------------------------------------------------------+ //| Crea el fondo para las pestañas | //+------------------------------------------------------------------+ bool CTabs::CreateTabsArea(void) { //--- Formación del nombre del objeto string name=CElement::ProgramName()+"_tabs_area_"+(string)CElement::Id(); //--- Coordenadas int x=CElement::X(); int y=CElement::Y(); //--- Tamaños int x_size=SumWidthTabs(); int y_size=0; //--- Cálculo de los tamaños respecto al posicionamiento de las pestañas if(m_position_mode==TABS_TOP || m_position_mode==TABS_BOTTOM) { y_size=m_tab_y_size; } else { y_size=m_tab_y_size*m_tabs_total-(m_tabs_total-1); } //--- Corregir las coordenadas para el posicionamiento de las pestañas abajo y arriba if(m_position_mode==TABS_BOTTOM) { y=CElement::Y2()-m_tab_y_size-1; } else if(m_position_mode==TABS_RIGHT) { x=CElement::X2()-x_size; } //--- Creación del objeto if(!m_tabs_area.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size)) return(false); //--- Establecemos las propiedades //--- Márgenes desde el punto extremo //--- Guardamos los tamaños //--- Guardamos las coordenadas //--- Guardamos el puntero del objeto //... return(true); }
En el método CTabs::CreateButtons() para la creación de pestañas vamos a necesitar sólo el cálculo de las coordenadas. El ancho se establece en la clase personalizada de la aplicación para la creación del control. De lo contrario, se utiliza el valor (ancho) predefinido. En el código de abajo se muestra la versión reducida de este método:
//+------------------------------------------------------------------+ //| Crea las pestañas | //+------------------------------------------------------------------+ bool CTabs::CreateButtons(void) { //--- Coordenadas int x =CElement::X(); int y =CElement::Y(); //--- Cálculo de las coordenadas respecto al posicionamiento de las pestañas if(m_position_mode==TABS_BOTTOM) y=CElement::Y2()-m_tab_y_size-1; else if(m_position_mode==TABS_RIGHT) x=CElement::X2()-SumWidthTabs(); //--- Comprobación del índice de la pestaña seleccionada CheckTabIndex(); //--- Creación de pestañas for(int i=0; i<m_tabs_total; i++) { //--- Formación del nombre del objeto string name=CElement::ProgramName()+"_tabs_edit_"+(string)i+"__"+(string)CElement::Id(); //--- Cálculo de las coordenadas respecto al posicionamiento de las pestañas para cada una de las pestañas separadamente if(m_position_mode==TABS_TOP || m_position_mode==TABS_BOTTOM) x=(i>0) ? x+m_tab[i-1].m_width-1 : CElement::X(); else y=(i>0) ? y+m_tab_y_size-1 : CElement::Y(); //--- Creación del objeto if(!m_tabs[i].Create(m_chart_id,name,m_subwin,x,y,m_tab[i].m_width,m_tab_y_size)) return(false); //--- Establecemos las propiedades //--- Márgenes desde el punto extremo del panel //--- Coordenadas //--- Tamaños //--- Inicialización del array del gradiente //--- Guardamos el puntero del objeto } //--- return(true); }
Para asignar algún control a una pestañas determinada, escribiremos el método CTabs::AddToElementsArray(). Tiene dos argumentos: (1) el índice de la pestaña a la que se adjunta el control y (2) la referencia al control cuyo puntero hay que guardar en el array de los controles de la pestaña.
class CTabs : public CElement { public: //--- Añade el control al array void AddToElementsArray(const int tab_index,CElement &object); }; //+------------------------------------------------------------------+ //| Añade el control al array de la pestaña especificada | //+------------------------------------------------------------------+ void CTabs::AddToElementsArray(const int tab_index,CElement &object) { //--- Comprobar la superación del rango int array_size=::ArraySize(m_tab); if(array_size<1 || tab_index<0 || tab_index>=array_size) return; //--- Añadimos el puntero del control pasado al array de la pestaña especificada int size=::ArraySize(m_tab[tab_index].elements); ::ArrayResize(m_tab[tab_index].elements,size+1); m_tab[tab_index].elements[size]=::GetPointer(object); }
Al cambiar de pestañas, hay que ocultar los controles de la pestaña activa anterior, y mostrar los controles de la pestaña recién activada. Para estos fines crearemos el método CTabs::ShowTabElements(). Al principio de este método se encuentra la comprobación de la visibilidad del control. Si el control está ocultado, entonces el programa sale del método. Luego se comprueba, y en caso de necesidad se corrige, el índice de la pestaña activa. Luego se comprueban todas las pestañas en el ciclo, y se ejecuta la tarea principal del método.
class CTabs : public CElement { public: //--- Mostrar los controles de la pestaña recién seleccionada void ShowTabElements(void); }; //+------------------------------------------------------------------+ //| Muestra los controles de la pestaña recién seleccionada | //+------------------------------------------------------------------+ void CTabs::ShowTabElements(void) { //--- Salir si las pestañas están ocultadas if(!CElement::IsVisible()) return; //--- Comprobación del índice de la pestaña seleccionada CheckTabIndex(); //--- for(int i=0; i<m_tabs_total; i++) { //--- Obtenemos el número de controles adjuntados a la pestaña int tab_elements_total=::ArraySize(m_tab[i].elements); //--- Si esta pestaña está seleccionada if(i==m_selected_tab) { //--- Mostrar los controles de la pestaña for(int j=0; j<tab_elements_total; j++) m_tab[i].elements[j].Show(); } //--- Ocultar los controles de las pestañas no activas else { for(int j=0; j<tab_elements_total; j++) m_tab[i].elements[j].Hide(); } } }
Para el procesamiento del evento del clic en la pestaña vamos a utilizar el método CTabs::OnClickTab(). Primero, el programa tiene que hacer dos comprobaciones: (1) por el nombre del objeto pulsado y (2) por el identificador del control que se extrae desde el nombre del objeto mediante el método CTabs::IdFromObjectName(). Si las comprobaciones han sido superadas con éxito, en el ciclo (1) buscamos la pestaña en la que ha sido hecho el clic, (2) guardamos su índice y (3) establecemos los colores correspondientes. Al final, los controles de la pestaña activa se hacen visibles a través del método CTabs::ShowTabElements().
class CTabs : public CElement { private: //--- Procesamiento del clic en la pestaña bool OnClickTab(const string pressed_object); //--- Obtención del identificador desde el nombre del objeto int IdFromObjectName(const string object_name); }; //+------------------------------------------------------------------+ //| Clic en la pestaña en el grupo | //+------------------------------------------------------------------+ bool CTabs::OnClickTab(const string clicked_object) { //--- Salimos si el clic no ha sido hecho en la celda de la tabla if(::StringFind(clicked_object,CElement::ProgramName()+"_tabs_edit_",0)<0) return(false); //--- Obtenemos el identificador desde el nombre del objeto int id=IdFromObjectName(clicked_object); //--- Salir si el identificador no coincide if(id!=CElement::Id()) return(false); //--- for(int i=0; i<m_tabs_total; i++) { //--- Si esta pestaña está seleccionada if(m_tabs[i].Name()==clicked_object) { //--- Guardar el índice de la pestaña seleccionada SelectedTab(i); //--- Establecer los colores m_tabs[i].Color(m_tab_text_color_selected); m_tabs[i].BackColor(m_tab_color_selected); } else { //--- Establecer el color para las pestañas no activas m_tabs[i].Color(m_tab_text_color); m_tabs[i].BackColor(m_tab_color); } } //--- Mostrar los controles de la pestaña recién seleccionada ShowTabElements(); return(true); }
Entonces, el código del manejador principal de los eventos del control CTabs::OnEvent() va a tener el siguiente aspecto:
//+------------------------------------------------------------------+ //| Manejador del evento del gráfico | //+------------------------------------------------------------------+ void CTabs::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; for(int i=0; i<m_tabs_total; i++) m_tabs[i].MouseFocus(x>m_tabs[i].X() && x<m_tabs[i].X2() && y>m_tabs[i].Y() && y<m_tabs[i].Y2()); //--- return; } //--- Procesamiento del evento del clic izquierdo en el objeto if(id==CHARTEVENT_OBJECT_CLICK) { //--- Clic en la pestaña if(OnClickTab(sparam)) return; } }
Hemos analizado todos los métodos de la clase CTabs .Ahora vamos a probar cómo funciona todo eso.
Prueba del control “Pestañas”
Para la prueba vamos a usar el Asesor Experto del artículo anterior dejando en su interfaz gráfica sólo el menú principal y la barra de estado. Hagamos que haya la posibilidad de probar rápidamente todos los modos de posicionamiento de las pestañas (arriba/abajo/a la derecha/a la izquierda), así como ajustar su tamaño (alto). Para eso, en el inicio del archivo con la clase personalizada Program.mqh añadimos los parámetros externos del EA:
//--- Parámetros externos del EA input ENUM_TABS_POSITION TabsPosition =TABS_TOP; // Tabs Position input int TabsHeight =20; // Tabs Height
Luego, en la clase personalizada de la aplicación (CProgram), declaramos la instancia de la clase CTabs y el método para la creación del control “Pestañas” con los márgenes desde el punto extremo del formulario:
class CProgram : public CWndEvents { private: //--- Pestañas CTabs m_tabs; //--- private: //--- Pestañas #define TABS1_GAP_X (4) #define TABS1_GAP_Y (45) bool CreateTabs(void); };
Que haya cuatro pestañas en total. Para ajustar el texto a mostrar y el ancho de las pestañas, se puede usar la inicialización de los arrays. Los valores de sus elementos luego se pasan en el ciclo a través del método CTabs::AddTab(). El alto de las pestañas y su posicionamiento va a establecerse con los parámetros externos. Por defecto, (durante el primer inicio del programa en el gráfico) que la segunda pestaña (índice 1) se quede seleccionada. Abajo se muestra el código completo del método CProgram::CreateTabs():
//+------------------------------------------------------------------+ //| Crea el área con las pestañas | //+------------------------------------------------------------------+ bool CProgram::CreateTabs(void) { #define TABS1_TOTAL 4 //--- Pasar el objeto del panel m_tabs.WindowPointer(m_window1); //--- Coordenadas int x=m_window1.X()+TABS1_GAP_X; int y=m_window1.Y()+TABS1_GAP_Y; //--- Arrays con el texto y el ancho para las pestañas string tabs_text[]={"Tab 1","Tab 2","Tab 3","Tab 4"}; int tabs_width[]={90,90,90,90}; //--- Establecemos las propiedades antes de la creación m_tabs.XSize(596); m_tabs.YSize(243); m_tabs.TabYSize(TabsHeight); m_tabs.PositionMode(TabsPosition); m_tabs.SelectedTab((m_tabs.SelectedTab()==WRONG_VALUE) ? 1 : m_tabs.SelectedTab()); m_tabs.AreaColor(clrWhite); m_tabs.TabBackColor(C'225,225,225'); m_tabs.TabBackColorHover(C'240,240,240'); m_tabs.TabBackColorSelected(clrWhite); m_tabs.TabBorderColor(clrSilver); m_tabs.TabTextColor(clrGray); m_tabs.TabTextColorSelected(clrBlack); //--- Añadimos las pestañas con propiedades especificadas for(int i=0; i<TABS1_TOTAL; i++) m_tabs.AddTab(tabs_text[i],tabs_width[i]); //--- Creamos el control if(!m_tabs.CreateTabs(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_tabs); return(true); }
La llamada al método debe realizarse en el método principal de la creación de la interfaz gráfica de la aplicación (véase la versión reducida del método más abajo):
//+------------------------------------------------------------------+ //| Crea el panel del EA | //+------------------------------------------------------------------+ bool CProgram::CreateExpertPanel(void) { //--- Creación del formulario 1 para los controles //--- Creación de controles: // Menú principal //--- Menús contextuales //--- Pestañas if(!CreateTabs()) return(false); //--- Redibujar el gráfico m_chart.Redraw(); return(true); }
Por favor, compile el programa y cárguelo en el gráfico. En los parámetros externos, vamos a cambiar los modos de posicionamiento de las pestañas de manea consecutiva (véase las capturas de pantalla de abajo):
Fig. 2. Modo de posicionar las pestañas - “Arriba”.
Fig. 3. Modo de posicionar las pestañas - “Abajo”.
Fig. 4. Modo de posicionar las pestañas - “A la izquierda”.
Fig. 5. Modo de posicionar las pestañas - “A la derecha”.
Ahora vamos a probar cómo funciona eso con los grupos de controles adjuntos a cada pestaña. Para eso crearemos otra copia del mismo EA y eliminaremos de ahí los parámetros externos. Aquí las pestañas van a ubicarse en la parte superior (TABS_TOP) del área de trabajo.
- A la primera pestaña le adjuntaremos la tabla a base de las etiquetas de texto.
- La segunda pestaña va a incluir la tabla a base de los campos de edición.
- A la tercera pestaña le adjuntaremos la tabla dibujada.
- La cuarta pestaña va a incluir el grupo de los siguientes controles:
- cuatro casillas de verificación (checkbox);
- cuatro checkbox con campos de edición;
- cuatro listas combinadas (combobox) con casillas de verificación (checkbox);
- una línea separadora.
En la clase personalizada (CProgram) de la aplicación de prueba, declaramos (1) las instancias de las clases de estos controles, (2) métodos para su creación y (3) los márgenes desde el punto extremo del formulario (véase el código de abajo):
class CProgram : public CWndEvents { private: //--- Tabla de las etiquetas de texto CLabelsTable m_labels_table; //--- Tabla a base de los campos de edición CTable m_table; //--- Tabla dibujada CCanvasTable m_canvas_table; //--- Casillas de verificación (checkbox) CCheckBox m_checkbox1; CCheckBox m_checkbox2; CCheckBox m_checkbox3; CCheckBox m_checkbox4; //--- Casillas de verificación con campos de edición CCheckBoxEdit m_checkboxedit1; CCheckBoxEdit m_checkboxedit2; CCheckBoxEdit m_checkboxedit3; CCheckBoxEdit m_checkboxedit4; //--- Combobox con checkbox CCheckComboBox m_checkcombobox1; CCheckComboBox m_checkcombobox2; CCheckComboBox m_checkcombobox3; CCheckComboBox m_checkcombobox4; //--- Línea separadora CSeparateLine m_sep_line; //--- private: //--- Tabla de las etiquetas de texto #define TABLE1_GAP_X (5) #define TABLE1_GAP_Y (65) bool CreateLabelsTable(void); //--- Tabla a base de los campos de edición #define TABLE2_GAP_X (5) #define TABLE2_GAP_Y (65) bool CreateTable(void); //--- Tabla dibujada #define TABLE3_GAP_X (5) #define TABLE3_GAP_Y (65) bool CreateCanvasTable(void); //--- Línea separadora #define SEP_LINE_GAP_X (300) #define SEP_LINE_GAP_Y (70) bool CreateSepLine(void); //--- Casillas de verificación (checkbox) #define CHECKBOX1_GAP_X (18) #define CHECKBOX1_GAP_Y (75) bool CreateCheckBox1(const string text); #define CHECKBOX2_GAP_X (18) #define CHECKBOX2_GAP_Y (175) bool CreateCheckBox2(const string text); #define CHECKBOX3_GAP_X (315) #define CHECKBOX3_GAP_Y (75) bool CreateCheckBox3(const string text); #define CHECKBOX4_GAP_X (315) #define CHECKBOX4_GAP_Y (175) bool CreateCheckBox4(const string text); //--- Casillas de verificación con campos de edición #define CHECKBOXEDIT1_GAP_X (40) #define CHECKBOXEDIT1_GAP_Y (105) bool CreateCheckBoxEdit1(const string text); #define CHECKBOXEDIT2_GAP_X (40) #define CHECKBOXEDIT2_GAP_Y (135) bool CreateCheckBoxEdit2(const string text); #define CHECKBOXEDIT3_GAP_X (337) #define CHECKBOXEDIT3_GAP_Y (105) bool CreateCheckBoxEdit3(const string text); #define CHECKBOXEDIT4_GAP_X (337) #define CHECKBOXEDIT4_GAP_Y (135) bool CreateCheckBoxEdit4(const string text); //--- Combobox con checkbox #define CHECKCOMBOBOX1_GAP_X (40) #define CHECKCOMBOBOX1_GAP_Y (205) bool CreateCheckComboBox1(const string text); #define CHECKCOMBOBOX2_GAP_X (40) #define CHECKCOMBOBOX2_GAP_Y (235) bool CreateCheckComboBox2(const string text); #define CHECKCOMBOBOX3_GAP_X (337) #define CHECKCOMBOBOX3_GAP_Y (205) bool CreateCheckComboBox3(const string text); #define CHECKCOMBOBOX4_GAP_X (337) #define CHECKCOMBOBOX4_GAP_Y (235) bool CreateCheckComboBox4(const string text); };
En los artículos anteriores, ya hemos mostrado varias veces cómo se crean los controles y cómo se adjuntan al formulario. Por eso aquí, como ejemplo, vamos a mostrar el código sólo de uno de estos métodos con el fin de demostrar cómo adjuntar el control a la pestaña. De ejemplo, será suficiente mostrar el control más simple de ellos (línea separadora). En el código de abajo, la línea donde se llama al método CTabs::AddToElementsArray() está marcada en amarillo. El índice de la pestaña a la que se adjunta el control se indica como el primer argumento, y aquí es el índice 3, es decir, la cuarta pestaña. El objeto del control que debe adjuntarse a la pestaña especificada se indica como el segundo argumento.
//+------------------------------------------------------------------+ //| Crea la línea separadora | //+------------------------------------------------------------------+ bool CProgram::CreateSepLine(void) { //--- Guardamos el puntero a la ventana m_sep_line.WindowPointer(m_window1); //--- Adjuntar a la cuarta pestaña del primer grupo de pestañas m_tabs.AddToElementsArray(3,m_sep_line); //--- Coordenadas int x=m_window1.X()+SEP_LINE_GAP_X; int y=m_window1.Y()+SEP_LINE_GAP_Y; //--- Tamaños int x_size=2; int y_size=210; //--- Establecemos las propiedades antes de la creación m_sep_line.DarkColor(C'213,223,229'); m_sep_line.LightColor(clrWhite); m_sep_line.TypeSepLine(V_SEP_LINE); //--- Creación del control if(!m_sep_line.CreateSeparateLine(m_chart_id,m_subwin,0,x,y,x_size,y_size)) return(false); //--- Añadimos el puntero al control a la base CWndContainer::AddToElementsArray(0,m_sep_line); return(true); }
Una vez creada la interfaz gráfica, es obligatorio llamar al método CTabs::ShowTabElements() con el fin de visualizar los controles sólo de la pestaña activa (véase la versión reducida del método más abajo). Si no lo hacemos, se mostrarán los controles de todas las pestañas.
//+------------------------------------------------------------------+ //| Crea el panel del EA | //+------------------------------------------------------------------+ bool CProgram::CreateExpertPanel(void) { //--- Creación del formulario 1 para los controles //--- Creación de controles: //--- Menú principal //--- Menús contextuales //--- Barra de estado //--- Pestañas //... //--- Tabla de las etiquetas de texto if(!CreateLabelsTable()) return(false); //--- Tabla a base de los campos de edición if(!CreateTable()) return(false); //--- Creación de la tabla dibujada if(!CreateCanvasTable()) return(false); //--- Línea separadora if(!CreateSepLine()) return(false); //--- Casillas de verificación (checkbox) if(!CreateCheckBox1("Checkbox 1")) return(false); if(!CreateCheckBox2("Checkbox 2")) return(false); if(!CreateCheckBox3("Checkbox 3")) return(false); if(!CreateCheckBox4("Checkbox 4")) return(false); //--- Casillas de verificación con campos de edición if(!CreateCheckBoxEdit1("Checkbox Edit 1:")) return(false); if(!CreateCheckBoxEdit2("Checkbox Edit 2:")) return(false); if(!CreateCheckBoxEdit3("Checkbox Edit 3:")) return(false); if(!CreateCheckBoxEdit4("Checkbox Edit 4:")) return(false); //--- Combobox con checkbox if(!CreateCheckComboBox1("CheckCombobox 1:")) return(false); if(!CreateCheckComboBox2("CheckCombobox 2:")) return(false); if(!CreateCheckComboBox3("CheckCombobox 3:")) return(false); if(!CreateCheckComboBox4("CheckCombobox 4:")) return(false); //--- Mostrar los controles sólo de la pestaña activa m_tabs.ShowTabElements(); //--- Redibujar el gráfico m_chart.Redraw(); return(true); }
En conclusión, debe obtener el resultado como en las capturas de pantalla de abajo:
Fig. 6. Controles de la primera pestaña.
Fig. 7. Controles de la segunda pestaña.
Fig. 8. Controles de la tercera pestaña.
Fig. 9. Controles de la cuarta pestaña.
Todo funciona perfectamente, y aquí ya podemos terminar la séptima parte de la serie sobre la librería para la creación de las interfaces gráficas. Como adición, en los archivos adjuntos a este artículo Usted puede descargar la clase del código (CIconTabs) para crear el control “Pestañas” con posibilidades ampliadas. A diferencia de la clase CTabs, en el control tipo CIconTabs se puede insertar los iconos (imágenes) para cada pestaña, lo que permitirá hacer la interfaz gráfica aún más comprensible para el usuario, en caso de necesidad.
Usted puede colocar con precisión las imágenes y el texto a mostrar respecto al punto extremo de cada pestaña usando los métodos especiales (véase el código de abajo):
//+------------------------------------------------------------------+ //| Clase para crear las pestañas con imágenes | //+------------------------------------------------------------------+ class CIconTabs : public CElement { private: //--- Márgenes del icono int m_icon_x_gap; int m_icon_y_gap; //--- Márgenes de la etiqueta de texto int m_label_x_gap; int m_label_y_gap; //--- public: //--- Márgenes del icono void IconXGap(const int x_gap) { m_icon_x_gap=x_gap; } void IconYGap(const int y_gap) { m_icon_y_gap=y_gap; } //--- 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; } };
En la captura de pantalla de abajo se puede ver el ejemplo del control “Pestañas con imágenes”:
Fig. 10 Control “Pestañas con imágenes”.
Se puede descargar el código de este EA desde los archivos adjuntos al artículo.
Conclusión
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. 11. Estructura de la librería en la fase actual del desarrollo.
En la séptima parte de la serie sobre la creación de las interfaces gráficas en los terminales MetaTrader, hemos analizado los controles como las tablas y las pestañas. Para la creación de las tablas, hay tres clases (CLabelsTable, CTable y CCanvasTable), y para la creación de las pestañas, hay dos clases (CTabs y CIconTabs).
En la siguiente (la octava) parte de la serie hablaremos de los siguientes controles.
- Calendario estático y desplegable.
- Lista jerárquica (lista en forma de árbol).
- Explorador de archivos.
Más abajo puede descargar el material de la séptima 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 séptima parte:
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/2503





- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso