omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    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

    Pythonista
    6
    14
    7778
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Phuket2
      Phuket2 @robertiii last edited by

      @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
      1 Reply Last reply Reply Quote 0
      • JonB
        JonB last edited by

        I think you want to put your code in should_return -- set begin_editing, and return false

        Phuket2 1 Reply Last reply Reply Quote 0
        • Phuket2
          Phuket2 @JonB last edited by

          @JonB, no that does not work. The should_return method does not get called if the tab key is pressed, only if return is pressed. Not sure if that is a bug or not. Sounds like it is to me.
          @omz, is this a bug or considered the correct behaviour for the should_return method?

          1 Reply Last reply Reply Quote 0
          • JonB
            JonB last edited by

            Have you tried without the in_background?

            Maybe with a ui.delay on begin_editing, if needed.

            1 Reply Last reply Reply Quote 0
            • omz
              omz last edited by

              @Phuket2 should_return only gets called when the return key is pressed, that's the expected behavior.

              Phuket2 1 Reply Last reply Reply Quote 1
              • Phuket2
                Phuket2 @omz last edited by

                @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

                1 Reply Last reply Reply Quote 0
                • dgelessus
                  dgelessus last edited by

                  @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.

                  Phuket2 1 Reply Last reply Reply Quote 0
                  • Phuket2
                    Phuket2 @dgelessus last edited by

                    @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

                    1 Reply Last reply Reply Quote 0
                    • zrzka
                      zrzka last edited by

                      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.

                      1 Reply Last reply Reply Quote 0
                      • JonB
                        JonB last edited by

                        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...

                        1 Reply Last reply Reply Quote 0
                        • zrzka
                          zrzka last edited by

                          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.

                          1 Reply Last reply Reply Quote 0
                          • zrzka
                            zrzka last edited by zrzka

                            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.

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post
                            Powered by NodeBB Forums | Contributors