TextField Mask

Hi
I’m using a mask ###,### on a textfield - but when enter digits the result is only the left 3 digits - other digits are ignored. I didn’t expect this behaviour…

Simple code is:

[code]Sub Open() Handles Open
me.validationmask = “###,###”
End Sub

Sub TextChange() Handles TextChange
Dim v As Double = Val(Me.value)
TextField2.value = Str(v)
End Sub
[/code]

that is to be expected… you type in 123456 and the mask makes it 123,456
the “,” is not a numeric digit so VAL stops at that point… same as if it were 123X456

Ah, so I have to do a replaceAll to get back to the numeric value…

Note that Val https://documentation.xojo.com/api/text/val.html always uses English/US notation, where the comma is a thousands separator (but, oddly, Val doesn’t handle that speicifc case).

If you want locale-specific number conversion and the comma is a decimal separator, then use CDbl https://documentation.xojo.com/api/deprecated/cdbl.html

Good advice about cdbl here, but I just want to point out that it’s not odd that Val has stopped on the non-numeric character. This behavior is documented. You should use cdbl for user input values! (also documented)

[quote]It is important to note that Val’ does not take separator characters into consideration. For example:
Dim d As Double
d = Val(“10,000.95”) // The “,” causes the string to stop being converted[/quote]

Good advice is to read the manual! :slight_smile:
So I see that CDbl is deprecated - use string.toDouble instead.

But now how do I get a textField to show data input with thousands separators, and with +/- with user input?
All the options seem to format the numbers in the wrong direction - left to right rather than right to left - so you end up with strange looking numbers (unless you are German) like 123,66

I’ve tried the manual but it doesn’t seem to give me what I want.

Are you taking input from one field and putting into a second field which is masked?

no, I’m simply trying to get numeric input formatted as it is entered, just like it is on a calculator.

Take out the part of TextChange where it sets it’s own value. Mask should be adding the comma in.

Text change isn’t changing its own value - in the example I’m simply taking it from textField1 (masked) to textField2 (unmasked).

Oh, my mistake. However, setting the Mask value as you have is working as expected here, where the comma is being added automatically. I’ve just tested and confirmed this in API 1 and 2019r1.1. I would hope it’s not related to API 2.0

So updating my code to this:

Sub Open() Handles Open me.validationmask = "###,###" End Sub Sub TextChange() Handles TextChange Dim v As Double = Me.value.ToDouble TextField2.value = Str(v) End Sub

Gives me output that looks like this (in 2019r.2.1) for entry of 5 8’s.
888,88

Ah, yes, that’s because it’s simple string validation. It’s working as expected. I think I get what you’re trying to do now.

The general idea of what you’ll want to do is write a method that takes the text field’s value, uses cdbl to get a double, use Format to get the correctly formatted string you’re looking for, then compare the string value to the original text field string value. Check that the value is different before setting text field value. If you always set the value you’ll get an event overflow.

That’ll take numbers and format them, but I’m thinking there might be issues with text entry carat positioning, so you may need to experiment with changing SelStart so the field functions as expected while typing. I may be able to try my hand at an implementation later today.

Technically, Cdbl is deprecated, so assuming you’re working in 2019R2 or later you might want to use its direct replacement String.ToDouble or you could use Double.FromString. I would go with Double.FromString since you could manage the locale of the conversion.

Then use Double.ToString where you again control the locale to update your second text field.

OK, I think I am close to the answer to my question.

Sub TextChange() Handles TextChange me.value = Me.value.ToDouble.ToString(locale.Current, ",") End Sub

This reformats the input to 88,888, but now trying to handle decimal points or +/- signs - ugly!

[quote=464658:@James Pitchford]Sub TextChange() Handles TextChange me.value = Me.value.ToDouble.ToString(locale.Current, ",") End Sub [/quote]

What is it that you’re trying to do here? I’m confused because it looks like you’re trying to format the text input, which is what TextField.Mask does.

He’s trying to format the input so that the separator is how a person would write it. The string based Mask function is working as expected, but doesn’t parse numbers on the fly the way a human might.

I was simply trying to recreate a calculator style input of numbers, formatted with 000’s commas, +/- and decimal places, allowing for any type of number to be input by the user. I was somewhat surprised that it wasn’t a standard format for textEdit.

TextField mask unfortunately seems to work on text input, rather than numeric input.

E.g. entering -1001000.876 should should show -1,001,000.876 and build correctly from right to left.

I create a string property called StringFormat in a subclassed textfield. StringFormat contains the mask I wish to apply on the LostFocus event. I’ve added StringFormat to control’s inspector.

Sub LostFocus() Handles LostFocus // apply the format, if any, when we leave the field If StringFormat <> "" and me.Text.IsNotEmpty then me.Format = StringFormat else me.Format = "" End If RaiseEvent LostFocus End Sub

I was asking because I noticed the subject of his TextChanged event changed from updating the value in a new textfield to the current one.

Maybe something along the lines of this:

Try Dim Input As String = Me.Value Dim arrInput() As String = Input.Split( "." ) If arrInput.LastRowIndex > 1 Then //You have an error Return End If Dim d As Double = Double.FromString( arrInput( 0 ), Locale.Current ) Dim s As String = d.ToString( Locale.Current, "," ) arrInput( 0 ) = s Dim output As String = Join( arrInput, "." ) If output <> Input Then Me.Value = output End If Catch e As InvalidArgumentException //Handle nonnumerics or other input problems here End Try

You’d have to control for the user entering commas and decimals in the wrong place, but this would format appropriately entered numbers. I’m sure this could be optimized and you could use RegEx if you have MBS’s plugins but I’m not sure it would be faster with Xojo’s built in RegEx engine.