I cannot change the state of an Entry() widget in Python and Tkinter

Asked

Viewed 766 times

4

In my code, my Entry() the state is originally as DISABLED. To enable entry, the user would need to mark one of the checkbuttons. Well, at least that’s the idea. What happens is I mark one of the boxes, but the entry is not released so you can type in it. Follow the code excerpt:

self.sum_l = Label(self.root, text = 'Soma', bg = 'Lightskyblue2')
self.sum_s = IntVar()
self.sum_c = Checkbutton(self.root, bg = 'Lightskyblue2', command = self.Sum, variable = self.sum_s)

self.sub_l = Label(self.root, text = 'Subtração', bg = 'Lightskyblue2')
self.sub_s = IntVar()
self.sub_c = Checkbutton(self.root, bg = 'Lightskyblue2', command = self.Sub, variable = self.sub_s)

self.mult_l = Label(self.root, text = 'Multiplicação', bg = 'Lightskyblue2')
self.mult_s = IntVar()
self.mult_c = Checkbutton(self.root, bg = 'Lightskyblue2', command = self.Mult, variable = self.mult_s)

self.div_l = Label(self.root, text = 'Divisão', bg = 'Lightskyblue2')
self.div_s = IntVar()
self.div_c = Checkbutton(self.root, bg = 'Lightskyblue2', command = self.Div, variable = self.div_s)

self.entry = Entry(self.root, bg = 'white')
if any([self.sum_s.get(), self.sub_s.get(), self.mult_s.get(), self.div_s.get()]):
    self.entry['state'] = NORMAL
else:
    self.entry['state'] = DISABLED

It’s probably something obvious I haven’t noticed. Can anyone tell what it is?

  • 1

    Avoid putting out-of-date code fragments - it’s worth just putting the class and method declaration on the list, and, if need be, skipping lines within the method - for example, lines that are repeated for sub, mult and div widgets, could be marked with a ... . But the method and class declaration make it easy to view cotnexto for those who help.

1 answer

3


Yes - what happens is that when we program to respond to desktop applications (and modern web applications, with asynchronous requests) - the thing changes a little of the programming to terminal.

There is no magic possible: if you write an excerpt of code like the above, it runs all at once. Then the program stops waiting for interaction with the user. When the user interacts, one of the functions of "callback".

In your house your if any([... is executed once as soon as the window is mounted, but there is no code monitoring if there has been any change in the widgets you look at in the list. The check is done only once.

So, you have to connect a function to run when your variables are changed - and not put the code together with the creation of widgets.

This can be done for example with the "trace" method of IntVar Tkinter: you pass it a function or method to call when it is changed - you can change your if into a method - and put a callback for each of its variables. The way to do this "in full" - that is, without using a for to set up various components once is put after creating each of your IntVara call like:

self.mult_s.trace('w', self.changed) 

(w indicates that the function will be called when the variable is amended (in writing))

And then you create the method changed where you can put exactly the same if that you put up:

def changed(self, *args):
    if any([self.sum_s.get(), self.sub_s.get(), self.mult_s.get(), self.div_s.get()]):
        self.entry['state'] = NORMAL
    else:
        self.entry['state'] = DISABLED

These changes should be sufficient for your case.

  • Gave the following error: Traceback (most recent call last):
 File "C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__
 return self.func(*args)
TypeError: Changed() takes 1 positional argument but 4 were given This also generated another error(I don’t put everything here to not exceed space) but solving this, the other must be solved too.

  • 1

    sorry - trace calls callback with some extra parameters - edits response to accept an undefined number of positional arguments now.

  • Now yes the code is working perfectly. Thank you very much.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.