Android Question Add currency format for edittext

devmobile

Active Member
Licensed User
Hello
I can change number format to currency
But i need to convert to currency format in TextChange event for edittext
When i use it in this event,it craches
Why?
 

devmobile

Active Member
Licensed User
My code :
B4X:
Sub txtprice_TextChanged (Old As String, New As String)
 
    If IsNumber(txtprice.Text.Replace(",","")) Then
        txtprice.Text = NumberToCurrency(txtprice.Text.Replace(",",""))
        End If
 
End Sub

NumberToCurrency is function that convert number to currency format
 
Upvote 0

devmobile

Active Member
Licensed User
What does NumberToCurrency do?
This function
B4X:
Sub ConvertNumber2Currency(MyNumber As Double) As String
    Dim AHL As AHLocale   'need the AHlocale library
    Dim res As String
    AHL.InitializeUS
    Dim MyFrac As Int =AHL.CurrencyFractionDigits
    res = NumberFormat2(MyNumber,1,MyFrac,MyFrac,True)
    Return res.SubString2(0,res.LastIndexOf("."))
End Sub
This function dont have problem
My problem is in TextChaned event only
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Setting the .Text property of the control appears to be recurisively calling the _TextChanged event, resulting in a stack overflow.

I would set a global variable to indicate we're adjusting the contents then check that variable in the event, something like:
B4X:
If MyGlobalBoolean = False then
   MyGlobalBoolean = True
    If IsNumber(txtprice.Text.Replace(",","")) Then
        txtprice.Text = NumberToCurrency(txtprice.Text.Replace(",",""))
    End If
   MyGlobalBoolean = False
End If
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Setting the .Text property of the control appears to be recurisively calling the _TextChanged event
The TextChanged event will fire whenever the text changes.

The problem in this code is that it modifies the text even when it is formatted properly. As a general rule, modifying the text in the TextChanged event leads to bad user experience. You should instead change it after the focus shifts to a different view or when the user clicks on the action button.
 
Upvote 0

devmobile

Active Member
Licensed User
The TextChanged event will fire whenever the text changes.

The problem in this code is that it modifies the text even when it is formatted properly. As a general rule, modifying the text in the TextChanged event leads to bad user experience. You should instead change it after the focus shifts to a different view or when the user clicks on the action button.
Yes it is bad experience.
Thanks
 
Upvote 0

devmobile

Active Member
Licensed User
Setting the .Text property of the control appears to be recurisively calling the _TextChanged event, resulting in a stack overflow.

I would set a global variable to indicate we're adjusting the contents then check that variable in the event, something like:
B4X:
If MyGlobalBoolean = False then
   MyGlobalBoolean = True
    If IsNumber(txtprice.Text.Replace(",","")) Then
        txtprice.Text = NumberToCurrency(txtprice.Text.Replace(",",""))
    End If
   MyGlobalBoolean = False
End If
Yes it is good solution
Thanks
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Maybe a bit late, but did you consider regex usage? Something like:
B4X:
Sub edAmount_TextChanged (Old As String, New As String)
   Dim pattern As String
   pattern = "[0-9]+(\.[0-9][0-9])"   'any number of digits, optionally followed by a dot and up to 2 digits
   Dim Matcher1 As Matcher
   Matcher1 = Regex.Matcher(pattern, New)
   If Not(Matcher1.Find) Then New = Old
End Sub

Edit: I tested above code and it didn't work correctly, so I tried something similar but a bit more complex and it seems to work. Here it is:
B4X:
Sub edAmount_TextChanged (Old As String, New As String)
   If Old = New Then Return
   Dim pattern As String
   pattern = "(\d+\.\d{1,2})"  'a few digits followed by a dot and 1 or 2 digits more
   Dim Matcher1 As Matcher
   Matcher1 = Regex.Matcher(pattern, New)
   If Not(Matcher1.Find) Then
     New = Old
     Return
   Else
     New = Matcher1.Group(0)
     Old = New
     edAmount.Text = New
     edAmount.SelectionStart =edImporto.Text.Length
   End If
End Sub

Note: adjust the pattern to suite your needs.


udg
 
Last edited:
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
The TextChanged event will fire whenever the text changes.

The problem in this code is that it modifies the text even when it is formatted properly. As a general rule, modifying the text in the TextChanged event leads to bad user experience. You should instead change it after the focus shifts to a different view or when the user clicks on the action button.

In some cases, I use a timer that fires a certain time after the text was changed. The timer does the formatting, so as long as the user types, the timer gets restarted before it has a chance to fire and nothing happens, but once the user stops typing for a second or two (set by the timer value), the timer_tick event fires and the box is reformatted. It avoids the problem above (modifying the text within the TextChanged event itself causing a loop) but does not wait for any other action to reformat the data.

I have used that method under Visual Basic for Windows for a long time.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
I have used that method under Visual Basic for Windows for a long time.
B4A (and even Android) is not Visual Basic for Windows.

You (resp. the TO) need to change the code to match the Android-Rules.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
As I see it the main issue with modifying the text in TextChanged is not the recursive loop. This can be solved by making sure that the code doesn't change the programmatically set text (which should already be formatted). The problem is that it can be annoying to the user:
1. The cursor will jump to a different location when the new text is set.
2. It is expected that the text will not always be valid. It should only be valid once the user completed writing it. So trying to format the intermediate text just makes it more difficult for the user to correct it.

There are cases where it is valid, for example if you want to limit the text length.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
As I see it the main issue with modifying the text in TextChanged is not the recursive loop. This can be solved by making sure that the code doesn't change the programmatically set text (which should already be formatted). The problem is that it can be annoying to the user:
1. The cursor will jump to a different location when the new text is set.

Yes, so I set the timer to a value long enough that I have reasonable confidence the user is finished entering all the data. Usually a couple of seconds is long enough.

2. It is expected that the text will not always be valid. It should only be valid once the user completed writing it. So trying to format the intermediate text just makes it more difficult for the user to correct it.

There are cases where it is valid, for example if you want to limit the text length.

That's a good point. There again, the timer avoids the checking routine getting in the way.

I have included a short example showing how it works. I included the IME library to close the keypad when the field is corrected and a Toastmessage when the field is not a number.

Be kind, this is my first upload :)
 

Attachments

  • TextChangedTimer.zip
    8 KB · Views: 445
Upvote 0
Top