Search code examples
pythonkivyinitializationattributeerrornonetype

AttributeError: 'NoneType' object has no attribute 'ids' in kivy


I tried to write an application with math problems, but something went wrong. When receiving an answer to a task, the program should, depending on the name of the task, verify the entered answer with the correct one and announce the result to the user, but this does not happen.When I enter the answer, I get an AttributError. Most likely I wrote something wrong here

    `def __init__(self, **kwargs):
         super().__init__(**kwargs)
         self.my_screen = Builder.load_string('<ThirdScreen>')
         return self.my_screen` 

but I don't understand what exactly and how to fix it. I will be glad of any help. Thanks!

Here is the whole code:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.textinput import TextInput

Builder.load_string('''

<MainScreen>:
    BoxLayout:
        orientation: 'vertical'
        padding: 90
        spacing: 40
    
        Label:
            text: 'Application name'
            font_size: 30
            
        Button:
            size_hint: 1, 0.4
            text: 'Mathematical problems'
            on_release:
                root.manager.current = 'Second'
            
<SecondScreen>:
    BoxLayout:
        orientation: 'vertical'
        spacing: 20
        
        Button:
            size_hint: 0.2, 0.1
            pos_hint:{'x': 0.01, 'top': 0.1}
            text: '<Back'
            on_release:
                root.manager.current = 'Main'
        Label:
            size_hint: 1, 0.2
            text: 'Mathematical problems'
            font_size: 22
            
        GridLayout:
            rows: 2
            padding: 40
            Button:
                text: '1'
                on_release:
                    root.manager.screens[2].ids.my_name.text = '- exercise 1 -'
                    root.manager.screens[2].ids.my_label.text = root.tasks[1]
                    root.manager.current = 'Third'
            Button:
                text: '2'
                on_release:
                    root.manager.screens[2].ids.my_name.text = '- exercise 2 -'
                    root.manager.screens[2].ids.my_label.text = root.tasks[2]
                    root.manager.current = 'Third'
            Button:
                text: '3'
                on_release:
                    root.manager.screens[2].ids.my_name.text = '- exercise 3 -'
                    root.manager.screens[2].ids.my_label.text = root.tasks[3]
                    root.manager.current = 'Third'
            
            Button:
                text: '4'
                on_release:
                    root.manager.screens[2].ids.my_name.text = '- exercise 4 -'
                    root.manager.screens[2].ids.my_label.text = root.tasks[4]
                    root.manager.current = 'Third'

<ThirdScreen>:
    BoxLayout:
        orientation: 'vertical'
        
        Button:
            size_hint: 0.2 , 0.1
            pos_hint: {'x': 0.01, 'top': 0.1}
            text: '<Back'
            on_release:
                root.manager.current = 'Second'
        Label:
            id: my_name
            size_hint: 1, 0.2
            text: 'name'
            font_size: 20
            
        Label:
            text_size: self.width - 200, None
            id: my_label
            text: ''
        
        TextInput:
            id: my_text
            size_hint: 0.8, 0.1
            pos_hint: {'x': 0.1, 'y': 0.2}
            multiline: False
            on_text:
                root.answer(self.text)
<FourScreen>:
    BoxLayout:
        Button:
            id: _n
            text: 'Верно!'
            on_release:
                root.manager.current = 'Second' 

''')

class MainScreen(Screen):
    pass

class SecondScreen(Screen):             
    tasks = {1 : '(((120 ÷ 2) ÷ (1÷5)) ÷ (1÷4)) ÷ (1÷3) = ? ', 2 : '0', 3: '0', 4: '0'} 

class ThirdScreen(Screen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.my_screen = Builder.load_string('<ThirdScreen>')
        return self.my_screen
    
    def answer(self, text):
        n = [ '- exercise 1 -', '- exercise 2 -', '- exercise 3 -', '- exercise 4 -']
        answers = {1 : '1', 2 : '0', 3 : '0', 4 : '0'}
        if text == answers[n.index(self.my_screen.ids.my_name) + 1]:
            self.manager.current = 'Four'

class FourScreen(Screen):
    pass

class MainApp(App):
    def build(self):
        sm = ScreenManager()
        sm.add_widget(MainScreen(name = 'Main'))
        sm.add_widget(SecondScreen(name = 'Second'))
        sm.add_widget(ThirdScreen(name = 'Third'))
        sm.add_widget(FourScreen(name = 'Four'))
        return sm
    
if __name__ == '__main__':
    MainApp().run()
    ```

Solution

  • You are accessing the ids incorrectly. Since you are accessing the ids from within the class that contains the ids, you can simply use self.ids. And your __init__() in the ThirdScreen is not needed. Try this modified version of ThirdScreen:

    class ThirdScreen(Screen):
        # def __init__(self, **kwargs):
        #     super().__init__(**kwargs)
        #     self.my_screen = Builder.load_string('<ThirdScreen>')
        #     return self.my_screen
    
        def answer(self, text):
            n = ['- exercise 1 -', '- exercise 2 -', '- exercise 3 -', '- exercise 4 -']
            answers = {1: '1', 2: '0', 3: '0', 4: '0'}
            if text == answers[n.index(self.ids.my_name.text) + 1]:
                self.manager.current = 'Four'