Search code examples
pythonkivy

Get variable from one Screen Class into another (KivyMD issue)


I'm building a KivyMD application, but I'm having some issues to get a variable defined in one Screen class into another. See my script below:

from kivymd.app import MDApp, Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import StringProperty
from api import gen_5_images

# --- this changes the app's default background --- #
Window.clearcolor = (.9, .9, .9, 1)
Window.size = (400, 500)

class HomeScreen(Screen):
    source = StringProperty()
    def __init__(self, **kwargs): 
        super(HomeScreen, self).__init__(**kwargs)
        self.text = 'dog'

    def get_text(self):
        self.text = self.ids.input.text
        return self.text

class ResultsScreen(HomeScreen):
    source = StringProperty()
    def on_manager(self, *args):
        # gets run when manager property is changed
        self.urls = gen_5_images(self.manager.get_screen('home').text)
        self.source = self.urls[0]
        
class Main(MDApp):
    def build(self):
        Builder.load_file("layout.kv")
        sm = ScreenManager()
        sm.add_widget(HomeScreen(name='home'))
        sm.add_widget(ResultsScreen(name='results'))
        return sm

Main().run()

When I switch from HomeScreen to ResultsScreen, I get the variable "dog" (defined in HomeScreen's init) as text, and I want the output of the "get_text" function instead.

See below my .kv file:

#:import hex kivy.utils.get_color_from_hex
<HomeScreen>:
    name: 'home'
    MDFloatLayout:
        md_bg_color: hex('#003153') # background color
        MDLabel:
            text: "DreamGen"
            color: hex('#f5deb3')
            halign: "center"
            pos_hint: {"center_x": .5, "center_y": .9}
            font_size: "40sp"
            font_name: "Pacifico"
        MDTextField:
            id: input
            hint_text: "I had a dream..."
            hint_text_color_normal: hex("#00aae4")
            hint_text_color_focus: hex("#00aae4")
            helper_text_color_focus: hex("#00aae4")
            line_color_normal: hex('#003153') #make line color of background
            line_color_focus: hex('#003153') #make line color of background
            helper_text: "Write what comes to your mind"
            helper_text_mode: "on_focus"
            text_color_focus: hex('#add8e6') # color of text clicked
            text_color_normal: hex('#add8e6') # color of text without clicked
            mode: "rectangle"
            multiline: True
            size_hint_x: 0.7
            size_hint_y: 0.5
            pos_hint: {"center_x": .5, "center_y": .5}
        MDFillRoundFlatButton:
            text: "Generate"
            text_color: hex('#003153')
            md_bg_color: hex('#add8e6')
            pos_hint: {"center_x": .5, "center_y": .1}
            font_size: "15sp"
            on_release: 
                root.get_text()
                root.manager.current = "results"

<ResultsScreen>:
    name: 'results'
    MDFloatLayout:
        md_bg_color: hex('#003153') # background color
        MDLabel:
            text: "DreamGen"
            color: hex('#f5deb3')
            halign: "center"
            pos_hint: {"center_x": .5, "center_y": .9}
            font_size: "40sp"
            font_name: "Pacifico"
        AsyncImage:
            size_hint: None,None
            size: root.height, root.height
            source: root.source
            mipmap: True
        MDFillRoundFlatButton:
            text: "Try again!"
            text_color: hex('#003153')
            md_bg_color: hex('#add8e6')
            pos_hint: {"center_x": .5, "center_y": .1}
            font_size: "15sp"
            on_release: root.manager.current = "home"

If someone can help me, I would very much appreciate.


Solution

  • Your code:

    self.urls = gen_5_images(HomeScreen().text)
    

    is creating a new instance of HomeScreen and accessing the text variable of that new instance. That new instance of HomeScreen is not the instance that is used in your GUI. To access the correct instance of HomeScreen, try changing that code to:

    self.urls = gen_5_images(self.manager.get_screen('home').text)
    

    Oops, that code will work, but not in the __init__() method, since the manager property is not yet set at that time. You can handle that by waiting until the manager property is set. Try replacing:

    class ResultsScreen(HomeScreen):
        source = StringProperty()
        def __init__(self, **kwargs):
            super().__init__()
            self.urls = gen_5_images(HomeScreen().text)
            self.source = self.urls[0]
    

    with:

    class ResultsScreen(HomeScreen):
        source = StringProperty()
    
        # def __init__(self, **kwargs):
        #     super().__init__()
        #     # self.urls = gen_5_images(HomeScreen().text)
        #     # self.source = self.urls[0]
    
        def on_enter(self, *args):
            # gets run each time this Screen is displayed
            self.urls = gen_5_images(self.manager.get_screen('home').text)
            self.source = self.urls[0]