python-3.xdictionarykivykivy-recycleview

Python3 - Kivy RecycleView's data Dictionary succefully updated, but not phisically the Widget


In a Kivy form i set 2 Recycleviews(A and B). I would add the item clicked in Recycleview A, to the RecycleView B, using a Python3 script:

from functools import partial
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.recycleview import RecycleView
class B(RecycleView):
    def __init__(self,**kwargs):
        super(B, self).__init__(**kwargs)
    def doet(self,x):
        self.data.append({'text':x})
        print(self.data) #it prints correctly, so why doesn't update?
class A(RecycleView):
    def __init__(self,**kwargs):
        super(A, self).__init__(**kwargs)
        self.data=[{'text':'FROM HERE','on_press':partial(app.b.doet,'TO HERE')}]
class app(App):
    b=B()
    def build(self):
        return Builder.load_file('lab.kv')
app().run()

'lab.kv':

BoxLayout:
    A:
        viewclass:'Button'
        RecycleBoxLayout:
            default_size: None, dp(56)
            default_size_hint: 1, None
            size_hint_y: None
            height: self.minimum_height
            orientation: 'vertical'
    B:
        viewclass:'Button'
        RecycleBoxLayout:
            default_size: None, dp(56)
            default_size_hint: 1, None
            size_hint_y: None
            height: self.minimum_height
            orientation: 'vertical'

My script correctly updates the Data's Dictionary, as I can see by printing it, but in RecycleView 'B' no items are phisically added.


Solution

  • The main problem with your code is that the line:

    b=B()
    

    is creating a new instance of B that is unrelated to the instance of B that is created in your kv. So anything done to that new instance of B will have no effect on what you see on the screen.

    There are many possible approaches to do what you want. Here is one:

    First, add an id to the B in your kv:

    B:
        id: b
    

    Then, add a modify the App class:

    class app(App):
        def build(self):
            root = Builder.load_file('lab.kv')
            self.b = root.ids.b
            return root
    
        def doit(self, x):
            self.b.doet(x)
    

    The above build() method uses the new id to get a reference to the correct B instance, and saves that reference. The doit() method is just an intermediary to direct the call to the correct instance of B.

    Then modify the A class to use this:

    class A(RecycleView):
        def __init__(self,**kwargs):
            super(A, self).__init__(**kwargs)
            self.data=[{'text':'FROM HERE','on_press':partial(App.get_running_app().doit,'TO HERE')}]