Home > Software engineering >  How to disable an Entry on tkinter when a Checkbutton is unchecked using for loop and dictionary
How to disable an Entry on tkinter when a Checkbutton is unchecked using for loop and dictionary

Time:02-13

I'm working on a Windows application for my work and my knowledge on Python is very limited, so I didn't know how to figure this out :

I want to make each entry widget inside the frame disabled when its checkbutton is unchecked and enabled when its checkbutton is checked and make them all checked by default. I tried this code that I took part of it from this tutorial but it didn't work as expected.

from tkinter import *

class Principal():
    def __init__(self):
        self.root= Tk()
        self.root.geometry('800x800') 

        self.prixArticlesFrame = LabelFrame(self.root, text="Prix des articles", width=2000)
        self.prixArticlesFrame.place(relx = 0.75, rely = 0.15,anchor = N)

        self.DefautArticlesCheckButton={
            "Deblai" : IntVar(),
            "Remblai" : IntVar(),
            "Blocage" : IntVar(),
            "Beton de propreté": IntVar(),
            "Beton armé": IntVar(),
            "Acier à haute adherence": IntVar(),
            "Joint de dilatation": IntVar(),
            
        }
        for index, (key, value) in enumerate(self.DefautArticlesCheckButton.items()):
            self.cur_check = Checkbutton(self.prixArticlesFrame, 
            text=key,variable=self.DefautArticlesCheckButton[key], onvalue=1, 
            offvalue=0,command=self.ArticlesEntryState) 
            self.cur_check.grid(row=index, column=0, padx=10, pady=10, sticky="W")

        self.DefautArticlesEntries={
            "Deblai" : StringVar(),
            "Remblai" : StringVar(),
            "Blocage" : StringVar(),
            "Beton de propreté": StringVar(),
            "Beton armé": StringVar(),
            "Acier à haute adherence": StringVar(),
            "Joint de dilatation": StringVar(),
            
        }

        for index, (key, value) in enumerate(self.DefautArticlesEntries.items()):
            self.cur_entry = 'DefautArticlesEntries'  key
            
            self.cur_entry=Entry(self.prixArticlesFrame,width=10,
                          textvariable=self.DefautArticlesEntries[key])
            self.cur_entry.grid(row=index,column=2,padx=10)
            self.cur_entry.config(state=NORMAL)
        self.root.mainloop()
    
    def ArticlesEntryState(self):
        for index, (key, value) in enumerate(self.DefautArticlesCheckButton.items()):
            
            if self.DefautArticlesCheckButton[key].get() == 1:
                self.cur_entry.grid(row=index,column=2,padx=10)
                self.cur_entry.config(state=NORMAL)

            elif self.DefautArticlesCheckButton[key].get() == 0:
                self.cur_entry.config(state=DISABLED)

app = Principal()

here is what I got in gif image

What I have done wrong? Thanks

CodePudding user response:

As per my understanding. you are asking to link check button and Line Edit. i given example code to link.

import tkinter
from tkinter import *

def test():
    if e['state'] == 'normal':
        e['state'] = 'disabled'
    else:
        e['state'] = 'normal'

w=Tk()
e=Entry()
e.pack()
cb=Checkbutton(command=test)
cb.select()
cb.pack()
w.mainloop()

CodePudding user response:

As @acw1668 said, I used self.cur_entry to change the entry's state when checkbutton is checked or unchecked and this only change the last entry's state. I created instead a list and appended the entries created to it :

from tkinter import *

class Principal():
    
    def __init__(self):
        
        self.root= Tk()

        self.root.geometry('800x800') 
        
        self.AjouterArticleFrame = LabelFrame(self.root, text="Ajouter un article", width=2000)
        self.AjouterArticleFrame.place_forget()

        self.DefautArticlesCheckButton={
            "Deblai" : IntVar(value=1),
            "Remblai" : IntVar(value=1),
            "Blocage" : IntVar(value=1),
            "Beton de propreté": IntVar(value=1),
            "Beton armé": IntVar(value=1),
            "Acier à haute adherence": IntVar(value=1),
            "Joint de dilatation": IntVar(value=1),
            }
        
        self.variablesList=[]
        for index, (key, value) in enumerate(self.DefautArticlesCheckButton.items()):
            checkbutton_=Checkbutton(self.prixArticlesFrame, text=key,variable=self.DefautArticlesCheckButton[key], onvalue=1, offvalue=0,command=self.DefaultArticlesEntryState)
            checkbutton_.grid(row=index, column=0, padx=10, pady=10, sticky="W")
            self.variablesList.append(self.DefautArticlesCheckButton[key])

        
        self.DefautArticlesPrix=[
            "Deblai" ,
            "Remblai" ,
            "Blocage" ,
            "Beton de propreté" ,
            "Beton armé" ,
            "Acier à haute adherence" ,
            "Joint de dilatation",
        ]
        self.DefautArticlesPrixEntriesWidgets=[]


        for i in self.DefautArticlesPrix:
            entry_prix=Entry(self.prixArticlesFrame,width=10)
            entry_prix.grid(row=self.DefautArticlesPrix.index(i),column=2,padx=10)
            self.DefautArticlesPrixEntriesWidgets.append(entry_prix)


    def DefaultArticlesEntryState(self):
        for i in range(len(self.variablesList)):
            if int(self.variablesList[i].get()) == 1:
                self.DefautArticlesPrixEntriesWidgets[i].grid(row=i,column=2,padx=10)
                self.DefautArticlesPrixEntriesWidgets[i].config(state=NORMAL)

            elif int(self.variablesList[i].get()) == 0:
                self.DefautArticlesPrixEntriesWidgets[i].config(state=DISABLED) 

app = Principal()
             
        
      

CodePudding user response:

Since you want all buttons checked by default, all variables should have an initial value that matches their onvalue.

Besides, both dicts refer to the variables rather than the actual widgets, so each Entry must be bound to the scope of the corresponding IntVar trace callback - otherwise, only the last loop item is referenced:

        for index, (key, value) in enumerate(self.DefautArticlesCheckButton.items()):
            value.set(1)
            check = Checkbutton(self.prixArticlesFrame, text=key, variable=value)
            check.grid(row=index, column=0, padx=10, pady=10, sticky="W")

        # ...

        for index, (key, value) in enumerate(self.DefautArticlesEntries.items()):
            entry = Entry(self.prixArticlesFrame, width=10, textvariable=value)
            entry.grid(row=index, column=1, padx=10)

            var = self.DefautArticlesCheckButton[key]
            handler = lambda *_, e=entry, v=var: e.config(state=NORMAL if v.get() else DISABLED)
            var.trace('w', handler)
  • Related