Search code examples
python-3.xkivysudoku

Python/ Kivy (no .kv): How do I change the background color of a button based on it's "__name__"?


I am making a Sudoku board (not a solver) and I want to disable (or at least change the background color of some buttons based on clicked status of other buttons. For example, if a "1" is selected in the 1st row, 7th column, I want to disable the "1" buttons of all other cells in the 1st row and in the 7th column and in the top right block.

Ive given each button a __name__ as below (in my example the __name__ would be [3, 1, 7, 1, 1]), so I would like all button with addresses [3, x, y, z, 1], [*, 1, *, , 1], and [, *, 7, *, 1] to be disabled, or at least grayed-out.

import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout


class SudokuLayout(GridLayout):
    def __init__(self, **kwargs):
        super(SudokuLayout, self).__init__(**kwargs)

        self.cols = 3
        self.rows = 3
        i_block = 0
        i_cell = 0
        i_row = 0
        i_col = 0
        i_inner = 0

        # Building grid and naming buttons
        for i_block in range(1, 10):
            dynamic_grid_name = f"Block_{i_block}"
            globals()[dynamic_grid_name] = GridLayout(cols=3, rows=3, padding=2)

            for i_cell in range(1, 10):
                dynamic_cells_name = f"Cell_{i_cell}"
                globals()[dynamic_cells_name] = GridLayout(cols=3, rows=3, padding=1)

                for i_inner in range(1, 10):
                    btn = Button(text=str(i_inner))

                    if i_block <= 3:
                        if i_cell <= 3:
                            i_row = 1
                        elif 4 <= i_cell <= 6:
                            i_row = 2
                        elif i_cell >= 7:
                            i_row = 3
                    elif 4 <= i_block <= 6:
                        if i_cell <= 3:
                            i_row = 4
                        elif 4 <= i_cell <= 6:
                            i_row = 5
                        elif i_cell >= 7:
                            i_row = 6
                    elif i_block >= 7:
                        if i_cell <= 3:
                            i_row = 7
                        elif 4 <= i_cell <= 6:
                            i_row = 8
                        elif i_cell >= 7:
                            i_row = 9

                    if i_block == 1 or i_block == 4 or i_block == 7:
                        if i_cell == 1 or i_cell == 4 or i_cell == 7:
                            i_col = 1
                        elif i_cell == 2 or i_cell == 5 or i_cell == 8:
                            i_col = 2
                        elif i_cell == 3 or i_cell == 6 or i_cell == 9:
                            i_col = 3
                    elif i_block == 2 or i_block == 5 or i_block == 8:
                        if i_cell == 1 or i_cell == 4 or i_cell == 7:
                            i_col = 4
                        elif i_cell == 2 or i_cell == 5 or i_cell == 8:
                            i_col = 5
                        elif i_cell == 3 or i_cell == 6 or i_cell == 9:
                            i_col = 6
                    elif i_block == 3 or i_block == 6 or i_block == 9:
                        if i_cell == 1 or i_cell == 4 or i_cell == 7:
                            i_col = 7
                        elif i_cell == 2 or i_cell == 5 or i_cell == 8:
                            i_col = 8
                        elif i_cell == 3 or i_cell == 6 or i_cell == 9:
                            i_col = 9

                    btn.__name__ = [i_block, i_row, i_col, i_cell, i_inner]
                    btn.bind(on_press=self.pressed)
                    globals()[dynamic_cells_name].add_widget(btn)

                globals()[dynamic_grid_name].add_widget(globals()[dynamic_cells_name])

            self.add_widget(globals()[dynamic_grid_name])

    def pressed(self, btn):

        print(btn.__name__)
        if btn.background_color == [0.5, 5, 0.5, 1]:
            btn.background_color = [.1, .1, .1, 1]
        elif btn.background_color == [.1, .1, .1, 1]:
            btn.background_color = [1, 1, 1, 1]
        elif btn.background_color == [1, 1, 1, 1]:
            btn.background_color = [0.5, 5, 0.5, 1][enter image description here][1]


class Example(App):
    def build(self):
        return SudokuLayout()


if __name__ == '__main__':
    x = Example()
    x.run()

I don't know where to begin. I've found a lot of information on doing something once a button is selected, but nothing on how to check all of the buttons by __name__. I would like to loop through each button and compare it's __name__ to the clicked button, and then change it's attribute if it matches. Something like:

#Check row
For x in range(1, 10):
    if button.__name__[*, 1, x, *, 1] == clicked_btn.__name__
        button.background_color = [.1, .1, .1, 1]

Solution

  • There's a lot of code there but I think I get what your looking for. You want to apply a function to each button that does "all button with addresses [3, x, y, z, 1], [*, 1, *, , 1], and [, *, 7, *, 1] to be disabled, or at least grayed-out." I'm not sure what the function coding will be but what you can do is create a list...

    for i_inner in range(1, 10):
        btn = Button(text=str(i_inner))
        self.btn_list.append(btn)
    

    ...then later, instead of check row you could loop through the list of all buttons

    #Check all buttons 
    For button in self.btn_list:
        if button.__name__[*, 1, x, *, 1] == clicked_btn.__name__
            button.background_color = [.1, .1, .1, 1]
    

    Depending on how you want to access btn_list making it a class variable might be more appropriate

    SudokuLayout.btn_list.append(btn)