kivy - getting a spinner to remember its selection

1.3k views Asked by At

I was hoping someone could tell me the way you can get a spinner to remember its value when an app is loaded.

I was thinking about using from kivy.storage.jsonstore import JsonStore to store and retrieve the value the user selects in a db, this is easy enough.

But having searched for hours I can't find any documentation on making the spinner say that value when it loads.

for example I have a lot of items in my spinner (about 60) and it takes a while to scroll through, as I said I can remember the last selected item but I cannot work out how to make it the default value.

    Spinner:
    id: stationSpinner
    text:'Select a Station'
    values: ('Reset Saved Station','Appledore','Axminster','Bampton','Barnstaple','Bere Alston','Bideford','Bovey Tracey','Braunton','Bridgwater','Brixham','Buckfastleigh','Budleigh Salterton','Burnham on Sea','Camels Head','Castle Cary','Chagford','Chard','Cheddar','Chulmleigh','Colyton','Combe Martin','Crediton','Crewkerne','Crownhill','Cullompton','Dartmouth','Dawlish','Danes Castle','Middlemoor','Exmouth','Frome','Glastonbury','Greenbank','Hartland','Hatherleigh','Holsworthy','Honiton','Ilfracombe','Ilminster','Ivybridge','Kingsbridge','Kingston','Lundy Island','Lynton','Martock','Minehead','Modbury','Moretonhampstead','Nether Stowey','Newton Abbot','North Tawton','Okehampton','Ottery St Mary','Paignton','Plympton','Plymstock','Porlock','Princetown','Salcombe','Seaton','Shepton Mallet','Sidmouth','Somerton','South Molton','Street','Taunton','Tavistock','Teignmouth','Tiverton','Topsham','Torquay','Torrington','Totnes','USAR','Wellington','Wells','Williton','Wincanton','Witheridge','Wiveliscombe','Woolacombe','Yelverton','Yeovil')
    size_hint: None, None
    size: (150, 44)
    pos_hint: {'center_x':0.5, 'y': 0.35}
    on_text: app.show_selected_value()

so the first time the app is loaded it says 'select a station'. The second time its loaded it shows the last selected station. Obviously I have put the reset option in to clear the db file.

I have tried just using

SvdStn = store.get('Stations')['Saved']
self.root.station.text = SvdStn

but it doesnt work, I'm guessing its fairly simple but as I can't find any documentation on it I can't get my head around it... I'll keep looking and maybe come at it from a different direction, maybe have a button become visible with the last one selected next to the spinner, but if the db is empty set the visible property to false.

edit: here is my code py file and logo on onedrive

Any ideas welcome

Thanks

Raif

This is the relevant part of code:

import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
from kivy.storage.jsonstore import JsonStore
from os.path import join

kv = '''
<IncidentScreen>:
    canvas.before:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            pos: self.pos
            size: self.size

    station: stationSpinner
    Image:
        source:'DSFRSLogo.png'
        allow_stretch:True
        pos_hint: {'root.x':0.5, 'y':.2}

    Spinner:
        id: stationSpinner
        text:'Select a Station'
        values: ('Reset Saved Station','Appledore','Axminster','Bampton','Barnstaple','Bere Alston','Bideford','Bovey Tracey','Braunton','Bridgwater','Brixham','Buckfastleigh','Budleigh Salterton','Burnham on Sea','Camels Head','Castle Cary','Chagford','Chard','Cheddar','Chulmleigh','Colyton','Combe Martin','Crediton','Crewkerne','Crownhill','Cullompton','Dartmouth','Dawlish','Danes Castle','Middlemoor','Exmouth','Frome','Glastonbury','Greenbank','Hartland','Hatherleigh','Holsworthy','Honiton','Ilfracombe','Ilminster','Ivybridge','Kingsbridge','Kingston','Lundy Island','Lynton','Martock','Minehead','Modbury','Moretonhampstead','Nether Stowey','Newton Abbot','North Tawton','Okehampton','Ottery St Mary','Paignton','Plympton','Plymstock','Porlock','Princetown','Salcombe','Seaton','Shepton Mallet','Sidmouth','Somerton','South Molton','Street','Taunton','Tavistock','Teignmouth','Tiverton','Topsham','Torquay','Torrington','Totnes','USAR','Wellington','Wells','Williton','Wincanton','Witheridge','Wiveliscombe','Woolacombe','Yelverton','Yeovil')
        size_hint: None, None
        size: (150, 44)
        pos_hint: {'center_x':0.5, 'y': 0.35}
        on_text: app.show_selected_value()

'''
class IncidentScreen(FloatLayout):
    station = ObjectProperty(None)
    results = ObjectProperty(None)
    data_dir = App().user_data_dir
    store = JsonStore(join(data_dir, 'storage.json'))
    try:
        store.get('stations')['saved']
    except KeyError:
        SvdStn = ""
    else:
        SvdStn = store.get('stations')['saved']
        print(SvdStn)
        self.root.station.text = SvdStn

class DSFRSapp(App):

    def build(self):            
        Builder.load_string(kv)
        fl = IncidentScreen()
        return fl

if __name__ =="__main__":
    DSFRSapp().run()
1

There are 1 answers

1
tiktok On

The method that you've mentioned for spinner works fine but It looks like you've misunderstood the use of self and App(). self refers to the current instance of a class and is supplied as an argument to a class method so you can't use it outside of a class method. You've tried to use it directly under the kivy properties but in that case it doesn't contain a value. You also attempt to use App() but this attempts to creates an instance of the App object. I would leave the loading and saving in the application class and allow the spinner to be initialised with an extra argument to it's constructor, like so:

class IncidentScreen(FloatLayout):
    station = ObjectProperty(None)
    results = ObjectProperty(None)

    def __init__(self, station, **kwargs):
        super(IncidentScreen, self).__init__(**kwargs)
        self.station.text = station

class DSFRSapp(App):

    def build(self):            
        Builder.load_string(kv)
        data_dir = self.user_data_dir
        store = JsonStore(join(data_dir, 'storage.json'))
        SvdStn = ""

        try:
            store.get('stations')['saved']
            SvdStn = store.get('stations')['saved']
        except KeyError:
            pass

        fl = IncidentScreen(SvdStn)
        return fl

You'll have to do something similar for the show_selected_value method. I had to disable it to get the code running because it's called immediately as the gui displays. Overall, I'd recommend that you take a careful look at how python handles classes. It'll save you a lot of effort later on. There are lots of tutorials if you google around.