Why does Python fail at finding my Kivy id?

Question:

I am trying to dynamically create OneLineListItems on my main Screen, but the id is not recognized. I tried a lot, but I’m not coming to a solution.

main.py :

class CustomDialogContent(MDGridLayout):
    pass

class Content(BoxLayout):
    manager = ObjectProperty()
    nav_drw = ObjectProperty()
    pass

class Demo(ScreenManager):
    pass


class Main(MDApp):

    def build(self):
        return Demo()

    def show_dialog(self):
        close_button = MDFlatButton(text='Close', pos_hint={'x': 0, 'y': -.3}, on_release=self.close_dialog)
        ok_button = MDFlatButton(text='OK', pos_hint={'x': 0, 'y': -.3}, on_release=self.ok_dialog)
        self.dialog = MDDialog(
            title="Dialog Title",
            size_hint=(0.8, 0.3),
            type="custom",
            content_cls=CustomDialogContent(),
            buttons=[ok_button, close_button],
            auto_dismiss= False

                          )
        self.dialog.open()

Here is my main including my classes, so far this part runs well, I have included a Navigationdrawer and a Dialog Box that opens upon Button press.

def post_text(self, text1, text2, *args):
    print(text1)
    print(text2)

    if text1:
        screen = self.root.ids.screen_manager.get_screen("First")
        screen.ids.list_view.add_widget(OneLineListItem(text=text1))
        screen.ids.list_view.add_widget(OneLineListItem(text=text2))

        #self.ids.list_view.add_widget(OneLineListItem(text=text1))
        #self.ids.list_view.add_widget(OneLineListItem(text=text1))

This is where my issue lies specifically, I don’t understand why id list_view is not being recognized when it should be stored in the self.ids dictionary. Doing the latter which is commented out doesn’t work either.

Here is the rest of my code, which is as well in my Main class

def ok_dialog(self, *args):

    text_field_1 = self.dialog.content_cls.ids.text_field_1
    text_field_2 = self.dialog.content_cls.ids.text_field_2
    self.post_text(text_field_1.text, text_field_2.text)
    self.close_dialog()

def close_dialog(self, *args):
    self.dialog.dismiss()



Main().run()

This also works fine, here I call my post_text function and it passes the input text like it should.

main.kv:

#: import NoTransition kivy.uix.screenmanager.NoTransition
<CustomDialogContent>
    #cols: 1
    rows: 2
    spacing: '12dp'
    padding: '12dp'
    size_hint_y: None
    height: '120dp'

    MDTextField:
        id: text_field_1
        size_hint_x: .5
        hint_text: "Text Field 1"

    MDTextField:
        id: text_field_2
        size_hint_x: .5
        hint_text: "Text Field 2"


<Content>:
    ScrollView:
        MDList:
            OneLineListItem:
                text: "Go to screen 1"
                on_release:
                    root.manager.transition = NoTransition()
                    root.manager.current  = "First"


            OneLineListItem:
                text: "Go to screen 2"
                on_release:
                    root.manager.transition = NoTransition()
                    root.manager.current  = "Second"


<Demo>:
    Screen:
        MDTopAppBar:
            pos_hint: {"top": 1}
            #title: "Navigation Drawer"
            evelation: 8
            left_action_items: [["menu",lambda x: nav_drawer.set_state("open")]]

        FloatLayout:
            MDTextField:
                hint_text: "Search"
                #color_mode: 'custom'
                max_text_length: 15
                size_hint_x: 0.425
                line_color_focus: 0.92, 0.25, 0.20
                hint_text_color_normal: "red"
                text_color_focus: '#ff0000'
                text_color_normal: '#00ff00'
                pos_hint: {"right": 1.0, "top": 1.0}


        MDNavigationDrawer:
            id: nav_drawer
            Content:
                manager: screen_manager
                nav_drw: nav_drawer

        MDNavigationLayout:
            ScreenManager:
                id: screen_manager
                Screen:
                    id: main_screen
                    name: "First"
                    MDLabel:
                        text: "First Screen"

                    MDList:
                        id:list_view
                        name: "list_view"

                    MDIconButton:
                        icon:'android'
                        pos_hint: {"y":0.1, "x": 0.8}
                        on_release:
                            app.show_dialog()

                Screen:
                    name: "Second"
                    MDLabel:
                        text: "2nd Screen"

As you can see list_view is defined in Screen (id: main_screen)

File "kivyproperties.pyx", line 961, in kivy.properties.ObservableDict.__getattr__
 KeyError: 'list_view'
 
 During handling of the above exception, another exception occurred:
 

     Traceback (most recent call last):
       File "C:UsersaddyiPycharmProjectsKivyApp2main.py", line 73, in <module>
         Main().run()
       File "C:UsersaddyiPycharmProjectsTestAppvenvlibsite-packageskivyapp.py", line 955, in run
         runTouchApp()
       File "C:UsersaddyiPycharmProjectsTestAppvenvlibsite-packageskivybase.py", line 574, in runTouchApp
         EventLoop.mainloop()
       File "C:UsersaddyiPycharmProjectsTestAppvenvlibsite-packageskivybase.py", line 339, in mainloop
         self.idle()
       File "C:UsersaddyiPycharmProjectsTestAppvenvlibsite-packageskivybase.py", line 383, in idle
         self.dispatch_input()
       File "C:UsersaddyiPycharmProjectsTestAppvenvlibsite-packageskivybase.py", line 334, in dispatch_input
         post_dispatch_input(*pop(0))
       File "C:UsersaddyiPycharmProjectsTestAppvenvlibsite-packageskivybase.py", line 302, in post_dispatch_input
         wid.dispatch('on_touch_up', me)
       File "kivy_event.pyx", line 731, in kivy._event.EventDispatcher.dispatch
       File "C:UsersaddyiPycharmProjectsTestAppvenvlibsite-packageskivymduixbuttonbutton.py", line 1187, in on_touch_up
         return super().on_touch_up(touch)
       File "C:UsersaddyiPycharmProjectsTestAppvenvlibsite-packageskivymduixbehaviorsripple_behavior.py", line 404, in on_touch_up
         return super().on_touch_up(touch)
       File "C:UsersaddyiPycharmProjectsTestAppvenvlibsite-packageskivyuixbehaviorsbutton.py", line 179, in on_touch_up
         self.dispatch('on_release')
       File "kivy_event.pyx", line 727, in kivy._event.EventDispatcher.dispatch
       File "kivy_event.pyx", line 1307, in kivy._event.EventObservers.dispatch
       File "kivy_event.pyx", line 1231, in kivy._event.EventObservers._dispatch
       File "C:UsersaddyiPycharmProjectsKivyApp2main.py", line 65, in ok_dialog
         self.post_text(text_field_1.text, text_field_2.text)
       File "C:UsersaddyiPycharmProjectsKivyApp2main.py", line 53, in post_text
         screen.ids.list_view.add_widget(OneLineListItem(text=text1))
       File "kivyproperties.pyx", line 964, in kivy.properties.ObservableDict.__getattr__
     AttributeError: 'super' object has no attribute '__getattr__'


I have also added the error code if anybody needs it
Asked By: SupEldrix

||

Answers:

The ids are created when the kv file is loaded, and they are added to the ids dictionary of the root widget that contains the id. So, in your case, the list_view id is defined in the <Demo> rule and that id will appear in the ids of the Demo instance.

Try changing:

    screen.ids.list_view.add_widget(OneLineListItem(text=text1))
    screen.ids.list_view.add_widget(OneLineListItem(text=text2))

to:

    self.root.ids.list_view.add_widget(OneLineListItem(text=text1))
    self.root.ids.list_view.add_widget(OneLineListItem(text=text2))

this assumes that the post_text() method is a method of your Main class.

Answered By: John Anderson
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.