Search code examples
pythonkivy

Add an event call back to kivy RecycleView


I am trying to create an app using kivy. I am using a RecycleView to dynamically create a bunch of buttons. My problem is that I am not sure how to bind a callback for when a button is pressed, since I am not quite sure how the code is actually making the buttons. Would I need to create a method within my RV class? And if so, how would I use it alongside the kivy language in the string builder? Additionally, how can I get access to the created buttons? Are they stored in the self.data variable? Lastly, are the created buttons widgets or some other type of data?

from kivy.app import App, ObjectProperty 
from kivy.uix.recycleview import RecycleView 
from kivy.lang import Builder

KV = """
<RV>: 
    viewclass: 'Button' # defines the viewtype for the data items. 
    orientation: "vertical"
    spacing: 40
    padding:10, 10
    space_x: self.size[0]/3

RecycleBoxLayout: 
    color:(0, 0.7, 0.4, 0.8) 
    default_size: None, dp(56) 
    default_size_hint: 0.4, None
    size_hint_y: None
    height: self.minimum_height 
    orientation: 'vertical' # defines the orientation of data items
"""
Builder.load_string(KV)

class RV(RecycleView): 
    def __init__(self, **kwargs): 
        super().__init__(**kwargs)
        self.data = [{'text': str(x)} for x in range(100)]

class SampleApp(App): 
    def build(self):
        return RV() 

SampleApp().run() 

Also, I am confused about the difference between a widget and view? Does specifying a viewclass in my tag make a difference?


Solution

  • The callback is a property of the Button. You can use on_press or on_release, but they must be specified in the data. Here is a modified version of your RV class that does it:

    class RV(RecycleView):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.data = [{'text': str(x), 'on_release': partial(self.butt, x)} for x in range(100)]
    
        def butt(self, x):
            print('button', x, 'pressed')
    

    The RecycleView makes a bunch of instances of viewclass (in your case Button), and uses the data to set properties of the Button. So the data can contain any property of a Button as a key, with the desired value as the dictionary value. The RecycleView reuses (recycles) those Button instances and just sets the Button properties from the data. The viewclass can be any Widget class that has the properties that are in the data. So, an instance of a specific Button in your RV could be the one with text 10, but later, that same button might be displayed with a different text (maybe 67). Accessing a specific Button probably does not make sense. If you want to change something about a specific Button, you could change the data for that Button.