organización de widgets en wxpython
TRANSCRIPT
Organización de widgets en wxPython (Parte II)
Publicado por Pablo Tilli a las03:14 .
Etiquetas:Python
Si has llegado aquí mediante un buscador o por simple casualidad, te cuento que
estas en la segunda parte de un tutorial que empieza AQUI.
Trabajando con los Sizers
Todos los sizers tienen algunas características en común; y otras, que hacen que
cada uno de ellos sea único. Podríamos ver una a una cuales son las similitudes y
cuales las diferencias para luego pasar a la practica con cosas concretas, pero no
quiero que tengas que leer un montón de teoría antes de poder ver algo de
practica, es por esto que iré intercalando la teoría y la practica de manera que el
tutorial no se te haga muy tedioso. Creo que va a ser mas fácil partir de un sizer en
particular (el GridSizer en este caso), y luego ir explicando en que se parecen y en
que se diferencian a medida que vayamos avanzando con cada uno de los otros
sizers.
Hay distintos enfoques a la hora de trabajar con interfaces gráficas con Wxpython:
1- Escribir todo el código necesario para ir generando la interface gráfica; llamando
a las funciones de wxPython que permiten crear los distintos widgets (botones,
listas, etc.) desde la propia aplicación que estemos desarrollando.
2- Generar un archivo XML que describe la interface gráfica, y que luego podemos
cargar desde la aplicación.
3- Utilizar un IDE para diseñar la interface gráfica. En este método, trabajamos de la
misma manera que en método 2, excepto que es el propio IDE el que genera el
archivo XML para que después lo carguemos desde nuestra aplicación.
De los tres métodos, vamos a empezar por el tercero. El IDE que vamos a usar
seráwxFormBuilder, pero existen otros como XRCed y wxGlade por nombrar sólo
algunos mas. Este método es el mas práctico porque (al igual que en el segundo)
logramos independizar la parte gráfica de la aplicación, del resto del código de la
aplicación en sí. A diferencia del segundo método, es mucho mas fácil delegar la
tarea de escribir el archivo XML en el IDE. Mas adelante veremos el primero y
segundo metodo tambien.
En mi caso trabajo sobre Ubuntu Intrepid Ibex (8.10), pero wxFormBuilder es un IDE
multiplataforma. Por lo menos en el caso de la mayoría de las distribuciones
populares de Linux, ya viene en los repositorios. Los usuarios de Windows y Mac los
pueden descargar desde el sitio del proyecto. wxFormBuilder es libre y gratuito.
A continuación te muestro una captura de pantalla para que te vayas familiarizando
con el programa:
Una vez que tenemos wxFormBuilder instalado en nuestro sistema, ya estamos
listos para empezar a trabajar.
Antes de poder crear un Sizer, debemos generar algún tipo de formulario que lo
contenga. Para este ejemplo crearemos un Frame como contenedor, el cual
visualmente no es mas que una clásica ventana (con su borde, botones de cerrar,
minimizar y maximizar, etc). Para esto vamos a la solapa “Forms” de la paleta de
componentes de wxFormBuilder y pulsamos el botón "Frame". Veamos una imágen
para que se entienda mejor:
Luego de pulsar el
botón “Frame”, el resultado será el siguiente:
Ahora que tenemos
creado el Frame, ya podemos agregar nuestro Sizer, que como dije antes, será un
GridSizer. Para logra esto, lo hacemos del mismo modo que agregamos el Frame,
sólo que ahora vamos a la solapa “Layout” y pulsamos el botón “wxGridSizer”:
El resultado lo vemos en la siguiente captura:
En la imágen se
muestran resalatadas 3 cosas importantes:
1- El panel izquierdo de wxFormBuilder ("Object Tree"), nos muestra toda la
interface en forma de árbol. En la imagen podemos apreciar que la raíz es el
proyecto en si (Proyect1 en este caso), inmediatamente después se encuentra el
Frame (llamado MyFrame2), y por último, dentro del Frame esta el GridSizer que
acabamos de agregar (cuyo nombre es gSizer1).
2- Si miramos bien dentro del Frame que creamos, veremos que el GridSizer esta
representado por un rectángulo rojo que ocupa todo el interior del Frame.
3- El panel derecho de wxFormBuilder ("Object Properties"), nos muestra las
propiedades del objeto que esta seleccionado actualmente en el Editor.
Para ver como se comporta el GridSizer, iremos agregando algunos widgets dentro
de éste. A modo de ejemplo, agregaremos cuatro botones. Esto realmente no tiene
ninguna complejidad, ya que el modo de trabajo es el mismo que usamos hasta
aquí. Ante todo, verificamos que esté seleccionado "gSizer1" en el "Object Tree" de
wxFormBuilder; de modo que el IDE "sepa" que los botones irán dentro del
GridSizer, luego vamos a la solapa“Common” y pulsamos el botón “wxButton”.
Esto agregará el primer botón al GridSizer.
Tras pulsar el botón “wxButton”, el Editor quedará como se ve a continuación:
Como podemos apreciar
el botón se creo en la esquina superior izquierda del GridSizer, ahora crearemos el
segundo botón. Para esto sólo pulsamos nuevamente el botón“wxButton”, con lo
cual el Editor ahora quedara así:
El segundo botón fue creado a la derecha del otro (pero con bastante espacio de
por medio). Sólo nos falta crear los dos botones restantes. Si has llegado hasta acá,
seguramente te imaginaras como hacerlo … claro, pulsas dos veces mas el
botón“wxbutton” (recuerda que debe estar seleccionado "gSizer1" en el "Object
Tree"). El resultado final que debes ver en el Editor es el siguiente:
Como te habrás dado cuenta, los últimos dos botones se encuentran en una
segunda fila (pero siempre alineados verticalmente con la primera). Tal vez todavía
no te hayas dado cuenta (o tal vez si), pero la distribución que conseguimos tiene
una lógica. Con la siguiente imagen tal vez lo veas mas claro:
Como muestra la imágen, y como el nombre del Sizer lo indica, un GridSizer no es
mas que una grilla, donde en cada celda podemos ir agregando el widget que
necesitemos. Hasta aquí hemos visto como agregar un Frame, un GridSizer y cuatro
botones dentro de éste.
Es importante que le vayas prestando atención al "Object Tree" de wxFormBuilder.
Este "árbol" nos da una clara visión de como se relacionan los distintos elementos
de nuestra interface. Entender este “árbol” también te servirá mucho si en algún
momento decides trabajar con el IDE XRCed (en otro tutorial lo veremos).
Veamos un poco mas en detalle el GridSizer.
Grid Sizer (wx.Grid Sizer)
Como ya hemos dicho, el GridSizer consiste en una grilla bidimensional, en la cual
se organizan los distintos widgets que necesitemos. Gráficamente un GridSizer no
es mas que una grilla, donde en cada celda podemos posicionar un widget.
El primer widget que se agrega a un GridSizer se ubica en la esquina superior
izquierda de la grilla; el resto se ubican de izquierda a derecha, y al llegar a la
ultima columna de una fila, se continua en la primera columna de la fila
inmediatamente inferior hasta llegar a la ultima celda de la grilla, que corresponde
a la esquina inferior derecha de la misma. Este comportamiento, lo habrás visto
bien claro si fuiste haciendo el ejemplo de agregar cuatro botones dentro del
GridSizer con wxFormBuilder; cada vez que pulsas el botón que agrega un
wxButton, puedes observar donde se posiciona el botón dentro de la grilla. Si no
hiciste el ejemplo, te invito a que lo hagas!.
Al redimensionar un GridSizer, cada celda de este, agranda o disminuye su tamaño
proporcionalmente, pero por defecto, los widgets contenidos en cada una de las
celdas, mantienen su tamaño original, y quedan “anclados” a la esquina superior
izquierda de la celda en la que se encuentran. Veamos una captura, donde vemos 2
veces una misma ventana, pero antes y después de ser redimensionada. La
ventana contiene un GridSizer que tiene cuatro botones en su interior (el ejemplo
que hicimos antes).
En la imagen, se puede
apreciar como las cuatro celdas, crecen de manera idéntica, siendo en todo
momento todas las celdas del mismo alto y ancho, pero como vemos los widgets no
cambiaron su tamaño. Si bien todas las celdas tienen el mismo tamaño, no
necesariamente el alto de las filas es igual al ancho de las columnas.
Como hemos visto; al crear un GridSizer con wxFormBuilder, nuestra grilla es de 2 X
2 en forma predeterminada, pero obviamente tenemos una forma de cambiar esto.
Entre las propiedades particulares del GridSizer se encuentran Rows y Cols, las
cuales nos permiten establecer la cantidad de filas y columnas respectivamente. Si
lo deseamos, también podemos especificar que haya un espacio entre las distintas
celdas; para esto contamos con la propiedad hgap para crear un espacio entre las
filas, y vgap para lograr el espaciado entre las columnas. El valor de vgap y hgap,
es un numero entero que representa el espaciado en pixeles. En la imagen
siguiente, vemos una una grilla de 3 X 2, con un espacio horizontal entre las celdas
de 2px y un espaciado vertical entre celdas de 3px:
Para lograrlo, simplemente seleccionamos el GridSizer ("gSizer1") desde el “Object
Tree” y luego establecemos los valores en el panel de propiedades (rows=2,
cols=3, vgap=3 y hgap=2).
Si bien dijimos que todas las celdas tienen el mismo tamaño, esto no quiere decir
que todos los elementos que estén en cada una de ellas, también deban tener las
mismas dimensiones ni tampoco la misma posición dentro la celda.
Como dijimos antes, al agregar un elemento en un GridSizer, por defecto éste
queda posicionado en la esquina superior izquierda de la celda que le corresponda,
y su tamaño NO se ve afectado al cambiar el tamaño del sizer. Este
comportamiento puede ser modificado a través de los Flags. Los Flags entran
dentro de las características comunes a todos los widgets que se encuentren
contenidos en un Sizer. Para entender mejor de que hablamos, veremos cuales son
los Flags y para que sirve cada uno de ellos.
Flags para establecer la alineación de los widgets
Las opciones disponibles para alinear los widgets que agregamos a los Sizers son
las siguientes:
wx.ALIGN_TOP: El widget es alineado en la parte superior de la celda en la que se
encuentre, si se omite, esta es la opcion por defecto.
wx.ALIGN_BOTTOM: El widget se alinea en la parte inferior de la celda en la que
es insertado.
wx.ALIGN_LEFT: El widget es alineado a la izquierda dentro la celda en la que se
encuentre, si se omite, esta es la opcion por defecto.
wx.ALIGN_RIGHT: El widget es alineado a la derecha dentro la celda en la que se
encuentre.
wx.ALIGN_CENTER_HORIZONTAL: El widget es centrado en forma horizontal. Se
omite el valor de wx.ALIGN_LEFT y wx.ALIGN_RIGHT.
wx.ALIGN_CENTER_VERTICAL: El widget es centrado en forma vertical. Se omite
el valor de wx.ALIGN_TOP y wx.ALIGN_BOTTOM.
wx.ALIGN_CENTER: El widget se alinea en la centro de la celda en la que es
insertado. En este caso se omiten todas las opciones anteriores.
wx.EXPAND: El widget toma el mismo tamaño que la celda en la que se encuentra.
wx.FIXED_MINSIZE: El widget mantiene siempre su tamaño mínimo (Luego
volveremos sobre este punto).
wx.SHAPED: El widget cambiara su tamaño de forma proporcional, manteniendo
su relación de aspecto (luego lo veremos con un ejemplo, para que se entienda
mejor).
wx.GROW: Funciona igual que wx.EXPAND.
Flags para establecer un borde (espacio) entre los widgets
Además de poder cambiar la alineación de los widgets, tenemos la
posibilidad de dejar un borde (espacio) entre el widget y la celda que lo
contiene. Para establecer este valor, podemos combinar las siguientes
opciones junto con las de alineación que vimos anteriormente:
wx.TOP: Establece que el espacio especificado en la propiedad “border”,
sea aplicado en la parte superior del widget.
wx.LEFT: Establece que el espacio especificado en la propiedad “border”,
sea aplicado a la izquierda del widget.
wx.RIGHT: Establece que el espacio especificado en la propiedad “border”,
sea aplicado a la derecha del widget.
wx.BOTTOM: Establece que el espacio especificado en la propiedad
“border”, sea aplicado en la parte inferior del widget.
wx.ALL: El espacio se establece a todos los lados del widget (Arriba,
Izquierda, Derecha y Abajo). Es la suma de las cuatro opciones anteriores
juntas.
Luego veremos algunas imágenes donde se puedan apreciar los resultados
de combinar estos valores de distintas formas.
Para que esta segunda parte no se haga mas larga, vamos a dejar aquí. En
esta parte, hemos avanzado bastante, y cada vez estamos mas cerca de
poder crear una interface mas “real” (léase útil).
Repasando un poco, hasta aquí dijimos que existen tres métodos para
trabajar con interfaces gráficas con wxPython, y que por ahora usaremos
la alternativa del IDE. Estuvimos viendo como se trabaja con
wxFormBuilder, hablamos de los Flags, y tenemos una idea mas clara de
como funciona el GridSizer.
Para dominar de forma fluida el diseño de interfaces gráficas con
wxPython, se requiere mucha práctica. Al principio puede ser un poco
desalentador, ya que cuesta mucho lograr lo que uno tiene en mente; y
sobre todo si eres un desarrollador que viene de otros lenguajes (como
Visual Basic, por ejemplo) donde la forma de trabajo es bastante distinta,
pero con el tiempo te darás cuenta de las ventajas que tiene esta manera
de hacer las cosas, y podras ir logrando lo que te propones.
Cualquier duda o sugerencia, puedes comentar.
... continuando con los Flags
En la segunda parte de este tutorial, les había prometido continuar con el tema de los Flags, y esto es lo que trataremos justamente ahora.
El primer caso que veremos, será sobre el Flag de alineación wx.ALIGN_CENTER:
En la imagen podemos apreciar el Editor (Arriba) y el panel de propiedades (Abajo) de wxFormBuilder. En el Editor dibuje una grilla de color rojo, para que tengas de
referencia el tamaño de cada celda. Como ya habíamos dicho, en un GridSizer todas las celdas son iguales, y de echo esto lo puedes apreciar en la imagen, pero como puedes ver, en la primera celda (Fila 0, Col. 0) el widget se encuentra con una alineación distinta a la del resto. Para lograr esto, en el Editor debes seleccionar el widget con el que quieres trabajar, y luego en el panel de propiedades desplegar la sección Flags (lo puedes ver en la parte de abajo de la imagen), y activar la opción wxALIGN_CENTER.
En la captura de pantalla, se pueden ver desplegados todos los Flags. Si quisiéramos cambiar alguno de ellos, simplemente la activamos o desactivamos desde el checkbox que tienen a la derecha.
En el siguiente ejemplo vamos a combinar algunos de ellos:
En este ejemplo vemos que cada una de los widgets posee una alineación distinta. Las opciones aplicadas en cada caso son las siguientes:
1- wx.ALIGN_CENTER
2- wx.ALIGN_BOTTOM + wx.ALIGN_RIGHT
3- wx.ALIGN_CENTER_VERTICAL
4- wx.ALIGN_CENTER_HORIZONTAL + wx.ALIGN_CENTER_BOTTOM
5- wx.ALIGN_CENTER_VERTICAL + wx.ALIGN_RIGHT
6- wx.ALIGN_BOTTOM
Si miras con detenimiento en la imagen, te puedes dar cuenta que los widgets nunca llegan hasta el borde de las “celdas virtuales” (que por claridad, yo las dibuje en rojo). Esto se debe a que el valor de la propiedad “border” esta en 5, y esta aplicado a los cuatro lados de los widgets (wx.ALL). En el ejemplo siguiente, variaremos los bordes (además de la alineación):
Las opciones de cada widget de la imagen son los siguientes:
1- border=0 + wx.ALIGN_RIGHT + wx.ALL
2- border=30 + wx.ALIGN_RIGHT + wx.RIGHT
3- border=40 + wx.LEFT + wx.TOP
4- border=30 + wx.ALIGN_LEFT
Ahora veremos un ejemplo donde usaremos los Flags wx.EXPAND, wx.SHAPED ywx.GROW.
Los Flags utilizados en cada widget de la imagen, son los siguientes:
1- border=0 + wx.ALL + wx.EXPAND
2- border=5 + wx.ALL + wx.SHAPED
3- border=20 + wx.ALL + wx.EXPAND
4- No hay widget en esta celda.
Si bien en las celdas 1 y 3 estamos usando el Flag wx.EXPAND, y por lo tanto los widgets deben ocupar la totalidad del espacio de la celda en la que estén, pareciera que en la celda 3 no se cumple, pero en realidad si. La diferencia entre las dos celdas, es que la primera tiene un borde de 0px en todos sus lados, y la celda 3
tiene un borde de 20px en todos sus lados, por lo que puedes deducir que con el Flag wx.EXPAND, el widget se expande, pero contempla los bordes especificados en la propiedad “border”.En el caso de la celda 2, es difícil entender como funciona el Flag wx.SHAPED, así que te voy a mostrar dos imágenes donde se encuentra la misma ventana, pero en dos tamaños distintos:
En estas ultimas 2 capturas, vemos que la celda 2, al utilizar el Flag wx.SHAPED,
hace que al agrandarse o achicarse la ventana, el widget lo haga también en forma
proporcional. Para que lo veas aun mejor, aislé el botón de la celda 2, de las dos
imágenes y aquí los tienes uno debajo del otro:
En este punto seria bueno que experimentes tu mismo combinando los distintos
Flags que hemos visto. El Flag wx.GROW no se encuentra disponible en
wxFormsBuilder, y esto es así porque en realidad (como dijimos antes) es lo mismo
que wx.EXPAND.
Por ahora llegaremos hasta aquí. A partir de la próxima parte del tutorial,
seguiremos viendo el resto de los Sizers. Si bien esta parte no fue muy extensa, era
necesaria para que podamos continuar.
Recuerda que puedes dejar tus dudas, sugerencias, experiencias o lo que quieras
para que todos podamos aprender de ti también.