63 - módulo ttk

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

Importar el módulo ttk

Debemos utilizar la siguiente sintaxis para importar el nuevo módulo:

from tkinter import 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: ejercicio234.py

Ver video

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:

tkinter.ttk Button Label

Recordemos como se veían utilizando el módulo tkinter:

tkinter Button Label

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.

Debemos seguir importando el paquete tkinter como lo veníamos haciendo:

import tkinter as tk

Se sigue utilizando la clase 'Tk' para crear la ventana principal:

        self.ventana1=tk.Tk()

El primer cambio es la necesidad de importar el módulo ttk que se encuentra en el paquete tkinter:

from tkinter import ttk

El segundo y último cambio es que cada vez que debemos crear un control visual lo referenciamos del nuevo módulo ttk:

        self.label1=ttk.Label(self.ventana1, text=self.valor)
        ...
        self.boton1=ttk.Button(self.ventana1, text="Incrementar", command=self.incrementar)
        ...
        self.boton2=ttk.Button(self.ventana1, text="Decrementar", command=self.decrementar)

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)

Resolvamos otros problemas ya resueltos empleando el nuevo módulo de Widged propuesto en el módulo tkinter.ttk.

Problema:

Ingresar el nombre de usuario y clave en controles de tipo Entry. Si se ingresa las cadena (usuario: juan, clave="abc123") luego mostrar en el título de la ventana el mensaje "Correcto" en caso contrario mostrar el mensaje "Incorrecto". Utilizar Widget del módulo ttk.

Programa: ejercicio235.py

Ver video

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:

tkinter.ttk Entry Button Label

Nuevamente los únicos cambios que hemos implementado es la importación del módulo ttk:

from tkinter import ttk

Y la creación de los 5 Widget:

        self.label1=ttk.Label(text="Ingrese nombre de usuario:")
        self.entry1=ttk.Entry(self.ventana1, width=30, textvariable=self.dato1)
        self.label2=ttk.Label(text="Ingrese clave:")
        self.entry2=ttk.Entry(self.ventana1, width=30, textvariable=self.dato2, show="*")
        self.boton1=ttk.Button(self.ventana1, text="Ingresar", command=self.ingresar)

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: ejercicio236.py

Ver video

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()

La interfaz visual con el módulo ttk queda:

tkinter.ttk Radiobutton Button Label

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: ejercicio237.py

Ver video

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()

La interfaz visual con el módulo ttk queda:

tkinter.ttk Checkbutton Button Label

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: ejercicio238.py

Ver video

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.curselection()[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:

tkinter.ttk Lisbox Label