Synchro_tr0n
Synchro_tr0n

Reputation: 89

Creating a form to populate a database in Kivy

The end goal is to create entries in a database with info from a form, using a variety of widgets (textinput, checkboxes,etc). I wanted to make a button at the end of the form to submit the responses to a dict, but I am getting stuck. The only way I can think of to accomplish this is to make all the ids to object properties, then individually reference them in a function like series1.value... series2.value...

This seems very cumbersome and would make it difficult to add further entries to the form later on.

Here is my .py:

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.checkbox import CheckBox
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.button import Button


class DermRoot(BoxLayout):
    dict_filled_from_form = {}
    def add_entry_to_db(self,dict_filled_from_form):
        pass

class DemographForm(BoxLayout):
    sex = ObjectProperty()
    age_input = ObjectProperty()

    def add_entry(self,dict_of_form):
        dict_filled_from_form = dict_of_form
        #is this possible?
        #or do I have to do dict_filled_from_form['series1'] = series1.value etc

class DermApp(App):
    pass

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

and my kv file

DermRoot:

<DermRoot>:
    DemographForm

<DemographForm>:
    orientation: "vertical"

    GridLayout:
        age_input: age_input
        sex: sex

        cols: 2
        Label:
            text: "Patient's Age:"
        TextInput:
            id: age_input
            focus: series4
            multiline: False
        Label:
            text: "Sex:"
        ToggleButton:
            id: sex 
            text: "Male" if self.state == 'normal' else "Female"
        Label:
            text: "Standard Series to Include?"
        GridLayout:
            series1: series1
            series2: series2
            series3: series3 
            series4: series4
            series5: series5

            cols: 2
            CheckBox:
                id: series1
            Label:
                text: "Series1"
            CheckBox:
                id: series2
            Label:
                text: "Series2"
            CheckBox:
                id: series3
            Label:
                text: "series"
            CheckBox:
                id: series4
            Label:
                text: "series4"
            CheckBox:
                id: series5
            Label:
                text: "Series 5"
    Button:
        height: "40dp"
        size_hint_y: None
        text: "Add Entry to Database"
        on_press: root.add_entry(dict_of_form = 'how do I get this?')

Upvotes: 5

Views: 4359

Answers (1)

kitti
kitti

Reputation: 14824

The best option is to use a DictProperty. Try adding one to DemographForm:

class DemographForm(BoxLayout):
    data = DictProperty({})

In your kv, you can use it like so:

    Label:
        text: "Patient's Age:"
    TextInput:
        multiline: False
        # set the value from the data dict. if the key
        # doesn't exist in the dict, then use a default value
        text: root.data['age'] if 'age' in root.data else ''
        # when the value changes, update the data dict
        on_text: root.data['age'] = self.text

This also makes it much easier to handle editing records later. If you set a new dict to data, it will populate all of the fields in the form. Let's add an edit() method to DemographForm:

    def edit(self, data=None):
        if data is not None:
            self.data = data
        else:
            self.data = {}  # reset the form

So you can populate or reset the form. How do you get the data back out? There are different ways to do this, but let's use an event. In DemographForm, add an __events__ attribute and a default handler:

    __events__ = ('on_save', )

    def on_save(self, data):
        pass

The default handler doesn't have to do anything. You're just required to define it if you create an event. Next we can hook it up to the save button in kv:

    Button:
        height: "40dp"
        size_hint_y: None
        text: "Add Entry to Database"
        # dispatch our new `on_save` event
        on_press: root.dispatch('on_save', root.data)

Now that you have an on_save event, you can bind to that in your kv in the same way:

<DermRoot>:
    DemographForm:
        # the arguments to the handler are available
        # as `args` - the last argument will be our
        # data, so we can grab it via `args[-1]`
        on_save: root.add_entry_to_db(args[-1])

Upvotes: 7

Related Questions