mm4096
mm4096

Reputation: 171

How to use python file to insert elements into kivy?

I'm trying to make an app with kivy and I want to be able to add a changeable amount of buttons with changeable text to a screen. Here's my code:

kv = Builder.load_file('main.kv')
class MyScreen(Screen):
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        label = Label(text="hello world!")
        for i in range(5):
            self.ids.FillIn.add_widget(label)

class MainApp(App):
    def build(self):
        return kv

if __name__ == "__main__":
    MainApp().run()

and kivy:


<WindowManager@ScreenManager>:
<MainPage@Screen>:
    Button:
        on_release: app.root.current = "MyPrayers"
<MyScreen@Screen>:
    name: 'MyScreen'
    BoxLayout:
        orientation: "vertical"
        BoxLayout:
            orientation: "vertical"
            id: FillIn

WindowManager:
    MainPage:
    MyScreen:

Upvotes: 0

Views: 79

Answers (1)

John Anderson
John Anderson

Reputation: 39152

The main problem with your code is that the line of code:

kv = Builder.load_file('main.kv')

is executed before the definition of MyScreen is loaded. So the NyScreen instance that is created by the Builder.load_file() has none of the attributes of the later defined MyScreen class. Other issues involve trying to access ids in the __init__() method (which is executed before ids are assigned) and trying to add the same Label widget multiple times (any widget can have only one parent).

Here is a modified version of your python code that fixes the above issues:

class MyScreen(Screen):

    def __init__(self, **kwargs):
        super(MyScreen, self).__init__(**kwargs)
        Clock.schedule_once(self.add_widgets)

    def add_widgets(self, *args):
        for i in range(5):
            label = Label(text="hello world!")
            self.ids.FillIn.add_widget(label)


class MainApp(App):
    def build(self):
        kv = Builder.load_file('main.kv')  # load kv here, after MyScreen is defined
        return kv


if __name__ == "__main__":
    MainApp().run()

And the slightly modified kv:

<WindowManager@ScreenManager>:

<MainPage@Screen>:
    Button:
        text: 'Go To MyScreen'
        on_release: app.root.current = "MyScreen"
        
<MyScreen>:  # the @Screen is not needed since the MyScreen class is defined in the python code
    name: 'MyScreen'
    BoxLayout:
        orientation: "vertical"
        BoxLayout:
            orientation: "vertical"
            id: FillIn

WindowManager:
    MainPage:
    MyScreen:

Upvotes: 1

Related Questions