Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
[Idea] Data Entry not using a ui.TableView or dialogs
-
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)
-
Why, in make_btn of ok, do you need action=... and in make_btn of cancel, not?
-
@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,
-
Thanks for your explanation, I didn't know this *arg, but, really, what do I know?
Surely, not a lot ðŸ˜