pythontkinterbooleancounting

Tkinter - How to check a buttons' state; repeat for multiple buttons, and total the results?


I have made a digital version of a pen-and-paper game as my first major python practice project. You can see from the attached picture that the main board consists of buttons. They can be toggled between two states: they start displaying a number and are True, when clicked they display an "X" and become False. You will see from the screenshot that there is a score multiplier that tells you how many points you get for each row depending on how many buttons are displaying "X", i.e. in the False state.

At the moment the user has to enter the score manually for each row. What I'm trying to do is have the appropriate score appear in the appropriate box depending on the number of buttons that are False. For example, if four red buttons have been clicked, so are False, 10 would be displayed in the red Score box.

The help I am seeking: I do not know how to check the current boolean state of each button, nor do I know how to total the results.

I am very new to programming and am learning for fun. I do not want or expect a whole program to be written for me that I can copy and paste; I would like to be pointed in the right direction.

The program

I have included below just the code relevent to the main board (the 4 coloured rows) and the score boxes. Below I have included the code for just the red row of the main board, and the score boxes.

import tkinter                       
import tkinter.messagebox          

class MyGUI:
    def __init__(self):
        
        # Window setup
        self.window = tkinter.Tk() 
        self.window.title("Quixx")
        self.window.geometry("600x400")
        self.window.maxsize(600, 400)
        self.window.minsize(600, 400)
        

        # Main board function variables
        self.state1 = True
        self.state2 = True
        self.state3 = True
        self.state4 = True
        self.state5 = True
        self.state6 = True
        self.state7 = True
        self.state8 = True
        self.state9 = True
        self.state10 = True
        self.state11 = True
        # Removed for brevity.
 

# Main board setup.
        button_frame = tkinter.Frame(self.window)
        button_frame.columnconfigure(0, weight=1)
        button_frame.columnconfigure(1, weight=1)
        button_frame.columnconfigure(2, weight=1)
        button_frame.columnconfigure(3, weight=1)
        button_frame.columnconfigure(4, weight=1)
        button_frame.columnconfigure(5, weight=1)
        button_frame.columnconfigure(6, weight=1)
        button_frame.columnconfigure(7, weight=1)
        button_frame.columnconfigure(8, weight=1)
        button_frame.columnconfigure(9, weight=1)
        button_frame.columnconfigure(10, weight=1)
        button_frame.columnconfigure(11, weight=1)

        # Red row
        self.btn1 = tkinter.Button(button_frame, text="2", background="red", command=self.btn1_change)
        self.btn1.grid(row=0, column=0, sticky="we",)
        
        self.btn2 = tkinter.Button(button_frame, text="3", background="red", command=self.btn2_change)
        self.btn2.grid(row=0, column=1, sticky="we")
        
        self.btn3 = tkinter.Button(button_frame, text="4", background="red", command=self.btn3_change)
        self.btn3.grid(row=0, column=2, sticky="we")
        
        self.btn4 = tkinter.Button(button_frame, text="5", background="red", command=self.btn4_change)
        self.btn4.grid(row=0, column=3, sticky="we")
        
        self.btn5 = tkinter.Button(button_frame, text="6", background="red", command=self.btn5_change)
        self.btn5.grid(row=0, column=4, sticky="we")
        
        self.btn6 = tkinter.Button(button_frame, text="7", background="red", command=self.btn6_change)
        self.btn6.grid(row=0, column=5, sticky="we")
        
        self.btn7 = tkinter.Button(button_frame, text="8", background="red", command=self.btn7_change)
        self.btn7.grid(row=0, column=6, sticky="we")
        
        self.btn8 = tkinter.Button(button_frame, text="9", background="red", command=self.btn8_change)
        self.btn8.grid(row=0, column=7, sticky="we")
        
        self.btn9 = tkinter.Button(button_frame, text="10", background="red", command=self.btn9_change)
        self.btn9.grid(row=0, column=8, sticky="we")
        
        self.btn10 = tkinter.Button(button_frame, text="11", background="red", command=self.btn10_change)
        self.btn10.grid(row=0, column=9, sticky="we")
        
        self.btn11 = tkinter.Button(button_frame, text="12", background="red", command=self.btn11_change)
        self.btn11.grid(row=0, column=10, sticky="we")

        

        # Yellow row
          # removed for brevity

        # Green row
          # removed for brevity

        # Blue row
          # removed for brevity
        

# Score calculation frame setup
        score_calc_frame = tkinter.Frame(self.window)
        score_calc_frame.columnconfigure(0, weight=1)
        score_calc_frame.columnconfigure(1, weight=1)
        score_calc_frame.columnconfigure(2, weight=1)
        score_calc_frame.columnconfigure(3, weight=1)
        score_calc_frame.columnconfigure(4, weight=1)
        score_calc_frame.columnconfigure(5, weight=1)
        score_calc_frame.columnconfigure(6, weight=1)
        score_calc_frame.columnconfigure(7, weight=1)
        score_calc_frame.columnconfigure(8, weight=1)
        score_calc_frame.columnconfigure(9, weight=1)
        score_calc_frame.columnconfigure(10, weight=1)
        score_calc_frame.columnconfigure(11, weight=1)

        # Score labels and textboxes
        self.score_calc_label1 = tkinter.Label(score_calc_frame, text="Score", font=('arial', 16))
        self.score_calc_label1.grid(row=0, column=0, sticky="we")

        self.score_calc_textbox_red = tkinter.Text(score_calc_frame, height=1, width=1, background="red")
        self.score_calc_textbox_red.grid(row=0, column=1, sticky="we",)

        self.score_calc_label2 = tkinter.Label(score_calc_frame, text="+", font=('Arial', 18))
        self.score_calc_label2.grid(row=0, column=2, sticky="we")

        self.score_calc_textbox_yellow = tkinter.Text(score_calc_frame, height=1, width=1, background="yellow")
        self.score_calc_textbox_yellow.grid(row=0, column=3, sticky="we")

        self.score_calc_label3 = tkinter.Label(score_calc_frame, text="+", font=('arial', 18))
        self.score_calc_label3.grid(row=0, column=4, sticky="we")

        self.score_calc_textbox_green = tkinter.Text(score_calc_frame, height=1, width=1, background="green")
        self.score_calc_textbox_green.grid(row=0, column=5, sticky="we")

        self.score_calc_label4 = tkinter.Label(score_calc_frame, text="+", font=('arial', 18))
        self.score_calc_label4.grid(row=0, column=6, sticky="we")

        self.score_calc_textbox_blue = tkinter.Text(score_calc_frame, height=1, width=1, background="blue")
        self.score_calc_textbox_blue.grid(row=0, column=7, sticky="we")

        self.score_calc_label5 = tkinter.Label(score_calc_frame, text="-", font=('arial', 18))
        self.score_calc_label5.grid(row=0, column=8, sticky="we")

        self.score_calc_textbox_subtract = tkinter.Text(score_calc_frame, height=1, width=1)
        self.score_calc_textbox_subtract.grid(row=0, column=9, sticky="we")

        self.score_calc_label6 = tkinter.Label(score_calc_frame, text="=", font=('arial', 18))
        self.score_calc_label6.grid(row=0, column=10, sticky="we")

        self.score_calc_label_result = tkinter.Label(score_calc_frame, height=1, width=1, background="white")
        self.score_calc_label_result.grid(row=0, column=11, sticky="we")

        
    # Main board button frame packing
        button_frame.pack(fill="x", anchor="n", padx=10, pady=20)
    
    # Score calculation frame packing
        score_calc_frame.pack(fill="x", padx=5, anchor="center")

        self.window.mainloop()

# Main board button functions
  
    # Red row
    def btn1_change(self):
        if self.state1 == True:
            self.btn1.config(text="X")
        else:
            self.btn1.config(text="2")
        self.state1 = not self.state1
            
    def btn2_change(self):
        if self.state2 == True:
            self.btn2.config(text="X")
        else:
            self.btn2.config(text="3")
        self.state2 = not self.state2 

    def btn3_change(self):
        if self.state3 == True:
            self.btn3.config(text="X")
        else:
            self.btn3.config(text="4")
        self.state3 = not self.state3

    def btn4_change(self):
        if self.state4 == True:
            self.btn4.config(text="X")
        else:
            self.btn4.config(text="5")
        self.state4 = not self.state4 

    def btn5_change(self):
        if self.state5 == True:
            self.btn5.config(text="X")
        else:
            self.btn5.config(text="6")
        self.state5 = not self.state5 

    def btn6_change(self):
        if self.state6 == True:
            self.btn6.config(text="X")
        else:
            self.btn6.config(text="7")
        self.state6 = not self.state6 

    def btn7_change(self):
        if self.state7 == True:
            self.btn7.config(text="X")
        else:
            self.btn7.config(text="8")
        self.state7 = not self.state7 

    def btn8_change(self):
        if self.state8 == True:
            self.btn8.config(text="X")
        else:
            self.btn8.config(text="9")
        self.state8 = not self.state8 

    def btn9_change(self):
        if self.state9 == True:
            self.btn9.config(text="X")
        else:
            self.btn9.config(text="10")
        self.state9 = not self.state9 

    def btn10_change(self):
        if self.state10 == True:
            self.btn10.config(text="X")
        else:
            self.btn10.config(text="11")
        self.state10 = not self.state10 

    def btn11_change(self):
        if self.state11 == True:
            self.btn11.config(text="X")
        else:
            self.btn11.config(text="12")
        self.state11 = not self.state11 

    
    
    
    # Yellow row
      # removed for brevity 
    
    # Green row
      # removed for brevity   
    
    # Blue row
      # removed for brevity

MyGUI()

And this is the code that I thought looked most promising from my research on how to solve this, but I'm unsure how to implement it:

def btn1_change(self):
        c=0
        for i in self.red_row_list:
            if(i==False):
                c+=1
        return c

Solution

  • Given that you save the state in various fields (state1, state2 etc.) you would have to check one by one:

        def btn1_change(self):
            if self.state1 == True:
                self.btn1.config(text="X")
            else:
                self.btn1.config(text="2")
            self.state1 = not self.state1
            c = 0
            if not self.state1:
                c += 1
            if not self.state2:
                c += 1
            if not self.state3:
                c += 1
            if not self.state4:
                c += 1
            if not self.state5:
                c += 1
            if not self.state6:
                c += 1
            if not self.state7:
                c += 1
            if not self.state8:
                c += 1
            if not self.state9:
                c += 1
            if not self.state10:
                c += 1
            if not self.state11:
                c += 1
            self.score_calc_textbox_red.replace('1.0', tkinter.END, c)
    

    Not only that, you would have to execute this in every callback, so you would either repeat this code or (preferably) move it to a function to be called from every button.

    But there are may ways in which it can be improved. Here I will suggest one improvement:

    You can reduce this amount of code by saving the state in a list, instead of having one field per state:

    class MyGUI:
        def __init__(self):
    
            # Window setup
            self.window = tkinter.Tk()
            self.window.title("Quixx")
            self.window.geometry("600x400")
            self.window.maxsize(600, 400)
            self.window.minsize(600, 400)
    
    
            # Main board function variables
            # Here we create a list with eleven True values
            self.state = [True] * 11
    
        def btn1_change(self):
            if self.state[0] == True:
                self.btn1.config(text="X")
            else:
                self.btn1.config(text="2")
            self.state[0] = not self.state[0]
            c = 0
            for s in self.state:
                # In general `not s` is preferable for `s == False`
                if not s:
                    c += 1
            self.score_calc_textbox_red.replace('1.0', tkinter.END, c)
    

    Of course, much more could be changed, but since you are still learning, I believe there is enough here for you to unpack. Good luck!