Search code examples
pythonpython-3.xuser-interfacekivykivy-language

My Kivy program has a random white square showing up in the bottom left corner


White Box Error Kivy

I am trying to create a program that outputs random 10x10 grids of black and white squares. It mostly works except that the bottom left corner has an unwanted white square covering up part of the grid.

I can't even figure out what widget would be causing this. I've tried printing all of the children starting at root to no avail.

import random
import kivy
kivy.require("1.10.1")
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.config import Config
from kivy.graphics import Color
from kivy.graphics import Rectangle


Config.set('graphics', 'width', '400')
Config.set('graphics', 'height', '400')

class Container(FloatLayout):
    pass

class ColorLabel(Label):
    def __init__(self, **kwargs):
        super(ColorLabel, self).__init__(**kwargs)

        with self.canvas:
            Color(1, 1, 1, 1)
            self.rect = Rectangle(size=self.size, pos=self.pos)

        self.bind(size=self._update_rect, pos=self._update_rect)

    def _update_rect(self, instance, value):
        self.rect.pos = instance.pos
        self.rect.size = instance.size

    def changeBG(self):
        with self.canvas.after:
            Color(0,0,0,1)
            self.rect = Rectangle(size=self.size, pos=self.pos)

class Main(App):
    def build(self):
        Builder.load_file("EveryImage.kv")
        the_grid = GridLayout(cols=10, spacing=1)

        i = 100
        while i > 0:
            i -= 1
            newLabel = ColorLabel()
            the_grid.add_widget(newLabel)
            x = random.randint(0,1)
            if x == 0:
                newLabel.changeBG()

        root = Container()
        root.add_widget(the_grid)           
        return root

# Keep everything below this last!      
if __name__ == '__main__':
    Main().run()

And here is the .kv file:

#EveryImage.kv
Container:

#Container holds all the other layouts
<Container>:
    id: contain
    canvas.before:
        Color:
            rgba: 0,0,0.5,1 #blue, just for the grid
        Rectangle:
            pos: self.pos
            size: self.size

<ColorLabel>:
    canvas.before:
        Color:
            rgba: 1,1,1,1 #white
        Rectangle:
            pos: self.pos
            size: self.size

Solution

  • The problem is that you are painting several times in different places, precisely in the function changeBG, instead you just have to paint in one place and set the background color as property so when this value is changed the Label will be repainted.

    Another error is that you are creating a Container that you do not use in the .kv.

    In the case of the while loop this can be simplified using a for loop.

    *.py

    import random
    
    import kivy
    kivy.require("1.10.1")
    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.gridlayout import GridLayout
    from kivy.uix.label import Label
    from kivy.config import Config
    
    Config.set('graphics', 'width', '400')
    Config.set('graphics', 'height', '400')
    
    class Container(FloatLayout):
        pass
    
    class ColorLabel(Label):
        pass
    
    class Main(App):
        def build(self):
            Builder.load_file("EveryImage.kv")
            the_grid = GridLayout(cols=10, spacing=1)
            for _ in range(100):
                newLabel = ColorLabel()
                the_grid.add_widget(newLabel)
                if random.choice([True, False]):
                    newLabel.bg_color = [0,0,0,1]
            root = Container()
            root.add_widget(the_grid)           
            return root
    
    # Keep everything below this last!      
    if __name__ == '__main__':
        Main().run()
    

    *.kv

    #Container holds all the other layouts
    <Container>:
        id: contain
        canvas.before:
            Color:
                rgba: 0,0,0.5,1 #blue, just for the grid
            Rectangle:
                pos: self.pos
                size: self.size
    
    <ColorLabel>:
        bg_color: 1, 1, 1, 1
        canvas.before:
            Color:
                rgba: self.bg_color # white
            Rectangle:
                pos: self.pos
                size: self.size
    

    enter image description here