0

I have created a set (6) of checkbuttons in a tkinter app using a for-loop. So far I have just created and laid them out but the don't do anything. What I want them to do is tell another function how to work depending on which checkbutton is clicked but when I try to access the checkbuttons I'm getting the error that's posted at the bottom of the question.

I have tried making all the buttons as individual codelines but obviously that was a lot of repeated code so instead I made them with a for loop and stored them in a nested dict like so:

for i in self.atts:
    self.att_buttons[i] = {}
    self.att_buttons[i]["checkbutton"] = tk.Checkbutton(
        self.check_frame, text=i, font=("Courier", 15),
        onvalue = 1, offvalue = 0,
    ).pack(side=tk.LEFT)

I'm not sure this is right but I'm new and I'm doin my best.

I have a roll() function and what I want is for the checkbuttons to modify the result of that function and so what I've attempted is

def roll(self):
    """Roll dice, add modifer and print a formatted result to the UI"""
    value = random.randint(1, 6)
    if self.att_buttons["Str"]["checkbutton"].get() == 1:
        result = self.character.attributes["Strength"]["checkbutton].get()
        self.label_var.set(f"result: {value} + {result} ")
File "main_page.py", line 149, in roll
    if self.att_buttons["Str"]["checkbutton"].get() == 1: 
AttributeError: 'NoneType' object has no attribute 'get'

Now I assume this is because I'm calling the nested dict incorrectly but I have tried moving my code around and trying different bits and pieces and I keep getting the same error.

Update

based on hugo's answer below I have edited the for loop to be

for i in self.atts:
    self.att_buttons[i] = {}
    self.att_buttons[i]["checkbutton"] = tk.Checkbutton(
        self.check_frame, text=i, font=("Courier", 15),
        variable = tk.BooleanVar()#this is the change 
    )
    self.att_buttons[i]["checkbutton"].pack(side=tk.LEFT)`

How would I call variable for specific checkbuttons in my roll() function?

KevOMalley743
  • 551
  • 3
  • 20

1 Answers1

2

self.att_buttons["Str"]["checkbutton"] returns None, that's why Python complains about you trying to call get() on it.

You wrote:

for i in self.atts:
    self.att_buttons[i]["checkbutton"] = ...`

Check that this actually happens before the line that has the error, and check that self.atts contains "Str".


Also, I don't think that's the right way to get the state of a checkbox -- see Getting Tkinter Check Box State.

In response to your edit:

You added a BooleanVar but you need to keep a reference to it, because that's how you will access the actual value:

# Make a dict associating each att with a new BooleanVar
self.att_values = {att: tk.BooleanVar() for att in self.atts}

for i in self.atts:
    self.att_buttons[i] = {}
    self.att_buttons[i]["checkbutton"] = tk.Checkbutton(
        self.check_frame, text=i, font=("Courier", 15),
        variable = self.att_values[i] 
    )
    self.att_buttons[i]["checkbutton"].pack(side=tk.LEFT)`

This is an example of how you may do it, you just have to keep a reference to the BooleanVar to access them later:

if self.att_values["Str"].get() == 1:
hugo
  • 3,067
  • 2
  • 12
  • 22
  • OK thanks a million, I've set each button to have a variable as `tk.BooleanVar()`, do I have to define those variables outside of the for loop and then call the state that way or can i define the variables inside the for loop, and if so, how would I call them in the roll function? – KevOMalley743 Aug 04 '19 at 17:43
  • Where is the part where you associate a variable with your CheckButton? I think it should be inside tk.Checkbutton(...) but I can't see it. – hugo Aug 04 '19 at 17:51
  • I've just added it to the main code ave in the update there. – KevOMalley743 Aug 04 '19 at 18:02