Desarrollo de interfaces gráficas en Python 3 con Tkinter

Tekst
Loe katkendit
Märgi loetuks
Kuidas lugeda raamatut pärast ostmist
Šrift:Väiksem АаSuurem Aa

Unidad 3



POSICIONAMIENTO Y DISEÑO





En el programa anterior, la interfaz se componía de un único

widget

. Pero, en la práctica, hasta la aplicación más sencilla que desarrolle requerirá más de uno. En ese caso, ¿cómo se indicaría la posición que debe ocupar cada uno de ellos en la ventana principal? La respuesta es haciendo uso de alguno de los tres gestores de geometría proporcionados por Tkinter:



•pack. Organiza los

widgets

 horizontal o verticalmente (por defecto, de arriba hacia abajo).



•grid. Distribuye los

widgets

 en cuadrícula, con una estructura similar a una tabla. Es el recomendado en interfaces gráficas complejas.



•place. Coloca los

widgets

 en coordenadas concretas.








Los gestores de geometría se utilizan tanto para distribuir los

widgets

 en la ventana principal como dentro de otros

widgets

 contenedores (por ejemplo, los

frames

 y los paneles que conocerá más adelante).



Veamos en detalle cómo funciona cada uno de ellos.





3.1

 EL GESTOR DE GEOMETRÍA

PACK



Este gestor de geometría distribuye los

widgets

 en horizontal o en vertical. Para utilizarlo, se tiene que invocar el siguiente método, común a todos ellos:








Las opciones disponibles son las siguientes:



•expand. Establece el espacio que el gestor de geometría asignaría al

widget

 dentro de la ventana principal (o

widget

 contenedor). Si su valor fuera True, sería el máximo disponible.



•fill. Determina si el

widget

 debe ocupar todo el espacio asignado por el gestor de geometría o mantiene sus propias dimensiones. En el último caso, el valor que tomaría esta opción sería NONE (predeterminado). Por el contrario, si pudiera crecer/disminuir para ocupar el área máxima disponible, se debería indicar si lo haría a lo ancho (X), a lo alto (Y), o en ambas direcciones (BOTH).



•side. De forma predeterminada, este gestor de geometría ubica los

widgets

 de arriba hacia abajo (su valor es TOP). Aquí se puede cambiar esta forma de organizarlos para que se coloquen de abajo hacia arriba (BOTTOM), de izquierda a derecha (LEFT) o de derecha a izquierda (RIGHT).








Recuerde que, para usar cualquier constante, previamente deberá haberla importado del módulo Tkinter. También puede usar directamente el valor que tiene cada una de ellas (por ejemplo, el de BOTTOM es "bottom", a TOP le correspondería "top", etc.).



Para que pueda entender el funcionamiento conjunto de estas opciones, en las siguientes imágenes (tomadas de

https://stackoverflow.com/questions/28089942/difference-between-fill-and-expandoptions-for-tkinter-pack-method

) se puede apreciar el efecto producido por estas opciones sobre una etiqueta, cuyo texto indica los valores asignados a cada una de ellas.



En la primera, el valor de la opción expand es False:








En esta segunda, el valor de la opción expand es True:








Como puede observar, muchas de las combinaciones de las tres opciones dan los mismos resultados, lo que indica que podrían obviarse. Así, por ejemplo, el resultado de la primera fila, en el que la etiqueta aparece centrada en la ventana, se podría conseguir utilizando únicamente la opción:








Además de las opciones anteriores, las siguientes opciones permiten separar un

widget

 de los límites de la ventana principal (o

widget

 contenedor) y del resto de los

widgets

:



•ipadx. Número de píxeles con los que se rellena el

widget

 horizontalmente, dentro de sus bordes.



•ipady. Número de píxeles con los que se rellena el

widget

 verticalmente, dentro de sus bordes.



•padx. Número de píxeles con los que se rellena el

widget

 horizontalmente, fuera de sus límites.



•pady. Número de píxeles con los que se rellena el

widget

 verticalmente, fuera de sus límites.



En la siguiente imagen, puede ver gráficamente cómo afectan estas opciones a la posición de una etiqueta (situada en la esquina superior izquierda de la ventana principal) y al texto que contiene (justificado a la izquierda). Se supone que, al crear tanto la ventana como la etiqueta, se han fijado sus dimensiones de forma explícita:








Si no se hubieran indicado las dimensiones de la ventana, esta se ajustaría a las de los

widgets

 que contuviera (en este caso, a las de la etiqueta). Por el mismo motivo, si no se hubiera especificado el ancho y el alto de la etiqueta, su tamaño correspondería al del texto que contuviera. La imagen de más abajo muestra gráficamente el resultado obtenido en ese caso:








Por último, para dejar de mostrar un

widget

 en la ventana principal (o

widget

 contenedor), se debe ejecutar el método:








Si quisiera volver a mostrar dicho

widget

, seguramente que no lo haría en la misma posición donde se encontraba antes de desaparecer, sino en aquella que le asigne el gestor de geometría una vez invocado el método pack() del resto de

widgets

.



Para probar el funcionamiento de este gestor de geometría, puesto que el único

widget

 que conoce por ahora son las etiquetas, creará cuatro etiquetas que distribuirá de dos formas diferentes. En primer lugar, lo hará según el comportamiento por defecto, es decir, de arriba hacia abajo:








Lo primero que se debe hacer es importar las clases que se van a utilizar del paquete Tkinter (Tk y Label):








Luego, se crea la ventana principal:








Acto seguido, se hace lo mismo con las cuatro etiquetas:








Finalmente, se muestran en la ventana con el método pack(). Estas se rodean con un borde de un grosor de 10 píxeles de ancho y 5 de alto. Eso hace que la primera etiqueta se aleje del límite superior de la ventana 5 píxeles (tal como se indicó en la opción pady), al igual que la última etiqueta del borde superior. Sin embargo, la separación vertical entre etiquetas es de 10 píxeles (5 del superior y 5 del inferior). Con los límites derecho e izquierdo de la ventana también se mantiene un espacio de 10 píxeles, tal como se ha establecido en la opción padx:








El resultado, como cabía esperar, son las cuatro etiquetas colocadas unas debajo de otras. La imagen de la izquierda muestra el resultado de la ejecución del programa, mientras que la imagen de la derecha muestra gráficamente el efecto de las opciones padx y pady, con las que se han separado las etiquetas de los límites de la ventana principal y entre sí:













Al utilizar las opciones padx y pady, ya no es necesario incluir los retornos de carro (carácter ‘\n’) ni los espacios en el texto de la etiqueta.








Para que el espacio que se establezca a la derecha de un

widget

 sea diferente que el de la izquierda, asigne una tupla con dos valores a la opción padx. Esto mismo es igualmente válido para la opción pady.

 



En el siguiente programa, se utiliza la opción side para situar las etiquetas en cada uno de los lados de la ventana:








De nuevo, se importan las clases Tk y Label de la librería Tkinter, pero, en este caso, también se hace lo mismo con las constantes TOP, BOTTOM, LEFT y RIGHT, que determinarán la posición de cada una de las etiquetas:








Para que el efecto sea más visible, una vez creada la ventana principal, esta se configura con un tamaño de 200 × 200 píxeles:








Las etiquetas se crean de la misma forma que en el programa anterior, por lo que no se van a dar explicaciones adicionales.



El principal cambio se produce al mostrarlas en la ventana principal con el método pack(), ya que ahora se añade la opción side para fijar la posición en la que se va a situar cada una de ellas. Además, dependiendo del lado de la ventana en el que se coloquen, se utilizarán las opciones padx o pady para separarlas del borde:








Ejecute el programa. Obtendrá el resultado mostrado en la siguiente imagen:










3.2

 EL GESTOR DE GEOMETRÍA

GRID



Cuando el diseño de una interfaz es complejo, puede resultar difícil y engorroso trabajar con el gestor de geometría

pack

. Por este motivo, es preferible utilizar el gestor

grid

, y dejar el anterior para las más sencillas. Con

grid

, la distribución de los

widgets

 se realiza de una manera más flexible, utilizando un diseño de cuadrícula (de ahí su nombre, ya que

grid

 se puede traducir por “cuadrícula”). De esta manera, cada

widget

 se sitúa en la celda determinada por la intersección de una fila y una columna.








Nunca use los gestores pack() y grid() dentro de la misma ventana, porque los algoritmos que utilizan para calcular las posiciones de los

widgets

 no son compatibles.



La forma de utilizarlo es invocando el siguiente método, presente en todos los

widgets

:



grid(

opciones

)



Las opciones posibles son:



•column. Columna en la que se va a colocar el

widget

 (por defecto, la 0).



•columnspan. Número de columnas que ocupa el

widget

 (por defecto, una).



•row. Fila en la que se va a colocar el

widget

 (por defecto, la 0).



•rowspan. Número de filas que ocupa el

widget

 (por defecto, una).



•ipadx. Número de píxeles con los que se rellena el

widget

 horizontalmente, dentro de sus bordes.



•ipady. Número de píxeles con los que se rellena el

widget

 verticalmente, dentro de sus bordes.



•padx. Número de píxeles con los que se rellena el

widget

 horizontalmente, fuera de sus límites.



•pady. Número de píxeles con los que se rellena el

widget

 verticalmente, fuera de sus límites.



•sticky. Determina dónde se ubica el

widget

 dentro de la celda (por defecto, estaría centrado). Como si de los puntos cardinales de una brújula se tratara, el valor de esta opción permite situarlo en una esquina (NE, SE, SW o NW) o centrado en cada uno de los lados de la celda (N, E, S y W). La siguiente imagen trata de mostrarlo gráficamente. El cuadrado exterior representa la celda, y los más pequeños representan

widgets

 situados en su interior, según el valor de esta opción.













El efecto de dichos valores solo sería apreciable si el tamaño del

widget

 fuera menor que el de la celda.



Si quisiera adaptar el ancho del

widget

 para que coincida con el de la celda, el valor de esta última opción debería ser EW. Si lo que desea es que tenga el mismo alto, asígnele el valor NS. Para que el tamaño del

widget

 corresponda con el de la celda en ambas dimensiones, el valor utilizado sería NSEW.



La siguiente imagen muestra gráficamente cómo cambia el tamaño del

widget

 con el de la celda en función del valor de esta opción:








Cuando se utiliza este gestor de geometría, el ancho de una columna será el de su celda más ancha. De la misma manera, la altura de una fila será la correspondiente a la celda más alta. Si desea cambiar este comportamiento, use los siguientes métodos de la ventana principal (o

widget

 contenedor):








Con ellos, podrá configurar aspectos del tamaño de una columna o de una fila concreta empleando diferentes opciones, entre la que se encuentran:



•minsize. Tamaño mínimo de la columna o de la fila indicada, en píxeles. Si no hubiera nada dentro, esta no aparecería.



•weight. Permite que el tamaño de una columna o de una fila se adapte al de la ventana principal (o

widget

 contenedor). El valor proporcionado establece el peso relativo de esta columna o fila respecto de las demás a la hora de distribuir el espacio existente.



Para entender esta última opción, imagine que la ventana principal (representada por el objeto ventana_principal) se divide en una cuadrícula de dos filas y dos columnas, tal como se muestra en la siguiente imagen:








Observe el resultado obtenido al añadir estas sentencias:








Ahora, el espacio se distribuye en la proporción de tres cuartos para la primera columna y un cuarto para la segunda. Además, al haber utilizado esta opción, el ancho de las columnas se adaptará al de la ventana cuando esta se modifique (en la proporción indicada).



El mismo razonamiento serviría para las filas. En ese caso, las sentencias que tendrían que añadirse son:








Por último, para dejar de mostrar un

widget

 situado previamente en la ventana principal (o

widget

 contenedor), se debe ejecutar el método:








Si volviera a mostrar dicho

widget

, lo haría en la misma posición donde se encontraba antes de desaparecer.



Con el fin de practicar con este nuevo gestor de geometría, va a desarrollar un programa que muestre una etiqueta en cada una de las celdas de una cuadrícula, cuyo texto indique el número de la fila y la columna en la que está situada; por ejemplo, el texto de la etiqueta situada en la fila 1 y la columna 2 será Etiqueta12, tal como se muestra a continuación:








El código del programa es el siguiente:








En primer lugar, se importan las conocidas clases Tk y Label:








Luego, se declaran las constantes que definen el número de filas y columnas que va a tener la rejilla en la que se van a distribuir las etiquetas:








A continuación, se crea la ventana principal:








El código principal de este programa está en los bucles for, mediante los que se crean y se sitúan las etiquetas en las posiciones correspondientes. El bucle exterior recorre las filas, mientras que el interior recorre las columnas:








Las etiquetas se crean con un texto que contiene el número de la fila y de la columna donde se van a colocar. La opción bg determina que el color de fondo sea amarillo:













Más adelante, estudiará todas las opciones de configuración de las etiquetas.



La siguiente sentencia sitúa cada etiqueta en la ventana principal con el método grid(). En este método se utilizan cuatro opciones: las que identifican la fila y la columna en la que deben ubicarse (row y column) y las que establecen los márgenes alrededor de cada una de ellas para separarlas entre sí (padx y pady):








El resultado obtenido al ejecutar este programa lo puede ver a continuación:








Ahora, redimensione la pantalla. Como podrá observar, las etiquetas se mantienen con el mismo tamaño y en la misma posición:








Si quiere que las celdas se adapten al tamaño de la ventana, deberá utilizar los métodos columnconfigure() y rowconfigure(), tal como aparece en la nueva versión de este mismo programa:








Ejecútelo de nuevo. En este caso, al aumentar el tamaño de la ventana, las celdas crecen para ocupar todo el espacio libre, pero no las etiquetas:








Para que estas ocupen todo el espacio de las celdas, deberá utilizar la opción sticky del método grid(). En el programa anterior, sustituya la sentencia








por esta otra:








El resultado que obtendrá ahora demuestra que tanto las celdas como las etiquetas que hay en su interior se ajustan al tamaño de la ventana en todas las circunstancias:

 










3.3

 EL GESTOR DE GEOMETRÍA

PLACE



Este gestor, a diferencia de los dos anteriores, permite colocar los

widgets

 en coordenadas específicas de la ventana principal (o

widget

 contenedor). Para utilizarlo, se debe llamar al siguiente método, disponible en todos los

widgets

:



place(

opciones

)



Las opciones de las que dispone son:



•anchor. Indica cómo situar el

widget

 en la ventana, tomando como referencia las coordenadas (x, y) contenidas en las opciones x e y (se describen más abajo). Su valor puede ser N, S, E, W, NE, NW (predeterminado, esquina superior izquierda del

widget

), SE, SW o CENTER. La siguiente imagen lo muestra gráficamente (el cuadrado representa el

widget

 tal como quedaría ubicado respecto del punto de referencia, dependiendo del valor de esta opción):








•bordermode. Determina si las coordenadas especificadas usan como referencia el interior del

widget

 contenedor (INSIDE, valor por defecto) o el exterior (OUTSIDE).



•height, width. Alto y ancho del

widget

 en píxeles.



•relheight, relwidth. Ancho y alto del

widget

, tomado de forma relativa al ancho y alto de la ventana principal (o

widget

 contenedor). Por lo tanto, determina sus dimensiones como una fracción de la ventana. Su valor estará comprendido entre 0,0 y 1,0; por ejemplo, si el alto de la ventana principal fuera de 800 píxeles y el valor de la opción relheight de uno de los

widgets

 fuera de 0,25, su alto sería de 200 píxeles. La utilidad de este método es ajustar el tamaño de los

widgets

 al de la ventana (o

widget

 contenedor), cuando esta se modifique.



•x. Coordenada x del punto utilizado como referencia para situar el

widget

 en la ventana principal (o

widget

 contenedor). Su valor viene dado en píxeles. Las coordenadas (0, 0) corresponden a la esquina superior izquierda de la ventana principal (o

widget

 contenedor).



•y. Coordenada y del punto utilizado como referencia para situar el

widget

 en la ventana principal (o

widget

 contenedor).



•relx, rely. Posición relativa, tanto horizontal como vertical, representada como una fracción del alto y ancho de la ventana principal (o

widget

 contenedor). Su valor, de nuevo, estará comprendido entre 0,0 y 1,0; por ejemplo, si el ancho de una ventana fuera de 500 píxeles y relx tuviera el valor 0,5, la coordenada x del

widget

 sería 250. La utilidad de esta opción es mantener la posición de los

widgets

, aunque cambie el tamaño de la ventana.



Por último, para dejar de mostrar un

widget

 situado previamente en la ventana principal (o

widget

 contenedor), se debe ejecutar el método:








A continuación, se describe el código de un programa que muestra una etiqueta centrada en la ventana principal:








Tras importar las clases Tk y Label del paquete Tkinter, se crea la ventana principal, a la que se asigna un tamaño de 200 × 200 píxeles.



Luego, se crea la etiqueta y se muestra en el centro de la ventana con el método place(). Para que esta quede realmente centrada en dicha posición, se asigna el valor "center" al atributo anchor:








Ejecute el programa y observe el resultado obtenido:








El problema viene cuando se cambia el tamaño de la ventana. En ese caso, la etiqueta se mantendrá fija en las mismas coordenadas (100, 100), y dejará de estar centrada:








Para resolverlo, puede evitar que el usuario modifique las dimensiones de la ventana con el método resizable(), o utilizar las opciones relx y rely (en vez de x e y) en el método place(). De esa forma, la posición de la etiqueta será relativa al tamaño de la ventana (no absoluta). Así, cuando la ventana se redimensione, la etiqueta seguirá estando centrada (en la misma posición relativa).



Por lo tanto, sustituya la sentencia








por:








Vuelva a ejecutar el programa. Tal como se acaba de comentar, ahora la etiqueta aparecerá centrada, independientemente de las dimensiones de la ventana:








        <div style=