0

I am trying to make a calculator using tkinter module and I need to disable all the buttons when I press the "off" button, but my code is not working. I'm not sure why.

def off():
    btnoff  = Button(win,command = off,state=DISABLED)
    btn1 = Button(win,command=lambda:add(1),state=DISABLED)
    btn2 = Button(win,command=lambda:add(2),state=DISABLED)
    btn3 = Button(win,command=lambda:add(3),state = DISABLED)
    btn4 = Button(win,command=lambda:add(4),state = DISABLED)
    btn5 = Button(win,command=lambda:add(5),state = DISABLED)
    btn6 = Button(win,command=lambda:add(6),state = DISABLED)
    btn7 = Button(win,command=lambda:add(7),state = DISABLED)
    btn8 = Button(win,command=lambda:add(8),state = DISABLED)
    btn9= Button(win,command=lambda:add(9),state = DISABLED)
    btn0 = Button(win,command=lambda:add(0),state = DISABLED)
    btn40 = Button(win,state = DISABLED)
    btnclear = Button(win,command = clear,state = DISABLED )
    btnequal =  Button(win,command =equal,state = DISABLED)
    btnadd = Button(win,command =add,state = DISABLED)
    btndivide = Button(win,command = divide,state = DISABLED)
    btnsubtract = Button(win,command = subtract,state = DISABLED)
    btn00 = Button(win,state = DISABLED)

This is my code.

3
  • 3
    Are you aware that each time you call this you are creating a whole new set of buttons ? For example, the first time you call this you'll have 18 buttons. The next time you call it you'll have 36, and so on. Is that what you're intending to do? Commented Jan 31, 2020 at 15:54
  • no i need to disable the entire buttons when i press "off"button Commented Jan 31, 2020 at 16:04
  • 1
    In order to change the state of the existing Buttons, you'll need to store them in some non-local variable (such as a list or dictionary) which will then allow you to reconfigure their state using the universal widget.config(option=new_value) method whenever desired. Commented Jan 31, 2020 at 16:08

3 Answers 3

1

What I suspect is you already created all of these buttons outside of the off function and simply do not understand how to configure a button and think that redefining the button will do what you want. It wont. for example btnoff = Button(...) should be btnoff.config(state='disabled')

That said I think the best approach is to iterate over all widgets in the win container and disable them dynamically.

As Bryan pointed out in the comments one issue with this approach is if your On button is in the same container. In that case you can write in a condition to check if the button is the on button and then chose what to do with its state.

For example:

import tkinter as tk


root = tk.Tk()


def off():
    widgets = root.winfo_children()
    for widget in widgets:
        if widget['text'] != 'On':
            widget.config(state='disabled')
        else:
            widget.config(state='normal')

def on():
    widgets = root.winfo_children()
    for widget in widgets:
        if widget['text'] != 'On':
            widget.config(state='normal')
        else:
            widget.config(state='disabled')


for i in range(4):
    btn = tk.Button(root, text='Button {}'.format(i), state='disabled')
    btn.pack()

off_btn = tk.Button(root, text='Off', command=off, state='disabled')
on_btn = tk.Button(root, text='On', command=on)
off_btn.pack()
on_btn.pack()

root.mainloop()

Now with on and off buttons:

enter image description here enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

You need to be careful with this - what if they have a button in that frame to re-enable all of the buttons? While this is a good example of using introspection, you may end up disabling an "on" button as well as the "off" button, making it impossible to re-enable the buttons.
@BryanOakley I updated my code to handle this potential issue.
0

That`s what you need:

def off():
    btnoff.config(state=DISABLED)
    btn1.config(state=DISABLED)
    btn2.config(state=DISABLED)
    btn3.config(state=DISABLED)
    btn4.config(state=DISABLED)
    btn5.config(state=DISABLED)
    btn6.config(state=DISABLED)
    btn7.config(state=DISABLED)
    btn8.config(state=DISABLED)
    btn9.config(state=DISABLED)
    btn0.config(state=DISABLED)
    btn40.config(state=DISABLED)
    btnclear.config(state=DISABLED)
    btnequal.config(state=DISABLED)
    btnadd.config(state=DISABLED)
    btndivide.config(state=DISABLED)
    btnsubtract.config(state=DISABLED)
    btn00.config(state=DISABLED)

But optimally would to pass for def off list of buttons. Then it would see like this:

def off(btns):
    for btn in btns:
        btn.config(state=DISABLED)

5 Comments

You need to mention that the button variables need to be globals for your solution to work.
Or seeing that the buttons are in the same window the function could simply iterate over all widgets in container and disable them.
@n1tr0xs I dont believe Bryan was telling you to write globals into the function. He was saying for your function to work the buttons needed to be in the global namespace to begin with.
@n1tr0xs No just remove the global's and mention that in order for this function to work the original buttons need to already be in the global namespace and not created say as local variables to another function.
@Mike-SMT Thanks, I misunderstood his words
0

As I said in a comment you should to save all the Buttons created in a container so you can refer to them as needed — such as when you want to change their state.

Here's an example of how to do that by storing them in a list, as well as illustrating how to retrieve and change each Button's current state.

import tkinter as tk
from tkinter.constants import *


def toggle(btns):
    """ Flip state of each Button widget in btns between normal and disabled. """
    for btn in btns:
        new_state = DISABLED if btn.cget('state') == NORMAL else NORMAL
        btn.config(state=new_state)


root = tk.Tk()

# Create Buttons and store them in a list.
btns = []
for i in range(1, 5):
    btn = tk.Button(root, state=NORMAL, text='Button {}'.format(i))
    btn.pack()
    btns.append(btn)

toggle_btn = tk.Button(root, text='Toggle', command=lambda: toggle(btns))
toggle_btn.pack()

root.mainloop()

Here are screenshots showing what things look like before and after clicking on the Toggle button to flip the state of the others:

before and after screenshot

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.