Search code examples
pythonkivykivy-language

Editable spinner


I need to make something like a spinner or dropdown list but with the ability to input the value manually when there is no right value on the list.

I'm trying to find some properties of spinner but no one seems to fit. Is there any posibility in kv language?


Solution

  • Here's a basic implementation using DropDown widget.

    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.dropdown import DropDown
    from kivy.uix.button import Button
    
    kv = """
    <CustomDropdown>:
        size_hint_y: None
        pos_hint: {"top": 1}
        height: 56.0
        orientation: "horizontal"
    
        TextInput:
            id: txt_input
            size_hint_x: 0.5
    
        Button:
            id: show_drop
            size_hint_x: 0.2
            text: "drop"
            on_release: root.show_dropdown()
        Button:
            id: submit_btn
            size_hint_x: 0.3
            text: "Submit"
            on_press: root.validate_txt()
    """
    
    
    class CustomDropdown(BoxLayout):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
    
            self.dropdown = DropDown()
            self.fakeValues = ["First", "Second", "Third"]
            for val in self.fakeValues:
                btn = Button(text=val, size_hint=[0.5, None])
                btn.height = 56.0
                btn.bind(on_press=self.change_value)
                self.dropdown.add_widget(btn)
    
        def change_value(self, *args):
            self.ids.txt_input.text = args[0].text
            self.hide_dropdown()
    
        def add_options(self, *args):
            btn = Button(text=args[0], size_hint=[0.5, None])
            btn.height = 56.0
            btn.bind(on_press=self.change_value)
            self.dropdown.add_widget(btn)
    
    
        def validate_txt(self, *args):
            curText = self.ids.txt_input.text
            if ((curText in self.fakeValues) or (curText == None) or (curText == "")):
                return
            self.fakeValues.append(curText)
            self.add_options(curText)
            self.hide_dropdown()
    
        def hide_dropdown(self):
            self.dropdown.dismiss()
    
        def show_dropdown(self, *args):
            if self.dropdown.parent:
                self.hide_dropdown()
            else:
                self.dropdown.open(self.ids.txt_input)
    
    class TestApp(App):
        def build(self):
            Builder.load_string(kv)
            return CustomDropdown()
    
    TestApp().run()
    

    Before doing anything:

    enter image description here

    Showing DropDown:

    enter image description here

    Typing some custom words and submitting it:

    enter image description here

    Showing DropDown again:

    enter image description here