Tutorial TKInter Python (GUI) Parte 2

RESUMEN INTERFAZ GRÁFICA
SEGUNDA PARTE
3 Noviembre del 2010
 
Autor: Grupo 50, Segundo Semestre 2010 (Sede San Carlos)
 
6. Irregularidades
 
Una de las cosas que dificulta a una persona nueva que quiere aprender interfaz en Python, es el conjunto de dificultades
 que aparecen conforme vas aprendiendo, sobre todo si no dominas bien más de un lenguaje o solo haz programado en Scheme
 una interfaz gráfica y piensas que todas se programan igual. Pues presenta una dificultad.
En el último código que vimos:
from Tkinter import * # Importa el módulo
 
v0 = Tk() # Tk() Es la ventana principal
v1=Toplevel(v0) # Crea una ventana hija
 
def mostrar(ventana): ventana.deiconify() # Muestra una ventana
def ocultar(ventana):ventana.withdraw() # Oculta una ventana
def ejecutar(f): v0.after(200,f) # Una forma alternativa de ejecutar una función
 
v0.config(bg="black") # Le da color al fondo
v0.geometry("500x500") # Cambia el tamaño de la ventana
 
b1=Button(v0,text="ABRIR VENTANA V1",command=lambda: ejecutar(mostrar(v1))) # Primer botón
b1.grid(row=1,column=1) # El botón es cargado
b2=Button(v0,text="OCULTAR VENTANA V1",command=lambda: ejecutar(ocultar(v1))) # Segundo botón
b2.grid(row=1,column=2) # El botón es cargado
 
v1.withdraw() # Oculta la ventana v1
v0.mainloop() # Es el evento que llama al inicio de nuestro programa. Siempre lo lleva la ventana principal.
Vemos que apareció:
Una nueva función llamada ejecutar
¿v0.after? ¡¿Qué es eso?!
¿Porqué el command de los botones tiene lambda dos puntos ejecutar y la función dentro de mostrar?
 
Esto fue así, porque hice varias pruebas y esta fué la mejor forma que encontré para que todo funcionara bien (Se testeó la
 interfaz en Windows XP).
 
Otra cosa que noté es que la interfaz de vez en cuando no actúa de la misma forma en Windows que en las distros de Linux
(Por ejemplo Ubuntu o Kubuntu).
 
Ya por ejemplo si yo quiero centrar una ventana de Python en windows, utilizo esta función:
 
def centrar(ventana):
    ventana.update_idletasks()
    w=ventana.winfo_width()
    h=ventana.winfo_height()
    extraW=ventana.winfo_screenwidth()-w
    extraH=ventana.winfo_screenheight()-h
    ventana.geometry("%dx%d%+d%+d" % (w,h,extraW/2,extraH/2))
 
Si escribimos el nombre de la ventana, entonces la centrará, pero en Windows, porque en Ubuntu desconfigura todo el tamaño
 de la ventana.
 
En cuánto a las preguntas de más arriba. La función llamada ejecutar, y lo de v0.after, es acerca de lo mismo. ¿Qué es lo
 que hace la ventana ejecutar?
 
Lo que hace es que pasados dos milisegundos en un momento dado del tiempo, ejecuta f. f es el nombre de una función que
 queremos ejecutar.
 
Por ejemplo abre una ventana, como se vió anteriormente.
 
Y para qué es el lambda? No estoy muy seguro pero es absolutamente necesario usarlo, además lambda permite que un botón
 ejecute dos eventos al mismo tiempo. 
 
Ejemplo 7:
 
Por ejemplo si queremos mostrar una ventana y también imprimir hola, sería de la siguiente forma:
 
from Tkinter import * # Importa el módulo
 
v0 = Tk() # Tk() Es la ventana principal
v1=Toplevel(v0) # Crea una ventana hija
 
def mostrar(ventana): ventana.deiconify() # Muestra una ventana
def ocultar(ventana):ventana.withdraw() # Oculta una ventana
def ejecutar(f): v0.after(200,f) # Una forma de ejecutar las funciones
def imprimir(texto): print texto # Imprime un texto
 
v0.config(bg="black") # Le da color al fondo
v0.geometry("500x500") # Cambia el tamaño de la ventana
 
b1=Button(v0,text="ABRIR VENTANA V1",command=lambda: ejecutar(mostrar(v1)) or imprimir("hola")) # Primer botón
b1.grid(row=1,column=1) # El botón es cargado
b2=Button(v0,text="OCULTAR VENTANA V1",command=lambda: ejecutar(ocultar(v1))) # Segundo botón
b2.grid(row=1,column=2) # El botón es cargado
 
v1.withdraw() # Oculta la ventana v1
v0.mainloop() # Es el evento que llama al inicio de nuestro programa. Siempre lo lleva la ventana principal.
 
Ejemplo 8:
 
Si dan click al botón ABRIR VENTANA V1, notarán que además de mostrar la ventana, imprime el texto. Si quisieramos que el
 botón hiciera tres cosas, sería de la siguiente forma:
 
from Tkinter import * # Importa el módulo
 
v0 = Tk() # Tk() Es la ventana principal
v1=Toplevel(v0) # Crea una ventana hija
 
def mostrar(ventana): ventana.deiconify() # Muestra una ventana
def ocultar(ventana):ventana.withdraw() # Oculta una ventana
def ejecutar(f): v0.after(200,f) # Una forma de ejecutar las funciones
def imprimir(texto): print texto # Imprime un texto
 
v0.config(bg="black") # Le da color al fondo
v0.geometry("500x500") # Cambia el tamaño de la ventana
 
b1=Button(v0,text="ABRIR VENTANA V1",command=lambda: ejecutar(mostrar(v1)) or imprimir("hola") or imprimir("tercera función")) # Primer botón
b1.grid(row=1,column=1) # El botón es cargado
b2=Button(v0,text="OCULTAR VENTANA V1",command=lambda: ejecutar(ocultar(v1))) # Segundo botón
b2.grid(row=1,column=2) # El botón es cargado
 
v1.withdraw() # Oculta la ventana v1
v0.mainloop() # Es el evento que llama al inicio de nuestro programa. Siempre lo lleva la ventana principal.
 
Con el lambda y los dos puntos, mezclado con la función ejecutar, podemos ejecutar varios eventos al mismo tiempo separados
 por or.
 
Ejemplo 9:
 
Ahora, no sé si lo habrán notado, pero cuando cerramos la ventana, tira error, pero cuando la ocultamos no nos da error. Yo
 la solución que le encontré a esto, fue quitando la opción de cerrar ventana, y colocando un botón salir en cada ventana.
 Para realizar eso se hace lo siguiente:
 
from Tkinter import * # Importa el módulo
 
v0 = Tk() # Tk() Es la ventana principal
v1=Toplevel(v0) # Crea una ventana hija
v1.protocol("WM_DELETE_WINDOW", "onexit") # Elimina la opción de salir para evitar el error
 
def mostrar(ventana): ventana.deiconify() # Muestra una ventana
def ocultar(ventana):ventana.withdraw() # Oculta una ventana
def ejecutar(f): v0.after(200,f) # Una forma de ejecutar las funciones
def imprimir(texto): print texto # Imprime un texto
 
v0.config(bg="black") # Le da color al fondo
v0.geometry("500x500") # Cambia el tamaño de la ventana
 
b1=Button(v0,text="ABRIR VENTANA V1",command=lambda: ejecutar(mostrar(v1)) or imprimir("hola") or imprimir("tercera función")) # Primer botón
b1.grid(row=1,column=1) # El botón es cargado
b2=Button(v1,text="OCULTAR VENTANA V1",command=lambda: ejecutar(ocultar(v1))) # Segundo botón
b2.grid(row=1,column=2) # El botón es cargado
 
b3=Button(v0,text="SALIR",command=lambda: ejecutar(ocultar(v1)))
b3.grid(row=1,column=2) # El botón es cargado
 
v1.withdraw() # Oculta la ventana v1
v0.mainloop() # Es el evento que llama al inicio de nuestro programa. Siempre lo lleva la ventana principal.
 
Ejemplo 10:
 
Otro truco interesante es evitar que una ventana pueda redimencionarse (Cambiar el tamaño de una ventana). Con lo siguiente
 se puede realizar:
 
from Tkinter import * # Importa el módulo
 
v0 = Tk() # Tk() Es la ventana principal
v1=Toplevel(v0) # Crea una ventana hija
v1.protocol("WM_DELETE_WINDOW", "onexit") # Elimina la opción de salir para evitar el error
v0.resizable(0,0) # Evita que la ventana se pueda cambiar de tamaño
v1.resizable(0,0) # Evita que se le pueda cambiar de tamaño a la ventana
 
def mostrar(ventana): ventana.deiconify() # Muestra una ventana
def ocultar(ventana):ventana.withdraw() # Oculta una ventana
def ejecutar(f): v0.after(200,f) # Una forma de ejecutar las funciones
def imprimir(texto): print texto # Imprime un texto
 
v0.config(bg="black") # Le da color al fondo
v0.geometry("500x500") # Cambia el tamaño de la ventana
 
b1=Button(v0,text="ABRIR VENTANA V1",command=lambda: ejecutar(mostrar(v1)) or imprimir("hola") or imprimir("tercera función")) # Primer botón
b1.grid(row=1,column=1) # El botón es cargado
b2=Button(v1,text="OCULTARME",command=lambda: ejecutar(ocultar(v1))) # Segundo botón
b2.grid(row=1,column=2) # El botón es cargado
 
b3=Button(v0,text="OCULTAR VENTANA V1",command=lambda: ejecutar(ocultar(v1)))
b3.grid(row=1,column=2) # El botón es cargado
 
v1.withdraw() # Oculta la ventana v1
v0.mainloop() # Es el evento que llama al inicio de nuestro programa. Siempre lo lleva la ventana principal.
 
http://i.imgur.com/255Af.jpg 
 
Con una lectura de los manuales de Tkinter se deberían poder solucionar algunas de estas irregularidades, entre otras más
 que se podrían comentar más adelante.
 
7. ELEMENTOS PADRES Y ELEMENTOS HIJOS
 
Tomando en cuenta todos los primeros 6 puntos, ahora vamos a analizar la interfaz por el lado de lo que son los elementos
 hijos de otros, cuál es el padre de un elemento, etcétera. Generalmente cuando trabajamos con Tkinter, el elemento padre
 es el primer argumento que recibe un objeto gráfico. El elemento Tk() no tiene ningún padre. Si declaramos una variable
 
v0 = Tk()
 
Entonces v0 es un Tk(), que es la ventana principal, y entre paréntesis no recibe ningún argumento. Pero si queremos
 introducir un elemento dentro de v0, dicho elemento debe saber que su padre es v0.
 
En el siguiente ejemplo se crean dos ventanas, la ventana principal del tipo Tk() y una ventana hija del tipo Toplevel().
 
La ventana Toplevel() es hija de la ventana Tk()
Luego creamos un botón en cada ventana. Lo que querría decir que uno de los botones tiene como padre a la ventana Tk() y el
 
otro botón tiene como padre a la ventana del tipo Toplevel()
 
Ejemplo 11:
 
A continuación se presenta el ejemplo
 
from Tkinter import *
 
v0=Tk()
v1=Toplevel(v0)
 
def mostrar(ventana): ventana.deiconify()
def ocultar(ventana):ventana.withdraw()
def ejecutar(f): v0.after(200,f)
 
b1=Button(v0,text="TERMINAR APLICACIÓN",command=v0.destroy).pack()
b2=Button(v1,text="OCULTAR VENTANA",command=lambda: ejecutar(ocultar(v1))).pack()
 
v0.mainloop()
 
http://i.imgur.com/IHG8J.jpg 
 
En este ejemplo se puede ver que para salir de la aplicación basta con destruir el objeto de la ventana principal, llamado
 v0. Así, cuando escribimos v0.destroy se destruye la ventana padre, y entonces la aplicación termina.
 
Otras formas que podrían presentar conflictos, pero que también son usadas, son v0.quit, y por supuesto, ocultar(v0) que
 sería lo mismo que decir v0.withdraw(). Sin embargo con el withdraw() solo la oculta no cerraría la aplicación.
 
También se puede usar en el command del botón lambda: exit()
 
Ahora introduzcamos más controles, como por ejemplo los Labels
 
8. QUE EL PROGRAMA TAMBIÉN SEA UN OBJETO
 
Ejemplo 12:
 
Creamos un programa que funcione con el paradigma de objetos y se puede implementar de la siguiente forma
 
from Tkinter import *
 
class programa:
    def __init__(self):
        self.v0 = Tk()
    def run(self):
        self.v0.mainloop()
 
test1=programa()
test1.run()
 
Se implementa todo lo visto anteriormente pero a manera de objetos. 
 
9. PROPIEDADES DE LOS CONTROLES (Parte 1)
 
Ya habíamos hablado de las ventanas Tk y Toplevel y de los controles Label, Button, Listbox, Scrollbar Entry, Text, Frame,
 Canvas, entre otros.
 
Pero, cómo se usan? Cómo se introduce un elemento en un Listbox? Cómo se le cambia el color de fondo y de letra a las
 cosas?
 
Label
 
Para el label se puede declarar una variable de tipo StringVar()
 
Ejemplo 13:
 
En este ejemplo, nos abre con raw_input un espacio para que escribamos algo. Luego simplemente imprimimos eso en un control
 de tipo Label, todo lo que tenemos que hacer es setear la variable de tipo StringVar(). De la siguiente manera:
 
from Tkinter import *
 
v0=Tk()
mitexto=StringVar()
label1=Label(v0,textvar=mitexto).pack()
 
escribir=raw_input("")
mitexto.set(escribir)
 
v0.mainloop()
 
http://i.imgur.com/JobRX.jpg 
 
Como se puede ver en el ejemplo anterior, para darle valor a una variable del tipo StringVar() se escriba
 variable.set(texto).
 
Ejemplo 14:
En el siguiente ejemplo veremos como se puede obtener valor de una variable de tipo StringVar(), utilizando variable.get()
 
from Tkinter import *
 
v0=Tk()
v0.geometry("200x60")
 
def cambiar_stringvar(nuevotexto,stringvar):
    stringvar.set(nuevotexto)
 
mitexto=StringVar()
textoentry=StringVar()
entry1=Entry(v0,textvar=textoentry).pack()
label1=Label(v0,textvar=mitexto).pack()
b1=Button(v0,text="Escribir",command=lambda: cambiar_stringvar(textoentry.get(),mitexto)).pack()
 
v0.mainloop()
 
http://i.imgur.com/D4325.jpg 
 
Ejemplo 15:
 
Ahora veamos el objeto Listbox. Supongamos que queremos introducir una palabra en un control de tipo Listbox. Una forma de
 implementarlo seria:
 
from Tkinter import *
 
v0=Tk()
 
list1=Listbox(v0)
list1.pack()
mivalor=StringVar()
e1=Entry(v0,textvar=mivalor).pack()
 
def insertar_en_listbox():
    if mivalor.get() != "":
        list1.insert(END,mivalor.get())
    else: print "Por favor esciba algún texto"
 
b1=Button(v0,text="Insertar en Listbox",command=insertar_en_listbox).pack()
 
v0.mainloop()
 
http://i.imgur.com/zAydM.jpg 
 
Si insertan muchos elementos se darán cuenta de que, en este tipo de controles normalmente aparece una Scrollbar
 automáticamente. El Scrollbar es otro tipo de control, y en Python, curiosamente, para que un Listbox tenga Scrollbar,
 deben unirse mediante un truco, por decirlo de alguna forma.
 
Ejemplo 16:
 
Para que el Listbox del ejemplo de arriba tenga un scrollbar, se debe hacer lo siguiente:
 
from Tkinter import *
 
v0=Tk()
 
def colocar_scrollbar(listbox,scrollbar):
    scrollbar.config(command=listbox.yview)
    listbox.config(yscrollcommand=scrollbar.set)
    scrollbar.pack(side=RIGHT, fill=Y)
    listbox.pack(side=LEFT, fill=Y)
 
frame1=Frame(v0)
frame1.pack()
scroll1=Scrollbar(frame1)
list1=Listbox(frame1)
list1.pack()
colocar_scrollbar(list1,scroll1)
mivalor=StringVar()
e1=Entry(v0,textvar=mivalor).pack()
 
def insertar_en_listbox():
    if mivalor.get() != "":
        list1.insert(END,mivalor.get())
    else: print "Por favor esciba algún texto"
 
b1=Button(v0,text="Insertar en Listbox",command=insertar_en_listbox).pack()
 
v0.mainloop()
 
http://i.imgur.com/NPt09.jpg 
 
De esta forma al tener más elementos de los que permite visualizar, coloca automáticamente un Scrollbar.
 
Cabe destacar que en Scheme, el control Listbox traía su propio Scrollbar. Al menos eso recuerdo...

No hay comentarios:

Publicar un comentario

gmendezm
Portada
Lista Principal