La ventana principal

La ventana principal de la aplicación se crea como un objeto de la clase Tk de tkinter.

import tkinter as tk

v_principal = tk.Tk()

Una vez creado un objeto de este tipo, se colocan los widgets que necesita y se ejecuta la aplicación usando el método mainloop(), que lanza el bucle principal, encargado de gestionar todos los eventos que reciba la aplicación.

v_principal.mainloop()

En este primer ejemplo he usado el identificador v_principal para la ventana principal de la aplicación. Sin rendirnos al lenguaje anglosajón, podemos admitir que main significa lo mismo cuando estamos desarrollando una aplicación visual, la ventana principal es la aplicación en sí, el elemento principal, main, de nuestro desarrollo. En la mayoría de ejemplos que encontraremos este elemento principal se denomina rooto main o app. En los ejemplos de estos apuntes encontraremos el identificador de la ventana principal de la aplicación bajo diferentes nombres.

Ejercicio 1

Guarda las tres líneas de código anteriores en un archivo con el nombre Tk-0.py, abre el terminal, sitúate en la carpeta en que has guardado el archivo y ejecuta:

$ python Tk-0.py

Comprueba las cualidades de la aplicación que has creado, su tamaño, título de la ventana, botones, menús, redimensionado...

Documentación

Para obtener documentación sobre esta clase recurriremos a la función interna help de Python (esto lo repetiremos con todas las clases que vayamos utilizando a lo largo del curso). Basta escribir en la consola interactiva de Python las siguientes sentencias1:

>>> import tkinter as tk
>>> help(tk.Tk)

La clase Tk se instancia sin argumentos. Crea un widget de alto nivel, generalmente usado como la ventana principal de la aplicación. Cada instancia tiene asociado su propio intérprete Tcl. Su prototipo es1:

class tkinter.Tk(tkinter.Tk(screenName=None, baseName=None, className='Tk', useTk=1, sync=0, use=None)

Métodos

En http://effbot.org/tkinterbook/widget.htm#Tkinter.Widget.after-method hay un listado de los métodos comunes a los widgets de tkinter:

config(option=value)
cget("option")
keys()
...

La ventana principal (Tk) y las ventanas de alto nivel (Toplevel) comparten métodos. Su comportamiento no es el mismo en todos los casos, algunos gestores de ventanas no soportan iconos, otros no soportan agrupaciones...

Iremos probando los métodos conforme los necesitemos, comenzaremos con los siguientes:

maxsize(width=None, height=None)
minsize(width=None, height=None)
resizable(width=None, height=None)
state(newstate=None)
title(string=None)
quit()
transient(master=None)
destroy()
...

Ejercicio 2

Edita el archivo Tk-0.py para añadirle las siguientes sentencias:

def cuenta_clics(self):
   global clics
   clics += 1
   main.title("Has hecho " + str(clics) + " clicks")

clics = 0

main.bind('<Button-1>', cuenta_clics)

Guarda el archivo con el nombre Tk-1.py, abre el terminal, sitúate en la carpeta en que has guardado el archivo y ejecuta:

python Tk-1.py

Comprueba cómo responde la aplicación al hacer clic con el botón principal del ratón sobre cualquiera de sus elementos (cuerpo, título, botones minimizar y maximizar) e incluso al redimensionarla.

Añadiendo widgets a la ventana principal

En el tema anterior hemos conocido los widgets de tkinter y de tkinter.ttk pero aún no sabemos cómo añadirlos a nuestra aplicación, concretamente a la ventana principal de nuestra aplicación. Cada widget tiene un tema dedicado en esta asignatura, para profundizar en su uso. En este tema se expondrá cómo añadir etiquetas y botones, sin profundizar, con el objetivo de poder usar más de un widget en los ejemplos de estos apuntes.

Para añadir un objeto visual a una aplicación primero se ha de crear el objeto, y a continuación utilizar algún método que lo coloque en la parte de la ventana que deseemos. Para crear un objeto en Python basta con llamar a su constructor con los parámetros necesarios. Para colocarlo en una ventana se puede usar su método pack(), que se estudiará a fondo en la siguiente unidad. Pueden hacerse ambas acciones en una única línea: crear el objeto y colocarlo en la ventana.

Añadiendo una etiqueta

Si queremos añadir una etiqueta a la ventana principal hemos de usar un objeto de la clase Label.

import tkinter as tk
import tkinter.ttk as ttk

tk.Tk()

ttk.Label(text='Esto es una etiqueta').pack()

mainloop()

Ejercicio

Identifica la ventana principal y crea la etiqueta indicando que su master es la ventana principal. Recuerda que en una aplicación compleja se reserva memoria para todos los objetos que utiliza y se debe desarrollar teniendo en mente que todos los objetos definidos han de ser destruidos correctamente antes de finalizar la ejecución de la aplicación.

Añadiendo un botón

Un botón es más complicado, ya que se supone que se utilizará para pulsarlo. Visualmente puede ser como una etiqueta, pero no es meramente informativo. Al pulsar un botón se llama directamente a una función, por lo que se ha de definir la función antes de crear el botón.

import tkinter as tk
import tkinter.ttk as ttk

def AlHacerClic():
    print('Has hecho clic')

v_principal = tk.Tk()

ttk.Label(v_principal, text='Esto es una etiqueta').pack()
ttk.Button(v_principal, text='Púlsame', command=AlHacerClic).pack()

v_principal.mainloop()

Para modificar el texto de un botón hay que conocer su identificador y utilizar su método configure o directamente acceder a la propiedad text de su diccionario. Para tenerlo identificado basta con declarar una variable al crearlo.

boton = ttk.Button(v_principal, text='Púlsame'), command=AlHacerClic).pack()

Para modificar su texto tenemos dos opciones:

boton.configure(text='Me has pulsado')

o

boton['text'] = 'Me has pulsado'

Ejercicios

Con esta información, recrea la aplicación que utilizamos para comprobar si tkinter está instalado en tu ordenador34:

$ python -m tkinter

Observa que con la información que tienes has recreado la aplicación usandotkinter.ttk.Label y tkinter.ttk.Button. Compara tu aplicación con la demo de tkinter y comprueba que la etiqueta y los botones son distintos. Recrea de nuevo la aplicación usando tkinter.Label y tkinter.Button.

Recetas

Control sobre el cierre de la aplicación

Para confirmar el cierre de la aplicación asociaremos el protocolo WM_DELETE_WINDOWa la ventana principal, obligando a la aplicación a pasar por una función que controla su cierre. Usaremos además un messageboxcon el que la aplicación pregunta al usuario si quiere cerrar la aplicación.

import tkinter as tk
from tkinter import messagebox

def ask_quit():
    if messagebox.askokcancel("Cerrar la aplicación", "¿Seguro que quieres cerrar la aplicación?\n\n*sniff*"):
        root.destroy()

root = tk.Tk()
root.protocol("WM_DELETE_WINDOW", ask_quit)
root.mainloop()

HolaMundo en POO

import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Hello World\n(click me)"
        self.hi_there["command"] = self.say_hi
        self.hi_there.pack(side="top")

        self.quit = tk.Button(self, text="QUIT", fg="red",
                              command=root.destroy)
        self.quit.pack(side="bottom")

    def say_hi(self):
        print("hi there, everyone!")

root = tk.Tk()
app = Application(master=root)
app.mainloop()

Controlando su redimensionado

El método resizable(width=None, height=None) recibe dos parámetros booleanos con los que se le indica a la ventana si se puede redimensionar o no tanto en ancho como en alto. Por defecto tienen el valor None, que se interpreta como verdadero. Si queremos que no se pueda redimensionar basta con escribir:

root.resizable(width=False, height=False)

Pero si queremos que sólo se pueda redimensionar en una dirección tendremos que usar tres líneas de código5

root.resizable(width=True, height=False)
root.update()
root.resizable(width=True, height=False)

Actualizando un widget cada cierto tiempo

Ejecuta el código mostrado en https://stackoverflow.com/questions/7573031/when-i-use-update-with-tkinter-my-label-writes-another-line-instead-of-rewriti para comprobar cómo usar el comando after(delay_ms, callback=None, *args) disponible en todos los widgets de tkinter.

import Tkinter as tk
import time

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.clock = tk.Label(self, text="")
        self.clock.pack()

        # start the clock "ticking"
        self.update_clock()

    def update_clock(self):
        now = time.strftime("%H:%M:%S" , time.gmtime())
        self.clock.configure(text=now)
        # call this function again in one second
        self.after(1000, self.update_clock)

if __name__== "__main__":
    app = SampleApp()
    app.mainloop()

Ejercicio

Copia el código de la aplicación Primitiva desarrollado por Javier Ceballos Fernández, comprueba las normas del juego de la Primitiva y corrige la aplicación.

Referencias

1. Obtenido de la órden help(tk.Tk) ejecutada en la consola interactiva de Python, donde aparece como una clase con el constructor __init__(self, screenName=None, baseName=None, className='Tk', useTk=1, sync=0, use=None). Para salir de la ayuda interactiva de Python hay que pulsar la tecla 'Q'.
2. Con dir(tk.Tk) o help(tk.Tk) tienes toda esta información sin conexión a internet.
3. Usada en el tema 1.6.
4. Además de estos apuntes, has de conocer cómo manipular cadenas de caracteres en Python.
5. Al menos en macOS, habrá que probarlo en MS-Windows y en Linux. Son muy pocos los detalles que hemos de tener en cuenta si trabajamos con diferentes sistemas operativos, como comprobarás a lo largo del curso.

results matching ""

    No results matching ""