Saltar a contenido
 No os perd谩is mi futuro contenido, seguidme en y Youtube 馃榿

Editor de texto

Para acabar la unidad he pensado en crear un peque帽o editor de texto, ser谩 una forma de trabajar en conjunto varios de los widgets que hemos ido aprendiendo.

Lo primero es tener claro el dise帽o del programa que vamos a crear. A parte del men煤 superior para gestionar las funcionalidades, nos viene como anillo al dedo un widget Text para manejar todo el contenido, as铆 que vamos a comenzar por crear esta estructura:

Note

from tkinter import *
root = Tk()
root.title("Mi editor")

# Men煤 superior
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Nuevo")
filemenu.add_command(label="Abrir")
filemenu.add_command(label="Guardar")
filemenu.add_command(label="Guardar como")
filemenu.add_separator()
filemenu.add_command(label="Salir", command=root.quit)
menubar.add_cascade(label="Archivo", menu=filemenu)

# Caja de texto central
texto = Text(root)
texto.pack(fill='both', expand=1)
texto.config(padx=6, pady=4, bd=0, font=("Consolas", 12))

# Menu y bucle de la aplicaci贸n
root.config(menu=menubar)
root.mainloop()

Tambi茅n he pensado, que de cara a abrir y guardar ficheros estar铆a bien mostrar un poco de informaci贸n en la parte inferior. Podemos por ejemplo a帽adir una label abajo a la izquierda:

Note

# Monitor inferior
mensaje = StringVar()
mensaje.set('Bienvenido a tu editor')
monitor = Label(root, textvar=mensaje, justify='right')
monitor.pack(side='left')

Muy bien, ya tenemos el dise帽o base. Ahora toca la l贸gica. Vamos a identificar bien todas las funciones que tendr谩 nuestro editor de texto, y podemos mostrar un mensaje utilizando nuestro monitor:

Note

def nuevo():
    mensaje.set('Nuevo fichero')

def abrir(): 
    mensaje.set('Nuevo fichero')

def guardar():
    mensaje.set('Guardar fichero')

def guardar_como():
    print("Guardar fichero como")

Ahora ya podemos dejarlas enlazadas:

Note

filemenu.add_command(label="Nuevo", command=nuevo)
filemenu.add_command(label="Abrir", command=abrir)
filemenu.add_command(label="Guardar", command=guardar)
filemenu.add_command(label="Guardar como", command=guardar_como)

Perfecto, ahora nos falta implementar la l贸gica de las funciones.

Nuevo fichero

Antes de nada vamos a crear una variable global ruta, fuera del 谩mbito de las funciones.

Note

ruta = ''  # La utilizaremos para almacenar informaci贸n

Comenzando por un nuevo fichero, lo que este comando har谩 es simplemente borrar el contenido del Texto dej谩ndolo vac铆o, y reiniciar cualquier posible configuraci贸n:

Note

def nuevo():
    mensaje.set('Nuevo fichero')
    texto.delete(1.0, END)  # En flotante, el primer car谩cter es un salto

Abrir fichero

Ya sabemos que podemos utilizar una ventana emergente para pedirle al usuario que seleccione un fichero del disco duro, as铆 que vamos a importar el m贸dulo file dialog:

Note

from tkinter import filedialog as FileDialog

Ahora tenemos que programar toda la l贸gica:

Note

def abrir():

    # Indicamos que la ruta es respecto a la variable global
    # Debemos de forzar esta lectura global porque los comandos
    # s贸lo son conscientes de las variables externas que son widgets 
    global ruta 

    mensaje.set('Abrir fichero')

    ruta = FileDialog.askopenfilename(
        initialdir='.',
        filetypes=(  # Es una tupla con un elemento
            ("Ficheros de texto", "*.txt"),  
        ), 
        title="Abrir un fichero."
    )

    # Si la ruta es v谩lida abrimos el contenido en lectura
    if ruta != "":  
        fichero = open(ruta, 'r')
        contenido = fichero.read()
        texto.delete(1.0, 'end')           # Nos aseguramos de que est茅 vac铆o
        texto.insert('insert', contenido)  # Le insertamos el contenido
        fichero.close()                    # Cerramos el fichero
        root.title(ruta + " - Mi editor")  # Cambiamos el t铆tulo

Muy bien, ya podemos abrir ficheros. Vamos a aprovechar y antes de continuar, importante que reiniciemos el t铆tulo de ventana y la ruta si hacemos Nuevo. Si no lo hacemos, como m铆nimo la ruta, a la hora de guardar no podremos distinguir si un fichero es nuevo, o se ha abierto desde el disco duro:

Note

def abrir():
    # Indicamos que la ruta es respecto a la variable global
    global ruta

    mensaje.set('Nuevo fichero')

    texto.delete(1.0, END)   # En flotante, el primer car谩cter es un salto
    root.title("Mi editor")  # Reiniciamos el t铆tulo
    ruta = ""                # Reiniciamos la ruta

Guardar fichero

A la hora de guardar un fichero tenemos dos opciones, o es un fichero ya existente, en ese caso en la ruta tendremos un valor, o ser谩 un fichero nuevo, una ruta vac铆a.

En el primer caso vamos a proceder a guardar normalmente el fichero como ya sabemos:

Note

def guardar():
    global ruta
    if ruta != "":
        contenido = texto.get(1.0, 'end')  # Recuperamos el texto
        fichero = open(ruta, 'w+')         # Creamos el fichero o abrimos
        fichero.write(contenido)           # Escribimos el texto
        fichero.close()
        mensaje.set('Fichero guardado correctamente')

Si lo probamos veremos que todo se guarda correctamente. Pero si guardamos un fichero y lo volvemos a abrir, curiosamente se nos va a帽adiendo un salto de l铆nea al final. Para solucionarlo, o le restamos ese 煤ltimo car谩cter manualmente antes de guardar, o bien le indicamos en el propio get que lo reste:

Note

contenido = texto.get(1.0, 'end-1c')  # recuperamos el texto -1 char

Ahora nos falta la otra posibilidad, cuando el fichero es nuevo y tenemos que guardarlo en el disco con un nombre. Para este caso lo que vamos a hacer es llamar desde la funci贸n guardar la funci贸n guardar como, ya que 茅sta nos deber铆a permitirhacer lo que necesitamos la primera vez eligiendo un nombre y un directorio:

Note

else:
    guardar_como()

Guardar fichero como

Ya s贸lo nos falta crear la 煤ltima opci贸n:

Note

def guardar_como():
    global ruta
    fichero = FileDialog.asksaveasfile(title="Guardar fichero", mode='w',
            defaultextension=".txt")
    ruta = fichero.name  # El atributo name es la ruta, si est谩 abierto
    if fichero is not None:
        contenido = texto.get(1.0, 'end-1c')  # recuperamos el texto
        fichero = open(ruta, 'w+') # creamos el fichero o abrimos
        fichero.write(contenido)  # escribimos el texto
        fichero.close()
        mensaje.set('Fichero guardado correctamente')
    else:
        mensaje.set('Guardado cancelado')

C贸digo final:

Note

from tkinter import *
from tkinter import filedialog as FileDialog
from io import open

ruta = "" # La utilizaremos para almacenar la ruta del fichero

def nuevo():
    global ruta
    mensaje.set("Nuevo fichero")
    ruta = ""
    texto.delete(1.0, "end")
    root.title("Mi editor")

def abrir():
    global ruta
    mensaje.set("Abrir fichero")
    ruta = FileDialog.askopenfilename(
        initialdir='.', 
        filetypes=(("Ficheros de texto", "*.txt"),),
        title="Abrir un fichero de texto")

    if ruta != "":
        fichero = open(ruta, 'r')
        contenido = fichero.read()
        texto.delete(1.0,'end')
        texto.insert('insert', contenido)
        fichero.close()
        root.title(ruta + " - Mi editor")

def guardar():
    mensaje.set("Guardar fichero")
    if ruta != "":
        contenido = texto.get(1.0,'end-1c')
        fichero = open(ruta, 'w+')
        fichero.write(contenido)
        fichero.close()
        mensaje.set("Fichero guardado correctamente")
    else:
        guardar_como()

def guardar_como():
    global ruta
    mensaje.set("Guardar fichero como")

    fichero = FileDialog.asksaveasfile(title="Guardar fichero", 
        mode="w", defaultextension=".txt")

    if fichero is not None:
        ruta = fichero.name
        contenido = texto.get(1.0,'end-1c')
        fichero = open(ruta, 'w+')
        fichero.write(contenido)
        fichero.close()
        mensaje.set("Fichero guardado correctamente")
    else:
        mensaje.set("Guardado cancelado")
        ruta = ""


# Configuraci贸n de la ra铆z
root = Tk()
root.title("Mi editor")

# Men煤 superior
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Nuevo", command=nuevo)
filemenu.add_command(label="Abrir", command=abrir)
filemenu.add_command(label="Guardar", command=guardar)
filemenu.add_command(label="Guardar como", command=guardar_como)
filemenu.add_separator()
filemenu.add_command(label="Salir", command=root.quit)
menubar.add_cascade(menu=filemenu, label="Archivo")

# Caja de texto central
texto = Text(root)
texto.pack(fill="both", expand=1)
texto.config(bd=0, padx=6, pady=4, font=("Consolas",12))

# Monitor inferior
mensaje = StringVar()
mensaje.set("Bienvenido a tu Editor")
monitor = Label(root, textvar=mensaje, justify='left')
monitor.pack(side="left")

root.config(menu=menubar)
# Finalmente bucle de la apliaci贸n
root.mainloop()

隆Y ya lo tenemos! Hemos creado nuestro propio bloc de notas en menos de 100 l铆neas de c贸digo.

Tened en cuenta no deja de ser una introducci贸n. Hay m谩s widgets y muchos par谩metros que no hemos visto. La clave como siempre es practicar y documentarse mucho por Internet, viendo ejemplos, en Youtube y sobretodo experimentando por vuestra cuenta.

Documentaci贸n de Tkinter

En la web http://effbot.org/tkinterbook/tkinter-index.htm encontrar茅is much铆simo contenido y ejemplos de Tkinter.


脷ltima edici贸n: 4 de Octubre de 2018