pythonkivykivy-languagekivymd

Kivy ScreenManager's current property not finding Screens with said name property


I'd like the App to change screen from the EntryWindow screen to the Home screen, after like one second. Since I had already problems with the ScreenManager current property to actually switch screens, I didn't try to even use Clock to trigger the switch after one second of EntryWindow. Could someone help me with this? I have python version 3.12, kivy version 2.3.0 and kivymd version 1.2.0. This is my .py file:

from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.metrics import dp
from kivy.core.window import Window
from kivy.clock import Clock
import random as rd

Window.size = (360,640)

class MainApp(MDApp):
    
    def build(self):
        screen = Builder.load_file("myKv.kv")
        self.theme_cls.primary_palette ="Orange"
        self.theme_cls.primary_hue = "A700"
        self.theme_cls.theme_style="Dark"
        return screen
    
class EntryWindow(Screen):
    def on_enter(self):
        sm.current = "home"       


class Home(Screen):
    pass
class Exercises(Screen):
    pass     

class Gender(Screen):
    
    def on_enter(self):
        self.ids.extractedWord.color = (1,1,1,1)
        f = open(".venv/genderWordDatabase.txt")
        red = f.readlines()
        stripped = [elem.strip() for elem in red]
        separato = [elem.split() for elem in stripped]
        dizWords = {}
        for i in separato:
            dizWords[i[1]] = (i[0],i[2])
        print(dizWords)
        extracted = list(dizWords.keys())[rd.randint(0,len(dizWords)-1)]
        self.ids.extractedWord.font_style = "H6"
        self.ids.extractedWord.text = extracted
    
    def recordUpdate(self,extractedWord,operand):
        f = open(".venv/genderWordDatabase.txt", "r")
        red = f.readlines()
        f.close()
        for i in range(0,len(red)):
            if extractedWord in red[i]:
                red[i] = " ".join(red[i].strip("\n").split()[:-1]) + " " + str(int(red[i].strip("\n").split()[2])+operand)+"\n"
        g = open(".venv/genderWordDatabase.txt", "w")
        g.writelines(red)
        
    def wordExtraction(self):
        self.ids.extractedWord.color = (1,1,1,1)
        f = open(".venv/genderWordDatabase.txt")
        red = f.readlines()
        f.close()
        stripped = [elem.strip() for elem in red]
        separato = [elem.split() for elem in stripped]
        dizWords = {}
        for i in separato:
            dizWords[i[1]] = (i[0],i[2])
        extracted = list(dizWords.keys())[rd.randint(0,len(dizWords)-1)]
        self.ids.extractedWord.font_style = "H6"
        self.ids.extractedWord.text = extracted
    
    def check(self, answer):
        f = open(".venv/genderWordDatabase.txt")
        red = f.readlines()
        f.close()
        stripped = [elem.strip("\n").strip() for elem in red]
        separato = [elem.split() for elem in stripped]
        dizWords = {}
        for i in separato:
            dizWords[i[1]] = (i[0],i[2])
        print(dizWords)
        parola  = self.ids.extractedWord.text
        if dizWords[parola][0] == answer:
            self.ids.extractedWord.color = (0,1,0,1)
            self.ids.extractedWord.font_style = "H6"
            self.ids.extractedWord.text = "Right +1"
            #Chiamo la funzione che aggiorna il record di ciascuna parola
            self.recordUpdate(dizWords[parola][0],1)
            Clock.schedule_once(lambda dt: self.wordExtraction(), 1)
        else:
            self.ids.extractedWord.color = (1,0,0,1)
            self.ids.extractedWord.font_style = "Body1"
            self.ids.extractedWord.text = "Wrong -1, the correct one was: " + dizWords[self.ids.extractedWord.text][0]
            self.recordUpdate(dizWords[parola][0],-1)
            Clock.schedule_once(lambda dt: self.wordExtraction(), 2)

sm =  ScreenManager()
sm.add_widget(EntryWindow(name="starting"))
sm.add_widget(Home(name="home"))
sm.add_widget(Exercises(name="exercises"))
sm.add_widget(Gender(name="gender"))

MainApp().run()

and this is my .kv file:

ScreenManager:
    EntryWindow:
    Home:
    Exercises:
    
<EntryWindow>:
    name: "starting"
    BoxLayout: 
        orientation: "vertical"
        Widget:
        MDLabel:
            text: "German"
            halign: "center"
            markup: True
            color: (1,1,1,1)
            font_style: "H3"
        MDLabel:
            text: "By Staffo"
            markup: True
            color: (1,1,1,1)
            halign: "center"
            font_style: "H6"
        Widget:
        Widget:
<Home>:
    name: "home"
    AnchorLayout:
        anchor_x: "center"
        anchor_y: "center"
        BoxLayout: 
            orientation: "vertical"
            spacing: 30
            Widget:
            MDFillRoundFlatButton:
                text: "exercises"
                pos_hint: {"center_x":0.5,"center_y":0.5}
                on_press:root.manager.current = "exercises"
            MDFillRoundFlatButton:
                text: "customize dictionary"
                pos_hint: {"center_x":0.5,"center_y":0.5}
                #on_press:root.manager.current = "customize"
            MDFillRoundFlatButton:
                text: "Settings"
                pos_hint: {"center_x":0.5,"center_y":0.5}
                #on_press:root.manager.current = "settings"
            MDFillRoundFlatButton:
                text: "Credits"
                pos_hint: {"center_x":0.5,"center_y":0.5}
                #on_press: root.manager.current = "credits"
            Widget:
<Exercises>:
    name: "exercises"
    AnchorLayout:
        anchor_x: "center"
        anchor_y: "center"
        BoxLayout: 
            orientation: "vertical"
            spacing: 30
            Widget:
            MDFillRoundFlatButton:
                text: "[b]M/F/N/P[/b]"
                markup: True
                pos_hint: {"center_x":0.5,"center_y":0.5}
                on_press:root.manager.current = "gender"
                text_color: (1,1,1,1)
                
            MDFillRoundFlatButton:
                text: "[b]Learn New Words[/b]"
                markup: True
                text_color: (1,1,1,1)
                pos_hint: {"center_x":0.5,"center_y":0.5}
                #on_press:root.manager.current = ""
            MDFillRoundFlatButton:
                text: "[b]Phrases[/b]"
                markup: True
                text_color: (1,1,1,1)
                pos_hint: {"center_x":0.5,"center_y":0.5}
                #on_press:root.manager.current = ""
            MDFillRoundFlatButton: 
                text: "[b]Listening[/b]"
                markup: True
                text_color: (1,1,1,1)
                pos_hint: {"center_x":0.5,"center_y":0.5}
                #on_press: root.manager.current = ""
            Widget:
<Gender>:
    name: "gender"
    AnchorLayout:
        anchor_x: "center"
        anchor_y: "center"
        BoxLayout:
            orientation: "vertical"
            Widget:
            Widget:
            Widget:
            MDCard:
                size_hint: .85, 2 
                pos_hint: {"center_x": .5, "center_y": .5}
                MDRelativeLayout:
                    MDLabel:
                        halign: "center"
                        id: extractedWord
                        markup: True
                        text: "extractedWord"
                        font_style: "H6"
                        color: (0,0,0,1)
            BoxLayout:
                spacing: 20
                Widget:
                MDFillRoundFlatButton:  
                    text: "[b]der[/b]"
                    markup: True
                    text_color: (1,1,1,1)
                    on_press: root.check("der")
                MDFillRoundFlatButton:  
                    text: "[b]die[/b]"
                    markup: True
                    text_color: (1,1,1,1)
                    on_press: root.check("die")
                MDFillRoundFlatButton:  
                    text: "[b]das[/b]"
                    markup: True
                    text_color: (1,1,1,1)
                    on_press: root.check("das") 
                Widget:
            Widget:
            Widget:
            Widget:
            Widget:

and I get the following error:

kivy.uix.screenmanager.ScreenManagerException: No Screen with name "home".

Solution

  • The problem is with your on_enter() method of EntryWindow. Because your kv creates an EntryWindow as the first Screen, and its on_enter() method is triggered before the other Screens are even created. A simple fix is to delay the screen change a bit using Clock.schedule_once(), like this:

    class EntryWindow(Screen):
        def on_enter(self):
            # delay the Screen switch
            Clock.schedule_once(self.switch_screen)
    
        def switch_screen(self, _dt):
            self.manager.current = "home"
    

    As you see, in the switch_screen() method, I changed sm to self.manager. The sm that you have defined in your code is unused and should be eliminated:

    # sm = ScreenManager()
    # sm.add_widget(EntryWindow(name="starting"))
    # sm.add_widget(Home(name="home"))
    # sm.add_widget(Exercises(name="exercises"))
    # sm.add_widget(Gender(name="gender"))