Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
[tkinter] Habilitar/deshabilitar un Entry con un checkbutton
#1
Hola !
Soy muy nuevo en esto de la programacion.
Estoy tratando de hacer una ventana que tiene varios objetos Entry, y que un grupo de ellos se habilite o inhabilite dependiendo de como esté activado un Checkbutton.

No logro hacerlo hasta ahora.
Les dejo un codigo de prueba mas simple, que intenta hacer lo algo parecido pero con un solo objeto.


Código:
from tkinter import *

valorcheck=1
root = Tk()
 
label = Label(root, text="LABEL")

#defino dos funciones para ocultar o visibilizar el objeto Label 
def hide_label():
   
    label.pack_forget()
 
def recover_label():
   
    label.pack()

#defino el checkbutton que controla la ejecucion de esas funciones
B1 = Checkbutton(root, text="Click To Show label", fg="green", variable=valorcheck, onvalue=1, offvalue=0)

label.pack()
B1.pack()

#con este condicional pretendo que segun el valor de valorcheck se llame a una funcion u otra, pero hasta ahora no funciona
if valorcheck==1:
    recover_label()
else:
    hide_label()

root.mainloop()

Con ese codigo, muestra la ventana, el objeto Label y el Checkbutton, pero no lo esconde o muestra al objeto Label al cliquear en el Checkbutton.
Espero que me puedan ayudar con lo que está fallando.

Saludos y gracias
Responder
#2
Hola, bienvenido.

Hay dos problemas. El primero tiene que ver la variable "valorcheck". Para que una variable reciba el estado de un checkbutton, hay que usar una instancia de tk.BooleanVar() en lugar de los tipos de dato tradicionales de Python. Te dejo este artículo sobre Checkbutton para que entiendas cómo funciona: https://recursospython.com/guias-y-manua...k-tkinter/. Por otro lado, este código:

  1. if valorcheck==1:
  2. recover_label()
  3. else:
  4. hide_label()


solo se está ejecutando al iniciarse la aplicación. Habría que hacer un chequeo como ese cada vez que el usuario cambia el valor del checkbutton. Para eso hay que usar un evento. Te dejo un ejemplo completo con un Checkbutton y un Entry:

  1. from tkinter import ttk
  2. import tkinter as tk
  3.  
  4. def checkbutton_clicked():
  5. if checkbutton_value.get():
  6. entry.pack()
  7. else:
  8. entry.pack_forget()
  9.  
  10. root = tk.Tk()
  11. checkbutton_value = tk.BooleanVar(value=True)
  12. checkbutton = ttk.Checkbutton(
  13. text="Entry activado",
  14. variable=checkbutton_value,
  15. command=checkbutton_clicked
  16. )
  17. checkbutton.pack()
  18. entry = ttk.Entry()
  19. entry.pack()
  20. root.mainloop()


Saludos
Responder
#3
(23-02-2022, 12:46 PM)Francisco escribió: Hola, bienvenido.

Hay dos problemas. El primero tiene que ver la variable "valorcheck". Para que una variable reciba el estado de un checkbutton, hay que usar una instancia de tk.BooleanVar() en lugar de los tipos de dato tradicionales de Python. Te dejo este artículo sobre Checkbutton para que entiendas cómo funciona: https://recursospython.com/guias-y-manua...k-tkinter/. Por otro lado, este código:

  1. if valorcheck==1:
  2.     recover_label()
  3. else:
  4.     hide_label()


solo se está ejecutando al iniciarse la aplicación. Habría que hacer un chequeo como ese cada vez que el usuario cambia el valor del checkbutton. Para eso hay que usar un evento. Te dejo un ejemplo completo con un Checkbutton y un Entry:

  1. from tkinter import ttk
  2. import tkinter as tk
  3.  
  4. def checkbutton_clicked():
  5.     if checkbutton_value.get():
  6.         entry.pack()
  7.     else:
  8.         entry.pack_forget()
  9.  
  10. root = tk.Tk()
  11. checkbutton_value = tk.BooleanVar(value=True)
  12. checkbutton = ttk.Checkbutton(
  13.     text="Entry activado",
  14.     variable=checkbutton_value,
  15.     command=checkbutton_clicked
  16. )
  17. checkbutton.pack()
  18. entry = ttk.Entry()
  19. entry.pack()
  20. root.mainloop()


Saludos

Muchas gracias Francisco por tu respuesta.
Voy a estudiar el flujo del código, que es lo que me está costando entender en la POO.
Si hay algo que convenga leer para eso, agradezco que me lo indiques.
Saludos!

Modifiqué el codigo que me pasó Francisco 2 post mas arriba para que hayan 2 Entrys, y para que se habilite o inhabilite al pulsar cada checkbutton el Entry correspondiente.
Eso funciona bien. Este es el codigo:
Código:
from tkinter import ttk
import tkinter as tk

def checkbutton_clicked():
    if checkbutton_value.get():
        entry.config(state=tk.NORMAL)
    else:
        entry.config(state=tk.DISABLED)

def checkbutton_clicked2():
    if checkbutton_value2.get():
        entry2.config(state=tk.NORMAL)
    else:
        entry2.config(state=tk.DISABLED)

root = tk.Tk()
checkbutton_value = tk.BooleanVar(value=True)
checkbutton = ttk.Checkbutton(
    text="Entry activado",
    variable=checkbutton_value,
    command=checkbutton_clicked
)
checkbutton_value2 = tk.BooleanVar(value=True)
checkbutton2 = ttk.Checkbutton(
    text="Entry2 activado",
    variable=checkbutton_value2,
    command=checkbutton_clicked2
)
checkbutton.grid(row=0,column=0)
entry = ttk.Entry()
entry.grid(row=2, column=1)
checkbutton2.grid(row=1,column=0)
entry2 = ttk.Entry()
entry2.grid(row=3, column=1)

root.mainloop()
Mi duda ahora es si no hay una manera mas elegante de hacerlo.
Algo así como, crear una clase de Checkbutton y una de Entry y definir un solo metodo al que se le pase el numero de Checkbutton pulsado para que con ese unico metodo pueda activar o desactivar el Entry correspondiente.
Eso es posible?
Pregunto porque no termino de darme cuenta como se haría.
Si alguien pudiera darme algun ejemplo lo agradezco.
Saludos y gracias ! ! !

Responder
#4
(23-02-2022, 05:00 PM)ruso946 escribió: Muchas gracias Francisco por tu respuesta.
Voy a estudiar el flujo del código, que es lo que me está costando entender en la POO.
Si hay algo que convenga leer para eso, agradezco que me lo indiques.

Creo que a lo que te referís es en realidad la programación orientada a eventos, que es el paradigma utilizado en las aplicaciones de escritorio (ya sea escritas usando Tk o cualquier otra librería), donde se asocian funciones con eventos de la ventana (como la presión de un botón). Te sugiero que leas este artículo introductorio a Tk que explica conceptos básicos y también se menciona algo sobre la programación orientada a objetos: https://recursospython.com/guias-y-manua...a-tkinter/.

(23-02-2022, 05:00 PM)ruso946 escribió: Mi duda ahora es si no hay una manera mas elegante de hacerlo.
Algo así como, crear una clase de Checkbutton y una de Entry y definir un solo metodo al que se le pase el numero de Checkbutton pulsado para que con ese unico metodo pueda activar o desactivar el Entry correspondiente.

Se podría crear una subclase de ttk.Checkbutton que sea específicamente para aquellos checkbuttons que vayan a ser usados para (des)habilitar cajas de texto y que encapsule toda esa lógica. Algo así:

  1. from tkinter import ttk
  2. import tkinter as tk
  3.  
  4.  
  5. class CheckbuttonForEntry(ttk.Checkbutton):
  6.     """
  7.     Checkbutton para deshabilitar un Entry.
  8.     """
  9.     def __init__(self, *args, **kwargs):
  10.         self._var = tk.BooleanVar(value=True)
  11.         kwargs["variable"] = self._var
  12.         self.entry = kwargs.pop("entry")
  13.         super().__init__(*args, **kwargs)
  14.         self.config(command=self.clicked)
  15.    
  16.     def clicked(self):
  17.         entry.config(state=tk.NORMAL if self._var.get() else tk.DISABLED)
  18.  
  19.  
  20. root = tk.Tk()
  21. entry = ttk.Entry()
  22. checkbutton = CheckbuttonForEntry(
  23.     text="Entry activado",
  24.     entry=entry
  25. )
  26. entry2 = ttk.Entry()
  27. checkbutton2 = CheckbuttonForEntry(
  28.     text="Entry2 activado",
  29.     entry=entry2
  30. )
  31. checkbutton.grid(row=0,column=0)
  32. entry.grid(row=2, column=1)
  33. checkbutton2.grid(row=1,column=0)
  34. entry2.grid(row=3, column=1)
  35.  
  36. root.mainloop()


Te dejo algunos artículos que tal vez quieras leer a raíz de este código:

Saludos
Responder
#5
Muchas Gracias Francisco por tus respuestas.
Tengo para leer un rato.
Muy interesante lo de crear una subclase de los Checkbuttons existentes.
No se me hubiera ocurrido.

saludos!

EDITO: ahora que estuve leyendo, te comento que los dos primeros me parecieron mas accesibles para mi nivel.

En cambio el articulo sobre super(), si bien creo comprender a qué apunta, me resulta mas dificil de seguir.

En todo caso, es muy interesante y te agradezco la ayuda con el codigo y las referencias para iniciar un acercamiento a la comprension.


Por otra parte, en el codigo de la subclase CheckbuttonForEntry hay un pequeño problema, que creo haber ubicado donde modificar: los dos checkbutton operan sobre un solo Entry.

La linea que sigue a :

def clicked(self):

dice:

entry.config(state=tk.NORMAL if self._var.get() else tk.DISABLED)

lo cual parece estar operando de manera fija sobre el mismo entry siempre.
y quizas debería decir:

self.entry.config(state=tk.NORMAL if self._var.get() else tk.DISABLED)

para que se refiera a la instancia actual que está representada por el self.
Es así?


Saludos
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)