Search code examples
pythondynamickivy

Assigning functions to dynamically created buttons in kivy?


I am working on this program in which a list buttons gets created dynamically, based on the items in a list. The code I am using for this is:

self.list_of_btns = []

    def create(self, list=items):                                               #Creates Categorie Buttons
        self.h = 1
        for i in list:
            self.h = self.h - 0.2
            self.btn = Button(text= f"{i}", size_hint=(.2,.22), pos_hint={"center_y":self.h, "center_x":.5}) 
            self.list_of_btns.append(self.btn)   
            self.add_widget(self.btn)
```
Now I want to add a function to each button. The function is suppose to write the button name (i) to a .txt file. This part of the code gets handled in an external module. 

The problem I am having rn is i cant bind the buttons to their individual functions. I alwasy get the error File "kivy/_event.pyx", line 238, in kivy._event.EventDispatcher.__init__
 TypeError: Properties ['command'] passed to __init__ may not be existing property names. Valid properties are ['always_release', 'anchors', 'background_color', 'background_disabled_down', 'background_disabled_normal', 'background_down', 'background_normal', 'base_direction', 'bold', 'border', 'center', 'center_x', 'center_y', 'children', 'cls', 'color', 'disabled', 'disabled_color', 'disabled_image', 'disabled_outline_color', 'ellipsis_options', 'font_blended', 'font_context', 'font_family', 'font_features', 'font_hinting', 'font_kerning', 'font_name', 'font_size', 'halign', 'height', 'ids', 'is_shortened', 'italic', 'last_touch', 'line_height', 'markup', 'max_lines', 'min_state_time', 'mipmap', 'motion_filter', 'opacity', 'outline_color', 'outline_width', 'padding', 'padding_x', 'padding_y', 'parent', 'pos', 'pos_hint', 'refs', 'right', 'shorten', 'shorten_from', 'size', 'size_hint', 'size_hint_max', 'size_hint_max_x', 'size_hint_max_y', 'size_hint_min', 'size_hint_min_x', 'size_hint_min_y', 'size_hint_x', 'size_hint_y', 'split_str', 'state', 'state_image', 'strikethrough', 'strip', 'text', 'text_language', 'text_size', 'texture', 'texture_size', 'top', 'underline', 'unicode_errors', 'valign', 'width', 'x', 'y']

Solution

  • .bind() method can be used. In this example, partial is used in order to preset an argument so that each button does something unique. self.btn was changed to _btn because the references are being added to a list and self.btn was repeatedly assigned a new object. I didn't think this was intended, but it is not a critical part of this answer.

    The self.h was changed to self.height in the dictionary describing the button because I think that may be the source of the error printed in the question.

    from functools import partial
    
    
    self.list_of_btns = []
    # EDITED after original posting
    def your_function(self, _button, your_argument, *args, **kwargs):
        print(type(self))
        print(type(_button))
        print(args)
        print(kwargs)
        print(your_argument)
    
    def create(self, list=items):                                               #Creates Categorie Buttons
        self.h = 1
        for i in list:
            self.h = self.h - 0.2
            _btn = Button(text= f"{i}", size_hint=(.2,.22), pos_hint={"center_y":self.height, "center_x":.5})
            myfun = partial(self.your_function, your_argument=i)
            # this should be a function, not function()
            _btn.bind(on_press=myfun)
            self.list_of_btns.append(_btn)
            self.add_widget(_btn)