Search code examples
python-3.xmacoskivy

I can't add a widget in a kivy app from python3 class. Error message: AttributeError: 'super' object has no attribute '__getattr__'


I have on MacOs this Python3 script:

from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
class Grid(GridLayout):
    cols=2
    def doet(self):
        self.ids.grid_id.add_widget(Button())
class app(App):
    def build(self):
        self.grid=Grid()
        return Builder.load_file('lab.kv')
app().run()

And this kv file (lab.kv):

BoxLayout:
    Button:
        text:'Doet'
        on_press:app.grid.doet()
    Grid:
        id:grid_id

I try to add a widget to the grid from python class by clicking a button, but it doesn't work. I get this error message:

AttributeError: 'super' object has no attribute '__getattr__'

P.s. I tried this too:

self.add_widget(Button())

I don't get error messages, but nothing happens.


Solution

  • A couple problems with your code:

    • Your doet() method tries to reference ids of the Grid class, but the Grid class has no ids. The ids defined in your kv are in the BoxLayout class. See the documentation.
    • The code: on_press:app.grid.doet() in your kv calls the doet() method of the grid attribute of your app class. That grid attribute is defined the the build() method (self.grid=Grid()) and is not included in your app display, so running its methods will have no effect on what you see.

    The fix is to eliminate unused widgets, and correctly access the widgets that are actually in your App. Here is a modified version of your code that does this:

    from kivy.app import App
    from kivy.lang.builder import Builder
    from kivy.uix.gridlayout import GridLayout
    from kivy.uix.button import Button
    
    class Grid(GridLayout):
        cols=2
        def doet(self):
            self.add_widget(Button())  # add new Button to the Grid
    
    class app(App):
        def build(self):
            # self.grid=Grid()
            return Builder.load_file('lab.kv')
    
    app().run()
    

    lab.kv:

    BoxLayout:
        Button:
            text:'Doet'
            on_press: grid_id.doet()
        Grid:
            id:grid_id
    

    The grid_id.doet() in the kv uses the defined id to access the Grid that is actually in the App.