0

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

Pythonicc
  • 3
  • 3
  • You have used same instance variable for all checkbuttons and another instance variable for all entries. You need to use two arrays to store those checkbuttons and entries. – acw1668 Feb 12 '22 at 08:48
  • I thought textvariable=self.DefautArticlesEntries[key] will store for each checkbutton its own off/on value because it's iterable through the dictionary. Otherwise could you show me piece of code that I need to change? – Pythonicc Feb 12 '22 at 14:06
  • You used `self.cur_entry` inside `ArticlesEntryState()`, but `self.cur_entry` refers to the last entry created `Principal.__init__()`. So you need to use list or dict to store the instances of entries instead of those `StringVar`s. – acw1668 Feb 12 '22 at 14:16
  • @acw1668 I really appreciate your help. I managed to figure it out by creating a list and append entries to it. Should I edit my question or answer it to make the update for others whom looking for solution to the same issue? – Pythonicc Feb 12 '22 at 16:29

3 Answers3

0

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()
Viswa
  • 134
  • 1
  • 13
  • As you can see on the code above I created Entries and Checkbuttons using for loop. Then I created a method that verify if the checkbutton is checked or not then disable and enable its Entry accordenly. I think the problem is that textvariable that I assigned for the checkbutton return to only one checkbutton and not eachone on the list – Pythonicc Feb 12 '22 at 14:11
0

Update:

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()
             
        
      
Pythonicc
  • 3
  • 3
0

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)
A. Rodas
  • 20,171
  • 8
  • 62
  • 72