Search code examples
pythonpython-3.xkivykivy-language

Add a widget that was created in kv from py


Is there a way to reference a custom widget from the py file?

I made a widget in kv, but I want to reference it from py, then add it again to another widget in kv. I tried doing this using id but I got an error (KeyError: 'words_entry').

This is what I tried:

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.textinput import TextInput
import os


class GetCount(Screen):

    count_input = ObjectProperty(None)

    def next(self):

        # Setup next screen
        text_inputs = [self.ids.words_entry for i in range(int(self.count_input.text))]

        for text_input in text_inputs:
            self.manager.ids.get_input.ids.grid.add_widget(text_input)

        # Switch to next screen
        self.manager.current = "get_input"


class GetInput(Screen):
    pass


kv_file = Builder.load_string("""
ScreenManager:

    GetCount:
        name: "get_count"
        id: get_count

    GetInput:
        name: "get_input"
        id: get_input

<WordEntry@TextInput>:
    id: words_entry

    multiline: False
    size_hint: (self.width, None)

<GetCount>:
    
    count_input: count_input
    
    FloatLayout:
        
        Label:
            text: "count"
            size_hint: 1, 0.05
            pos_hint: {"top":0.9}

        TextInput:
            id: count_input 

            size_hint: 0.8, 0.05
            pos_hint: {"top":0.7, "x":0.1}
            multiline: False

        Button:
            text: "Next"
            on_release: root.next()
            size_hint: 0.8, 0.05
            pos_hint: {"top":0.5, "x":0.1}

<GetInput>:
    
    ScrollView:

        GridLayout:
            size_hint_y: None
            height: self.minimum_height
            id: grid

            cols: 1
""")


class MainApp(App):

    def build(self):
        return kv_file


if __name__ == "__main__":

    app = MainApp()
    app.run()

In this code, I want to add WordEntry to the GridLayout in GetInput from py (the reason is that I need to add multiple depending on the user's input).


Solution

  • You can use Factory to create an instance of a class that has been defined in kv. So your GetCount class can be:

    from kivy.factory import Factory
    
    class GetCount(Screen):
        count_input = ObjectProperty(None)
    
        def next(self):
            # Setup next screen
            for _ in range(int(self.count_input.text)):
                new_word_entry = Factory.WordEntry()
                self.manager.ids.get_input.ids.grid.add_widget(new_word_entry)
    
            # Switch to next screen
            self.manager.current = "get_input"