Search code examples
pythonkivy

How to change kivy label text in .kv dynamically from .py using Screenmanager?


i am very new to kivy and trying to build a multiple screen application, thus i a am using Screenmanager. The user is supposed to start at WelcomeScreen and shall be enabled to search for items on the SearchScreen. So far, so good. Unfortunately, i can not find the right way to access the MDLabels (name: 'searchResult') text property on the SearchScreen. Any ideas?

The Python File:

from kivymd.app import MDApp
from kivymd.uix.screenmanager import MDScreenManager
from kivymd.uix.screen import MDScreen
import requests


class WelcomeScreen(MDScreen):
    pass


class SearchScreen(MDScreen):
    pass


class WindowManager(MDScreenManager):
    pass


class FoodApp(MDApp):

    sm = WindowManager()
    searchCache = []

    def magnify_callback(self):
        self.sm.transition.direction = "down"
        self.sm.current = "searchScreen"

    def search_something(self, text):
        results= []
        for name in self.searchCache:
            if text.lower() in name.lower():
                results.append(name)
        # Plus: Change the text of 'searchResult' MDLabel on SearchScreen, depending on search results.
        # Plus: Instantiate as many Labels as Results exist... (max. 20)



    def fetch_searchindex(self):
        try:
            request = requests.get("https://api.sampleapis.com/beers/ale")
            request = request.json()
            for obj in request:
                self.searchCache.append(obj["name"])

        except:
            pass

    def build(self):

        self.sm.add_widget(WelcomeScreen(name='welcomeScreen'))
        self.sm.add_widget(SearchScreen(name='searchScreen'))
        self.fetch_searchindex()

        return self.sm


if __name__ == '__main__':
    FoodApp().run()

The kivy file:

WindowManager:
    WelcomeScreen:
    SearchScreen:

<WelcomeScreen>:
    name: 'welcomeScreen'

    MDTopAppBar:
        title: 'Welcome!'
        right_action_items: [['magnify', lambda x: app.magnify_callback()]]

<SearchScreen>:
    name: 'searchScreen'

    MDLabel:
        name: 'searchResult'
        text: 'Lorem Ipsum Dolor'
        size_hint: 0.8, None
        pos_hint: {'center_x': 0.5, 'top': 0.8}

    MDTextField:
        name: 'searchText'
        pos_hint: {'center_x': 0.5, 'top': 1}
        size_hint: 0.8, None
        hint_text: 'Search for...'
        icon_left: 'magnify'
        on_text: app.search_something(self.text)

    MDIconButton:
        icon: 'close'
        pos_hint: {'right': 0.99, 'top': 0.99}
        on_release:
            root.manager.transition.direction = 'up'
            root.manager.current = 'welcomeScreen'

I tried to use id instead of name in the .kv File and change the MDLabel.text property via self.sm.get_screen('searchScreen').ids.searchResult.text = 'New text' in .py File, unfortunately i receive this error in any case...

[...]
File "C:\Projectpath\venv\lib\site-packages\kivy\lang\builder.py", line 55, in custom_callback
     exec(__kvlang__.co_value, idmap)
   File "C:\Projectpath\foodapp.kv", line 27, in <module>
     on_text: app.search_something(self.text)
   File "C:\Projectpath\main.py", line 33, in search_something
     self.sm.get_screen('searchScreen').ids.searchResult.text = "Hello"
   File "kivy\properties.pyx", line 964, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'. Did you mean: '__setattr__'?

Solution

  • self.sm.get_screen('searchScreen').ids is a dictionary, as can be read in the documentation.

    And a dictionary doesn't define a __getattr__ (attribute access) or __setattr__ (setting attributes). Dicts in python only supports item access through dictionary['my_key']. So the correct way of accessing the label would be:

    self.sm.get_screen('searchScreen').ids['searchResult'].text = 'New text'
    

    Also note, that the ids dict is usually empty and only gets populated when you use ids, what isn't the case looking at your kv file. (And do not put your id in quotes, as they would affect the key name to be 'searchResult' or "searchResult" instead of just searchResult (without the quotes))