Kivy Python edit Label text from another class

Question:

I have two screens.
The first screen has a "Play" button that sends me to the "PlayScreen".
The second screen has a Label and two buttons;
Button "NewRandom": loads a random number from SomeApp.RandomGen(),
Button "Clear": Clears

What I would like to happen is that initiate_random_number() executes as soon as the buttons are created.

However, App.get_running_app().root.ids.play_screen.random_num.text is None because I’m guessing some ids dictionary under the hood is still not built?

Is there anyway I can access the Label from this RandomNumber class?

thanks.

Python app:

from kivy.app import App

from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty

import numpy as np


class MainWindow(Screen):
    def __init__(self, **kwargs):
        super(MainWindow, self).__init__(**kwargs)

class PlayScreen(Screen):
    def __init__(self, *args, **kwargs):
        super(PlayScreen, self).__init__(*args, **kwargs)

class WindowManager(ScreenManager):
    def __init__(self, **kwargs):
        super(WindowManager, self).__init__(**kwargs)
        main_window = ObjectProperty(None)
        play_screen = ObjectProperty(None)        

class RandomNumber(GridLayout):

    def __init__(self, *args, **kwargs):
        super(RandomNumber, self).__init__(*args, **kwargs)
        self.cols = 2

        self.add_widget(Button(text='NewRandom', on_release=self.on_release))
        self.add_widget(Button(text='Clear', on_release=self.on_release))

    def initiate_random_number(self):
        random_num = str(SampleApp.RandomGen())
        App.get_running_app().root.ids.play_screen.random_label.text = random_num 

    def on_release(self, btn):
        if btn.text == 'NewRandom':
           random_num = str(SampleApp.RandomGen())
           App.get_running_app().root.ids.play_screen.random_label.text = random_num 
        else:
           App.get_running_app().root.ids.play_screen.random_label.text = ''

#kv = Builder.load_file('sample.kv')

class SampleApp(App):
    def __init__(self, **kwargs):
        super(SampleApp, self).__init__(**kwargs)

    def build(self):
        sm = WindowManager()
        return sm

    def RandomGen(self):
        return np.random.randint(100)

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

kv:

<WindowManager>:
    id: window_manager
    main_window: main_window
    play_screen: play_screen
    
    MainWindow:
        id: main_window
        name: "main_window"
        manager: window_manager      
    PlayScreen:
        id: play_screen
        name: "play_screen"
        manager: window_manager    

<MainWindow>:
    BoxLayout:
        orientation: "vertical"
        Button:
            text: "Play"
            on_release: 
                app.root.current = "play_screen"
                root.manager.transition.direction = "left"

<PlayScreen>:
    random_label: random_label
    BoxLayout:
        orientation: "vertical"
        Label:
            id: random_label
            #text: #TODO: show the output of initiate_random_number or Button
        RandomNumber:
        Button:
            text: "Back!"
            on_release: 
                app.root.current = "main"
                root.manager.transition.direction = "right"

the solution should give me a way to call the random_label via python and not just Kivy.

Asked By: RealRageDontQuit

||

Answers:

If you want initiate_random_number() to run before the PlayScreen Buttons are displayed (although your code only has one Button), you can define an on_enter() method in the PlayScreen class:

def on_enter(self, *args):
    RandomNumber.initiate_random_number()

However, this requires a couple other changes. Some methods need to redefined as static and the access to the random_label must be corrected:

@staticmethod
def initiate_random_number():
    random_num = str(SomeApp.RandomGen())
    App.get_running_app().root.get_screen('play_screen').ids.random_label.text = random_num

Another method in the App that needs to be static:

@staticmethod
def RandomGen():
    return np.random.randint(100)
Answered By: John Anderson

Formalising @John Anderson solution above:

Python:

from kivy.app import App

from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty

import numpy as np


class MainWindow(Screen):
    def __init__(self, **kwargs):
        super(MainWindow, self).__init__(**kwargs)

class PlayScreen(Screen):
    def __init__(self, *args, **kwargs):
        super(PlayScreen, self).__init__(*args, **kwargs)
        
    def on_enter(self, *args):
        RandomNumber.initiate_random_number()

class WindowManager(ScreenManager):
    def __init__(self, **kwargs):
        super(WindowManager, self).__init__(**kwargs)
        # main_window = ObjectProperty(None)
        # play_screen = ObjectProperty(None)        

class RandomNumber(GridLayout):

    def __init__(self, *args, **kwargs):
        super(RandomNumber, self).__init__(*args, **kwargs)
        self.cols = 2

        self.add_widget(Button(text='NewRandom', on_release=self.on_release))
        self.add_widget(Button(text='Clear', on_release=self.on_release))
        
    @staticmethod
    def initiate_random_number():
        random_num = str(SampleApp.RandomGen())
        App.get_running_app().root.ids.play_screen.random_label.text = random_num 

    def on_release(self, btn):
        if btn.text == 'NewRandom':
           random_num = str(SampleApp.RandomGen())
           App.get_running_app().root.ids.play_screen.random_label.text = random_num 
        else:
           App.get_running_app().root.ids.play_screen.random_label.text = ''

#kv = Builder.load_file('sample.kv')

class SampleApp(App):
    def __init__(self, **kwargs):
        super(SampleApp, self).__init__(**kwargs)

    def build(self):
        sm = WindowManager()
        return sm
    
    @staticmethod
    def RandomGen():
        return np.random.randint(100)

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

kv:

<WindowManager>:
    id: window_manager
    main_window: main_window
    play_screen: play_screen
    
    MainWindow:
        id: main_window
        name: "main_window"
        manager: window_manager      
    PlayScreen:
        id: play_screen
        name: "play_screen"
        manager: window_manager    

<MainWindow>:
    BoxLayout:
        orientation: "vertical"
        Button:
            text: "Play"
            on_release: 
                app.root.current = "play_screen"
                root.manager.transition.direction = "left"

<PlayScreen>:
    random_label: random_label
    BoxLayout:
        orientation: "vertical"
        Label:
            id: random_label
            #text: #TODO: show the output of initiate_random_number or Button
        RandomNumber:
        Button:
            text: "Back!"
            on_release: 
                app.root.current = "main_window"
                root.manager.transition.direction = "right"
Answered By: RealRageDontQuit
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.