Home > OS >  Problem with buttons inside grid layout inside grid layout
Problem with buttons inside grid layout inside grid layout

Time:08-15

Can you help me fix a problem with buttons? My layout looks like this (pic-1): BoxLayout->GridLayout->GridLayout->Button(x9)

My problem is that I cant change the text of the buttons in other sub-grids. Have a look at my idea of doing that:

Classes:

class SmallGrid(GridLayout):
    buttons = []
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        for i in range(0, 9):
            obj = SudokuButton()
            self.buttons.append(obj)
            self.add_widget(obj)


class BigGrid(GridLayout): 
    small_grids = []
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        for i in range(0, 9):
            obj = SmallGrid()
            self.grids.append(obj)
            self.add_widget(obj)   

Small part of my main class/pseudocode:

big_grid = BigGrid()

for i in range(0, 9):
            for j in range(0, 9):
                self.big_grid.small_grids[i].buttons[j].text = ...

I can get access to other SmallGrid() layous and their buttons but it looks like the SmallGrids() are in the same place, but their buttons are in their destinated place.

FULL code here (if u would like to try your ideas):

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.graphics import Rectangle
from kivy.graphics import Color
from kivy.graphics.vertex_instructions import Line
from kivy.properties import NumericProperty, ObjectProperty, StringProperty
from kivy.metrics import dp
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.config import Config

import random


class KivySudokuApp(App):
    def build(self):
        return Sudoku()


class SmallGrid(GridLayout):
    buttons = []
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        for i in range(0, 9):
            obj = SudokuButton()
            self.buttons.append(obj)
            self.add_widget(obj)


class BigGrid(GridLayout): 
    grids = []
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        for i in range(0, 9):
            obj = SmallGrid()
            self.grids.append(obj)
            self.add_widget(obj)       

class MenuWidget(RelativeLayout):
    pass   
    
        
class Sudoku(BoxLayout):
    original_board = [[0, 0, 0, 0, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 0, 0]]
    
    player_board = [[0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0]]
    
    
    useable_values = numberList=[1, 2, 3, 4, 5, 6, 7, 8, 9]  
    
    seconds_passed = 0
    minutes_passed = 0
    
    last_key = ""
    
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        
        self.orientation = 'vertical'
        
        self.title = Label(text = "KivySudoku",
                           font_size = self.height * 0.5,
                           font_name = "label_font.ttf",
                           color = (0, 0.25, 0.3, 1),
                           bold = True,
                           size_hint = (1, 0.1))
        
        self.timer = Label(font_size = self.height * 0.2,
                           font_name = "label_font.ttf",
                           color = (0, 0.25, 0.3, 1),
                           bold = True,
                           size_hint = (1, 0.05))
        
        self.number = Label(font_size = self.height * 0.2,
                           font_name = "label_font.ttf",
                           color = (0, 0.25, 0.3, 1),
                           bold = True,
                           size_hint = (1, 0.05))
        
        self.menu = MenuWidget()
        self.add_widget(self.menu)
        
        self._keyboard = Window.request_keyboard(self.keyboard_closed, self)
        self._keyboard.bind(on_key_down=self.on_key_down)
        
        Clock.schedule_interval(self.update, 1/60)


    def on_key_down(self, keyboard, keycode, text, modifiers):
        for i in range(1, 10):
            if keycode[1] == str(i):
                self.last_key = str(i)
        return True
    
    
    def keyboard_closed(self):
        self._keyboard.unbind(on_key_down = self.on_key_down)
        self._keyboard = None
    
    
    def original_board_init(self):
        for i in range(0, 81):
            row = int(i/9)
            col = i%9
            if self.original_board[row][col] == 0:
                random.shuffle(self.useable_values)      
                for value in self.useable_values:
                    if self.value_check(row, col, value):
                        self.original_board[row][col] = value
                        if self.is_full(self.original_board):
                            return True
                        else:
                            if self.original_board_init():
                                return True
                break
        self.original_board[row][col] = 0  
        
    
    def player_board_init(self, to_del):
        self.player_board = self.original_board
        
        to_remove = random.sample(range(0, 81), to_del)
        
        for i in to_remove:
            row = int(i/9)
            col = i%9  
            self.player_board[row][col] = ""
        
        for i in range(0, 9):
            for j in range(0, 9):
                self.grid.grids[i].buttons[j].text = str(self.player_board[i][j])
#                if self.grid.grid1.buttons[j].text == "":
#                    self.grid.grid1.buttons[j].disabled = True


    def solve_board(self):
        for i in range(0, 81):
            row = int(i/9)
            col = i%9
            if self.original_board[row][col] == 0:
                for value in range(1,10):
                    if self.value_check(row, col, value):
                        self.original_board[row][col] == value
                        self.solve_board()
                        self.original_board[row][col] = 0
                return False     
            

    def is_full(self, board):
        for row in range(0, 9):
            for col in range(0, 9):
                if board[row][col] == 0:
                    return False
        return True
                    
                    
    def value_check(self, row, col, value):
        R = int(row/3) * 3
        C = int(col/3) * 3
        
        for i in range(0, 9):
            if self.original_board[i][col] == value:
                return False
            for j in range(0, 9):
                if self.original_board[row][j] == value:
                    return False
        for i in range(R, R   3):
            for j in range(C, C   3):
                if value == self.original_board[i][j]:
                    return False
        return True

                
    def update(self, dt):
        self.seconds_passed  = dt
        self.number.text = "Enter number: "   str(self.last_key)
        
#        for i in range(0, 9):
#            for j in range(0, 9):
#                self.grid.big_grid.small_grids[i].buttons[j].last_key = self.last_key
         
        self.update_time()
        
        
    def update_time(self):
        if self.seconds_passed > 60:
            self.seconds_passed -= 60
            self.minutes_passed  = 1
            
        seconds = str(format(int(self.seconds_passed), '02'))
        minutes = str(format(self.minutes_passed, '02'))
        
        self.timer.text = "Time: "   minutes   ":"   seconds
        
        
    def easy_button(self):
        self.switch_menu() 
        self.player_board_init(31)    
        
        
    def medium_button(self):
        self.switch_menu()
        self.player_board_init(51) 
        
        
    def hard_button(self):
        self.switch_menu()
        self.player_board_init(61) 
        
    
    def switch_menu(self):
        self.seconds_passed = 0
        self.minutes_passed = 0
        
        self.original_board_init()
        
        self.remove_widget(self.menu)
        
        self.grid = BigGrid()
        self.grid.pos_hint = {"center_x": 0.5, "center_y:": 0.5}
        
        self.add_widget(self.title)
        self.add_widget(self.timer)
        self.add_widget(self.number)
        self.add_widget(self.grid)
        
              
class SudokuButton(Button):
    last_key = ""
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        
        self.background_normal = ""
        self.background_color = (0.2, 0.2, 0.2)
    
        
    def on_press(self):
        if self.last_key != "":
            self.text = self.last_key
        return super().on_press()


KivySudokuApp().run()

kivysudoku.kv file:

#:kivy 2.1.0

Sudoku:
<Sudoku>:
    canvas.before:
        Color:
            rgba: [0.1, 0.1, 0.1, 1]
        Rectangle:
            pos: self.pos
            size: self.size    

<BigGrid>:
    cols: 3
    size_hint: (None, 0.8)  
    width: self.height  
    spacing: 4  
    padding: 8  
    canvas.before:
        Color:
            rgba: [0, 0.25, 0.3, 1]
        Rectangle:
            pos: self.pos
            size: self.size    

<SmallGrid>:
    cols: 3
    spacing: 1
    canvas.before:
        Color:
            rgba: [0, 0.25, 0.3, 1]  
        Rectangle:
            pos: self.pos
            size: self.size    

<MenuWidget>:
    canvas.before:
        Color:
            rgba: 0.1, 0.1, 0.1
        Rectangle:
            size: self.size
    Label:
        text: "difficuty"
        color: 0, 0.35, 0.4, 1
        font_size: self.height * 0.8
        font_name: "label_font.ttf"
        pos_hint: { "center_x": .5, "center_y": 0.8}
        size_hint: 0.4, 0.15
    Button:
        color: 0, 0.25, 0.3, 1
        background_color: 0.95 ,0.95, 0.95, 0.8
        font_size: self.height * 0.8
        font_name: "label_font.ttf"
        text: "easy"
        pos_hint: { "center_x": .5, "center_y": 0.6}
        size_hint: 0.4, 0.15
        on_press: root.parent.easy_button()
        background_normal: ""
    Button:
        color: 0, 0.25, 0.3, 1
        background_color: 0.95 ,0.95, 0.95, 0.8
        font_size: self.height * 0.8
        font_name: "label_font.ttf"
        text: "medium"
        pos_hint: { "center_x": .5, "center_y": 0.4}
        size_hint: 0.4, 0.15
        on_press: root.parent.medium_button()
        background_normal: ""
    Button:
        color: 0, 0.25, 0.3, 1
        background_color: 0.95 ,0.95, 0.95, 0.8
        font_size: self.height * 0.8
        font_name: "label_font.ttf"
        text: "hard"
        pos_hint: { "center_x": .5, "center_y": 0.2}
        size_hint: 0.4, 0.15
        on_press: root.parent.hard_button()
        background_normal: ""

CodePudding user response:

The problem is that you are using class variables for grids and buttons. You really need them to be instance variables. Just change your definitions slightly to:

class BigGrid(GridLayout):
    # grids = []

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.grids = []

        for i in range(0, 9):
            obj = SmallGrid()
            self.grids.append(obj)
            self.add_widget(obj)

and

class SmallGrid(GridLayout):
    # buttons = []

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.buttons = []

        for i in range(0, 9):
            obj = SudokuButton()
            self.buttons.append(obj)
            self.add_widget(obj)
  • Related