KSully2
KSully2

Reputation: 149

Kivy binding to on_property doesn't seem to work

Essentially, I have a grid with squares, and I keep track of which squares are occupied with a BooleanProperty on each square. Here's a simplified version of all the places in my code I declare the "occupied" property:

class Board(GridLayout):
    def __init__(self):
        super().__init__()
        self.cols = 4
        self.grid = []
        self.create_slots()




    def create_slots(self):
        for i in range(10):
            self.grid.append([])
            for j in range(4):
                temp = Square(i,j, "sideboard")
                self.grid[i].append(temp)
                self.add_widget(temp)
                temp.bind(on_occupied = self.do_a_thing)


    def do_a_thing(self):
        for square in self.children:
            #do a thing

class Square(Button):
    def __init__(self, row, col, type):
        self.row = row
        self.col = col
        self.id = str(self.row) + "," + str(self.col)
        self.type = type
        self.occupied = BooleanProperty(False)
        super().__init__()

My goal is to bind the "do_a_thing" method to be called each time the value of the square's "occupied" property changes. Because the Square class is used elsewhere in my app, I don't want to set the callback for on_occupied in the kivy language, and I was hoping to avoid creating a Square sub-class just to change the one binding.

When I run my code, it throws no errors, and I've verified that the "occupied" property does actually change. But the "do_a_thing" method never gets fired. Can anyone tell me what I'm doing wrong?

Upvotes: 1

Views: 1766

Answers (1)

zeeMonkeez
zeeMonkeez

Reputation: 5157

Note that for a property my_property, the change event is called my_property as well. The callback receives two arguments: instance that fired the event, and new value of the property, as shown in the docs. Also, if the class has a method called on_propertyname, this will be called as well. Here is a self-contained example that works for me:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.properties import BooleanProperty

class Board(GridLayout):
    def __init__(self, **kwargs):
        super(Board, self).__init__(**kwargs)
        for i in range(10):
            self.add_widget(Square())
        for square in self.children:
            print square
            square.bind(occupied=self.do_a_thing)

    def do_a_thing(self, *args):
        print "hello from {}, new state: {}".format(*args)
        for square in self.children:
            pass
            #do a thing

class Square(Button):
     occupied = BooleanProperty(False)
     def on_occupied(self, *args):
         print "Callback defined in class: from {} state {}".format(*args)


class mApp(App):
    def build(self):
        return Builder.load_string("""
Board:
    cols: 4
    rows: 3
<Square>:
    on_press: self.occupied = ~self.occupied
""")
mApp().run()

Upvotes: 3

Related Questions