jueves, 2 de abril de 2020

Tkinter - de marciano a humano - sección 5 - Atributos estándar


Sección 5 - Atributos estándar

Antes de mirar los widgets, echemos un vistazo a cómo se especifican algunos de sus atributos comunes, como tamaños, colores y fuentes.
  • Cada widget tiene un conjunto de opciones que afectan su apariencia y comportamiento: atributos tales como fuentes, colores, tamaños, etiquetas de texto, etc.
  • Puede especificar opciones al llamar al constructor del widget utilizando argumentos de palabras clave como text='PANIC!' o height=20.
  • Después de haber creado un widget, puede cambiar cualquier opción con posterioridad simplemente utilizando el método .config() del widget y puede recuperar la configuración actual de cualquier opción utilizando el método .cget() del widget. (No quiero adelantarme pero puede consultar la Sección 26).

5.1. Dimensiones

Se pueden describir varias longitudes, anchos y otras dimensiones de widgets en muchas unidades diferentes. 
  • Si establece una dimensión en un entero, se supone que está en píxeles.
  • Puede especificar unidades estableciendo una dimensión en una cadena que contenga un número seguido de:
Tabla 3: Unidades dimensionales
c
centímetros
i
pulgadas
m
milímetros
p
puntos de la impresora (aproximadamente 1/72”)

5.2. El sistema de coordenadas


Como en la mayoría de los sistemas de visualización contemporáneos, el origen de cada sistema de coordenadas está en su esquina superior izquierda, con la coordenada x aumentando hacia la derecha y la coordenada y aumentando hacia la parte inferior:
La unidad base es el píxel, con el píxel superior izquierdo con coordenadas (0,0). Las coordenadas que especifique como enteros siempre se expresan en píxeles, pero cualquier coordenada puede especificarse como una cantidad acotada; consulte la Sección 5.1, “Dimensiones” (p. 9) .

5.3. Colores


Hay dos formas generales de especificar colores en Tkinter. Puede usar una cadena que especifique la proporción de rojo, verde y azul en dígitos hexadecimales:
  • #rgb ................ Cuatro bits por color
  • #rrggbb ........... Ocho bits por color
  • #rrrgggbbb ...... Doce bits por color
Por ejemplo, '#fff' es blanco, '#000000' es negro, '#000fff000' es verde puro y '#00ffff' es cian puro (verde más azul).
  • También puede usar cualquier nombre de color estándar definido localmente. Los colores 'white' (Blanco), 'black' (Negro), 'red' (Rojo), 'green' (Verde), 'blue' (Azul), 'cyan' (Cian), 'yellow' (Amarillo) y  'magenta' (Magenta) siempre estarán disponibles, aunque otros nombres pueden llegar a funcionar dependiendo de su instalación local, el problema es que cuando distribuya el programa el que reciba su programa deberá tener esos colores disponibles en su instalación.

5.4. Fuentes tipográficas


Dependiendo de su plataforma, puede haber hasta tres formas de especificar el estilo de letra.
  • Como una tupla cuyo primer elemento es la familia de fuentes, seguido de un tamaño (en puntos si es positivo, en píxeles si es negativa), seguido opcionalmente por una cadena que contiene uno o más de los modificadores de estilo bold (negrita), italic (cursiva), underline (subrayado), y overstrike.
Ejemplos: ('Helvetica', '16') para un Helvética regular de 16 puntos, ('Times', '24', 'bold italic') para un Times de 24 puntos en negrita y cursiva. Para una fuente en negrita Times de 20 píxeles, use ('Times', -20, 'bold').
Puede crear un "objeto de fuente" importando el módulo tkFont y utilizando su constructor de clase Font:

import tkFont
font=tkFont.Font (option , ...)

donde las opciones incluyen: 
  • family (familia): El nombre de la familia de fuentes como una cadena.  
  • size (tamaño): La altura de la fuente como un entero en puntos. Para obtener una fuente de n píxeles de altura, use -n. 
  • weight (peso): 'bold' para negrita, 'normal' para peso regular. 
  • slant (sesgado): 'italic' para cursiva, 'roman' para no sellado. 
  • underline (subrayado): 1 para texto subrayado, 0 para normal. 
  • overstrike (sobrecarga): 1 para texto sobrecargado, 0 para normal.
Por ejemplo, para obtener una negrita cursiva Helvetica de 36 puntos:

helv36=tkFont.Font(family='Helvetica', size=36, weight='bold')

  • Si está ejecutando bajo el sistema X Window, puede usar cualquiera de los nombres de fuente X. Por ejemplo, la fuente llamada '- * - lucidatypewriter-medium-r - * - * - * - 140 - * - * - * - * - * - *' es una buena fuente de ancho fijo para uso en pantalla. Use el programa xfontsel para ayudarlo a seleccionar fuentes agradables.
Para obtener una lista de todas las familias de fuentes disponibles en su plataforma, llame a esta función:

tkFont.families()

El valor de retorno es una lista de cadenas.

Nota: Debe crear su ventana raíz antes de llamar a esta función.

Estos métodos se definen en todos los objetos Font:

.actual(option=None): Si no pasa argumentos, obtiene un diccionario de los atributos reales de la fuente, que pueden diferir de los que solicitó. Para recuperar el valor de un atributo, pase su nombre como argumento. 

.cget(option): Devuelve el valor de la opción dada. 

.configure(option, ...): Use este método para cambiar una o más opciones en una fuente. Por ejemplo, si tiene un objeto Font llamado titleFont, si llama titleFont.configure (family='times', size=18), esa fuente cambiará a 18pt Times y cualquier widget que use esa fuente también cambiará. 

.Copy(): Devuelve una copia de un objeto Font. 

.measure(text): Pase a este método una cadena, y devolverá el número de píxeles de ancho que esa cadena tomará en la fuente.

Advertencia: algunos caracteres inclinados pueden extenderse fuera de esta área 

.metrics(option): Si llama a este método sin argumentos, devuelve un diccionario de todas las métricas de fuente. Puede restablecer el valor de una sola métrica pasando su nombre como argumento. Las métricas incluyen:
  • assent: Número de píxeles de altura entre la línea base y la parte superior del ascendente más alto. 
  • descent: Número de píxeles de altura entre la línea de base y la parte inferior del ascendente más bajo.
  • fixed: Este valor es 0 para una fuente de ancho variable y 1 para una fuente monoespaciada.
  • linespace: Número de píxeles de altura total. Este es el líder del conjunto de tipos sólido en la fuente dada.

5.5. Anchors


El módulo Tkinter define una serie de constantes de anclaje que puede usar para controlar dónde se colocan los elementos en relación con su contexto. Por ejemplo, las anclas (anchors) pueden especificar dónde se encuentra un widget dentro de un marco cuando éste es más grande que el widget.
Estas constantes se dan como puntos cardinales, donde el norte está arriba y el oeste está a la izquierda. Pedimos disculpas a nuestros lectores del hemisferio sur por este chovinismo del hemisferio norte.
Las constantes de anclaje se muestran en este diagrama:


Por ejemplo, si crea un widget pequeño dentro de un marco grande y usa la opción anchor=tk.SE, el widget se colocará en la esquina inferior derecha del marco. Si usó anchor=tk.N, el widget se centraría a lo largo del borde superior.
Los anclajes también se utilizan para definir dónde se coloca el texto en relación con un punto de referencia. Por ejemplo, si usa tk.CENTER como un ancla de texto, el texto se centrará horizontal y verticalmente alrededor del punto de referencia. anchor=tk.NW posicionará el texto de modo que el punto de referencia coincida con la esquina noroeste (superior izquierda) del cuadro que contiene el texto. anchor=tk.W centrará el texto verticalmente alrededor del punto de referencia, con el borde izquierdo del cuadro de texto pasando por ese punto, y así sucesivamente.

5.6. Relief Styles


El estilo de relieve de un widget se refiere a ciertos efectos 3D simulados alrededor del exterior del widget. Aquí hay una captura de pantalla de una fila de botones que muestran todos los estilos de relieve posibles:



La anchura de estas fronteras depende de borderwidth que es una de las opciones del widget. El gráfico de arriba muestra cómo se ven con un borde de 5 píxeles, el ancho del borde predeterminado es 2.

5.7. Mapas de bits (Bitmaps)


Para las opciones de mapa de bits en widgets, se garantiza que estos mapas de bits estarán disponibles:



El gráfico de arriba muestra widgets de botones con los mapas de bits estándar. De izquierda a derecha, son 'error', 'gray75', 'gray50', 'gray25', 'gray12', 'hourglass', 'info', 'questhead', 'question', y 'warning'.
Puedes usar tus propios mapas de bits. Cualquier archivo en formato .xbm (mapa de bits X) funcionará. En lugar de un nombre de mapa de bits estándar, use la cadena '@' seguida de la ruta del archivo .xbm.

5.8 Cursores


Hay diferentes cursores disponibles, en la siguiente lista se muestra el nombre y gráfico correspondiente, el gráfico exacto puede variar según su sistema operativo.

Tabla 4. Valores de la opción de cursor
arrow
based_arrow_up
bogosity
bottom_right_corner
bottom_tee
center_ptr
clock
cross
crosshair
dot
middlebutton
pirate
question_arrow
right_side
rightbutton
sailboat
sb_h_double_arrow
sb_right_arrow
sb_v_double_arrow
doublé_arrow
draft_small
exchange
gobbler
hand1
heart
iron_cross
left_side
leftbutton
lr_angle
sizing
spraycan
target
top_left_arrow
top_right_corner
top_tee
ul_angle
ur_angle
xterm
based_arrow_down
boat
bottom_left_corner
bottom_side
box_spiral
circle
coffee_mug
cross_reverse
diamond_cross
man
pencil
plus
right_ptr
right_tee
rtl_logo
sb_down_arrow
sb_left_arrow
sb_up_arrow
dotbox
draft_large
draped_box
fleur
gumby
hand2
icon
left_ptr
lefr_tee
ll_angle
shuttle
spider
star
tcross
top_left_corner
top_side
trek
umbrella
watch
x_cursor
 

5.9. Imágenes


Existen tres métodos generales para mostrar imágenes gráficas en su aplicación Tkinter.
  • Para mostrar imágenes de mapa de bits (dos colores) en el formato .xbm, consulte la Sección 5.9.1. 
  • Para mostrar imágenes a todo color en formato .gif, .pgm o .ppm, consulte la Sección 5.9.2. 
  • La Biblioteca de imágenes de Python (PIL) admite imágenes en una variedad mucho más amplia de formatos (Consulte el documento complementario del autor para obtener documentación de PIL).

5.9.1. La clase BitmapImage 


Para mostrar una imagen de dos colores en formato .xbm, necesitará este constructor: 
tk.BitmapImage(file=f[, background=b][, foreground=c])

donde f es el nombre del archivo de imagen .xbm.
Normalmente, los bits de primer plano (1) en la imagen se mostrarán como píxeles negros, y los bits de fondo (0) en la imagen serán transparentes. Para cambiar este comportamiento, use la opción opcional background=b para establecer el fondo en color b, y la opción opcional foreground=c para establecer el primer plano en color c. Para la especificación del color, consulte la Sección 5.3.
Este constructor devuelve un valor que puede usarse en cualquier lugar donde Tkinter espere una imagen. Por ejemplo, para mostrar una imagen como etiqueta, use un widget de etiqueta (consulte la Sección 12) y proporcione el objeto BitmapImage como el valor de la opción de imagen:

logo=tk.BitmapImage('logo.xbm', foreground='red')
Label(image=logo).grid()

5.9.2. La clase PhotoImage

Para mostrar una imagen en color en formato .gif, .pgm o .ppm, necesitará este constructor:

tk.PhotoImage(file=f)

donde f es el nombre del archivo de imagen. El constructor devuelve un valor que puede usarse en cualquier lugar donde Tkinter espere una imagen. 

5.10. Geometry Strings (Cadenas de geometría)


Una cadena de geometría es una forma estándar de describir el tamaño y la ubicación de una ventana de nivel superior en un escritorio.
Una cadena de geometría tiene esta forma general:

'wxh±x±y'

dónde:
  • Las partes “w” y “h” dan el ancho y alto de la ventana en píxeles. Están separados por el caracter “x”. 
  • Si la siguiente parte tiene la forma “+x”, especifica que el lado izquierdo de la ventana debe ser “x” píxeles del lado izquierdo del escritorio. Si tiene la forma “-x”, el lado derecho de la ventana es “x” píxeles del lado derecho del escritorio. 
  • Si la siguiente parte tiene la forma “+y”, especifica que la parte superior de la ventana debe estar “y” píxeles debajo de la parte superior del escritorio. Si tiene la forma “-y”, la parte inferior de la ventana estará “y” píxeles arriba del borde inferior del escritorio.
Por ejemplo, una ventana creada con geometry='120x50-0+20' tendría 120 píxeles de ancho por 50 píxeles de alto, y su esquina superior derecha estará a lo largo del borde derecho del escritorio y 20 píxeles debajo del borde superior.

5.11. Nombres de ventanas


El término ventana describe un área rectangular en el escritorio.
  • Una ventana de nivel superior o raíz es una ventana que tiene una existencia independiente bajo el administrador de ventanas. Cuenta con las decoraciones del administrador de ventanas y se puede mover y cambiar de tamaño de forma independiente. Su aplicación puede usar cualquier cantidad de ventanas de nivel superior. 
  • El término "ventana" también se aplica a cualquier widget que sea parte de una ventana de nivel superior. Tkinter nombra todas estas ventanas usando un nombre de ruta de ventana jerárquica. 
  • El nombre de la ventana raíz es '.'. 
  • Las ventanas secundarias tienen nombres de la forma '.n', donde n es un número entero en forma de cadena. Por ejemplo, una ventana llamada '.135932060' es hija de la ventana raíz ('.'). 
  • Las ventanas secundarias dentro de las ventanas secundarias tienen nombres de la forma 'p.n' donde p es el nombre de la ventana principal y n es algún número entero. Por ejemplo, una ventana llamada '.135932060.137304468' tiene la ventana principal '.135932060', por lo que es un nieto de la ventana raíz. 
  • El nombre relativo de una ventana es la parte pasada el último '.' en el nombre del camino. Para continuar con el ejemplo anterior, la ventana del nieto tiene un nombre relativo '137304468'.
Para obtener el nombre de ruta para un widget w, use str(w), consulte también la Sección 26 para conocer los métodos que puede usar para operar en los nombres de ventanas, especialmente los métodos .winfo_name, .winfo_parent y .winfo_pathname. 

5.12 Limitar y unir estilos

Para una representación agradable y efectiva de diagramas, a veces es una buena idea prestar atención a los estilos de cap y join.
  1. El estilo de límite de una línea (cap stile) es la forma del final de la línea. Los estilos son:
    • tk.BUTT: el final de la línea se corta cuadrado en una línea que pasa por el punto final.
    • tk.PROJECTING: el final de la línea se corta al cuadrado, pero la línea de corte se proyecta más allá del punto final una distancia igual a la mitad del ancho de la línea.
    • tk.ROUND: el final describe un semicírculo centrado en el punto final.
  2. El estilo de unión (join style) describe la forma en la que dos segmentos de línea se encuentran en ángulo.
    • tk.ROUND: la unión es un círculo centrado en el punto donde se encuentran los segmentos de línea adyacentes.
    • tk.BEVEL: se dibuja una faceta plana en un ángulo intermedio entre los ángulos de las líneas adyacentes.
    • tk.MITER: los bordes de los segmentos de línea adyacentes se siguen encontrando en un punto agudo.
Esta ilustración muestra cómo funcionan las opciones de tapa y unión de Tkinter con una línea hecha de dos segmentos de línea conectados. Los pequeños círculos rojos muestran la ubicación de los puntos que definen esta línea.
 

 

 

5.13. Patrones de tablero


Varios widgets le permiten especificar un esquema discontinuo. Las opciones de guión y compensación de guión le brindan un control preciso sobre el patrón exacto de los guiones.

dash(guión)


Esta opción se especifica como una tupla de enteros. El primer entero especifica cuántos píxeles se deben dibujar. El segundo entero especifica cuántos píxeles se deben omitir antes de comenzar a dibujar nuevamente, y así sucesivamente. Cuando se agotan todos los enteros de la tupla, se reutilizan en el mismo orden hasta que se completa el borde.
Por ejemplo, dash=(3,5) produce guiones alternos de 3 píxeles separados por espacios de 5 píxeles. Un valor de dash=(7,1,1,1) produce un patrón de guión y puntos, con el guión siete veces más largo que el punto o los espacios alrededor del punto. Un valor de dash=(5,) produce guiones alternos de cinco píxeles y espacios de cinco píxeles.

dashoff


Para comenzar el patrón de guión en un punto de ciclo diferente en lugar de al principio, use una opción de dashoff=n, donde n es el número de píxeles que se omiten al comienzo del patrón.
Por ejemplo, para las opciones dash=(5, 1, 2, 1) y dash=3, el primer patrón producido será: 2 encendido, 1 apagado, 2 encendido y 1 apagado. Los patrones posteriores serán 5 encendidos, 1 apagado, 2 encendidos y 1 apagado. Aquí hay una captura de pantalla de una línea dibujada con esta combinación de opciones:

 

 

5.14. Matching stipple patterns(Patrones de punteado)


Esto puede parecer un punto de estilo increíblemente exigente, pero si dibuja un gráfico que tiene dos objetos con patrones punteados, un verdadero profesional se asegurará de que los patrones se alineen a lo largo de su límite.

Aquí hay un ejemplo, la captura de pantalla de la izquierda muestra dos cuadrados adyacentes de 100 × 100 punteados con el patrón ‘gray12’, pero el cuadrado de la derecha está desplazado verticalmente por un píxel. La línea negra corta en el centro de la figura se dibuja a lo largo del límite de las dos figuras.

 
La segunda captura de pantalla es la misma, excepto que los dos cuadrados de 100 × 100 tienen sus patrones punteados alineados.
En la práctica, esto surge en dos situaciones. La alineación de grandes áreas punteadas se controla mediante una opción denominada desplazamiento. Para figuras con contornos punteados, la opción de desplazamiento del contorno controla su alineación. Ambas opciones tienen valores de una de estas formas:

'x,y': desplaza los patrones de punteado por este valor x e y relativo a la ventana de nivel superior o al origen del lienzo.
'#x,y': Para los objetos en un lienzo, utiliza el desplazamiento x e y en relación con la ventana de nivel superior.
tk.NE, tk.SE, tk.SW, tk.NW: alinee una esquina del patrón de punteado con la esquina correspondiente del objeto contenedor. Por ejemplo, tk.NE significa que la esquina superior izquierda del patrón de punteado coincide con la esquina superior izquierda del área a puntear.
tk.N, tk.E, tk.S, tk.W: alinee el patrón de punteado con el centro de un lado del objeto que lo contiene. Por ejemplo, tk.E significa que el centro del patrón de punteado coincidirá con el centro del lado derecho del área a puntear.
tk.CENTER: alinee el centro del patrón de punteado con el centro del objeto que lo contiene.
Hasta el próximo jueves, salud y saludos!
Mauricio José Tobares

jueves, 26 de marzo de 2020

Tkinter - de marciano a humano - sección 4 - gestión del diseño


Sección 4 - Gestión del diseño

Más adelante discutiremos sobre los widgets, los componentes básicos de su aplicación GUI.

4.0 ¿Cómo se organizan los widgets en una ventana?

Aunque hay tres diferentes "administradores de geometría" en Tkinter (pack, grid y place), el autor prefiere el administrador de geometría .grid() para casi todo (aunque se verán todos, el que más utilizaremos será .grid()). Este administrador trata cada ventana o marco como una tabla, una cuadrícula de filas y columnas.
  • Una celda es el área en la intersección de una fila y una columna.
  • El ancho de cada columna es el ancho de la celda más ancha en esa columna.
  • La altura de cada fila es la altura de la celda más grande de esa fila.
  • Para los widgets que no llenan toda la celda, puede especificar qué sucede con el espacio extra, por ejemplo puede dejar el espacio extra fuera del widget o bién estirar el widget para que se ajuste, ya sea en la dimensión horizontal como en la vertical.
  • Puede combinar varias celdas en un área más grande, este es un proceso llamado expansión.
Cuando crea un widget, no aparece hasta que lo registra en un administrador de geometría. Por lo tanto, la construcción y colocación de un widget es un proceso de dos pasos que va más o menos así:

self.thing=tk.Constructor(parent, ...)
self.thing.grid(...)

Donde Constructor es una de las clases de widgets como "Button", "Frame", etc., y "parent" es el widget principal en el que se está construyendo este widget secundario. Todos los widgets tienen un método .grid() que puede usar para indicarle al administrador de geometría dónde colocarlo.

4.1. El método .grid()

Para mostrar un widget "w" en la pantalla de su aplicación:

w.grid(option=value, ...)

Este método registra un widget "w" con el administrador de geometría de cuadrícula, si no hace esto, el widget existirá internamente, pero no será visible en la pantalla.
Para explicar mejor lo anteriormente dicho, veamos este fragmento del código de nuestra aplicación de ejemplo:

46 self.botonSalida.grid(row=0, column=0, pady=5, padx=5)

Como obsevaremos a continuación, si comentamos esta línea, agregando un "#" en la parte izquierda al inicio del renglón, el botón estará en el programa, pero NO se mostrará en la ventana, el colocar un "hash" delante del renglón es lo que se llama "comentar una línea", es útil a la hora de testear y es una practica bastante común, veamos este renglón comentado y el resultado obtenido:

46 # self.botonSalida.grid(row=0, column=0, pady=5, padx=5)



Como podemos ver, ahora no aparece el botón, pero si "descomentamos" la línea quitando el "#" entonces volverá a verse la ventana y el botón como se muestra en la sección 2.

4.1.1 Argumentos del administrador de geometría .grid()

 

Tabla 1: Argumentos del administrador de geometría .grid()
column El número de columna donde desea que se cuadricule el widget, contando desde cero. El valor por defecto es cero.
columnspan Normalmente, un widget ocupa solo una celda en la cuadrícula, sin embargo, puede tomar varias celdas de una fila y fusionarlas en una celda más grande configurando la opción de la columna en el número de celdas, por ejemplo:

w.grid(row=0, column=2, columnspan=3)

colocaría el widget w en una celda que abarca las columnas 2, 3 y 4 de la fila 0.
_in Para registrar "w" como hijo de algún widget "w2", debemos usar in_=w2. El nuevo padre "w2" debe ser un descendiente del widget principal utilizado cuando se creó "w".
ipadx Espacio interno "x". Esta dimensión se agrega dentro del widget dentro de su lado izquierdo y derecho.
ipady Espacio interno "y". Esta dimensión se agrega dentro del widget en su parte superior e inferior.
padx Espacio externo "x". Esta dimensión se agrega a la izquierda y a la derecha "fuera del widget".
pady Espacio externo "y". Esta dimensión se agrega arriba y debajo "fuera del widget".
row El número de fila en el que desea insertar el widget, contando desde 0. El valor predeterminado es el de la siguiente fila desocupada con un número más alto.
rowspan Normalmente un widget ocupa solo una celda en la cuadrícula, pero puedes agarrar múltiples adyacentes. Sin embargo, las celdas de una columna establecen la opción de la "fila de filas" en el número de celdas que se desea capturar. Esta opción se puede usar en combinación con la opción de columnas para tomar un bloque de células. Por ejemplo:

w.grid(row=3, column=2, rowspan=4, columnspan=5)

lo anterior colocaría el widget "w" en un área formada al fusionar 20 celdas, con los números de fila 3–6 y números de columna 2–6.
sticky Esta opción determina cómo distribuir cualquier espacio extra dentro de la celda que no se tome arriba por el widget en su tamaño natural, lo que causa este efecto es el de "estirar" el widget en todo el espacio posible de acuerdo a como estiremos la ventana, por ejemplo, si estiramos la ventana hacia abajo el botón se estirará hacia abajo, si estiramos la ventana hacia un lado se estirará de lado, todo esto depende de las siguientes configuraciones:
  • Si no proporciona un atributo fijo, el comportamiento predeterminado es centrar el widget en la celda.
  • Puede colocar el widget en una esquina de la celda usando:
    • sticky=tk.NE (arriba a la derecha)
    • sticky=tk.SE (abajo a la derecha)
    • sticky=tk.SW (abajo a la izquierda)
    • sticky=tk.NW (arriba a la izquierda)
  • Puede colocar el widget centrado contra un lado de la celda usando:
    • sticky=tk.N (centro superior)
    • sticky=tk.E (centro derecho)
    • sticky=tk.S (centro inferior)
    • sticky=tk.W (centro izquierdo)

Podemos usar sticky=tk.N+tk.S para estirar el widget verticalmente pero déjelo centrado horizontalmente.

Podemos usar sticky=tk.E+tk.W para estirarlo horizontalmente pero déjelo centrado verticalmente.

podemos usar sticky=tk.N+tk.E+tk.S+tk.W para estirar el widget tanto horizontal como verticalmente para llenar la celda.

Las otras combinaciones también funcionarán. Por ejemplo, sticky=tk.N+tk.S+tk.W estirará el widget verticalmente y lo colocará contra la pared oeste (izquierda).

Si al script le agregamos un padx=0, pady=0 (que sería el default) no va a a notarse diferencia en el diseño, pero si colocamos, por ejemplo, padx=5, pady=5 entonces notamos una mejora ya que “despega” nuestro botón de los bordes en 5 pixeles, en este cuadro se pueden comparar ambas imágenes:

.grid(row=0, column=0, pady=0, padx=0)

.grid(row=0, column=0, pady=5, padx=5)

 

 

 4.2. Otros métodos para gestionar .grid()

Estos métodos relacionados con la cuadrícula se definen en todos los widgets:

 

w.grid_bbox(column=None, row=None, col2=None, row2=None)

Devuelve una tupla de 4 valores que describe el cuadro delimitador de algunos o todos los sistemas de cuadrícula en el widget w, en este caso column y row son las coordenadas x e y de la esquina superior izquierda del área, col2 y row2 son el ancho y la altura. Si pasa argumentos de columna y fila, el cuadro delimitador devuelto describe el área de la celda en esa columna y fila. Si también pasa los argumentos col2 y row2, el cuadro delimitador devuelto describe el área de la cuadrícula de columnas column a col2 inclusive, y de las filas row a row2 inclusive. Por ejemplo, w.grid_bbox(0, 0, 1, 1) devuelve el cuadro delimitador de cuatro celdas, no una.

w.grid_forget()

Este método hace que el widget w desaparezca de la pantalla. Todavía existe, simplemente no es visible. Puede usar .grid() para que aparezca de nuevo, pero no recordará sus opciones de cuadrícula.

w.grid_info()

Devuelve un diccionario cuyas claves son nombres de opciones de w, con los valores correspondientes de esas opciones.

w.grid_location(x, y)

Dadas las coordenadas (x, y) relativas al widget que contiene, este método devuelve una tupla (column, row) que describe qué celda del sistema de cuadrícula de w contiene esa coordenada de pantalla.

w.grid_propagate()

Normalmente, todos los widgets propagan sus dimensiones, lo que significa que se ajustan para adaptarse a los contenidos. Sin embargo, a veces desea forzar que un widget tenga un tamaño determinado, independientemente del tamaño de su contenido. Para hacer esto se llama a w.grid_propagate(0) donde w es el widget cuyo tamaño desea forzar.

w.grid_remove()

Este método es como .grid_forget(), pero sus opciones de cuadrícula se recuerdan, por lo que si .grid() lo vuelve a usar, usará las mismas opciones de configuración de cuadrícula.

w.grid_size()

Devuelve una tupla de 2 valores que contiene el número de columnas y el número de filas respectivamente, en el sistema de cuadrícula de w.

w.grid_slaves (row=None, column=None)

Devuelve una lista de los widgets administrados por el widget w. Si no se proporcionan argumentos, obtendrá una lista de todos los widgets administrados. Use el argumento row= para seleccionar solo los widgets en una fila, o el argumento column= para seleccionar solo los widgets en una columna.

4.3. Configurar tamaños de columna y fila

A menos que tome ciertas medidas, el ancho de una columna de cuadrícula dentro de un widget dado será igual al ancho de su celda más ancha, y el alto de una fila de cuadrícula será el alto de su celda más alta. El atributo adhesivo (sticky) en un widget controla solo dónde se colocará si no llena completamente la celda. Si desea anular este tamaño automático de columnas y filas, use estos métodos en el widget principal w que contiene el diseño de cuadrícula:

w.columnconfigure(N, option=value, ...)

En el diseño de cuadrícula dentro del widget w, configure la columna N para que la opción dada tenga el valor dado.

w.rowconfigure(N, option=value, ...)

En el diseño de cuadrícula dentro del widget w, configure la fila N para que la opción dada tenga el valor dado.


Tabla 2: Opciones de configuración de columna y fila para el administrador de geometría .grid()
minimize El tamaño mínimo de la columna o fila en píxeles. Si no hay nada en la columna o fila dada, no aparecerá, incluso si usa esta opción.
pad Una cantidad de píxeles que se agregarán a la columna o fila dada, más allá de la celda más grande en la columna o fila.
weight para hacer que una columna o fila se pueda estirar, use esta opción y proporcione un valor que le proporcione “peso relativo” a esta columna o fila al distribuir el espacio extra. Por ejemplo, si un widget w contiene un diseño de cuadrícula, estas líneas distribuirán tres cuartas partes del espacio extra para la primera columna y un cuarto para la segunda columna, si no se usa esta opción, la columna o fila no se estirará.

w.columnconfigure (0, weight=3) w.columnconfigure (1, weight=1)

4.4. Hacer que la ventana raíz sea redimensionable

¿Desea que el usuario cambie el tamaño de toda la ventana de su aplicación y distribuya el espacio adicional entre sus widgets internos? Esto requiere algunas operaciones que no son obvias.
Es necesario utilizar las técnicas para la gestión del tamaño de fila y columna, descritas en la Sección 4.3 para hacer que la cuadrícula del widget de la Aplicación se pueda estirar, pero eso por sí solo no es suficiente.
Considere la aplicación básica discutida en la Sección 2, que contiene solo un botón SALIR. Si ejecuta esta aplicación y cambia el tamaño de la ventana, el botón permanece del mismo tamaño y en el mismo lugar (fila 0 columna 0, o sea arriba a la izquierda).
Aquí hay una nueva versión del ejemplo 001 que reemplaza al método .__createWidgets(), en esta versión, el botón "SALIR" siempre llena todo el espacio disponible.

#!/user/bin/env python
#-------------------------------------------------------------------------------
# Name: tkinter ejemplo 002
# Purpose: El proposito de este script es demostrar características básicas
# de tkinter, es parte de la sección 4.4 de la guía de tkinter 8.5
#
# Author: Mauricio José Tobares
#
# Created: 25/01/2020
# Copyright: (c) SplinterStudio 2020
# Licence:
#-------------------------------------------------------------------------------

'de entrada esta importación no es correcta en python 3.x'
# import Tkinter as tk
'la forma correcta de importar tkinter es esta:'
import tkinter as tk

class Prototipo2(tk.Frame):
    def __init__(self, parent):
        super(Application, self).__init__(parent)
        'se trae el contenido de la función crearboton'
        self.crearboton()
    def crearboton(self):
        'ventana de nivel superior.'
        top=self.winfo_toplevel()
        'hace que la fila 0 de la ventana de nivel superior pueda expandirse.'
        top.rowconfigure (0, weight=1)
        'hace que la columna 0 de la ventana de nivel superior pueda expandirse.'
        top.columnconfigure (0, weight=1)
        'hace que la fila 0 del widget pueda expandirse'
        self.rowconfigure (0, weight=1)
        'hace que la columna 0 del widget pueda expandirse'
        self.columnconfigure (0, weight=1)
        'esto es así porque se destruye a root que es el padre o raiz.'
        self.botonSalida=tk.Button(self, text='SALIR', command=root.destroy)
        self.botonSalida.grid(row=0, column=0, sticky=tk.N+tk.S+tk.E+tk.W)

if __name__ == "__main__":
    'ventana root o raiz'
    root=tk.Tk()
    'con esto ejecutamos la aplicación'
    main=Prototipo2(root)
    main.pack(fill="both", expand=True)
    root.mainloop()


La "ventana de nivel superior" es la ventana más externa de la pantalla, sin embargo, esta no es la ventana de su aplicación, es la principal de la instancia de la aplicación.
Para obtener la ventana de nivel superior deberá llamar al método .winfo_toplevel() en cualquier widget de su aplicación (no quiero apurarme mucho pero puede consultar la Sección 26).
La línea top.rowconfigure(0, weight=1) hace que la fila "0" de la cuadrícula de la ventana del nivel superior se pueda estirar, la línea que sigue, top.columnconfigure(0, weight=1) hace lo mismo que la anterior pero con la columna "0".
Los siguientes dos renglones, self.rowconfigure(0, weight=1) y self.columnconfigure(0, weight=1) hacen que la fila "0" y la columna "0" de la cuadrícula del widget Prototipo2 se puedan estirar.
El argumento sticky=tk.N+tk.S+tk.E+tk.W hace que el botón se expanda para llenar su celda de la cuadrícula.
Si notamos en este ejemplo quitamos la parte en que la ventana inicia maximizada para que el ejemplo sea más claro.

Hasta el próximo jueves, salud y saludos!
Mauricio José Tobares

jueves, 19 de marzo de 2020

Tkinter - de marciano a humano - sección 3 - Definiciones


Sección 3 - Definiciones

Antes de continuar, definamos algunos de los términos comunes (y algunos ya utilizados en la revisión de código del primer ejemplo).

window:

Este término tiene diferentes significados en diferentes contextos, pero en general se refiere a un área rectangular en algún lugar de la pantalla.

top-level window:

Una ventana que existe independientemente en su pantalla. Estará decorado con el marco estándar y los controles para el administrador de escritorio de su sistema. Puede moverlo en su escritorio. En general, puede cambiar su tamaño, aunque su aplicación puede evitar esto.

Widget:

El término genérico para cualquiera de los componentes básicos que componen una aplicación en una interfaz gráfica de usuario. Ejemplos de widgets:

Botones (Button)
Botones de radio (Radiobutton)
Campos de texto (text field)
Marcos (Frame)
Etiquetas de texto (text label)

NOTA: Para facilitar la lectura de este y otras publicaciones posteriores muchas veces me voy a referir a un radiobutton como "radiobutton y no como botón de radio, ya que es más simple entender que un radiobutton es un radiobutton y no que es un "botón de radio", lo tenemos más incorporado como terminología que como su traducción literal y no me refiero solo al radiobutton, en general hay muchas palabras que es mejor NO traducir literalmente aunque tienen una traducción.

Frame:

En Tkinter, el widget Frame es la unidad básica de organización para diseños complejos. Un marco (en adelante "Frame") es un área rectangular que puede contener otros widgets.

parent-child:

Cuando se crea cualquier widget, se crea una relación padre-hijo, por ejemplo, si coloca una etiqueta de texto (en adelante Label) dentro de un Frame, el Frame es el padre del  Label.

Hasta el próximo jueves, salud y saludos!
Mauricio José Tobares

jueves, 12 de marzo de 2020

Tkinter - de marciano a humano - sección 2 - Una aplicación mínima


Sección 2 - Una aplicación mínima

La semana anterior en la sección 1 vimos la generador de interfaz gráfica de usuario multiplataforma para Python, en esta ocación veamos la forma de hacer una ventana básica, este pequeño programa solamente contiene un botón para salir:

Crearemos un archivo prototipo001.py y dentro del mismo colocaremos el siguiente código:
(cambienle el autor si quieren...)

01 #!/user/bin/env python
02 #-------------------------------------------------------------------------------
03 # Name: tkinter ejemplo 001
04 # Purpose: El proposito de este script es demostrar las características
05 # básicas de tkinter y llegar a crear interfaces profesionales,
06 # es en parte inspirado en la guía oficial de tkinter 8.5 y con
07 # conocimientos ampliados que luego fueron incorporados a la guía
08 #
09 # Author: Mauricio José Tobares
10 #
11 # Created: 24/01/2020
12 # Copyright: (c) SplinterStudio 2020
13 # Licence: <lo que? licencia? que es eso?>
14 #-------------------------------------------------------------------------------
15
16 from tkinter import *
17 from tkinter import ttk
18
19 # Crea una clase Python para definir el interfaz de usuario de la aplicación.
20 # Cuando se cree un objeto del tipo 'Prototipo1' se ejecutará automáticamente
21 # el método __init__() que construye y muestra la ventana con todos sus widgets
22 class Prototipo1():
23 def __init__(self):
24 'ventana root o raiz'
25 self.root=Tk()
26 'título de la ventana root'
27 tituloVentanaRoot="Prototipo 001"
28 self.root.title(tituloVentanaRoot)
29 ' se coloca el boton de salida'
30 'esto es así porque se destruye a root que es el padre o raiz.'
31 self.botonSalida=ttk.Button(self.root, text='SALIR', command=self.root.destroy)
32 self.botonSalida.grid(row=0, column=0)
33 'se ejecuta el programa'
34 self.root.mainloop()
35
36 # Define la función main() que es en realidad la que indica
37 # el comienzo del programa. Dentro de ella se crea el objeto
38 # aplicación 'mi_app' basado en la clase 'Prototipo1':
39 def main():
40 mi_app=Prototipo1()
41 return 0
42
43 # Mediante el atributo __name__ tenemos acceso al nombre de un
44 # un módulo. Python utiliza este atributo cuando se ejecuta
45 # un programa para conocer si el módulo es ejecutado de forma
46 # independiente (en ese caso __name__ = '__main__') o es
47 # importado:
48 if __name__ == '__main__':
49 main()

ACLARACIÓN: yo se que se ve feo el poner el número de línea, pero este manual va de principiante que no sabe absolutamente nada a contenidos avanzados, por tanto al inicio será muy conveniente colocar el número de la línea!

nuestra pequeña aplicación se ve así:
Por ahora se ve bastante fea... la típica interfaz marciana tan cuestionada por muchos...
Como se puede apreciar hay unas cuantas diferencias entre Python 2.7 y Pythn 3.8.1, principalmente la forma en que se trabajan (con clases), el documento original NO FUNCIONARÁ en las versiones de python 3.x (este ejemplo fue testeado en Python 3.8.1), a lo largo de todo este artículo se trabajaremos solo con Python 3.8.1, seguramente funcionará de igual modo en las versiones anteriores de Python 3.x.

Agregando unos extras

Para comenzar vamos a colocar un logo al proyecto (un pequeño .ico de 128x128 que encontré en una web de iconos gratuitos), lo que se debe hacer es (y como es lógico) pensar a futuro, para ello vamos a crear una carpera llamada “modulos” en la carpeta donde se tiene el script prototipo001.py, dentro de esta carpeta colocaremos una carpeta llamada “img”, y dentro de esta carpeta pondremos nuestro logo.ico. Una ruta posible hacia nuestro pequeño logo sería ./modulos/img/logo.ico

Ahora bien, vamos a los códigos, en primer lugar colocaremos a continuación de la línea n° 28 el siguiente código:

28           self.root.title(tituloVentanaRoot) # dejo este renglon solo para referencia
29           'con esto colocamos el logo personalizado de la ventana root'
30           try:
31               'el icono DEBE ser .ico de lo contrario no funcionara'
32               self.root.iconbitmap('./modulos/img/logo.ico') # ATENCION: Cuidado con la ruta del ícono!!
33           except TclError:
34               'imprime este mensaje si el icono no se encuentra o no pudo ser cargado'
35               print("ERROR: El icono de la ventana no pudo ser cargado")
36               pass
El resultado se verá así:
Pueden poner cualquier logo... yo puse ese porque es lo que encontré!!

Ahora le agrego una forma de maximizar la ventana al tamaño que tenga el usuario, aporte que se agradece pues la mayoría de los programas comienzan maximizados (o al menos esa debería ser la regla general)
NOTA IMPORTANTE:
Es siempre recomendable que a la ventana padre se la llame “root”, ya que la gran mayoría de los programadores así le llama a la raiz de sus aplicaciones, en nuestro caso la ventana padre.

Siguiendo el mismo procedimiento de agregar código colocaremos a partir de la línea n° 25 lo siguiente:

25        self.root=Tk()
26        'lo siguiente hace que la ventana root inicie maximizada'
27        toplevel=self.root.winfo_toplevel()
28        toplevel.wm_state('zoomed')

No voy a profundizar mucho en detalles porque seguidamente se van a explicar algunos conceptos.

Hasta el próximo jueves, salud y saludos!
Mauricio José Tobares

jueves, 5 de marzo de 2020

TkInter - de marciano a humano - sección 1 - Generador de interfaz gráfica de usuario multiplataforma para Python

TKINTER DE MARCIANO A HUMANO

Sección 1 - Generador de interfaz gráfica de usuario multiplataforma para Python

Tkinter es un widget de interfaz gráfica de usuario (GUI) configurado para Python.

El documento original fue escrito para Python 2.7 y Tkinter 8.5 ejecutándose en el sistema X Window bajo Linux, pero como bien se aclaró en el prefacio esta versión del documento fue adaptada a la versión Python 3.8.1, su versión puede variar mucho, poquito o nada desde Python 2.7 a la 3.8.1 (o superiores) por lo que hay que tener muy en cuenta, todo el tiempo, que este documento fue probado en un sistema windows 10 (es lo que hay!!), python 3.8.1 y tkinter 8.5.

Comenzaremos mirando la parte visible de Tkinter creando los widgets y organizándolos en la pantalla. Más adelante hablaremos sobre cómo conectar la cara (el "panel frontal") de la aplicación a la lógica detrás de ella.

Refefrencias pertinentes (en perfecto ingles):

  • Fredrik Lundh, who wrote Tkinter, has two versions of his An Introduction to Tkinter: a more complete 1999 version 3 and a 2005 version 4 that presents a few newer features.

  • Python 2.7 quick reference 5: general information about the Python language.

Para ver un ejemplo de una aplicación de trabajo considerable (alrededor de 1000 líneas de código), vea una herramienta de selección de color y fuente. El diseño de esta aplicación demuestra cómo construir widgets compuestos.

TkInter - de marciano a humano - sección 13 - El Widget LabelFrame

  13 El widget LabelFrame El widget LabelFrame al igual que el widget Frame es un contenedor espacial, un área rectangular que puede...