Python 3 Bis 2
Python 3 Bis 2
La interfaz gráfica de usuario, conocida también como GUI (graphical user interface) son
fundamentales cuando queremos implementar programas para usuarios finales que faciliten la
entrada y salida de datos.
Vimos en el concepto anterior que Python puede hacer uso de la GUI wxPython mediante la
instalación del paquete respectivo. Python por defecto instala el módulo 'tkinter' para la
implementación de interfaces visuales. El editor IDLE que viene con Python está desarrollado
utilizando este módulo.
Veremos en una serie de conceptos como implementar interfaces visuales con ventanas, botones,
checkbox, label etc. haciendo uso del módulo 'tkinter'.
Lo primero que hay que tener en cuenta es que el módulo 'tkinter' (tk interface) viene instalado por
defecto con Python.
Problema:
El programa en Python haciendo uso del módulo 'tkinter' requiere el siguiente algoritmo:
Programa
import tkinter as tk
ventana1=tk.Tk()
ventana1.title("Hola Mundo")
ventana1.mainloop()
Lo primero que hacemos es importar el módulo tkinter y le definimos un alias luego de la palabra
clave as. Es más fácil luego escribir 'tk' en lugar de 'tkinter':
import tkinter as tk
ventana1=tk.Tk()
Seguidamente llamamos al método 'title' y le pasamos un string con el mensaje que queremos que
aparezca en la barra del título de la ventana:
ventana1.title("Hola Mundo")
Para que se muestre la ventana en el monitor debemos llamar por último al método 'mainloop' que
pertenece a la clase Tk:
ventana1.mainloop()
Hemos codificado el programa más pequeño utilizando el módulo 'tkinter':
Acotaciones
Si utilizamos el editor VSCode en lugar del editor IDLE podemos tener grandes ventajas cuando
codificamos el programa. Por ejemplo luego de escribir el nombre del objeto podemos ver que
gracias a 'IntelliSense' se nos muestran todos sus métodos y una descripción del mismo:
Aplicación orientada a objetos
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.ventana1.title("Hola Mundo")
self.ventana1.mainloop()
aplicacion1=Aplicacion()
Planteamos una clase llamada 'Aplicacion' y en su método '__init__' creamos el objeto de la clase
'Tk' para que se muestre la ventana.
aplicacion1=Aplicacion()
En las interfaces visuales las ventanas son controles visuales contenedores de otros controles como
los botones y etiquetas de texto.
Veremos los pasos que debemos dar si queremos que se muestren objetos de la clase Button y Label
en nuestras ventanas.
Problema:
Mostrar una ventana y en su interior dos botones y una label. La label muestra inicialmente el valor
1. Cada uno de los botones permiten incrementar o decrementar en uno el contenido de la label
Programa
import tkinter as tk
class Aplicacion:
def __init__(self):
self.valor=1
self.ventana1=tk.Tk()
self.ventana1.title("Controles Button y Label")
self.label1=tk.Label(self.ventana1, text=self.valor)
self.label1.grid(column=0, row=0)
self.label1.configure(foreground="red")
self.boton1=tk.Button(self.ventana1, text="Incrementar",
command=self.incrementar)
self.boton1.grid(column=0, row=1)
self.boton2=tk.Button(self.ventana1, text="Decrementar",
command=self.decrementar)
self.boton2.grid(column=0, row=2)
self.ventana1.mainloop()
def incrementar(self):
self.valor=self.valor+1
self.label1.config(text=self.valor)
def decrementar(self):
self.valor=self.valor-1
self.label1.config(text=self.valor)
aplicacion1=Aplicacion()
self.valor=1
self.ventana1=tk.Tk()
self.ventana1.title("Controles Button y Label")
Ahora creamos un objeto de la clase Label y le pasamos como primer parámetro la referencia a la
ventana donde debe aparecer la label y el parámetro text con el valor inicial de la Label:
self.label1=tk.Label(self.ventana1, text=self.valor)
Para ubicar los controles visuales en la ventana veremos más adelante que hay diferentes Layout,
por ahora en forma muy sencilla mediante la llamada al método grid indicaremos en los parámetros
column y row la ubicación del mismo:
self.label1.grid(column=0, row=0)
Para que el texto de la Label se muestre de color rojo llamamos al método configure y le pasamos
en el parámetro foreground el string "red":
self.label1.configure(foreground="red")
La creación de los dos botones es similar a la creación de la label, en el primer parámetro indicamos
la referencia de la ventana donde se debe mostrar el botón, en el parámetro text indicamos el texto a
mostrar dentro del botón y finalmente en el parámetro command pasamos la referencia del método
que se ejecutará cuando el operador lo presione:
self.boton1=tk.Button(self.ventana1, text="Incrementar",
command=self.incrementar)
self.boton1.grid(column=0, row=1)
self.boton2=tk.Button(self.ventana1, text="Decrementar",
command=self.decrementar)
self.boton2.grid(column=0, row=2)
Para que los botones se encuentren abajo de la Label al llamar al método grid pasamos en el
parámetro row los valores 1 y 2. Como todos los controles se encuentran en la misma columna
pasamos en column el valor 0.
self.ventana1.mainloop()
El método incrementar se ejecuta cuando el operador presiona el boton1 (dentro del mismo
incrementamos en uno el atributo valor y actualizamos el contenido de la label1 llamando al método
config y en el parámetro text el nuevo valor a mostrar):
def incrementar(self):
self.valor=self.valor+1
self.label1.config(text=self.valor)
El algoritmo del método decrementar solo difiere en que decrementa en uno el atributo valor:
def decrementar(self):
self.valor=self.valor-1
self.label1.config(text=self.valor)
aplicacion1=Aplicacion()
Cuando ejecutamos la aplicación tenemos una interfaz visual similar a esta:
Acotaciones
La sintaxis para modificar la propiedad 'text' de la label1 se puede hacer llamando al método config
como lo hemos hecho:
self.label1.config(text=self.valor)
O mediante la sintaxis:
self.label1["text"]=self.valor
Problema:
Mostrar dos Label, en una se muestra el nombre del programa y en la segunda el año de creación.
Disponer un botón para finalizar el programa.
No permitir al usuario redimensionar la ventana.
Programa:
import tkinter as tk
import sys
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.ventana1.title("Prueba")
self.label1=tk.Label(self.ventana1, text="Sistema de
facturación")
self.label1.grid(column=0, row=0)
self.label2=tk.Label(self.ventana1, text="2018")
self.label2.grid(column=0, row=1)
self.boton1=tk.Button(self.ventana1, text="Finalizar",
command=self.finalizar)
self.boton1.grid(column=0, row=2)
self.ventana1.resizable(False, False)
self.ventana1.mainloop()
def finalizar(self):
sys.exit(0)
aplicacion1=Aplicacion()
En esta aplicación para no permitir redimensionar ni el ancho ni el alto del la ventana debemos
llamar al método resizable y pasar el valor False a cada parámetro.
Cuando queremos finalizar un programa en Python debemos llamar a la función exit que se
encuentra en el módulo sys, por ello hemos importado dicho módulo al principio:
import sys
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.label1=tk.Label(self.ventana1,text="Ingrese un
número:")
self.label1.grid(column=0, row=0)
self.dato=tk.StringVar()
self.entry1=tk.Entry(self.ventana1, width=10,
textvariable=self.dato)
self.entry1.grid(column=0, row=1)
self.boton1=tk.Button(self.ventana1, text="Calcular
Cuadrado", command=self.calcularcuadrado)
self.boton1.grid(column=0, row=2)
self.label2=tk.Label(self.ventana1,text="resultado")
self.label2.grid(column=0, row=3)
self.ventana1.mainloop()
def calcularcuadrado(self):
valor=int(self.dato.get())
cuadrado=valor*valor
self.label2.configure(text=cuadrado)
aplicacion1=Aplicacion()
La ejecución de
esta aplicación
muestra una
interfaz visual
similar a esta:
Veamos lo nuevo que aparece para definir un objeto de la clase Entry:
self.dato=tk.StringVar()
self.entry1=tk.Entry(self.ventana1, widt=10,
textvariable=self.dato)
self.entry1.grid(column=0, row=1)
Cuando trabajamos con la clase Entry debemos también crear un objeto de la clase StringVar y
pasar dicho objeto al parámetro textvariable cuando se crea el objeto de la clase Entry.
La clase StringVar al igual que la clase Entry están declaradas en el módulo tkinter.
Cuando debemos rescatar el dato ingresado por el operador en el control de la clase Entry en
realidad lo hacemos del objeto de la clase StringVar mediante el método get:
def calcularcuadrado(self):
valor=int(self.dato.get())
cuadrado=valor*valor
self.label2.configure(text=cuadrado)
Problema:
Confeccionar un programa que permita ingresar el nombre de usuario en un control Entry y cuando
se presione un botón mostrar el valor ingresado en la barra de títulos de la ventana.
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.label1=tk.Label(self.ventana1,text="Ingrese nombre de
usuario:")
self.label1.grid(column=0, row=0)
self.dato=tk.StringVar()
self.entry1=tk.Entry(self.ventana1, width=20,
textvariable=self.dato)
self.entry1.grid(column=1, row=0)
self.boton1=tk.Button(self.ventana1, text="Ingresar",
command=self.ingresar)
self.boton1.grid(column=1, row=1)
self.ventana1.mainloop()
def ingresar(self):
self.ventana1.title(self.dato.get())
aplicacion1=Aplicacion()
La ejecución de esta aplicación muestra una interfaz visual similar a esta:
Para que el botón aparezca debajo del control Entry debemos fijar el parámetro 'column' con el
valor 1:
self.boton1.grid(column=1, row=1)
Debemos pensar nuestra pantalla como una cuadrícula donde definimos la fila y columna para cada
control:
self.label1.grid(column=0, row=0)
self.entry1.grid(column=1, row=0)
self.boton1.grid(column=1, row=1)
Debajo de la Label no aparece nada, eso debido a que no hemos dispuesto un control en dicha
posición.
Cuando se presiona el botón extraemos del objeto de la clase StringVar el dato ingresado por el
operador en el control Entry:
def ingresar(self):
self.ventana1.title(self.dato.get())
tkinter : control Radiobutton
Otro control visual muy común es el Radiobutton que normalmente se muestran un conjunto de
Radiobutton y permiten la selección de solo uno de ellos. Se los debe agrupar para que actúen en
conjunto, es decir cuando se selecciona uno automáticamente se deben deseleccionar los otros.
Problema:
Mostrar dos controles de tipo Radiobutton con las etiquetas "Varón" y "Mujer", cuando se presione
un botón actualizar una Label con el Radiobutton seleccionado.
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.seleccion=tk.IntVar()
self.seleccion.set(2)
self.radio1=tk.Radiobutton(self.ventana1,text="Varon",
variable=self.seleccion, value=1)
self.radio1.grid(column=0, row=0)
self.radio2=tk.Radiobutton(self.ventana1,text="Mujer",
variable=self.seleccion, value=2)
self.radio2.grid(column=0, row=1)
self.boton1=tk.Button(self.ventana1, text="Mostrar
seleccionado", command=self.mostrarseleccionado)
self.boton1.grid(column=0, row=2)
self.label1=tk.Label(self.ventana1,text="opcion
seleccionada")
self.label1.grid(column=0, row=3)
self.ventana1.mainloop()
def mostrarseleccionado(self):
if self.seleccion.get()==1:
self.label1.configure(text="opcion
seleccionada=Varon")
if self.seleccion.get()==2:
self.label1.configure(text="opcion
seleccionada=Mujer")
aplicacion1=Aplicacion()
La ejecución de esta aplicación muestra una interfaz visual similar a esta:
Definimos dos objetos de la clase Radiobutton e iniciamos el parámetro variable con la referencia
de un objeto de la clase IntVar:
self.radio1=tk.Radiobutton(self.ventana1,text="Varon",
variable=self.seleccion, value=1)
self.radio1.grid(column=0, row=0)
self.radio2=tk.Radiobutton(self.ventana1,text="Mujer",
variable=self.seleccion, value=2)
self.radio2.grid(column=0, row=1)
Previamente hemos definido el objeto de la clase IntVar que se encuentra en el módulo tk:
self.seleccion=tk.IntVar()
self.seleccion.set(2)
Aparece seleccionado por defecto el Radiobutton con la etiqueta "Mujer" ya que mediante el
método set fijamos el valor 2.
def mostrarseleccionado(self):
if self.seleccion.get()==1:
self.label1.configure(text="opcion
seleccionada=Varon")
if self.seleccion.get()==2:
self.label1.configure(text="opcion
seleccionada=Mujer")
Problema:
Disponer dos controles de tipo Entry para el ingreso de enteros. Mediante dos controles
Radiobutton permitir seleccionar si queremos sumarlos o restarlos. Al presionar un botón mostrar el
resultado de la operación seleccionada.
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.label1=tk.Label(self.ventana1,text="Ingrese primer
valor:")
self.label1.grid(column=0, row=0)
self.dato1=tk.StringVar()
self.entry1=tk.Entry(self.ventana1, width=20,
textvariable=self.dato1)
self.entry1.grid(column=1, row=0)
self.label2=tk.Label(self.ventana1,text="Ingrese segundo
valor:")
self.label2.grid(column=0, row=1)
self.dato2=tk.StringVar()
self.entry2=tk.Entry(self.ventana1, width=20,
textvariable=self.dato2)
self.entry2.grid(column=1, row=1)
self.seleccion=tk.IntVar()
self.radio1=tk.Radiobutton(self.ventana1,text="Sumar",
variable=self.seleccion, value=1)
self.radio1.grid(column=1, row=2)
self.radio2=tk.Radiobutton(self.ventana1,text="Restar",
variable=self.seleccion, value=2)
self.radio2.grid(column=1, row=3)
self.boton1=tk.Button(self.ventana1, text="Operar",
command=self.operar)
self.boton1.grid(column=1, row=4)
self.label3=tk.Label(self.ventana1,text="resultado")
self.label3.grid(column=1, row=5)
self.ventana1.mainloop()
def operar(self):
if self.seleccion.get()==1:
suma=int(self.dato1.get())+int(self.dato2.get())
self.label3.configure(text=suma)
if self.seleccion.get()==2:
resta=int(self.dato1.get())-int(self.dato2.get())
self.label3.configure(text=resta)
aplicacion1=Aplicacion()
La ejecución de esta aplicación muestra una interfaz visual similar a esta:
self.boton1=tk.Button(self.ventana1, text="Operar",
command=self.operar)
En el método operar rescatamos de los objeto StringVar los valores ingresados en los
controles Entry:
def operar(self):
if self.seleccion.get()==1:
suma=int(self.dato1.get())+int(self.dato2.get())
self.label3.configure(text=suma)
if self.seleccion.get()==2:
resta=int(self.dato1.get())-int(self.dato2.get())
self.label3.configure(text=resta)
tkinter : control Checkbutton
El control visual Checkbutton permite implementar un botón de dos estados, más conocido como un
cuadro de selección.
Problema:
Mostrar una ventana y en su interior tres controles de tipo Checkbutton cuyas etiquetas
correspondan a distintos lenguajes de programación. Cuando se presione un botón mostrar en una
Label la cantidad de Checkbutton que se encuentran chequeados.
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.seleccion1=tk.IntVar()
self.check1=tk.Checkbutton(self.ventana1,text="Python",
variable=self.seleccion1)
self.check1.grid(column=0, row=0)
self.seleccion2=tk.IntVar()
self.check2=tk.Checkbutton(self.ventana1,text="C++",
variable=self.seleccion2)
self.check2.grid(column=0, row=1)
self.seleccion3=tk.IntVar()
self.check3=tk.Checkbutton(self.ventana1,text="Java",
variable=self.seleccion3)
self.check3.grid(column=0, row=2)
self.boton1=tk.Button(self.ventana1, text="Verificar",
command=self.verificar)
self.boton1.grid(column=0, row=4)
self.label1=tk.Label(self.ventana1,text="cantidad:")
self.label1.grid(column=0, row=5)
self.ventana1.mainloop()
def verificar(self):
cant=0
if self.seleccion1.get()==1:
cant+=1
if self.seleccion2.get()==1:
cant+=1
if self.seleccion3.get()==1:
cant+=1
self.label1.configure(text="cantidad:"+str(cant))
aplicacion1=Aplicacion()
La ejecución de esta aplicación muestra una interfaz visual similar a esta:
A cada control de tipo Checkbutton lo asociamos con un objeto de la clase IntVar (por defecto el
objeto de la clase IntVar almacena un cero indicando que el Checkbutton debe aparecer no
seleccionado):
self.seleccion1=tk.IntVar()
self.check1=tk.Checkbutton(self.ventana1,text="Python",
variable=self.seleccion1)
self.check1.grid(column=0, row=0)
Cuando se presiona el botón se ejecuta el método 'verificar' donde analizamos que almacenan los
objetos seleccion1, seleccion2 y seleccion3. En el caso de almacenar un 1 significa que el
Checkbutton asociado está seleccionado:
def verificar(self):
cant=0
if self.seleccion1.get()==1:
cant+=1
if self.seleccion2.get()==1:
cant+=1
if self.seleccion3.get()==1:
cant+=1
self.label1.configure(text="cantidad:"+str(cant))
Problema:
Disponer un control Checkbutton que muestre el siguiente mensaje: ¿Está de acuerdo con los
términos y condiciones?, además agregar un Button desactivo. Cuando se tilde el Checkbutton
inmediatamente activar el botón.
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.seleccion=tk.IntVar()
self.check1=tk.Checkbutton(self.ventana1,text="¿Está de
acuerdo con los términos y condiciones?", variable=self.seleccion,
command=self.cambiarestado)
self.check1.grid(column=0, row=0)
self.boton1=tk.Button(self.ventana1, text="Entrar",
state="disabled", command=self.ingresar)
self.boton1.grid(column=0, row=1)
self.ventana1.mainloop()
def cambiarestado(self):
if self.seleccion.get()==1:
self.boton1.configure(state="normal")
if self.seleccion.get()==0:
self.boton1.configure(state="disabled")
def ingresar(self):
self.ventana1.title("Ingresando...")
aplicacion1=Aplicacion()
Inmediatamente se inicia la aplicación el botón aparece desactivo (es decir el operador no lo puede
presionar) debido a que hemos inicializado el parámetro state con el valor "disabled":
self.boton1=tk.Button(self.ventana1, text="Entrar",
state="disabled", command=self.ingresar)
Otro concepto importante de este ejemplo es que podemos asociar un evento a un control de tipo
Checkbutton mediante el parámetro "command" (el mismo se ejecuta cada vez que hacemos un
cambio en el control):
self.check1=tk.Checkbutton(self.ventana1,text="¿Está de
acuerdo con los términos y condiciones?", variable=self.seleccion,
command=self.cambiarestado)
El método "cambiarestado" tiene por objetivo activar o desactivar el botón según el estado del
Checkbutton:
def cambiarestado(self):
if self.seleccion.get()==1:
self.boton1.configure(state="normal")
if self.seleccion.get()==0:
self.boton1.configure(state="disabled")
El control visual Listbox se emplea para mostrar una lista de items. El usuario puede seleccionar
uno o más elementos de la lista según como se lo configure al crearlo.
Problema:
Disponer un Listbox con una serie de nombres de frutas. Permitir la selección solo de uno de ellos.
Cuando se presione un botón recuperar la fruta seleccionada y mostrarla en una Label.
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.listbox1=tk.Listbox(self.ventana1)
self.listbox1.grid(column=0,row=0)
self.listbox1.insert(0,"papa")
self.listbox1.insert(1,"manzana")
self.listbox1.insert(2,"pera")
self.listbox1.insert(3,"sandia")
self.listbox1.insert(4,"naranja")
self.listbox1.insert(5,"melon")
self.boton1=tk.Button(self.ventana1, text="Recuperar",
command=self.recuperar)
self.boton1.grid(column=0, row=1)
self.label1=tk.Label(self.ventana1,text="Seleccionado:")
self.label1.grid(column=0, row=2)
self.ventana1.mainloop()
def recuperar(self):
if len(self.listbox1.curselection())!=0:
self.label1.configure(text=self.listbox1.get(self.listbox1.cursele
ction()[0]))
aplicacion1=Aplicacion()
La ejecución de esta aplicación muestra una interfaz visual similar a esta:
Creamos un objeto de la clase Listbox, por defecto solo se puede seleccionar un único elemento:
self.listbox1=tk.Listbox(self.ventana1)
Insertamos una serie de items en el Listbox mediante el método insert (indicamos en el primer
parámetro la posición y en el segundo el valor a insertar):
self.listbox1.insert(0,"papa")
self.listbox1.insert(1,"manzana")
self.listbox1.insert(2,"pera")
self.listbox1.insert(3,"sandia")
self.listbox1.insert(4,"naranja")
self.listbox1.insert(5,"melon")
def recuperar(self):
if len(self.listbox1.curselection())!=0:
self.label1.configure(text=self.listbox1.get(self.listbox1.cursele
ction()[0]))
El método curselection retorna una tupla con todas las posiciones seleccionadas del Listbox. Como
se trata de un Listbox que permite la selección de un único item luego por eso accedemos al item de
la tupla de la posición 0.
Problema:
Disponer un Listbox con una serie de nombres de frutas. Permitir la selección de varias frutas.
Cuando se presione un botón recuperar todas las frutas seleccionadas y mostrarlas en una Label.
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.listbox1=tk.Listbox(self.ventana1,
selectmode=tk.MULTIPLE)
self.listbox1.grid(column=0,row=0)
self.listbox1.insert(0,"papa")
self.listbox1.insert(1,"manzana")
self.listbox1.insert(2,"pera")
self.listbox1.insert(3,"sandia")
self.listbox1.insert(4,"naranja")
self.listbox1.insert(5,"melon")
self.boton1=tk.Button(self.ventana1, text="Recuperar",
command=self.recuperar)
self.boton1.grid(column=0, row=1)
self.label1=tk.Label(self.ventana1,text="Seleccionado:")
self.label1.grid(column=0, row=2)
self.ventana1.mainloop()
def recuperar(self):
if len(self.listbox1.curselection())!=0:
todas=''
for posicion in self.listbox1.curselection():
todas+=self.listbox1.get(posicion)+"\n"
self.label1.configure(text=todas)
aplicacion1=Aplicacion()
self.listbox1=tk.Listbox(self.ventana1,
selectmode=tk.MULTIPLE)
Para mostrar todas las frutas seleccionadas ahora debemos disponer un for para recorrer la tupla que
retorna el método curselection y concatenarlas:
def recuperar(self):
if len(self.listbox1.curselection())!=0:
todas=''
for posicion in self.listbox1.curselection():
todas+=self.listbox1.get(posicion)+"\n"
self.label1.configure(text=todas)
Barra de scroll
Por defecto no aparece una barra de scroll si la cantidad de item supera el tamaño del cuadro del
Listbox. Para que se muestre una barra de scroll la debemos crear y enlazar con el Listbox.
El mismo programa anterior pero con la barra de scroll queda:
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.scroll1 = tk.Scrollbar(self.ventana1,
orient=tk.VERTICAL)
self.listbox1=tk.Listbox(self.ventana1,
selectmode=tk.MULTIPLE, yscrollcommand=self.scroll1.set)
self.listbox1.grid(column=0,row=0)
self.scroll1.configure(command=self.listbox1.yview)
self.scroll1.grid(column=1, row=0, sticky='NS')
self.listbox1.insert(0,"papa")
self.listbox1.insert(1,"manzana")
self.listbox1.insert(2,"pera")
self.listbox1.insert(3,"sandia")
self.listbox1.insert(4,"naranja")
self.listbox1.insert(5,"melon")
self.listbox1.insert(6,"limon")
self.listbox1.insert(7,"kiwi")
self.listbox1.insert(5,"banana")
self.listbox1.insert(5,"uva")
self.listbox1.insert(5,"papaya")
self.listbox1.insert(5,"mandarina")
self.listbox1.insert(5,"frutilla")
self.boton1=tk.Button(self.ventana1, text="Recuperar",
command=self.recuperar)
self.boton1.grid(column=0, row=1)
self.label1=tk.Label(self.ventana1,text="Seleccionado:")
self.label1.grid(column=0, row=2)
self.ventana1.mainloop()
def recuperar(self):
if len(self.listbox1.curselection())!=0:
todas=''
for posicion in self.listbox1.curselection():
todas+=self.listbox1.get(posicion)+"\n"
self.label1.configure(text=todas)
aplicacion1=Aplicacion()
self.scroll1 = tk.Scrollbar(self.ventana1,
orient=tk.VERTICAL)
Al crear el Listbox pasamos en el parámetro yscrollcommand la referencia del método set del
Scrollbar creado:
self.listbox1=tk.Listbox(self.ventana1,
selectmode=tk.MULTIPLE, yscrollcommand=self.scroll1.set)
Al Scrollbar configuramos el parámetro command con la referencia del método yview del Listbox:
self.scroll1.configure(command=self.listbox1.yview)
Finalmente ubicamos el Scrollbar en la segunda columna y hacemos que se expanda de 'N' North a
'S' South configurando sticky:
Tk hemos dicho que es una biblioteca de controles visuales que los podemos acceder desde Python
y desde otros lenguajes de programación.
En la versión Tk 8.5 sumó una nueva serie de controles visuales ( Notebook, Combobox etc.) y
modernizó los que hemos visto en los conceptos anteriores. Para hacer uso de esta nueva versión de
la biblioteca en Python se implementó un nuevo módulo y se lo agregó al paquete tkinter.
Para hacer uso de este conjunto de Widget (controles visuales) debemos importar el paquete ttk.
Todo lo que conocemos hasta ahora de los controles visuales del módulo tkinter funciona
prácticamente sin cambios, lo que deberemos hacer es crear objetos de la clase Button, Entry etc.
recuperándolos ahora del módulo tkinter.ttk
Veamos algunos de los ejemplos ya resueltos pero haciendo uso de los Widget de este nuevo
módulo.
Problema:
Mostrar una ventana y en su interior dos botones y una label utilizando el módulo ttk. La label
muestra inicialmente el valor 1. Cada uno de los botones permiten incrementar o decrementar en
uno el contenido de la label
Programa:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.valor=1
self.ventana1=tk.Tk()
self.ventana1.title("Controles Button y Label")
self.label1=ttk.Label(self.ventana1, text=self.valor)
self.label1.grid(column=0, row=0)
self.label1.configure(foreground="red")
self.boton1=ttk.Button(self.ventana1, text="Incrementar",
command=self.incrementar)
self.boton1.grid(column=0, row=1)
self.boton2=ttk.Button(self.ventana1, text="Decrementar",
command=self.decrementar)
self.boton2.grid(column=0, row=2)
self.ventana1.mainloop()
def incrementar(self):
self.valor=self.valor+1
self.label1.config(text=self.valor)
def decrementar(self):
self.valor=self.valor-1
self.label1.config(text=self.valor)
aplicacion1=Aplicacion()
Como los tres controles (Label y Button) son de este nuevo módulo podemos ver que su
representación visual es distinta:
Si bien los cambios visuales que aparecen en la clase Button no son significativos el módulo
tkinter.ttk trae nuevas funcionalidades, nuevos controles y permite que nuestra interfaz visual se
adapte al sistema operativo donde se está ejecutando (Windows, Mac, Linux etc.)
Analicemos que cambios debemos disponer a nuestra aplicación para utilizar las componentes
Button y Label del módulo tkinter.ttk.
import tkinter as tk
self.ventana1=tk.Tk()
El primer cambio es la necesidad de importar el módulo ttk que se encuentra en el paquete tkinter:
Recordemos que antes creábamos los controles haciendo referencia al módulo tkinter mediante el
alias tk:
self.label1=tk.Label(self.ventana1, text=self.valor)
Programa:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.label1=ttk.Label(text="Ingrese nombre de usuario:")
self.label1.grid(column=0, row=0)
self.dato1=tk.StringVar()
self.entry1=ttk.Entry(self.ventana1, width=30,
textvariable=self.dato1)
self.entry1.grid(column=1, row=0)
self.label2=ttk.Label(text="Ingrese clave:")
self.label2.grid(column=0, row=1)
self.dato2=tk.StringVar()
self.entry2=ttk.Entry(self.ventana1, width=30,
textvariable=self.dato2, show="*")
self.entry2.grid(column=1, row=1)
self.boton1=ttk.Button(self.ventana1, text="Ingresar",
command=self.ingresar)
self.boton1.grid(column=1, row=2)
self.ventana1.mainloop()
def ingresar(self):
if self.dato1.get()=="juan" and
self.dato2.get()=="abc123":
self.ventana1.title("Correcto")
else:
self.ventana1.title("Incorrecto")
aplicacion1=Aplicacion()
La interfaz visual queda:
Nuevamente los únicos cambios que hemos implementado es la importación del módulo ttk:
Es importante notar que los objetos de la clase StringVar pertenecen al paquete tkinter y no al nuevo
paquete ttk:
self.dato1=tk.StringVar()
Problema:
Mostrar dos controles de tipo Radiobutton con las etiquetas "Varón" y "Mujer", cuando se presione
un botón actualizar una Label con el Radiobutton seleccionado.
Programa:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.seleccion=tk.IntVar()
self.seleccion.set(2)
self.radio1=ttk.Radiobutton(self.ventana1,text="Varon",
variable=self.seleccion, value=1)
self.radio1.grid(column=0, row=0)
self.radio2=ttk.Radiobutton(self.ventana1,text="Mujer",
variable=self.seleccion, value=2)
self.radio2.grid(column=0, row=1)
self.boton1=ttk.Button(self.ventana1, text="Mostrar
seleccionado", command=self.mostrarseleccionado)
self.boton1.grid(column=0, row=2)
self.label1=ttk.Label(text="opcion seleccionada")
self.label1.grid(column=0, row=3)
self.ventana1.mainloop()
def mostrarseleccionado(self):
if self.seleccion.get()==1:
self.label1.configure(text="opcion
seleccionada=Varon")
if self.seleccion.get()==2:
self.label1.configure(text="opcion
seleccionada=Mujer")
aplicacion1=Aplicacion()
Problema:
Mostrar una ventana y en su interior tres controles de tipo Checkbutton cuyas etiquetas
correspondan a distintos lenguajes de programación. Cuando se presione un botón mostrar en una
Label la cantidad de Checkbutton que se encuentran chequeados. Utilizar Widget del módulo ttk.
Programa:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.seleccion1=tk.IntVar()
self.check1=ttk.Checkbutton(self.ventana1,text="Python",
variable=self.seleccion1)
self.check1.grid(column=0, row=0)
self.seleccion2=tk.IntVar()
self.check2=ttk.Checkbutton(self.ventana1,text="C++",
variable=self.seleccion2)
self.check2.grid(column=0, row=1)
self.seleccion3=tk.IntVar()
self.check3=ttk.Checkbutton(self.ventana1,text="Java",
variable=self.seleccion3)
self.check3.grid(column=0, row=2)
self.boton1=ttk.Button(self.ventana1, text="Verificar",
command=self.verificar)
self.boton1.grid(column=0, row=4)
self.label1=ttk.Label(text="cantidad:")
self.label1.grid(column=0, row=5)
self.ventana1.mainloop()
def verificar(self):
cant=0
if self.seleccion1.get()==1:
cant+=1
if self.seleccion2.get()==1:
cant+=1
if self.seleccion3.get()==1:
cant+=1
self.label1.configure(text="cantidad:"+str(cant))
aplicacion1=Aplicacion()
Acotaciones
El módulo ttk no implementa el Widget Listbox, pero podemos mezclar en una aplicación controles
visuales de los dos paquetes.
Problema:
Disponer un Listbox con una serie de nombres de frutas. Permitir la selección solo de uno de ellos.
Cuando se presione un botón recuperar la fruta seleccionada y mostrarla en una Label.
Programa:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.listbox1=tk.Listbox(self.ventana1)
self.listbox1.grid(column=0,row=0)
self.listbox1.insert(0,"papa")
self.listbox1.insert(1,"manzana")
self.listbox1.insert(2,"pera")
self.listbox1.insert(3,"sandia")
self.listbox1.insert(4,"naranja")
self.listbox1.insert(5,"melon")
self.boton1=ttk.Button(self.ventana1, text="Recuperar",
command=self.recuperar)
self.boton1.grid(column=0, row=1)
self.label1=ttk.Label(text="Seleccionado:")
self.label1.grid(column=0, row=2)
self.ventana1.mainloop()
def recuperar(self):
if len(self.listbox1.curselection())!=0:
self.label1.configure(text=self.listbox1.get(self.listbox1.cursele
ction()[0]))
aplicacion1=Aplicacion()
Notemos que la clase Listbox la recuperamos del módulo tkinter a través de su alias tk:
self.listbox1=tk.Listbox(self.ventana1)
Si tratamos de recuperarla del otro módulo se nos informará que no existe mediante un mensaje de
error:
ttk : control Combobox
El control Combobox del paquete ttk permite seleccionar un string de un conjunto de items que se
despliegan.
Podemos indicar cual elemento muestre por defecto mediante el método 'current'.
Por defecto el operador puede además de seleccionar un elemento cargar por teclado cualquier
cadena.
Problema:
Mostrar en una ventana un control de tipo Combobox con los días de la semana. Cuando se presione
un botón actualizar una Label con el día seleccionado.
Programa:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.label1=ttk.Label(self.ventana1, text="Seleccione un
día de la semana")
self.label1.grid(column=0, row=0)
self.opcion=tk.StringVar()
diassemana=("lunes","martes","miércoles","jueves","viernes","sábad
o","domingo")
self.combobox1=ttk.Combobox(self.ventana1,
width=10,
textvariable=self.opcion,
values=diassemana)
self.combobox1.current(0)
self.combobox1.grid(column=0, row=1)
self.boton1=tk.Button(self.ventana1, text="Recuperar",
command=self.recuperar)
self.boton1.grid(column=0, row=2)
self.label2=ttk.Label(self.ventana1, text="Día
seleccionado:")
self.label2.grid(column=0, row=3)
self.ventana1.mainloop()
def recuperar(self):
self.label2.configure(text=self.opcion.get())
aplicacion1=Aplicacion()
self.opcion=tk.StringVar()
diassemana=("lunes","martes","miércoles","jueves","viernes","sábad
o","domingo")
self.combobox1=ttk.Combobox(self.ventana1,
width=10,
textvariable=self.opcion,
values=diassemana)
self.combobox1.current(0)
self.combobox1.grid(column=0, row=1)
Debemos pasar en el parámetro values una tupla con los elementos que debe mostrar el control
Combobox. Asociamos al parámetro textvariable un objeto de la clase StringVar para poder
posteriormente recuperar el valor seleccionado.
Mediante el método current podemos indicar cual de los elementos debe aparecer seleccionado.
Si ejecutamos la aplicación y escribimos dentro del Combobox podemos ver que nos deja ingresar
cualquier string. Para desactivar la edición del Combobox debemos iniciar el parámetro state con el
valor 'readonly':
self.combobox1=ttk.Combobox(self.ventana1,
width=10,
textvariable=self.opcion,
values=diassemana,
state='readonly')
tkinter : control Menu
Para implementar los típicos menú de barra horizontales que aparecen en las aplicaciones cuando
utilizamos la librería Tk necesitamos crear objetos de la clase Menu que se encuentra declarada en
el paquete tkinter y no en el paquete tkinter.ttk.
Confeccionar una aplicación que muestre dos opciones en el menú de barra superior. La primer
opción despliega un submenú que permita cambiar el color de fondo del formulario y la segunda
permita cambiar el tamaño de formulario:
Programa:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
menubar1 = tk.Menu(self.ventana1)
self.ventana1.config(menu=menubar1)
opciones1 = tk.Menu(menubar1)
opciones1.add_command(label="Rojo",
command=self.fijarrojo)
opciones1.add_command(label="Verde",
command=self.fijarverde)
opciones1.add_command(label="Azul",
command=self.fijarazul)
menubar1.add_cascade(label="Colores", menu=opciones1)
opciones2 = tk.Menu(menubar1)
opciones2.add_command(label="640x480",
command=self.ventanachica)
opciones2.add_command(label="1024x800",
command=self.ventanagrande)
menubar1.add_cascade(label="Tamaños", menu=opciones2)
self.ventana1.mainloop()
def fijarrojo(self):
self.ventana1.configure(background="red")
def fijarverde(self):
self.ventana1.configure(background="green")
def fijarazul(self):
self.ventana1.configure(background="blue")
def ventanachica(self):
self.ventana1.geometry("640x480")
def ventanagrande(self):
self.ventana1.geometry("1024x800")
aplicacion1=Aplicacion()
Importamos solo el módulo tkinter ya que no utilizamos controles del módulo tkinter.ttk:
import tkinter as tk
Luego de crear el objeto de la clase Tk procedemos a crear un objeto de la clase Menu y pasar como
referencia la ventana:
self.ventana1=tk.Tk()
menubar1 = tk.Menu(self.ventana1)
Pasamos al parámetro menu de la ventana el objeto de la clase Menu que acabamos de crear (si no
hacemos esto no aparecerá luego el menú de opciones:
self.ventana1.config(menu=menubar1)
Creamos un segundo objeto de la clase Menu, pero en este caso le pasamos la referencia del primer
objeto de la clase Menu que creamos, también añadimos las tres opciones que mostrará:
opciones1 = tk.Menu(menubar1)
opciones1.add_command(label="Rojo",
command=self.fijarrojo)
opciones1.add_command(label="Verde",
command=self.fijarverde)
opciones1.add_command(label="Azul",
command=self.fijarazul)
Finalmente llamamos al método 'add_cascade' del menubar1 que creamos anteriormente indicando
en el parámetro menu el otro objeto de la clase Menu:
menubar1.add_cascade(label="Colores", menu=opciones1)
opciones2 = tk.Menu(menubar1)
opciones2.add_command(label="640x480",
command=self.ventanachica)
opciones2.add_command(label="1024x800",
command=self.ventanagrande)
menubar1.add_cascade(label="Tamaños", menu=opciones2)
Cuando ejecutamos alguna de las opciones se dispara el método que hemos configurado en el
parámetro command, por ejemplo si seleccionamos 'Verde':
Variantes en un menú.
opciones1 = tk.Menu(menubar1)
opciones1.add_command(label="Rojo",
command=self.fijarrojo)
opciones1.add_command(label="Verde",
command=self.fijarverde)
opciones1.add_separator()
opciones1.add_command(label="Azul",
command=self.fijarazul)
-Los menú desplegables muestran una línea de puntos antes de la primer opción. Si el operador hace
clic sobre la misma el menú desplegable se muestra en una barra de herramientas fuera de la
ventana principal (puede tener sentido si en un programa debemos seleccionar opciones en forma
muy seguida y no queremos tener que estar abriendo el menú desplegable):
Si queremos evitar esta característica de los menú desplegables de tkinter debemos pasar el
parámetro 'tearoff' con el valor 0:
-Otra posibilidad es agregar teclas de acceso rápido a opciones de nuestro menú. Esto se resuelve la
parte visual agregando el parámetro 'acelerator', y por otro lado asignar a cada una de las teclas de
acceso rápido la ejecución de un método:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
menubar1 = tk.Menu(self.ventana1)
self.ventana1.config(menu=menubar1)
opciones1 = tk.Menu(menubar1, tearoff=0)
opciones1.add_command(label="Rojo",
command=self.fijarrojo, accelerator="Ctrl+R")
opciones1.add_command(label="Verde",
command=self.fijarverde, accelerator="Ctrl+V")
opciones1.add_separator()
opciones1.add_command(label="Azul",
command=self.fijarazul, accelerator="Ctrl+A")
self.ventana1.bind_all("<Control-r>", self.cambiar)
self.ventana1.bind_all("<Control-v>", self.cambiar)
self.ventana1.bind_all("<Control-a>", self.cambiar)
menubar1.add_cascade(label="Colores", menu=opciones1)
opciones2 = tk.Menu(menubar1)
opciones2.add_command(label="640x480",
command=self.ventanachica)
opciones2.add_command(label="1024x800",
command=self.ventanagrande)
menubar1.add_cascade(label="Tamaños", menu=opciones2)
self.ventana1.mainloop()
def fijarrojo(self):
self.ventana1.configure(background="red")
def fijarverde(self):
self.ventana1.configure(background="green")
def fijarazul(self):
self.ventana1.configure(background="blue")
def ventanachica(self):
self.ventana1.geometry("640x480")
def ventanagrande(self):
self.ventana1.geometry("1024x800")
aplicacion1=Aplicacion()
El método cambiar se ejecuta cuando presionamos al mismo tiempo la tecla Ctrl y alguna de las
otras teclas "R", "V" o "A":
-Podemos disponer dentro de un menú desplegable una opción que despliegue otro submenú, la
interfaz visual debe ser similar a esta:
import tkinter as tk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
menubar1 = tk.Menu(self.ventana1)
self.ventana1.config(menu=menubar1)
opciones1 = tk.Menu(menubar1)
opciones1.add_command(label="Rojo",
command=self.fijarrojo)
opciones1.add_command(label="Verde",
command=self.fijarverde)
opciones1.add_command(label="Azul",
command=self.fijarazul)
menubar1.add_cascade(label="Colores", menu=opciones1)
opciones2 = tk.Menu(menubar1)
opciones2.add_command(label="640x480",
command=self.ventanachica)
opciones2.add_command(label="1024x800",
command=self.ventanagrande)
submenu1=tk.Menu(menubar1)
submenu1.add_command(label="1024x1024",
command=self.tamano1)
submenu1.add_command(label="1280x1024",
command=self.tamano2)
opciones2.add_cascade(label="Otros tamaños", menu=
submenu1)
menubar1.add_cascade(label="Tamaños", menu=opciones2)
self.ventana1.mainloop()
def fijarrojo(self):
self.ventana1.configure(background="red")
def fijarverde(self):
self.ventana1.configure(background="green")
def fijarazul(self):
self.ventana1.configure(background="blue")
def ventanachica(self):
self.ventana1.geometry("640x480")
def ventanagrande(self):
self.ventana1.geometry("1024x800")
def tamano1(self):
self.ventana1.geometry("1024x1024")
def tamano2(self):
self.ventana1.geometry("1280x1024")
aplicacion1=Aplicacion()
tkinter : Layout Manager (administrador de diseño)
Una de las herramientas fundamentales cuando armamos interfaces visuales es la metodología que
utilizamos para disponer los controles dentro del formulario. Hasta ahora hemos utilizado el
administrador de diseño Grid.
En la librería GUI tkinter disponemos de tres Layout Manager para disponer controles dentro de
una ventana:
Grid
Pack
Place
Solo se puede utilizar uno de estos Layout Manager dentro de un contenedor, recordemos que un
contenedor puede ser la ventana propiamente dicha, un Frame o un LabelFrame.
El gestor de diseño más completo y que se adapta en la mayoría de las situaciones es el Grid, pero
podemos en muchos casos crear Frame o LabelFrame y definir dentro de estos Layout Manager de
tipo Pack o Place.
Problema:
Disponer una serie de botones utilizando el Layout Manager de tipo Pack.
La representación visual debe ser:
Programa:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.boton1=ttk.Button(self.ventana1, text="Boton 1")
self.boton1.pack(side=tk.TOP, fill=tk.BOTH)
self.boton2=ttk.Button(self.ventana1, text="Boton 2")
self.boton2.pack(side=tk.TOP, fill=tk.BOTH)
self.boton3=ttk.Button(self.ventana1, text="Boton 3")
self.boton3.pack(side=tk.TOP, fill=tk.BOTH)
self.boton4=ttk.Button(self.ventana1, text="Boton 4")
self.boton4.pack(side=tk.LEFT)
self.boton5=ttk.Button(self.ventana1, text="Boton 5")
self.boton5.pack(side=tk.RIGHT)
self.boton6=ttk.Button(self.ventana1, text="Boton 6")
self.boton6.pack(side=tk.RIGHT)
self.boton7=ttk.Button(self.ventana1, text="Boton 7")
self.boton7.pack(side=tk.RIGHT)
self.ventana1.mainloop()
aplicacion1=Aplicacion()
Para ubicar los controles empleando el administrador de diseños Pack utilizamos el método 'pack'
que cuenta con una serie de parámetros.
El boton1 se ubica en la parte superior de la ventana ya que en el parámetro side hemos pasado la
contante tk.TOP:
El segundo y tercer botón se ubican debajo del primero porque también en el parámetro side hemos
pasado el valor 'tk.TOP':
El cuarto botón hemos indicado en el parámetro side el valor 'tk.LEFT' y los siguientes botones el
valor 'tk.RIGHT':
tk.TOP
tk.LEFT
tk.RIGHT
tk.BOTTOM
Podemos pasar los parámetros padx y pady para dejar espacio entre los controles visuales y el borde
del contenedor:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.boton1=ttk.Button(self.ventana1, text="Boton 1")
self.boton1.pack(side=tk.TOP, fill=tk.BOTH, padx=5,
pady=5)
self.boton2=ttk.Button(self.ventana1, text="Boton 2")
self.boton2.pack(side=tk.TOP, fill=tk.BOTH, padx=15,
pady=15)
self.boton3=ttk.Button(self.ventana1, text="Boton 3")
self.boton3.pack(side=tk.TOP, fill=tk.BOTH, padx=25,
pady=25)
self.boton4=ttk.Button(self.ventana1, text="Boton 4")
self.boton4.pack(side=tk.LEFT)
self.boton5=ttk.Button(self.ventana1, text="Boton 5")
self.boton5.pack(side=tk.RIGHT, padx=10)
self.boton6=ttk.Button(self.ventana1, text="Boton 6")
self.boton6.pack(side=tk.RIGHT)
self.boton7=ttk.Button(self.ventana1, text="Boton 7")
self.boton7.pack(side=tk.RIGHT)
self.ventana1.mainloop()
aplicacion1=Aplicacion()
Este tipo de Layout Manager lo hemos estado utilizando en muchos conceptos anteriores, veremos
otras posibilidades que nos suministra.
Este tipo de Layout define una tabla con columnas y filas, cada vez que agregamos un Widget
indicamos en que columna y fila se debe ubicar:
Un tema que no vimos es que podemos expandir celdas de la tabla para que se ocupen más de una
columna o más de una fila.
Problema:
Disponer una serie de botones utilizando el Layout Manager de tipo Grid.
La representación visual debe ser:
Programa:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.boton1=ttk.Button(self.ventana1, text="Boton 1")
self.boton1.grid(column=0, row=0)
self.boton2=ttk.Button(self.ventana1, text="Boton 2")
self.boton2.grid(column=1, row=0)
self.boton3=ttk.Button(self.ventana1, text="Boton 3")
self.boton3.grid(column=2, row=0, rowspan=2, sticky="ns")
self.boton4=ttk.Button(self.ventana1, text="Boton 4")
self.boton4.grid(column=0, row=1)
self.boton5=ttk.Button(self.ventana1, text="Boton 5")
self.boton5.grid(column=1, row=1)
self.boton6=ttk.Button(self.ventana1, text="Boton 6")
self.boton6.grid(column=0, row=2, columnspan=3,
sticky="we")
self.ventana1.mainloop()
aplicacion1=Aplicacion()
Los dos primeros botones como ocupan una celda única no varía con lo que hemos visto hasta
ahora:
En la propiedad sticky (se traduce como 'pegajoso') pedimos que el botón se expanda de north
(norte) a south (sur), si no disponemos sticky luego el botón ocupa las dos celdas pero aparece
centrado.
Este tipo de Layout Manager nos permite disponer un Widget en una posición y con un tamaño con
valor absoluto a nivel de píxeles. Hay que tener cuidado en que casos utilizar este tipo de
administrador de diseños ya que si agrandamos o reducimos el tamaño de la ventana puede ser que
los controles queden fuera de la ventana y el operador no pueda visualizarlos.
Problema:
Disponer dos botones en la parte inferior derecha de la ventana utilizando el Layout Manager de
tipo Place. El ancho y alto de la ventana debe ser de 800 por 600 píxeles.
La representación visual debe ser:
Programa:
import tkinter as tk
from tkinter import ttk
class Aplicacion:
def __init__(self):
self.ventana1=tk.Tk()
self.ventana1.geometry("800x600")
self.ventana1.resizable(0,0)
self.boton1=ttk.Button(self.ventana1, text="Confirmar")
self.boton1.place(x=680, y=550, width=90, height=30)
self.boton2=ttk.Button(self.ventana1, text="Cancelar")
self.boton2.place(x=580, y=550, width=90, height=30)
self.ventana1.mainloop()
aplicacion1=Aplicacion()
self.ventana1.geometry("800x600")
No permitimos que el operador la redimensione con el mouse (esto debido a que si reduce el
tamaño los botones quedarán fuera de la ventana):
self.ventana1.resizable(0,0)
Al botón que tiene la etiqueta "Confirmar" lo ubicamos en la columna 680 (indicado en píxeles) y la
fila 550, también definimos el ancho y alto:
self.boton1=ttk.Button(self.ventana1, text="Confirmar")
self.boton1.place(x=680, y=550, width=90, height=30)
self.boton2=ttk.Button(self.ventana1, text="Cancelar")
self.boton2.place(x=580, y=550, width=90, height=30)
Podemos utilizar el método 'place' para ubicar cualquiera de los controles visuales que hemos visto
hasta ahora: Button, Label, Entry, etc.
Recomendación
Siempre que tenga que implementar una interfaz gráfica es conveniente que en un papel se haga un
croquis y a partir de este agrupar controles relacionados dentro de Frame o LabelFrame.