Search code examples
pythonkivykivy-language

How to manage values for a kivy Spinner widget in kv?


I'm trying to implement a feature that would change spinner values (dropdown items) depending on which button was previously pressed. But for some reason, any attempt to write if statement directly in kv file results in just the latest list being selected for the values.

Some context - pressing one of three client buttons adds a value in the 'collected_info' dictionary 'Client' key. Then, ideally, Spinner widget should check what's the value in that key, and change it's (Spinner's) value property accordingly.

Here's python code:

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import BooleanProperty
from kivy.uix.popup import Popup
from kivy.core.window import Window
from kivy.uix.recycleview import RecycleView
from kivy.lang import Builder
from kivy.uix.widget import Widget


class ProtocolInfoPage(Screen):
    collected_info = {'Client': '', 'Work': '', 'Object': '',
                      'Pilot Drill': '', 'Extender': '', 'Reamer': '',
                      'Liners': {'4x20': [], '8x10': []}, 'Caula/Casing': ''}

    mup = ['1','2','3','4','5']

    olaf = ['6','7','8','9']

    fnb = ['10','10','10','10']

    def collect_info(self):
        self.collected_info['Pilot Drill'] = self.ids.pilot.text
        self.collected_info['Extender'] = self.ids.extender.text
        self.collected_info['Reamer'] = self.ids.reamer.text
        self.collected_info['Caula/Casing'] = self.ids.caula.text


kv = Builder.load_file("test.kv")


class MyApp(App):
    def build(self):
        return ProtocolInfoPage()


if __name__ == '__main__':
    MyApp().run()

And here's kv file:

<ProtocolInfoPage>:
    BoxLayout:
        orientation: 'vertical'

        GridLayout:
            cols:3
            size: 50,50
            ToggleButton:
                group: 'client'
                text: 'MUP'
                on_press: root.collected_info['Client'] = 'MUP'
            ToggleButton:
                group: 'client'
                text: 'Olaf Sitte'
                on_press: root.collected_info['Client'] = 'Olaf Sitte'
            ToggleButton:
                group: 'client'
                text: 'FNB'
                on_press: root.collected_info['Client'] = 'FNB'
        Spinner:
            id: object_dropdown
            size_hint: 1, None
            text: 'Choose Object'
            height: 44
            sync_height: True
            values: root.olaf
            on_text:
                root.collected_info['Object'] = object_dropdown.text

I understand that it might be easier and better to do such tasks in the python code itself, but I'm slightly confused with the way widgets declared in python are inserted in already written kv layout with other widgets.

Any help would be greatly appreciated!


Solution

  • One of the few ways you can achieve that as follows,

    First define a method in your class ProtocolInfoPage say, update_collected_info as,

        def update_collected_info(self, text):
            self.collected_info['Client'] = text
            # Access the dropdown.
            dropdown = self.ids.object_dropdown
            # Now map separately or use a predefined dictionary for efficient access.
            if text == "MUP":
                dropdown.values = self.mup
            elif text == "Olaf Sitte":
                dropdown.values = self.olaf
            elif text == "FNB":
                dropdown.values = self.fnb
            print(self.collected_info)
    

    Now from each button in your kvlang pass the arg 'text' to this method as,

            ...
            GridLayout:
                cols:3
                size: 50,50
                ToggleButton:
                    group: 'client'
                    text: 'MUP'
                    # Assuming the value for the key "Client" will always be its text.
                    # If necessary change and pass something you need.
                    on_press: root.update_collected_info(self.text)
                ToggleButton:
                    group: 'client'
                    text: 'Olaf Sitte'
                    on_press: root.update_collected_info(self.text)
                ToggleButton:
                    group: 'client'
                    text: 'FNB'
                    on_press: root.update_collected_info(self.text)
            Spinner:
                id: object_dropdown
            ...