'Drawing a an array of rectangles on the screen using kivy language in python file

I'm trying to draw a array of rectangles, which could be dynamically changed (that's something not implemented yet).

The expected behavior is having a orange rectangle all along the top of the screen (for future add some labels), and then the array of rectangles blue and green. But instead the top orange rectangle doesn't show and the array of green and blue displays only in the 100x100 canvas with a weird extension on the edges.

Any advice?

enter image description here

Python file:

from kivy.app import App
from kivy.graphics import Color, Rectangle
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import ListProperty, NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.widget import Widget


class cell(Widget):
    color = ListProperty([1, 1, 1, 1])

    def __init__(self, number, **kwargs):
        super(cell, self).__init__(**kwargs)
        self.number = number
        self.update_color()

    def update_color(self):
        if self.number == 1:
            self.color = (0, 1, 0, 1)
        else:
            self.color = (0, 0, 1, 1)

    def resize(self, pos, size):
        self.pos = pos
        self.size = size


class game_screen(Screen):
    neighbors = [(0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0), (-1, 1)]

    screen_width = NumericProperty(0)
    screen_height = NumericProperty(0)

    def __init__(self, **kwargs):
        super(game_screen, self).__init__(**kwargs)
        self.x_size = 5
        self.y_size = 7
        self.world = self.new_world(self.x_size, self.y_size)
        self.resize(self.world)

    def new_world(self, x, y):
        world = [["" for i in range(y)] for j in range(x)]
        return world

    def resize(self, world):
        self.cell_size = (self.screen_width / self.x_size, self.screen_height / self.y_size)

        main_layout = BoxLayout(size=self.size, orientation='vertical')
        top_info = RelativeLayout(size_hint=(1, None), size=(self.width, dp(50)))
        with self.canvas:
            Color(1, .5, 0, 1)
            self.rect= Rectangle(size=(self.width, self.height), pos=self.pos)
            self.bind(pos=self.update_rect,
                      size=self.update_rect)
        main_layout.add_widget(top_info)
        world_layout = RelativeLayout(size=self.size)
        for i in range(len(world)):
            for j in range(len(world[0])):
                print (f'x:{i}, y:{j}')
                num = i + j
                if num % 2 == 0:
                    numero = 1
                else:
                    numero = 0
                position = (self.cell_size[0] * i, self.cell_size[1] * j)
                celula = cell(numero)
                celula.update_color()
                celula.resize(pos=position, size=self.cell_size)
                world[i][j] = celula
                world_layout.add_widget(celula)
        main_layout.add_widget(world_layout)
        self.add_widget(main_layout)

    def update_rect(self, *args):
        self.rect.pos = (0, self.height-dp(50))
        self.rect.size = (self.width, dp(50))


Builder.load_file("CellWorld.kv")


class GameOfLifeApp(App):
    sm = None
    def build(self):
        self.sm = ScreenManager()
        self.sm.add_widget(game_screen(name="game"))
        return self.sm


GameOfLifeApp().run()

Kivy file, honestly I'm not really sure I need 'screen_width' and 'screen_height'. I was using it for testing solutions I found on other codes while trying to solve this issue.

<game_screen>:
    screen_width: self.width
    screen_height: self.height

<cell>:
    canvas:
        Color:
            rgba: self.color
        Rectangle:
            pos: self.pos
            size: self.size


Solution 1:[1]

The problem is that the size that you set for your Cell widgets is being ignored, because size_hint takes precedence over size. Just add size_hint: None, None to your kv in the <Cell>: rule:

<cell>:
    size_hint: None, None
    canvas:
        Color:
            rgba: self.color
        Rectangle:
            pos: self.pos
            size: self.size

You should also delay calling the resize() method until the game_screen gets its size set. You can use Clock.schedule_once() to accomplish this. First remove self.resize(self.world) from the game_screen __init__() method, Then add the Clock.schedule_once() call to the build() method:

def build(self):
    self.sm = ScreenManager()
    gs = game_screen(name="game")
    self.sm.add_widget(gs)
    Clock.schedule_once(partial(gs.resize, gs.world))
    return self.sm

And modify the signature of resize() to handle the extra arg added by the Clock.schedule_once():

def resize(self, world, *args):

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1