La mayoría de nosotros estaremos de acuerdo que el Layout es una de las funcionalidades más importantes provenientes de QT e incorporadas al diseño de formularios en vDevelop. Seguro también que todos usamos los layouts sin mayor problema y de forma automática.
Pero primero os invito a repasar el Tutorial Layouts en Velneo V7, un objeto para dominarlos a todos en este mismo blog y un video resumen de Jesús Arboleya . Ambos recursos dejan clara la función que tienen los layouts y cómo organizan los controles automáticamente en el formulario.
Solo recordar un par de cosas antes de ver con ejemplos algunas propiedades interesantes de los layouts.
- Existen otros controles que también pueden funcionar como layouts, son el formulario, la caja de grupo y el dibujo.
Los layouts solo son visibles en tiempo de diseño, pero podemos enumerarlos con el API mediante la clase VObjectInfo (Tipo de control 22). - Los layouts dentro del formulario solo funcionarán cuando el formulario es también un tipo de layout.
Los layouts pueden anidarse unos dentro de otros, siendo el layout Principal el formulario que los engloba a todos.
Tipo de Layout
El Tipo de layout determina cómo se distribuyen los controles dentro del Layout. Hasta la versión 24 existían 3 tipos de layout, Horizontal, Vertical y Grid. En la versión 25 se han añadido 2 nuevos tipos, Flujo Horizontal y Flujo Vertical que nos van a permitir diseño Responsive en nuestros formularios. Disponemos también de espaciador Fijo y espaciador Expandible.
En el layout Horizontal los controles se distribuyen horizontalmente de izquierda a derecha ordenados por el valor de la propiedad Posición X. Si coincide el valor de X se toma primero el que tiene menor valor de Y.
En el layout Vertical los controles se distribuyen verticalmente de arriba a abajo ordenados por el valor de la propiedad Posición Y. Si coincide el valor de Y se toma primero el que tiene menor valor de X.
- El layout Grid organiza los controles en una cuadrícula de filas y columnas, pero también nos servirá cuando tenemos que superponer uno o varios controles encima de otro. Si lo que vamos a superponer son imágenes, tendremos que usar el canal Alfa o de transparencia.
Velneo permite cargar en el proyecto imágenes con transparencia o crearlas con el editor de imágenes, sin embargo, no podemos guardarlas en un campo dibujo porque solo admite el formato jpeg*. Si queremos trabajar con registros de una tabla que contengan imágenes con transparencia no tenemos más remedio que codificarlas en* Base64 y usar el API para leer y guardar en un campo de Texto.
El formulario siguiente es de tipo Grid con 2 layouts: el layout Artículo con los campos y el layout Tampón con una imagen con fondo transparente.
Para atenuar los controles que hay detrás de la imagen se puede activar la propiedad «Fondo opaco» del layout Tampón y usar un «Color de fondo» con transparencia.
Superponiendo el layout Tampón un poco con el layout Artículo, el resultado es un Grid con una sola celda que contiene ambos controles.
Propiedad «Fondo opaco» del layout Tampón desactivada.
Propiedad «Fondo opaco» del layout Tampón activada para atenuar los controles del formulario.
Si no lo haces ya, ¡¡hazlo!!, activa la Rejilla de puntos en el editor de formularios. Los controles estarán siempre anclados en múltiplos de 10px. Te aseguro que una vez activado ya no sabrás trabajar sin él.
Ancho y Alto en layout
Las propiedades Ancho en layout y Alto en layout determinan el tamaño de los controles dentro de un layout y pueden tener 3 valores:
- Por defecto: el control se pintará en el formulario con el ancho y alto asignado por defecto.
- Fijo: el control se pintará en el formulario con el ancho y alto especificado en las propiedades Ancho y Alto.
- Proporcional: el control se pintará en el formulario ocupando el máximo espacio que le permita el layout y en el caso de que comparta el espacio con otro control, lo hará de forma proporcional al tamaño indicado en las propiedades Ancho y Alto.
Este será el comportamiento habitual de la mayoría de controles, lo que les permite adaptarse a los diferentes tamaños de pantalla.
Más adelante veremos qué implicaciones tiene esto.
Si no hemos aplicado CSS, siempre que sea necesario, el alto y ancho del layout del formulario crecerán para albergar todos los controles que contenga.
El formulario se expande en Horizontal y Vertical
Veamos un ejemplo con controles de tamaño Por defecto y cómo se distribuyen a lo ancho o a lo alto dentro del layout.
El formulario siguiente contiene en tiempo de diseño 6 textos estáticos con las letras de Velneo en 2 layouts, uno Horizontal y otro Vertical.
Se han fijado el Espaciado y los Márgenes a 0 en ambos layouts.
En ejecución los textos estáticos se distribuyen (horizontalmente o verticalmente) y expandirán el formulario hasta que se muestren todos los controles a su tamaño Por defecto.
Un efecto negativo de este comportamiento es que el usuario no puede redimensionar la ventana de la aplicación en el caso de que ésta desborde las medidas de la pantalla. Podemos solucionar este problema mediante el siguiente CSS:
QMainWindow
{
min-width: 200px;
min-height: 40px;
}
Estableciendo un valor mínimo al ancho y alto de la ventana principal los controles del formulario ya no intentarán redimensionarlo, pero surge otro problema cuando dichos controles desbordan el espacio disponible. En el siguiente formulario vemos lo que ocurre:
En la versión 23 se añadió un nuevo control de formulario área de scroll que soluciona éste y otros escenarios similares. Más información sobre el área de scroll en el siguiente artículo de este mismo blog.
Flujo Horizontal y Vertical para el diseño Responsive
El layout Flujo Horizontal distribuye los controles horizontalmente de izquierda a derecha ordenados por el valor de la propiedad Posición X siempre que haya espacio horizontal disponible. El layout Flujo Vertical distribuye verticalmente los controles de arriba a abajo ordenados por el valor de la propiedad Posición Y siempre que haya espacio vertical disponible.
Estos layouts de Flujo no modifican el tamaño del formulario, en su lugar distribuyen los controles creando un flujo horizontal (de izquierda a derecha y de arriba a abajo) o vertical (de arriba a abajo y de derecha a izquierda).
En el formulario siguiente tenemos 2 layouts de Flujo, uno de cada tipo. El layout de Flujo Horizontal contiene 2 layouts de ancho fijo y otros 2 proporcionales. En el layout de Flujo Vertical hay 2 layouts de alto fijo y otros 2 proporcionales.
En ejecución el formulario no se ha redimensionado para distribuir los elementos en los layouts de Flujo Horizontal (200px de ancho) y Flujo Vertical (200px de alto).
En el layout de Flujo Horizontal los layouts fijos naranja y verde caben en la primera fila porque miden 160px (70 + 90px) y todavía queda espacio para el layout proporcional amarillo. La segunda fila se ocupa proporcionalmente por el layout azul.
En el layout de Flujo Vertical el layout fijo naranja ocupa él solo la primera columna con 150px, el layout fijo amarillo de 70px pasa a la segunda columna porque ya no queda espacio disponible. Los layouts verde y azul ocupan proporcionalmente el espacio disponible de la segunda columna.
Cuando aumentamos el tamaño del formulario la distribución de los elementos del formulario cambia.
El layout de Flujo Horizontal ha aumentado a 300px de ancho y ya da cabida al layout azul que tendrá la mitad del ancho del layout amarillo por la proporción que tienen en diseño. El layout de Flujo Vertical aumenta a 220px de alto y mete en la primera columna el layout amarillo con sus 70px de alto. La segunda columna se reparte al 50% entre los layouts verde y azul que son iguales en diseño.
Los layouts de Flujo solucionan el problema de recolocar los controles cuando giramos las pantallas de los móviles y tablets.
En el siguiente formulario el layout de Flujo Horizontal de color verde colocará el Dibujo a la derecha o en la parte inferior según la orientación del formulario. Para determinar en qué momento el dibujo fluye de la posición horizontal a la vertical establecemos un control fijo de 140px que forzará el cambio cuando el formulario cambie de tamaño y ya no permita albergar a éste.
En ejecución con orientación horizontal del formulario.
En ejecución con orientación vertical del formulario.
Espaciado y Márgenes
Las propiedades Espaciado y Márgenes de los layouts tienen un valor por defecto de -1 que equivale a 5px y 10px respectivamente.
Usaremos estas propiedades para agrupar o separar visualmente los controles en un determinado formulario. Para aplicar estos valores de manera global usaremos CSS.
El valor «margin» del CSS de los controles se sumará al Espaciado del layout.
El formulario siguiente tiene un margen izquierdo y superior a un valor personalizado de 50px. Los 4 layouts verdes se distribuyen dentro del layout principal con un espaciado de 10px y márgenes personalizados de 20,30,20,30 (sup, der, inf, izq).
En este otro formulario los márgenes se han fijado a 50px y el espaciado entre controles a 30px. Dentro de cada Layout se han definido espaciados y márgenes personalizados.
Ancho y Alto proporcional
El diseño de la mayoría de los formularios se resuelve dejando los valores Por defecto en las propiedades Ancho en layout y Alto en layout.
En la tabla siguiente se listan algunos controles y los valores Por defecto que tendrán el Ancho y Alto dentro de un Layout.
Observamos que el valor más común es Proporcional, pero ¿qué tamaño efectivo tomará el control en tiempo de ejecución?
Rellenar proporcionalmente el espacio disponible
En el formulario siguiente hemos colocado 2 layouts con la propiedad Alto en layout a valor Por defecto. El layout «cabecera» mide en diseño 240px de alto y el layout «botones» 80px.
En ejecución los layouts se adaptan por defecto a la suma del tamaño de los controles que contienen. El layout «cabecera» mide en pantalla unos 220px de alto y el layout «botones» unos 65px.
Cambiemos en diseño los valores de Alto en layout de ambos layouts a Proporcional. Vemos que ahora la Altura de los layouts es 300px y 100px respectivamente. Los valores se han repartido de arriba a abajo del formulario (400px) de manera Proporcional, según la relación (3/1 = 240px/80px ) que tienen en diseño.
Finalmente pongamos el Alto del layout «botones» al valor Por defecto.
En este caso el layout «botones» ocupa el espacio mínimo necesario, unos 65px, y el layout «cabecera» ocupará el resto del formulario.
Resumiendo, cuando establecemos el tamaño de un control en diseño al valor Proporcional, tendremos 2 casos en tiempo de ejecución:
- Si el control es el único Proporcional dentro del layout, entonces se expandirá para ocupar todo el ancho o alto disponible en el layout.
- Si comparte layout con otros controles tendrá que adaptar su tamaño proporcionalmente al de dichos controles. Los tamaños en tiempo de ejecución estarán siempre referenciados proporcionalmente al tamaño que tenían en tiempo de diseño.
Mantener Proporción en horizontal y vertical
Compliquemos un poco el diseño de nuestro formulario para jugar con la Proporción en horizontal y vertical. En este caso tenemos 3 layouts que deben tener cada uno la mitad del tamaño que el siguiente.
El formulario es un layout vertical. En diseño creamos 3 layouts Horizontales (azul, naranja y verde) de tamaños proporcionales de 30, 60 y 120px de lado respectivamente. Los 2 layouts Horizontales amarillos son de igual ancho que el layout verde (120px). Los espaciadores Expansibles mantienen la proporción en sentido horizontal.
El layout azul siempre ocupará la cuarta parte del ancho del formulario, el naranja la mitad y el verde el total.
En ejecución, la relación del área entre los layouts azul, naranja y verde siempre es constante e igual a 1,4,8.
Los espaciadores expansibles son proporcionales
Los espaciadores Expansibles consiguen anclar controles en coordenadas exactas y se adaptarán proporcionalmente al tamaño de la pantalla.
En el siguiente formulario queremos que el marge derecho sea siempre la mitad que el margen izquierdo y el margen superior igual al inferior. En diseño colocamos los espaciadores expansibles y el control con los tamaños proporcionales planteados.
En ejecución el formulario mantiene las mismas proporciones cuando ha duplicado el tamaño respecto al que tenía en diseño.
Superposición parcial de controles
Ya sabemos que para superponer 2 elementos en el formulario necesitamos un layout Grid. Pero necesito ahora superponer elementos de forma parcial, como cuando montamos un puzzle.
Planteamos el siguiente Puzzle con 4 piezas que tienen una parte de solapamiento:
La 4 piezas en diseño las colocamos en un layout Grid sin solapamiento. En este caso no encajan.
Si en diseño solapamos las 4 piezas tampoco se obtiene el resultado deseado.
Hagamos uso de los layouts y espaciadores proporcionales. Planteamos un diseño con 2 layouts proporcionales, uno Horizontal y otro Vertical y 2 espaciadores. El layout Vertical es el que engloba el resto de controles. La pieza es un dibujo proporcional con la propiedad Aspecto en Estirar / Encoger.
Manteniendo en diseño las adecuadas proporciones obtenemos en ejecución la pieza ocupando la cuarta parte del formulario. No olvidemos poner a 0 todos los espaciados y márgenes de los layouts.
Haciendo lo mismo con el resto de piezas y solapando los cuatro layouts Verticales obtenemos el resultado deseado.
Ya tenemos un marco que pueda encuadrar, por ejemplo, un gráfico de tipo Tarta.
Como siempre encuadramos el gráfico en un layout proporcional estableciendo los márgenes con espaciadores proporcionales. El gráfico deberá tener los márgenes a cero y el fondo transparente para que funcione correctamente el solapamiento con otros layouts del Grid.
Juntamos todo añadiendo leyendas y un título y este es el resultado final.
Con semejante cantidad de controles solapados entenderemos la importancia de disponer en tiempo de diseño de eficaces herramientas de edición.
En la versión 24 se han incorporado dos nuevas funcionalidades, la selección de layouts solapados y la posibilidad de desactivarlos. Por supuesto, poder agrupar los controles y desactivarlos facilitaría enormemente el trabajo de diseño y edición de formularios complejos.
Conclusiones
Los layouts y espaciadores expansibles son elementos básicos en el diseño y ejecución de nuestros formularios.
Hemos hecho un repaso, quizás algo peculiar, de algunas aplicaciones de los layouts que considero interesantes. Espero que se haya entendido el significado de la propiedad «Ancho en layout Proporcional» para que a partir de ahora no sea un problema colocar y dimensionar los controles del formulario exactamente dónde y cómo queremos.
Algo de código para terminar
Los layouts son controles cuya propiedad Tipo de control es igual a 22. Los espaciadores expansibles son Tipo de control igual a 23.
Con este código se puede obtener el Id y el tipo de control de todos los elementos de un formulario.
// Obtiene todos los controles del Formulario y Separadores de Formularios
var oForm = theRoot.dataView()
var oFormInfo = theRoot.objectInfo()
var nNumObj = oFormInfo.subObjectCount(VObjectInfo.TypeControl)
var oListaCtr = [], cCtr = ""
// Los objetos se recorren con subObjectInfo que devuelve otro VObjectInfo
for ( var numControl = 0; numControl < nNumObj ; numControl++ ) {
objInfo = oFormInfo.subObjectInfo(VObjectInfo.TypeControl, numControl)
// La función objInfo.id() devuelve el nombre del Control
// La función objInfo.propertyData(0) devuelve el Tipo de Control
cCtr = objInfo.**propertyData(0)** + " - " + objInfo.id()
oListaCtr.push(cCtr)
// Comprobamos el **Separador de formularios**
if (objInfo.propertyData(0) == 13) {
var oSep = oForm.control(objInfo.id())
// Recorremos los Separadores de formularios
for (var numSep = 0; numSep < oSep.count ; numSep++ ) {
var oFormSep = oSep.form(numSep)
var oFormSepInfo = oFormSep.objectInfo()
var nNumObjSub = oFormSep.controlCount()
cCtr = "SubForm - " + oFormSepInfo.id()
oListaCtr.push(cCtr)
for ( var nCtrl = 0; nCtrl < nNumObjSub ; nCtrl++ ) {
objetoSub = oFormSepInfo.
subObjectInfo(VObjectInfo.TypeControl, nCtrl)
cCtr = "SubCtrl " +
objetoSub.propertyData(0) + " - " + objetoSub.id()
oListaCtr.push(cCtr)
}
}
}
}
alert (JSON.stringify(oListaCtr))
Espero que después de estar «master-class» sobre los layouts del maestro Satué no quede ninguna duda al respecto…