Forum Archive

[Idea] Data Entry not using a ui.TableView or dialogs

Phuket2

This has probably done before, cant remnber seeing it though. But the code below is just using a view with a repeating number of labels and textfields to collect some data. What I have done is pretty crappy, but it does illustrate a different idea from using the dialogs module or a tableview to collect data. The difficulty to move away from them is the flexibility they offer thats built in. But this approach in my mind could be ok if you had modest needs. Hmmm, maybe. As I say It's just an idea.
Look many things are missing from this idea, like a scrolling view.
Maybe this type of an idea would be better moved in to a class. Maybe it should be disregarded altogether. I just wanted to try it out!

import ui


def text_form(items=None, width=320, **kwargs):
    if not items or not len(items):
        raise ValueError('items needs to be a list of strings or dicts')

    global _results
    input_flds = []
    _results = None
    _current_y = 6
    _gap = 6

    v = ui.View(frame=(0, 0, width, 100), **kwargs)

    def obj_kwargs_setter(obj, **kwargs):
        '''
        generic way to set the kwargs for a given object
        '''
        [setattr(obj, k, v) for k, v in kwargs.items() if hasattr(obj, k)]

    def _collect_data(sender):
        '''
        collect the data in the textfields
        '''
        global _results
        _results = [{'key': obj.key, 'value': obj.text} for obj in input_flds]
        sender.superview.close()

    def _cancel_action(sender):
        sender.superview.close()

    def make_btn(name, title, action=None, **kwargs):
        '''
        create what I think is a std btn.  kwargs will overwite any attr
        '''
        btn = ui.Button(height=32,
                        name=name,
                        title=title,
                        border_width=.5,
                        border_color='black',
                        bg_color='white',
                        corner_radius=6,
                        action=action,
                        )
        btn.width = 80
        obj_kwargs_setter(btn, **kwargs)
        return btn

    def make_field(fld_dict, y, **kwargs):
        '''
        create what I think is a std label + textField.
        kwargs will overwite any attr of the textfield
        '''
        current_y = y
        lb = ui.Label(frame=(6, current_y, 100, 32),
                      text=str(fld_dict['title']),
                      name=str(fld_dict['title']),
                      )

        fld = ui.TextField(frame=(82, current_y, 230, 32))
        fld.key = fld_dict['key']
        input_flds.append(fld)
        obj_kwargs_setter(fld, **kwargs)
        v.add_subview(lb)
        v.add_subview(fld)
        return fld.height + _gap

    flds = []
    '''
    step 1. checking to see if we have a list of strings or dicts.
    hmmm, only checking the first element :(
    This is imcomplete, just looking at a list of str's at the moment,
    but still creating dict items. Although they are still not finished yet
    '''
    if isinstance(items[0], str):
        for l in items:
            flds.append(dict(type='Text', key=l, value='', title=l))
    elif isinstance(items[0], dict):
        '''
        Not implemented yet
        '''
        pass

    # make the labels & fields
    for fld in flds:
        y = make_field(fld, _current_y)
        _current_y += y

    # make & position the ok and canel buttons
    ok_btn = make_btn('ok', 'OK', bg_color='purple', action=_collect_data,
                      tint_color='white')
    v.add_subview(ok_btn)

    cancel_btn = make_btn('cancel', 'Cancel', _cancel_action,
                          bg_color='deeppink', tint_color='white')
    v.add_subview(cancel_btn)

    ok_btn.y = _current_y + _gap
    ok_btn.x = v.frame.max_x - (ok_btn.width + _gap)
    _current_y += ok_btn.height + _gap

    cancel_btn.y = ok_btn.y
    cancel_btn.x = ok_btn.frame.min_x - (ok_btn.width + _gap)

    v.height = _current_y + _gap

    # make the first field ready for input, without having to tap it
    input_flds[0].begin_editing()

    v.present('sheet', animated=False)
    v.wait_modal()
    return _results

if __name__ == '__main__':
    results = text_form(['Service', 'Account', 'Password'], bg_color='white',
                        name='Add KeyChain Service')
    #results = text_form(['First', 'Last', 'Age', 'email'], bg_color='white',
                        #name='Add Person')

    print(results)
cvp

Why, in make_btn of ok, do you need action=... and in make_btn of cancel, not?

Phuket2

@cvp , it was inconsistency poor on my part. action is an arg, so its being accepted as a named arg or a positional arg.
To be consistent i should have done :

cancel_btn = make_btn('cancel', 'Cancel',action=_cancel_action,
                          bg_color='deeppink', tint_color='white')

or left out the action specifier altogether in both calls, as they are positional arguments.

ok_btn = make_btn('ok', 'OK', bg_color='purple', action=_collect_data,
tint_color='white')
cancel_btn = make_btn('cancel', 'Cancel', action=_cancel_action,
bg_color='deeppink', tint_color='white')

ok_btn = make_btn('ok', 'OK', bg_color='purple', _collect_data,
tint_color='white')
cancel_btn = make_btn('cancel', 'Cancel', _cancel_action,
bg_color='deeppink', tint_color='white')
``````
Its not clear but should be equivalent,

cvp

Thanks for your explanation, I didn't know this *arg, but, really, what do I know?
Surely, not a lot 😭