sábado, 19 de marzo de 2022

Lista de widgets en tkinter y guizero.


Imagen introductoria: widgets




Lista de Widgets en Tkinter y Guizero.


En este capítulo vamos a repasar algunos de los elementos más importantes que podemos encontrar en una aplicación Gráfica (GUI) y una descripción sencilla del código para generarlo tanto en Tkinter como en Guizero.

Ejemplos de código para los widgets de tkinter.
Ejemplos de código para los widgets de Guizero.

¿Que es un widget? 


Un widget describe cada una de las diferentes partes que pueden ser usadas para crear una interfaz de usuario o GUI
Aunque no te suenen sus nombre, reconocerás muchos de ellos en los diferentes programas o websites que utilizas.

El siguiente ejemplo muestra siete widgets en Guizero. Aunque sus nombres en Tkinter pueden variar un poco básicamente son los mismos, ya que recuerda que Guizero usa Tkinter para funcionar. 


diferentes widgets


Vamos a ir viéndolos uno a uno junto una pequeña descripción de su uso. Luego haremos un pequeño ejemplo con ambos programas para ver como programarlos. En otros capítulos veremos las diferentes propiedades y métodos que pueden tener cada uno y entraremos más en detalle.

Tipos de Widgets.

_______________________________________________________________________________
 
Nombre en Tkinter Nombre en Guizero
Frame Box

Es un widget que actúa como contenedor para otros widgets. Es invisible por defecto y puede ser usado para colocar más fácilmente otros widgets dentro de la ventana y alterar su diseño. En el ejemplo crearemos una caja (llámale Frame o Box) y colocamos dos botones dentro.

Tkinter
demostración de frame


from tkinter import *
# Creamos la aplicacion principal y su tamaño
raiz = Tk()
raiz.geometry("200x150")

# Creamos una caja alineada a la izquierda que ocupe toda la ventana y con borde
# para que podamos verlo.
frame=Frame(raiz)
frame.config(bg="lightblue")
frame.pack(side="left", fill="x", expand=1)

# Colocamos un boton dentro del Frame
button=Button(frame,text="botón")
button.pack()
# Colocamos otro boton dentro del mismo Frame
button1= Button(frame, text="Otro botón")
button1.pack()

raiz.mainloop()

Guizero

demostración de widget frame


# importamos la ventana principal, una caja y un botón
from guizero import App, Box, PushButton
# Creamos la aplicación principal
app = App(width=200, height=150)

# Creamos una caja alineada a la izquierda que ocupe toda la ventana y con borde
# para que podamos verlo.
box = Box(app, align="left", width="fill", border=2)
# Colocamos un botón
button = PushButton(box)
# Colocamos otro que se pone debajo
button1 = PushButton(box, text="another button")

app.display()
_______________________________________________________

Nombre en TkinterNombre en Guizero
ButtonPushButton

Es un botón que se puede pulsar y que sirve para una multitud de propósitos. Es uno de los que más frecuentemente se utiliza. Una vez que se pulsa lanza alguna acción en el programa. 

Tkinter

widget button en tkinter


from tkinter import *
 
def set():
    print("Hola Mundo")
 
root = Tk()
root.geometry("200x150")
 
frame = Frame(root)
frame.pack()
button = Button(frame, text = "Botón1", command = set,
                fg = "red", font = "Verdana 14 underline",
                bd = 2, bg = "light blue", relief = "groove")
button.pack(pady = 5)
 
root.mainloop()
Guizero

button widget en guizero



# importamos la ventana principal, una caja y un botón
from guizero import App, Box, PushButton

def set():
    print("Hola Mundo")
    
# Creamos la aplicación principal
app = App(width=200, height=150)

# Creamos una caja alineada a la izquierda que ocupe toda la ventana y con borde
# para que podamos verlo.
box = Box(app)
# Colocamos el botón con una serie de propiedades iniciales
button = PushButton(box, text="Botón1", command=set)
# Propiedades adicionales de los botones
button.bg="light blue"
button.text_color="red"
# incluso podemos usar directamente un método de tkinter en guizero
# <nombre>.tk.config()
button.tk.config(bd=2, relief = "groove",font = "Verdana 14 underline")
button.tk.pack(pady=5)
_______________________________________________________

Nombre en TkinterNombre en Guizero
EntryTextBox

Se usa para que el usuario pueda introducir datos desde la aplicación. Es una caja de texto en donde el usuario puede introducir datos.

Tkinter




from tkinter import *
 
root = Tk()
root.geometry("200x150")
 
frame = Frame(root)
frame.pack()
 
my_entry = Entry(frame, width = 20)
my_entry.insert(0,'Username')
my_entry.pack(padx = 5, pady = 5)
 
my_entry2 = Entry(frame, width = 15)
my_entry2.insert(0,'password')
my_entry2.pack(padx = 5, pady = 5)
 
root.mainloop()

Guizero



from guizero import App, TextBox, Box
raiz = App(width=200, height=150)

# no existen paddings para los box en guizero
# para lograr lo mismo hay que usar tkinter o como en
# este caso meter algo por medio.

# Caja de relleno que no se ve pero esta ahí
Box(raiz, align="top", width="fill", height=5)
# Caja Principal que contiene los inputs.
box = Box(raiz)

inputA = TextBox(box, width=20,text="Username")
inputB = TextBox(box, width=15, text="Password")
raiz.display()

_______________________________________________________

Nombre en TkinterNombre en Guizero
Check Button 
CheckBox

Las casillas de verificación permiten al usuario escoger entre un conjunto de acciones que ya están predefinidas. El usuario puede escoger más de una opción.


Tkinter

check button en tkinter


root = Tk()
root.geometry("200x150")
 
frame = Frame(root)
frame.pack()
 
Var1 = IntVar()
Var2 = IntVar()
 
ChkBttn = Checkbutton(frame, width = 15, text="Opción 1", variable = Var1)
ChkBttn.pack(padx = 5, pady = 5)
 
ChkBttn2 = Checkbutton(frame, width = 15, text="Opción2", variable = Var2)
ChkBttn2.pack(padx = 5, pady = 5)

root.mainloop()

Guizero

checkbox en guizero


from guizero import App, CheckBox, Box

# Creamos la aplicación principal
app = App(width=200, height=150)

# Creamos una contenedor
box = Box(app)
# Incorporamos las casillas de verificación.
checkbox_1 = CheckBox(box, text="Opción1")
checkbox_1 = CheckBox(box, text="Opción2")

app.display()

______________________________________________________

Nombre en TkinterNombre en Guizero
Radio Button 
ButtonGroup

Se muestra un conjunto de casillas de verificación redondas, en donde el usuario puede escoger una única opción.

Tkinter

Radio Button en tkinter


from tkinter import *
 
root = Tk()
root.geometry("200x150")
frame = Frame(root)
frame.pack()
 
Var1 = StringVar()
 
RBttn = Radiobutton(frame, text = "Option1", variable = Var1,
                    value = 1)
RBttn.pack(padx = 5, pady = 5)
 
RBttn2 = Radiobutton(frame, text = "Option2", variable = Var1,
                     value = 2)
RBttn2.pack(padx = 5, pady = 5)
 
root.mainloop()

Guizero.

En el ejemplo usamos un ButtonGroup que muestra la selección en una caja de texto.

ButtonGroup en guizero


from guizero import App, ButtonGroup, Text, Box

def update_text():
    seleccionada.value = opciones.value

app = App(width=200, height=150)
opciones = ButtonGroup(app, options=
                              ["Opción 1",
                              "Opción 2"],
                            selected="Opción 1", command=update_text)

caja = Box(app, border=2)
seleccionada = Text(caja, "Opción 1")
app.display()

______________________________________________________

Nombre en TkinterNombre en Guizero
LabelText, Picture

Muestra un texto dentro de la aplicación que el usuario no puede modificar. Es bastante útil para poner títulos, etiquetas o instrucciones. Es muy versátil y lo podemos usar incluso para incluir imágenes.

Tkinter.

Label en tkinter



from tkinter import *
 
root = Tk()
root.geometry("200x150")
 
frame = Frame(root)
frame.pack()
 
var = StringVar()
var.set("Hola Mundo")
 
label = Label(frame, textvariable = var )
label.pack()
 
root.mainloop()

Guizero.

text en guizero


from guizero import App, Text

app = App(width=200, height=150)

texto = Text(app, text="Hola Mundo!")

app.display()
* Usamos el widget Picture si en vez de mostrar un texto queremos que se incluya una imagen.

_____________________________________________________


Nombre en TkinterNombre en Guizero
MenuMenuBar

Este wigdet muestra un menú en la parte superior de la pantalla, y cada opción del menú conduce a un submenú.

Tkinter

Menu en Tkinter


from tkinter import *
 
def save():
    #Código a ser escrito
    pass
 
def load():
    #Código a ser escrito
    pass   
 
root = Tk()
root.geometry("200x150")
frame = Frame(root)
frame.pack()
 
mainmenu = Menu(frame)
mainmenu.add_command(label = "Save", command= save)  
mainmenu.add_command(label = "Load", command= load)
mainmenu.add_command(label = "Exit", command= root.destroy)
 
root.config(menu = mainmenu)
 
root.mainloop()
Guizero.

MenuBar en guizero


from guizero import App, MenuBar
def file_function():
    pass #codigo a rellenar

def edit_function():
    pass #codigo a rellenar
    
def exit_function():
    app.destroy()

app = App(width=200, height=150)
menubar = MenuBar(app,
                  toplevel=["Save", "Load", "Exit"],
                  options=[
                      [ ["Guardar", file_function], ["Guardar como..", file_function] ],
                      [ ["Cargar", edit_function], ["Cargar archivo", edit_function] ],
                      [ ["Salir", exit_function]],
                  ])
app.display()

_______________________________________________________

Nombre en TkinterNombre en Guizero
ComboBoxCombo

Este objeto lo que hace es mostrar un cuadro desplegable que permite seleccionar una sola opción dentro de una lista de opciones.

Tkinter.

Combobox de tkinter



from tkinter import *
from tkinter import ttk
 
root = Tk()
root.geometry("200x150")
 
frame = Frame(root)
frame.pack()
 
vlist = ["Option1", "Option2", "Option3",
          "Option4", "Option5"]
 
Combo = ttk.Combobox(frame, values = vlist)
Combo.set("Escoge una opción")
Combo.pack(padx = 5, pady = 5)
 
root.mainloop()

Guizero.

Combo en guizero


from guizero import App, Combo
app = App(width=200, height=150)
combo = Combo(app, options=["Opción 1", "Opción 2", "Opción 3"])
app.display()

_______________________________________________________

Nombre en TkinterNombre en Guizero
List Box
ListBox

Se utiliza para mostrar una lista de opciones al usuario en donde elegir. Se puede escoger una o varias de ellas.

Tkinter.

List box en tkinter


from tkinter import *
root = Tk()
root.geometry("200x220")
frame = Frame(root)
frame.pack()
 
label = Label(root,text = "Escoge elementos a comprar.")  
label.pack()  
   
listbox = Listbox(root)  
   
listbox.insert(1,"Pan")  
listbox.insert(2, "Leche")  
listbox.insert(3, "Carne")  
listbox.insert(4, "Queso")
listbox.insert(5, "Verduras")  
   
listbox.pack()  
root.mainloop()

Guizero.

ListBox en guizero

from guizero import App, ListBox, Text
app = App(width=200, height=150)
Text(app, text="lista de la compra")
listbox = ListBox(app, items=["Pan", "Leche", "Carne", "Queso"])
app.display()

______________________________________________________

Nombre en TkinterNombre en Guizero
Menu Button-


Es una combinación entre el widget de menú y el de botón. Muestra un menú desplegable con una lista de opciones cuando hacemos click en él. Este widget es único porque puede incorporar aspectos de botones de opción y de opciones de verificación.

Tkinter

Menu Button en tkinter


from tkinter import *
 
root = Tk()
root.geometry("200x150")
frame = Frame(root)
frame.pack()
 
MenuBttn = Menubutton(frame, text = "Favourite food", relief = RAISED)
 
Var1 = IntVar()
Var2 = IntVar()
Var3 = IntVar()
 
Menu1 = Menu(MenuBttn, tearoff = 0)
 
Menu1.add_checkbutton(label = "Pizza", variable = Var1)
Menu1.add_checkbutton(label = "Cheese Burger", variable = Var2)
Menu1.add_checkbutton(label = "Salad", variable = Var3)
 
MenuBttn["menu"] = Menu1
 
MenuBttn.pack()
root.mainloop()

______________________________________________________

Nombre en TkinterNombre en Guizero
CanvasDrawing

Aunque no son exactamente igual en ambas librerías, nos permite dibujar formas, imágenes o texto. Es como una pizarra en la que puedes pintar o dibujar cualquier cosa.

Tkinter.

Canvas en Tkinter


from tkinter import *
 
root = Tk()
 
frame=Frame(root,width=300,height=300)
frame.pack(expand = True, fill=BOTH)
 
canvas = Canvas(frame,bg='white', width = 300,height = 300)
 
coordinates = 20, 50, 210, 230
arc = canvas.create_arc(coordinates, start=0, extent=250, fill="blue")
arc = canvas.create_arc(coordinates, start=250, extent=50, fill="red")
arc = canvas.create_arc(coordinates, start=300, extent=60, fill="yellow")
 
canvas.pack(expand = True, fill = BOTH)
 
root.mainloop()

Guizero.

Drawing in guizero


from guizero import App, Drawing
app = App(width=200, height=150)
drawing = Drawing(app)
drawing.rectangle(10, 10, 60, 60, color="blue")
app.display()
_______________________________________________________


Nombre en TkinterNombre en Guizero
ScalaSlider


Este objeto muestra una barra y un selector que puede usarse para especificar un valor en un rango.

Tkinter.

Scala en tkinter


from tkinter import * 
 
root = Tk()
root.geometry("200x200")
frame = Frame(root)
frame.pack()
 
Scala = Scale(frame, from_=0, to=10)
Scala.pack(padx=5, pady=5)
 
Scala2 = Scale(frame, from_=0, to=10, orient=HORIZONTAL)
Scala2.pack(padx=5, pady=5)
 
root.mainloop()

Guizero.



from guizero import App, Slider
app = App(width=200, height=150)
slider = Slider(app, horizontal=False)
slider = Slider(app)
app.display()
______________________________________________________


Nombre en TkinterNombre en Guizero
ScrollBar-

Este widget nos va a permitir el desplazarnos por un ventana de Tkinter o mejor dicho habilitar el desplazamiento para ciertos widgets. Por lo general se usa cuando tienes un espacio limitado para una ventana en Tkinter pero quieres más espacio para el widget. Veámoslo con un ejemplo.

ScrollBar in tkinker


root.geometry("200x250") 
    
mylabel = Label(root, text ='Scrollbars', font = "30")  
mylabel.pack() 
 
myscroll = Scrollbar(root) 
myscroll.pack(side = RIGHT, fill = Y) 
 
mylist = Listbox(root, yscrollcommand = myscroll.set )  
for line in range(1, 100): 
    mylist.insert(END, "Number " + str(line)) 
mylist.pack(side = LEFT, fill = BOTH )    
 
myscroll.config(command = mylist.yview) 
    
root.mainloop() 

_______________________________________________________

Nombre en TkinterNombre en Guizero
ToplevelWindow

Este widget nos va a permitir nuevas ventanas.

Tkinter.



from tkinter import *
 
def NuevaVentana():
    window = Toplevel()
    window.geometry('150x150')
    newlabel = Label(window, text = "Settings Window")
    newlabel.pack()
 
 
root = Tk()
root.geometry('200x200')
 
myframe = Frame(root)
myframe.pack()
 
mybutton = Button(myframe, text = "Settings", command = NuevaVentana)
mybutton.pack(pady = 10)
 
root.mainloop()

Guizero.

window in guizero


from guizero import App, Window, PushButton

def open_window():
    window.show(wait=True)

app = App(title="My app", height=200, width=200)

window = Window(app, title = "2nd ventana", height=150, width=150)
# La ventana esta creada pero la ocultamos para que no se vea
# hasta que se pulse el botón que la vuelva visible.
window.hide()

open=PushButton(app, text="Segunda ventana", command=open_window)

app.display()

_______________________________________________________

Nombre en TkinterNombre en Guizero
Notebook


Este Widget nos permite seleccionar páginas de contenido haciendo clic en las pestañas.

Tkinter.



Cuando se hace clic en alguna de estas pestañas, el widget Notebook mostrará un panel secundario asociado a la pestaña seleccionada. Normalmente este panel secundario mostrado es un widget Frame de tkinter. 

Para crear este widget, usamos la clase ttk.Notebook de la siguiente forma:

notebook = ttk.Notebook(contenedor, opciones**)
Por lo general el contenedor suele ser la raíz del proyecto.

Este contenedor tiene algunas opciones útiles. Por ejemplo se puede especificar las opciones height and width para especificar el alto y ancho en pixeles asociados al widget.

Además también podemos agregar algo de espacio alrededor del widget usando la opción "padding".


Métodos del Notebook.


La clase ttk.Notebook tiene varios métodos que permiten gestionar las ventanas de una manera efectiva.

Veamos los más utilizados: 

add(child, Kwargs**)

El método add agrega un widget secundario a una ventana. Se le puede pasar una o más opciones.

child es el widget para agregar al Notebook o cuaderno.

La opción "text" especifica la etiqueta que aparecerá en la ventana. 

La opción "image" especifica la imagen que se mostrará en la pestaña.

Si usamos ambas tenemos que describir la posición de la imagen en relación al texto. Puede ser:
tk.TOP , tk.BOTTOM, tk.LEFT, tk.RIGHT o tk.CENTER.

La opción "underline" toma como valores 0 o un número positivo. Esto subraya el caracter que le indiquemos, pero solo uno. Si ponemos underline=0, solo subrayará el primer carácter, si ponemos 1 subrayará el segundo y así sucesivamente.

hide(tabId) 

Este método oculta temporalmente la pestaña identificada por el tabId del Notebook. Como siempre la primera pestaña es la 0, la siguiente la 1 y así sucesivamente.

Para volver a mostrar la ventana hay que volver a utilizar el método add() ya que en este caso no hay un método show()

forget(child)

Elimina permanentemente el widget indicado del Notebook.

El siguiente programa muestra como crear un Notebook con dos pestañas:

import tkinter as tk
from tkinter import ttk

# root window
root = tk.Tk()
root.geometry('400x300')
root.title('Ejemplo de Widget Notebook')

# create a notebook
notebook = ttk.Notebook(root)
notebook.pack(pady=10, expand=True)

# create frames
frame1 = ttk.Frame(notebook, width=400, height=280)
frame2 = ttk.Frame(notebook, width=400, height=280)

frame1.pack(fill='both', expand=True)
frame2.pack(fill='both', expand=True)

# add frames to notebook

notebook.add(frame1, text='Pestaña A', underline=1)
notebook.add(frame2, text='Pestaña B')


root.mainloop()

Guizero.

No existe un elemento especifico para crear un Notebook en guizero asi que tenemos que usar el elemento ttk.Notebook de tkinter.

from guizero import App, Box
from tkinter import ttk
from tkinter.ttk import Notebook

# set up app to use grid layout
app = App(title="Uso de ttk Notebook", layout="grid")

# set up box to use grid and place it in app at 0,0
box = Box(app, border=True, layout='grid', grid=[0,0])

# create a notebook
nb = Notebook(box.tk)

# create some frames for the tabs
pestana_a = ttk.Frame(nb)
pestana_b = ttk.Frame(nb)

# add the tabs
nb.add(pestana_a, text='Pestaña A')
nb.add(pestana_b, text='Pestaña B')

# important - add tk widget only after it is completed
box.add_tk_widget(nb, grid=[0,0])


app.display()
Puedes ver como usar esta forma de utilizar elementos de tk en Guizero en este enlace a la página del manual de Guizero.






jueves, 17 de marzo de 2022

Interfaces gráficas de usuario con Python. (Tkinter y Guizero). Introducción.

 


¿Que es GUI?

Llamámos GUI (Grafical User Interface) a una interfaz de software basado en elementos visuales, tales como ventanas, botones y cajas de texto. Cuando utilizas un sistema operativo como Windows, Mac o Rapsbian estás usando el GUI propio de cada sistema operativo. 

¿Qué necesitaremos?

A lo largo de tema, que nos llevará varios capítulos, crearemos nuestros propios GUI usando Python 3 y varias librerías:

- TKinter. Será nuestra librería principal. Se basa en una biblioteca anterior llamada tcl/tk que está disponible también para otros lenguajes como Perl y Rubi. 

- Guizero. Importante. Necesita tener la anterior librería instalada (tkinter) para que funcione. Su misión es permitirnos crear GUI´s para nuestras aplicaciones más rápida y fácilmente que con Thinker pero basándose en la anterior.

Y si Guizero se basa o necesita tkinter ¿Por que utilizarla? Pues porque Guizero está pensado para usuarios noveles y es a mi gusto, más rápida de aprender y fácil de utilizar. No obstante, para ver cual te viene mejor, vamos a ver los diferentes temas que trataremos usando ambas librerías para que puedas comparar y utilizar la que mejor te venga.

Pero recuerda que puedes usar uno u otro indistintamente, e incluso puedes usar los dos a la vez como veremos más adelante.


Consultar la versión de tkinter.

Normalmente el paquete Tkinter está disponible en la instalación de Python que tengamos. No obstante para comprobar si realmente la tenemos instalada y cual es su versión, vamos a crear un entorno virtual e introducir los siguientes comandos:

>>> import tkinter

>>> tkinter.Tcl().eval('info patchlevel')

comprobación de versión de tkinter


 Instalar tkinter.

Si por lo que fuese en nuestra instalación de Python, en un equipo con GNU/linux, no se encuentra el paquete tkinter lo podemos hacer manualmente dentro o fuera del entorno virtual con:

pip3 install tk

o

si lo queremos instalar fuera del entorno virtual, es decir para que este disponible para todo el equipo lo podemos hacer con:

 $ sudo apt-get install python3-tk

Instalación de Guizero.


Desde el gestor Pip, y en mi caso dentro de un entorno virtual, tecleamos:

miEntorno $ pip3 install guizero
En este enlace puedes encontrar la documentación del programa, que aunque está en ingles, viene muy bien estructurada y explicada.

Ahora que tenemos todo instalado vamos a hacer la primera aplicación usando ambos sistemas tkinter y guizero. Los siguientes ejemplos los he puesto para que veas la estructura general de la aplicación en ambos sistemas, pero no te preocupes si de momento no entiendes mucho. Lo iremos viendo poco a poco en próximos capítulos.

La primera aplicación con tkinter.

En el siguiente ejemplo crearemos un simple ventana con un botón. Cuando presionemos dicho botón, el programa termina su ejecución y se cerrará. La ventana es el elemento principal en este tipo de aplicaciones gráficas y todo gira en torno a ellas. Va a ser el primer elemento que se crea siempre en un programa y sobre el que se colocan el resto de objetos llamados widgets (menús, barras, botones, cajas de texto etc)




""" Crea una ventana simple con un botón para salir """

# Las dos líneas siguientes son necesarias para hacer 
# compatible el interfaz Tkinter con los programas basados 
# en versiones anteriores a la 8.5, con las más recientes. 

from tkinter import *    # Carga módulo tk (widgets estándar)
import tkinter.ttk as ttk  # Carga ttk (para poder usar widgets nuevos 8.5+)

# Define la ventana principal de la aplicación

raiz = Tk()

# Define las dimensiones de la ventana. 
# Si se omite esta línea, es decir no se especifica su tamaño, la
# ventana se adaptará a los widgets que se coloquen en
# ella. 

raiz.geometry('300x200') # anchura x altura

# Asigna un color de fondo a la ventana. Si se omite
# esta línea el fondo será gris

raiz.configure(bg = 'beige')

# Asigna un título a la ventana

raiz.title('Aplicación')

# Define un botón en la parte inferior de la ventana
# que cuando sea presionado hará que termine el programa.
# El primer parámetro indica el nombre de la ventana 'raiz'
# donde se ubicará el botón

ttk.Button(raiz, text='Salir', command=quit).pack(side=BOTTOM)

# Después de definir la ventana principal y un widget botón
# la siguiente línea hará que cuando se ejecute el programa
# construya y muestre la ventana, quedando a la espera de 
# que alguna persona interactúe con ella.

# Si el usuario presiona sobre el botón Cerrar 'X', o bien,
# sobre el botón 'Salir' el programa llegará a su fin.

raiz.mainloop()

La primera aplicación con guizero.


Ahora que hemos hecho nuestra primera ventana con Tkinter vamos a hacer lo mismo, pero usando la librería Guizero. No te preocupes si no entiendes todos los conceptos ya que iremos profundizando en ellos a lo largo del curso. Por ahora se trata de tener una idea general de su funcionamiento. 

Lo importante es ver como se crea la aplicación y entender que dentro de la ventana principal iremos colocando los diferentes widgets o elementos. Cuales son y su funcionamiento, los iremos viendo con calma mas adelante.




from guizero import *

def claro():
    boton.bg = "#ececec"
    boton.when_mouse_leaves = oscuro

def oscuro():
    boton.bg = "#d9d9d9"


raiz=App(title="Aplicación", bg='beige', width=300, height=200)

boton = PushButton(raiz, text='Salir', align='bottom', padx=25, pady=2, command=quit)
boton.bg="#d9d9d9"

boton.when_mouse_enters = claro

raiz.display()

Echemos un vistazo al código creado línea por línea para ver que hace.

from guizero import *

Esta línea le dice a Python que importe todos los objetos existentes en la librería Guizero. Por ejemplo, en este código hemos usado los objetos App y Pushbutton.

def claro():
    boton.bg = "#ececec"
    boton.when_mouse_leaves = oscuro

def oscuro():
    boton.bg = "#d9d9d9"

Estas dos funciones no serían estrictamente necesarias pero si, si queremos que este ejemplo con Guizero sea exactamente igual al comportamiento del creado con Tkinter. Veras, si ejecutas el ejemplo de Tkinter y pasas el puntero por encima del botón, verás que su color de fondo pasa a un gris muy claro para dar una sensación de movimiento y vuelve a ser oscuro cuando se sale de él.

Sin embargo en Guizero, si no definiésemos estas funciones y un evento posterior que hace que el botón tenga un color claro cuando se entra a el y oscuro cuando se sale, el botón siempre tendría el mismo color. Si no se especifica sería el mismo que el fondo de la ventana. Vamos quedaría una cosa como esta:

botón sin eventos

Para que se vea más claro el código que genera la imagen de arriba es este:

from guizero import *

raiz=App(title="Aplicación", bg='beige', width=300, height=200)

boton = PushButton(raiz, text='Salir', align='bottom', padx=25, pady=2, command=quit)

raiz.display()

Seguimos con la explicación del código original.

La siguiente línea es:

raiz=App(title="Aplicación", bg='beige', width=300, height=200)

Aquí estamos asignando a la variable que hemos llamado "raiz" un objeto que es la aplicación o ventana principal de guizero. Este objeto "App()" es el básico de todas las GUIs creadas con guizero ya que es la ventana principal en la que se recogerán todos los demás elementos. 

También configuramos su titulo (title), color de fondo (bg) y dimensiones, tanto ancho (width) como alto(heigth). En esta aplicación es donde colocaremos todos los otros widgets a medida que construyamos la interfaz del usuario. Nota: En este punto aun no hemos pedido que se dibuje nada en la pantalla, solo hemos definido la ventana principal.

boton = PushButton(raiz, text='Salir', align='bottom', padx=25, pady=2, command=quit)
boton.bg="#d9d9d9"

boton.when_mouse_enters = claro

Hemos asignado a la variable "boton" un objeto que no es otra cosa que un "PushButton" es decir un botón que se pueda pulsar. Lo primero le hemos especificado que lo coloque en la ventana principal (raiz), que le asigne un texto (salir), que lo coloque en la parte baja (align='bottom') con un determinado tamaño. Cuando se pulse el botón lo que este hará será salir de la aplicación (command=quit);

Luego por tema estético, como ya te explique antes, le damos a ese botón un color de fondo (gris) y creamos un evento, que es que cuando el puntero del ratón entre en ese botón se ejecuta la función claro, que pone el color de fondo en un gris más claro. Acto seguido se crea otro evento para que cuando se salga del área definida por el ratón se vuelva al color original.

Por último,

raiz.display()

¡Ahora si!. Este último comando es el que le dice al ordenador que muestre en la pantalla todo lo que hemos dibujado.

Lo mismo pero con programación orientada a objetos.


Si has trabajado antes con la programación orientada a objetos, te habrás dado cuenta que los objetos tienen diferentes propiedades. Si no lo has hecho, ¡No te preocupes! Las programación de GUI´s es una de las mejores formas de familiarizarse con ellas.

A continuación vamos a hacer las mismas aplicaciones que antes, con las mismas librerías, pero con una programación orientada a objetos. Lo vamos a ver porque programarlo de esta forma nos facilita la gestión de los widgets y los eventos que se producirán en las mismas. 

Normalmente cuando haces una aplicación de este tipo la persona va a interactuar con ella, presionando un botón, escribiendo algo en una caja de texto, seleccionando una opción de un menú etc. En estos casos lo habitual será relacionar estos eventos con unas acciones a realizar y esto lo facilita bastante la POO.

Primer ejemplo con Tkinter.

from tkinter import *
from tkinter import ttk

# Crea una clase Python para definir el interfaz de usuario de
# la aplicación. Cuando se cree un objeto del tipo 'Aplicacion'
# se ejecutará automáticamente el método __init__() qué
# construye y muestra la ventana con todos sus widgets:


class Aplicacion():
    def __init__(self):
        raiz = Tk()
        raiz.geometry('300x200')
        raiz.configure(bg = 'beige')
        raiz.title('Aplicación')
        ttk.Button(raiz, text='Salir', command=raiz.destroy).pack(side=BOTTOM)
        raiz.mainloop()
        
# Define la funcion main() que es en realidad la que indica
# el comienzo del programa. Dentro de ella se crea el objeto
# aplicacion 'mi_app' basado en la clase 'Aplicacion':

def main():
    mi_app = Aplicacion()
    return 0

# Mediante el atributo __name__ tenemos acceso al nombre de un
# módulo. Python utiliza este atributo cuando se ejecuta
# un programa para conocer si el módulo es ejecutado de forma
# independiente (en este caso __name__ = '__main__' o es
# importado:       

if __name__ == '__main__':
    
    main()
    

Es lo mismo que el primer ejemplo pero creando una clase "Aplicación" e inicializándola con las propiedades de la misma.


Primer ejemplo pero con POO y Guizero.

# Importa la libreria guizero
from guizero import *

class Aplicacion():
    # Definimos el constructor de la clase aplicación.
    def __init__(self):        
                                     
        # Definimos la ventana principal con su título, color de fondo, ancho, 
        # alto de la ventana principal.
        self.raiz = App(title='Aplicación', bg='beige', width=300, height=200)
        # Creamos un objeto boton
        # Texto, alineación abajo, distancia de las letras al x e y, 
        # comando del botón destruir la raiz.
        self.boton = PushButton(self.raiz, text='Salir', align='bottom', padx=25, pady=2, 
        command=self.raiz.destroy)
        # Le asignamos el color de fondo inicial del boton
        self.boton.bg="#d9d9d9"
        # Vamos a definir un evento para cuando el raton entre en el boton lance
        # la funcion claro
        self.boton.when_mouse_enters=self.claro
        # Despues de definir todo, mostramos la aplicación
        self.raiz.display()       
        
    def claro(self):
            self.boton.bg="#ececec"
            #evento para cuando el ratón sale del botón que vuelva la color normal
            self.boton.when_mouse_leaves=self.normal
        
    def normal(self):
            self.boton.bg="#d9d9d9"
        
# Define la funcion main() que es en realidad la que indica
# el comienzo del programa. Dentro de ella se crea el objeto
# aplicacion 'mi_app' basado en la clase 'Aplicación':       

def main():
    mi_app = Aplicacion()
    return 0
    
# Mediante el atributo __name__ tenemos acceso al nombre de un
# módulo. Python utiliza este atributo cuando se ejecuta
# un programa para conocer si el módulo es ejecutado de forma
# independiente (en este caso __name__ = '__main__' o es
# importado:      

if __name__ == '__main__':
    main() # Ejecuta la función que lanza el programa

     

Ejemplo práctico de como mostrar información en una ventana.

Para acabar el capitulo vamos a crear una aplicación que haga algo. En este caso mostrar una serie de información sobre ella misma, es decir sobre la ventana que lo ejecuta. 

Para ello en la ventana de la aplicación, además del botón salir de los ejemplos anteriores hemos añadido dos nuevos widgets. Un boton "info" que al pulsarse  (evento) haga aparecer información sobre la ventana, en una caja de texto que anteriormente estaba vacía.


Usando tkinter.




3_info.py

from tkinter import *
from tkinter import ttk

# La clase 'Aplicacion' ha crecido. En el ejemplo se incluyen
# nuevos widgets en el método constructor __init__(): Uno de
# ellos es el botón 'Info'  que cuando sea presionado llamará 
# al método 'verinfo' para mostrar información en el otro 
# widget, una caja de texto: un evento ejecuta una acción: 

class Aplicacion():
    def __init__(self):
        
        # En el ejemplo se utiliza el prefijo 'self' para
        # declarar algunas variables asociadas al objeto 
        # ('mi_app')  de la clase 'Aplicacion'. Su uso es 
        # imprescindible para que se pueda acceder a sus
        # valores desde otros métodos:
        
        self.raiz = Tk()
        self.raiz.geometry('300x200')
        
        # Impide que los bordes puedan desplazarse para
        # ampliar o reducir el tamaño de la ventana 'self.raiz':
        
        self.raiz.resizable(width=False, height=False)
        self.raiz.title('Ver info')
        
        # Define el widget Text 'self.tinfo ' en el que se
        # pueden introducir varias líneas de texto:
        
        self.tinfo = Text(self.raiz, width=40, height=10)
        
        # Sitúa la caja de texto 'self.tinfo' en la parte
        # superior de la ventana 'self.raiz':
        
        self.tinfo.pack(side=TOP)
        
        # Define el widget Button 'self.binfo' que llamará 
        # al metodo 'self.verinfo' cuando sea presionado
        
        self.binfo = ttk.Button(self.raiz, text='Info', 
                                command=self.verinfo)
        
        # Coloca el botón 'self.binfo' debajo y a la izquierda
        # del widget anterior
                                
        self.binfo.pack(side=LEFT)
        
        # Define el botón 'self.bsalir'. En este caso
        # cuando sea presionado, el método destruirá o
        # terminará la aplicación-ventana 'self.raíz' con 
        # 'self.raiz.destroy'
        
        self.bsalir = ttk.Button(self.raiz, text='Salir', 
                                 command=self.raiz.destroy)
                                 
        # Coloca el botón 'self.bsalir' a la derecha del 
        # objeto anterior.
                                 
        self.bsalir.pack(side=RIGHT)
        
        # El foco de la aplicación se sitúa en el botón
        # 'self.binfo' resaltando su borde. Si se presiona
        # la barra espaciadora el botón que tiene el foco
        # será pulsado. El foco puede cambiar de un widget
        # a otro con la tecla tabulador [tab]
        
        self.binfo.focus_set()
        self.raiz.mainloop()
    
    def verinfo(self):
        
        # Borra el contenido que tenga en un momento dado
        # la caja de texto
        
        self.tinfo.delete("1.0", END)
        
        # Obtiene información de la ventana 'self.raiz':
        
        info1 = self.raiz.winfo_class()
        info2 = self.raiz.winfo_geometry()
        info3 = str(self.raiz.winfo_width())
        info4 = str(self.raiz.winfo_height())
        info5 = str(self.raiz.winfo_rootx())
        info6 = str(self.raiz.winfo_rooty())
        info7 = str(self.raiz.winfo_id())
        info8 = self.raiz.winfo_name()
        info9 = self.raiz.winfo_manager()
        
        # Construye una cadena de texto con toda la
        # información obtenida:
        
        texto_info = "Clase de 'raiz': " + info1 + "\n"
        texto_info += "Resolución y posición: " + info2 + "\n"
        texto_info += "Anchura ventana: " + info3 + "\n"
        texto_info += "Altura ventana: " + info4 + "\n"
        texto_info += "Pos. Ventana X: " + info5 + "\n"
        texto_info += "Pos. Ventana Y: " + info6 + "\n"
        texto_info += "Id. de 'raiz': " + info7 + "\n"
        texto_info += "Nombre objeto: " + info8 + "\n" 
        texto_info += "Gestor ventanas: " + info9 + "\n"
        
        # Inserta la información en la caja de texto:
        
        self.tinfo.insert("1.0", texto_info)

def main():
    mi_app = Aplicacion()
    return 0

if __name__ == '__main__':
    main()

En la aplicación se utiliza el método pack() para ubicar los widgets en una posición determinada dentro de la ventana. Dicho método da nombre a uno de los tres gestores de geometría existentes en Tkinter, que son los responsables de esta tarea.

- Gestor de Geometría Grid.
  - Gestor de Geometría Pack.
  - Gestor de Geometria Place.

Su uso lo veremos más adelante.

Usando Guizero.

ventana informativa con guizero


'''Crea una ventana con dos botones. Uno da información de la ventana y otro para salir'''

from guizero import *

class Aplicacion():    
      
    def __init__(self):
        
        self.raiz=App(title='Ver Info', bg='beige', width=310, height=210)
        
        # Vamos a impedir que los bordes puedan desplazarse para
        # ampliar o reducir el tamaño de la ventana 'self.raiz'. Esto no esta disponible directamente en guizero.
        # En guizero no encontré la opción para no poder cambiar el tamaño de la ventana, así que
        # como al fin y al cabo la raíz es un objeto de tk uso una orden de tk.resizable()
        self.raiz.tk.resizable(width=False, height=False)
        
        self.tinfo = TextBox(self.raiz, width=40, height=10, multiline=True,text="")
        self.tinfo.bg='white'
        
        self.binfo = PushButton(self.raiz, text='Info', align='left', padx=25, pady=2, command=self.verinfo)
        self.binfo.focus()
        self.binfo.when_mouse_enters=self.claro
        
        
        self.bsalir = PushButton(self.raiz, text='Salir', align='right', padx=25, pady=2, command=self.raiz.destroy)
        self.bsalir.when_mouse_enters=self.claro
        
    def verinfo(self):
            
        info1 = self.raiz.tk.winfo_class()
        info2 = self.raiz.tk.winfo_geometry()
        info3 = str(self.raiz.tk.winfo_width())
        info4 = str(self.raiz.tk.winfo_height())
        info5 = str(self.raiz.tk.winfo_rootx())
        info6 = str(self.raiz.tk.winfo_rooty())
        info7 = str(self.raiz.tk.winfo_id())
        info8 = str(self.raiz.tk.winfo_name())
        info9 = str(self.raiz.tk.winfo_manager())
            
        texto_info = "Clase de 'raiz': " + info1 + "\n"
        texto_info += "Resolución y posición: " + info2 + "\n"
        texto_info += "Anchura ventana: " + info3 + "\n"
        texto_info += "Altura ventana: " + info4 + "\n"
        texto_info += "Pos. Ventana X: " + info5 + "\n"
        texto_info += "Pos. Ventana Y: " + info6 + "\n"
        texto_info += "Id. de 'raiz': " + info7 + "\n"
        texto_info += "Nombre objeto: " + info8 + "\n" 
        texto_info += "Gestor ventanas: " + info9 + "\n"
            
        print(texto_info)
        self.tinfo.value=texto_info
        
    def claro(self, event_data):
        event_data.widget.bg="#ececec"
        #evento para cuando el ratón sale del botón que vuelva la color normal
        event_data.widget.when_mouse_leaves=self.normal
        
    def normal(self, event_data):
        event_data.widget.bg="#f5f5dc"
               
def main():
    mi_app = Aplicacion()
    return 0

if __name__ == '__main__':
    
    main()

Y con esto finalizamos el capítulo de introducción. Puedes encontrar en los siguientes links el manual de Tkinter y el de Guizero.

También puedes encontrar mucha y buena información en "Python 3 para impacientes".