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