Search code examples
pythontkinterttk

Can't change state of other Ttk Checkbutton using command- Tkinter


Output *after some changes

How do i make one CheckButton get disabled and checked, when any other CheckButton is clicked.

I want to disable as well set chk1 to Checked upon hitting chk2 as Checked and if Unchecked i want chk1's state to be set as normal.

I get an error using below-

import tkinter as tk
from tkinter import ttk

class Root(tk.Tk):
    def __init__(self):
        super().__init__()

        var1 = tk.IntVar()
        chk1 = ttk.Checkbutton(self, text = 'Class', variable = var1)
        #chk1.state(['selected'])
        chk1.pack(side = 'left')
        var2 = tk.IntVar()
        chk2 = ttk.Checkbutton(self, text = 'Section', variable = var2,
        command = lambda: self.chk(chk1, var2))
        #chk2.state(['selected'])
        chk2.pack(side = 'left')

    def chk(self, obj, self_val):
        if self_val.get() == 1: #changed from 0 to 1
            obj.state['selected']
            obj.configure(state = 'disabled')
        else:
            obj.configure(state = 'normal')

if __name__ == '__main__':
    Root().mainloop()
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Sagar\Anaconda3\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "d:\chkbtn.py", line 18, in <lambda>
    command = lambda: self.chk(chk1, var2))
  File "d:\chkbtn.py", line 24, in chk
    obj.state['selected']
TypeError: 'method' object is not subscriptable

Solution

  • I think after some confusion you need to add a 3rd variable to your lambda and method.

    In order to set the state and to update the variable.

    Try the below and let me know if that helps:

    import tkinter as tk
    from tkinter import ttk
    
    
    class Root(tk.Tk):
        def __init__(self):
            super().__init__()
            var1 = tk.IntVar(self)
            var2 = tk.IntVar(self)
            chk1 = ttk.Checkbutton(self, text='chk1', variable=var1)
            chk2 = ttk.Checkbutton(self, text='chk2', variable=var2, command=lambda: self.chk(var1, chk1, var2))
            chk1.pack(side='left')
            chk2.pack(side='left')
    
        def chk(self, var1, chk1, chk2):
            if chk2.get() == 1:
                var1.set(1) # need to set the value of var1 to update chk1
                chk1.configure(state='disabled')
            else:
                var1.set(0)
                chk1.configure(state='normal')
    
    
    if __name__ == '__main__':
        Root().mainloop()
    

    Here is an example using class attributes instead of a lambda.

    import tkinter as tk
    from tkinter import ttk
    
    
    class Root(tk.Tk):
        def __init__(self):
            super().__init__()
            self.var1 = tk.IntVar(self)
            self.var2 = tk.IntVar(self)
            self.chk1 = ttk.Checkbutton(self, text='chk1', variable=self.var1)
            chk2 = ttk.Checkbutton(self, text='chk2', variable=self.var2, command=self.chk)
            self.chk1.pack(side='left')
            chk2.pack(side='left')
    
        def chk(self):
            if self.var2.get() == 1:
                self.var1.set(1)  # need to set the value of var1 to update chk1
                self.chk1.configure(state='disabled')
            else:
                self.var1.set(0)
                self.chk1.configure(state='normal')
    
    
    if __name__ == '__main__':
        Root().mainloop()