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.
Set next field for tab
-
How do I set a logical tab order so when the user enters text and hits tab on a keyboard the focus swaps to the correct field?
-
@robertiii, I am not sure you can (Well it appears you can by the order you add say the textfield views to the view using add_subview). I put some test code below I was playing with to try and override the which field would get the focus. I tried a few small things to try and override the order , but I couldn't. Not to say it cant be done though, I just didn't see the way.
Initially I thought I was going to be able to capture the tab key in the method 'textfield_should_change' and then use the begin_editing() method on the field I wanted to get the focus, but it does not appear you can capture a tab press in that method.import ui class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.make_view() def make_view(self): fld1 = ui.TextField(frame=(0, 0, 200, 32), name='fld1', delegate=self, placeholder='Fld1') self.add_subview(fld1) fld2 = ui.TextField(frame=(0, 0, 200, 32), name='fld2', delegate=self, placeholder='Fld2') fld2.y = fld1.frame.max_y + 5 self.add_subview(fld2) fld3 = ui.TextField(frame=(0, 0, 200, 32), name='fld3', delegate=self, placeholder='Fld3') fld3.y = fld2.frame.max_y + 5 self.add_subview(fld3) fld3.begin_editing() def textfield_should_return(self, textfield): 'Print Leaving' def textfield_should_change(self, textfield, range, replacement): print(replacement) return True def textfield_did_end_editing(self, textfield): if textfield.name == 'fld3': self['fld2'].begin_editing() if __name__ == '__main__': f = (0, 0, 300, 400) v = MyClass(frame=f) v.present(style='sheet', animated=False)
-
@robertiii, the below almost works. In my example I want fld2 to get focus after hitting the tab key when in fld3 instead of fld1. Same code below basically, but used the ui.in_background decorator. You can see it wants to work, but there are some timing issues that I dont understand. I suspect its not even a valid way to approach this. But I posted anyway, as it may spark a thought for another member to get it right.
import ui from time import sleep class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.make_view() def make_view(self): fld_width = self.width fld1 = ui.TextField(frame=(0, 5, fld_width, 32), name='fld1', delegate=self, placeholder='Fld1') self.add_subview(fld1) fld2 = ui.TextField(frame=(0, 0, fld_width, 32), name='fld2', delegate=self, placeholder='Fld2') fld2.y = fld1.frame.max_y + 5 self.add_subview(fld2) fld3 = ui.TextField(frame=(0, 0, fld_width, 32), name='fld3', delegate=self, placeholder='Fld3') fld3.y = fld2.frame.max_y + 5 self.add_subview(fld3) fld3.begin_editing() def textfield_should_return(self, textfield): print('print Leaving') def textfield_should_change(self, textfield, range, replacement): print(replacement) return True @ui.in_background def textfield_did_end_editing(self, textfield): # print('in here, did_end_editing') if textfield.name == 'fld3': self['fld2'].begin_editing() if __name__ == '__main__': f = (0, 0, 300, 400) v = MyClass(frame=f) v.present(style='sheet', animated=False) ```python
-
I think you want to put your code in should_return -- set begin_editing, and return false
-
-
Have you tried without the in_background?
Maybe with a ui.delay on begin_editing, if needed.
-
@Phuket2
should_return
only gets called when the return key is pressed, that's the expected behavior. -
@omz , should you also add tab to the should_return method? Too me it seems like it should be included as a Tab in this case is equivalent to a Return
-
@Phuket2 I wouldn't consider Tab and Return to be equivalent. For example, when you have a standard username/password login screen, you want Tab to switch between the fields, and Return to log in with the details you entered. Tab is like the keyboard version of tapping on another text field, Return is like tapping an "OK" button.
-
@dgelessus, I sort of agree with you. But I would think if you were in the username field, you would want return or tab to advance you to the password field. Once in the password field you would want tab to take you back to the username field and return to act the same as hitting ok.
Of course the context would vary on a case but case basis.
But ok, maybe a bad choice of wording, But it seems like should return_method should capture both tabs and returns. At the moment the method is using the return key to cycle through the fields on the view based on their order in which they were added to the view. Seems like you should be able to look at the key in conjunction which field you are in and then cleanly select the next field you deem to be the next field depending on your form.
Maybe it should be done another way, some how it does not really matter. I just think there should be a clear way to navigate your fields via the keyboard, on screen or external -
It shouldn't capture both tabs and returns. textFieldShouldReturn: docs clearly states:
Asks the delegate if the text field should process the pressing of the return button.
return
in this case means Return a.k.a. Enter button (both SW or HW keyboard). Return in the delegate method name is not about leave, end editing, ... it's about Return (Enter) button only. -
omz is just passing on ios system behavior. Looking at stack overflow, tab order is an annoying thing that you don't have much control over on ios.
For instance, here are the pains some have gone to:
https://weaklyreferenced.wordpress.com/2012/11/13/responding-to-the-tab-and-shift-tab-keys-on-ios-5-ios-6-with-an-external-keyboard/
In theory, You could implement something like this... -
This post is quite old and things did evolve little bit. Anyway it's solvable via should begin editing delegate method. Return false for every field except the desired one. You can control text fields order for tab key in this case.
-
Here's the sample how to use Tab or Enter key on HW keyboard to switch between text fields ...
import ui _COUNT = 5 class TextFields(ui.View): def __init__(self, **kwargs): super().__init__(**kwargs) self._current_text_field = None self._next_text_field = None self._fields = [ ui.TextField( frame=(12, 12 + (44 + 12) * i, self.bounds.size.width - 12, 44), flex='W', bordered=True, delegate=self, placeholder=f'Index {i}, next index {self._next_field_index(i)}' ) for i in range(_COUNT) ] for x in self._fields: self.add_subview(x) @staticmethod def _next_field_index(index): return index - 1 if index > 0 else _COUNT - 1 def textfield_should_begin_editing(self, textfield): if not self._next_text_field: return True # Tricky part - if you do omit second part of this condition, iOS will INSERT # tab character into your text field instead of switching to another text field. # Basically this method should return True for text field you would like to switch # to AND True for the current text field. Otherwise Tab character will be inserted # as mentioned. # # Try it, remove `or ...` and you'll see how it behaves. return textfield is self._next_text_field or textfield is self._current_text_field def textfield_did_begin_editing(self, textfield): self._next_text_field = self._fields[self._next_field_index(self._fields.index(textfield))] self._current_text_field = textfield def textfield_should_return(self, textfield): self._next_text_field.begin_editing() return True v = TextFields(frame=(0, 0, 500, 500), background_color='white') v.present('sheet')
... please, don't forget what @JonB wrote - Pythonista "just" wraps iOS components. If you're lost, consult UIKit reference.