B4A Library [Class] EditText Field Order

Here is a class that makes it easy to set the tab order for EditTexts on an activity and/or panel(s).

Set up a layout in the normal way then in Sub Globals:

B4X:
Dim FieldOrder As FOrder

And in Activity_Create:

B4X:
FieldOrder.Initialize(Array As Object(EditText1,EditText6,EditText5,EditText2,EditText3,EditText4),False)

The tab order will be the order the EditTexts are added to the array.

ForceDone is selected for the last EditText in the list unless Repeat is set to true. This is simple to change in the Class code if you want to.

It will compile directly to a usable library if you don't want to see the code as a module in the tabs.

I hope someone can make use of it.


Requires the Reflection Library.

V 1.0 attached
 

Attachments

  • FieldOrder.zip
    8.4 KB · Views: 931

stevel05

Expert
Licensed User
Longtime User
I can't run it as I don't have a library it contains, but another thought crossed my mind.

If the fields must be entered in the correct order, which it sounds like it does, you could add a panel covering the whole screen, then in the ontouch callback, test the fields in order and send it back from there with IME.Showkeyboard and return True from the onfocus to consume the event. If none fail return false from the ontouch and the click will pass through.

You'd have to setup the ontouch using Reflection to achieve this though.

Something like this:

B4X:
    'Add the ontouch listener in Activity create
    Dim R As Reflector
    R.Target = Panel1
    R.SetOnTouchListener("Panel1_Touched")
  
'Then as the touch sub
Sub Panel1_Touched (viewtag As Object,action As Int,x As Float,y As Float, Mevent As Object) As Boolean
  
    If edtOSGBGridRef1Valid = False The
        'Message if required
        IME.ShowKeyboard(edtOSGBGridRef1)
        'Consume the touch event
        Return True
    End If
    If edtOSGBGridRef2Valid = False Then
        'Message if required
        IME.ShowKeyboard(edtOSGBGridRef2)
        'Consume the touch event
        Return True
    End If
  
'    Test Them all
'    .
'    .
'    .
  
'    'If they all pass then Return False to pass the touch through
    Return False
End Sub

That should stop the focus or touch going anywhere else when validation fails. You can obviously add a pertinent message if you wish.

I've tested it with FieldOrder and it seems to work OK.

You would still need the inline validation as pressing next on the keyboard wouldn't go through the panel.
 
Last edited:

johnaaronrose

Active Member
Licensed User
Longtime User
I can't run it as I don't have a library it contains, but another thought crossed my mind.

If the fields must be entered in the correct order, which it sounds like it does, you could add a panel covering the whole screen, then in the ontouch callback, test the fields in order and send it back from there with IME.Showkeyboard and return True from the onfocus to consume the event. If none fail return false from the ontouch and the click will pass through.

You'd have to setup the ontouch using Reflection to achieve this though.

Something like this:

B4X:
    'Add the ontouch listener in Activity create
    Dim R As Reflector
    R.Target = Panel1
    R.SetOnTouchListener("Panel1_Touched")
 
'Then as the touch sub
Sub Panel1_Touched (viewtag As Object,action As Int,x As Float,y As Float, Mevent As Object) As Boolean
 
    If edtOSGBGridRef1Valid = False The
        'Message if required
        IME.ShowKeyboard(edtOSGBGridRef1)
        'Consume the touch event
        Return True
    End If
    If edtOSGBGridRef2Valid = False Then
        'Message if required
        IME.ShowKeyboard(edtOSGBGridRef2)
        'Consume the touch event
        Return True
    End If
 
'    Test Them all
'    .
'    .
'    .
 
'    'If they all pass then Return False to pass the touch through
    Return False
End Sub

That should stop the focus or touch going anywhere else when validation fails. You can obviously add a pertinent message if you wish.

I've tested it with FieldOrder and it seems to work OK.

You would still need the inline validation as pressing next on the keyboard wouldn't go through the panel.

I'm trying to understand your suggestion. Is the purpose of "R.SetOnTouchListener("Panel1_Touched")" to action calling of "Sub Panel1_Touched" when the panel is touched anywhere (e.g. when one of the EditText views is clicked? What's the difference between using this & Touch (or even Click) event Sub for the Panel? How does the above Sub know which EditText value is to be validated? Hopefully, I've attached the missing library files.
 

Attachments

  • GPStoOSGB.zip
    7.1 KB · Views: 238

stevel05

Expert
Licensed User
Longtime User
Using the reflection ontouchlistener allows consuming the touch event so it doesn't pass through the panel, or conversely allowing it to pass through to the views below. This is not available to the standard touch or click event handlers.

My opening assumption was that the fields need to be entered in the correct order, if this is the case and they all need to be valid to proceed, then using the touch panel to test all in order will ensure that if the user attempts to touch another view while there is invalid data in any of the edittexts, the focus will be returned to the first edittext that contains invalid data.

That's is my understanding of what you are trying to achieve.
 
Last edited:

johnaaronrose

Active Member
Licensed User
Longtime User
Using the reflection ontouchlistener allows consuming the touch event so it doesn't pass through the panel, or conversely allowing it to pass through to the views below. This is not available to the standard touch or click event handlers.

My opening assumption was that the fields need to be entered in the correct order, if this is the case and they all need to be valid to proceed, then using the touch panel to test all in order will ensure that if the user attempts to touch another view while there is invalid data in any of the edittexts, the focus will be returned to the first edittext that contains invalid data.

That's is my understanding of what you are trying to achieve.

Your understanding is correct. I'm not sure if you included this: as each EditText has value entered & the Next/Done key is pressed, then that value is validated before the focus moves to the next EditText.

I've now got the app working as I want without using your Panel method. It uses FieldOrder & HandleAction (part of IME library). It also uses (to prevent the focus moving to a later view than the current one until a valid value is entered but to allow the user to press a previous view to correct the value in it) a technique I saw in another thread of using the Reflector library to setFocusable & setFocusableInTouchMode to False. After the last EditText value is entered & validated OK, I'm using setFocusable & setFocusableInTouchMode (I don't understand why I need to set both to True) to True (though I could have used your equivalent code acting directly on a Java object) to obtain focus on the Convert button using btnConvert.RequestFocus: I'm doing this using CallSubDelayed coded in the HandleAction.

Only remaining problem is that when the app starts, the screen has the focus on the first EditText view but I am not able to have the keyboard opened ready to enter a value. This is in spite of my having IME.ShowKeyboard(edtOSGBGridRef1) coded in both the Activity_Create & Activity_Resume events. Is it possible that this has something to do with the FOrder class code?
 

stevel05

Expert
Licensed User
Longtime User
According to the documentation setFocusableInTouchMode should automatically set the view Focusable so you should only need to call setFocusableInTouchMode.

Did you try putting IME.ShowKeyboard(edtOSGBGridRef1) in a separate sub and calling it using CallSubDelayed from activity_create or Activity_Resume?
 

johnaaronrose

Active Member
Licensed User
Longtime User
I've just done that for both activity subs & it worked! At last, the app does what I want. Thanks for all your help.
 

johnaaronrose

Active Member
Licensed User
Longtime User
I've just done that for both activity subs & it worked! At last, the app does what I want. Thanks for all your help.
I spoke too soon. There is a problem with Landscape orientation. I've changed the design layout of the Landscape variant to have the views much higher on the screen & therefore see all the views at runtime when the keyboard is displayed. One point I noticed is that a Return symbol key is shown in the keyboard rather than Next/Done. How can this be rectified (i.e. display Next/Done as appropriate)?
PS The Next/Done usage was set by your FOrder code , executed before Landscape was set using Phone.SetScreenOrientation(0).
PPS I raised this point on thread http://www.b4x.com/android/forum/th...with-the-ime-library.14832/page-7#post-223401
Erel's response was "Next / Done button should appear when the EditText is in single line mode.". My response to that was "SingleLine is set to True on all my EditText views: it's the default in the Designer and I have not changed it in either the Designer or code.".
 

stevel05

Expert
Licensed User
Longtime User
Is the return button shown for all the edit texts? What happens when you actually press the return key. and is it only in landscape?

The FOrder class only changes the order of the Edittext's entry, it should have no other effect on the views.
 

johnaaronrose

Active Member
Licensed User
Longtime User
Is the return button shown for all the edit texts? What happens when you actually press the return key. and is it only in landscape?

The FOrder class only changes the order of the Edittext's entry, it should have no other effect on the views.
The Return key is shown for all EditText views' entry. Pressing the Return key calls the HandleAcion event's sub (which is expected) & the app proceeds as expected. In Portrait, the Next/Done key is displayed as expected. My feeling is that the cause is due to either Phone.SetScreenOrientation(0) or Landscape orientation. Erel (on http://www.b4x.com/android/forum/th...with-the-ime-library.14832/page-7#post-223401) has asked me to "create a simple project that demonstrates it and upload the project (preferably in a new thread)". So I'll now do that.
 

johnaaronrose

Active Member
Licensed User
Longtime User
The Return key is shown for all EditText views' entry. Pressing the Return key calls the HandleAcion event's sub (which is expected) & the app proceeds as expected. In Portrait, the Next/Done key is displayed as expected. My feeling is that the cause is due to either Phone.SetScreenOrientation(0) or Landscape orientation. Erel (on http://www.b4x.com/android/forum/th...with-the-ime-library.14832/page-7#post-223401) has asked me to "create a simple project that demonstrates it and upload the project (preferably in a new thread)". So I'll now do that.
A simple project (named Test) has been created in the new thread http://www.b4x.com/android/forum/threads/next-done-keys-not-shown-in-landscape-orientation.37830/
 

WZSun

Member
Licensed User
Longtime User
Hi
Managed to find a workaround to 'turn off' the focus after entering an EditText. It works for me, and hopefully it can work for you too.

Assuming you want to trun off the focus on EditText1 after user enter some text and press a Button. In the button script, you simply issue the 2 statements below:

EditText1.Visible = False
EditText1.Visible = True

That's it. Just 2 simple statements and the focus on the EditText1 is off.
 

incendio

Well-Known Member
Licensed User
Longtime User
Dear Steve,

Thanks for your class, it is very useful for me.
I don't have a problem when using it with EditText.

But I have a problem when using it with Custom View. This View is a descendants of EditText. Since B4A does not supports inheritance, this view don't have all property & method of EditText. I only add properties & methods for my need.

These is the error message :
An error has occured in sub:forder_initialize(java line:104) java.lang.NoSuchMethodException:setImeOptions[int]

Could you point me how to fix these error?

Thanks in advance.
 
Last edited:

stevel05

Expert
Licensed User
Longtime User
I would need to see your Custom view to give you a concrete answer but if your Custom view includes an edit text, you would need to expose it's object and add that to the FieldOrder.
 

incendio

Well-Known Member
Licensed User
Longtime User
EDITED :
Found the solution by made EditText var accessible from outside CustomView
 
Last edited:
Top