0

I have a larger program I am working on that loads and displays objects that a user creates. Each object has specific settings that can be changed by check buttons in a menu. When an object is loaded the display settings are overwritten using .set() to whatever specific settings the object has. I am using .trace() to modify the display when the settings are changed. The problem is I want the callback to happen only when the user changes and not when a new object is loaded and the settings are overwritten.

To make the problem simpler say I have 4 checkboxes and a function that prints the index that the user clicked. Then I have a button that checks only the even boxes. Is there a way I could make it so my callback function printIndex only happens when the user clicks the checkbox and not when the button sets the values??

enter image description here

Here is the simplified code:

import tkinter as tk

def printIndex(index):
    print("User clicked {}".format(index))

def setOnlyOdds():
    print("\nSetting only Evens")
    for i in range(4):
        value = True if (i + 1 ) % 2 == 0 else False
        print("{} is being set to {}".format(i+1,value))
        bools[i].set(value)

root = tk.Tk()
root.title("Qhat Apps")
root.grid()

bools = [] # 4 total 
checkBoxes = [] # 4 total
for i in range(4):
    bools.append(tk.BooleanVar())
    checkBoxes.append(tk.Checkbutton(root,variable = bools[i]))
    checkBoxes[i].grid(column = 1, row = i)

label1 = tk.Label(text = "1").grid(column = 0, row = 0)
label2 = tk.Label(text = "2").grid(column = 0, row = 1)
label3 = tk.Label(text = "3").grid(column = 0, row = 2)
label4 = tk.Label(text = "4").grid(column = 0, row = 3)

bools[0].trace("w", lambda *args: printIndex(1))
bools[1].trace("w", lambda *args: printIndex(2))
bools[2].trace("w", lambda *args: printIndex(3))
bools[3].trace("w", lambda *args: printIndex(4))

evens = tk.Button(root,text = "Only Evens", command = setOnlyOdds).grid(columnspan = 2)

root.mainloop()

Thanks in advance!

Jadon Erwin
  • 551
  • 5
  • 25
  • 2
    Why not just set the output callback on the `Checkbutton` instances, since it's when those are clicked that you want output to occur? – Karl Knechtel Apr 08 '20 at 16:45
  • 1
    @KarlKnechtel, I changed the lines bools[0].trace... to checkBoxes[0].config(command = printIndex(1)) and it still doesn't work??? Is another way I should go about it? – Jadon Erwin Apr 08 '20 at 16:57
  • 1
    Read [Why is Button parameter “command” executed when declared?](https://stackoverflow.com/q/5767228/7432) – stovfl Apr 08 '20 at 17:18

1 Answers1

1

So I changed my checkbutton to have the command instead of putting it in trace.

import tkinter as tk

def printIndex(index):
    print("User clicked {}".format(index))

def setOnlyOdds():
    print("\nSetting only Evens")
    for i in range(4):
        value = True if (i + 1 ) % 2 == 0 else False
        print("{} is being set to {}".format(i+1,value))
        bools[i].set(value)

root = tk.Tk()
root.title("Qhat Apps")
root.grid()

bools = [] # 4 total 

for i in range(4):
    bools.append(tk.BooleanVar())
checkBox1 = tk.Checkbutton(root,variable = bools[0], command = lambda: printIndex(1))
checkBox2 = tk.Checkbutton(root,variable = bools[1], command = lambda: printIndex(2))
checkBox3 = tk.Checkbutton(root,variable = bools[2], command = lambda: printIndex(3))
checkBox4 = tk.Checkbutton(root,variable = bools[3], command = lambda: printIndex(4))
checkBox1.grid(column = 1, row = 0)
checkBox2.grid(column = 1, row = 1)
checkBox3.grid(column = 1, row = 2)
checkBox4.grid(column = 1, row = 3)

label1 = tk.Label(text = "1").grid(column = 0, row = 0)
label2 = tk.Label(text = "2").grid(column = 0, row = 1)
label3 = tk.Label(text = "3").grid(column = 0, row = 2)
label4 = tk.Label(text = "4").grid(column = 0, row = 3)

evens = tk.Button(root,text = "Only Evens", command = setOnlyOdds).grid(columnspan = 2)

root.mainloop()
Jadon Erwin
  • 551
  • 5
  • 25