How can I restrict a users input to be only numeric (allowing decimals) when typing into certain fields in a desktop application?
~Roger
How can I restrict a users input to be only numeric (allowing decimals) when typing into certain fields in a desktop application?
~Roger
Note that Ben's answer doesn't cover every case
You can do all those with
local sExisting
on openfield
put the text of me into sExisting
end openfield
on textChanged
put the selectedText && sExisting && the text of me into msg
if the text of me is a number or me is empty then
put the text of me into sExisting
else
put sExisting into me
end if
end textChanged
NB - if you type an invalid character, the input cursor is moved to the start of the line; if you want to do anything different then you can lockscreen (as the first action in 'textChanged') and unlock when you are done.
A keydown message is sent to your field everytime a user presses a key:
on keydown pKey
-- check the input --
-- pass on the keydown message --
end keydown
Add the following code to check that the key typed is a number of a "." and that the field doesn't already contain a ".":
on keydown pKey
if pKey is a number then
pass keydown
else if pKey is "." then
set the itemdel to "."
if the number of items of me < 2 then
pass keydown
end if
end if
end keydown
Alex, I like your your script, but it doesn't cover every case also. It's not working if you want to type negative number (if you start with "-" sign in empty field). So below is corrected script, I hope this time cover every case, but it losing selection if you type not allowed character (something to do there yet).
local sExisting, sSelected
on openfield
put the text of me into sExisting
end openfield
on textChanged
--put the selectedText && sExisting && the text of me into msg
put the selectedChunk into sSelected
if the text of me is a number or me is empty or me is "-" then
put the text of me into sExisting
else
put sExisting into me
end if
select sSelected
end textChanged
I found it was easier and probably better to add this as a separate answer than to edit my earlier one. This takes Marek's improvement, adds one more case of leading "." and also allows leading and trailing blank spaces generally, rather than only after a number has been typed.
It also restores the selection / insertion point after a failed attempt to type or paste additional characters (selection can't be fully restored, but the insertion point should always finish up immediately after any previous selection.
Note that we are definitely trading off ease of understanding for more completeness ...
We still do not fully cover the case of inserting scientific notation (e.g. 1.2e34) becuae in that case the final value is valid but one of the intervening states (1.2e) is not.
local sExisting
on openfield
put the text of me into sExisting
end openfield
on textChanged
local tMe, tChunk, tDeltaLength, tWhere
put the selectedChunk of me into tChunk
put word 1 to -1 of the text of me into tMe -- strip leading/trailing spaces
if tMe is a number or tMe = "-" or tMe = "." or tMe is empty then
put the text of me into sExisting
else
-- calculate how many characters were inserted,
-- and move the insertion point back to there
put the number of chars in me - the number of chars in sExisting into tDeltaLength
put sExisting into me
put word 4 of tChunk - tDeltaLength into tWhere
put tWhere into word 4 of tChunk
put tWhere into word 2 of tChunk
do ("select after " & tChunk & " of me")
end if
end textChanged
How about using "is a number"? The only special case is that you need to allow for "-" at the beginning:
on KeyDown theKey
if (the text of me & theKey) is a number then
pass keyDown
else if the text of me is empty and theKey is "-" then
pass keyDown
end if
end KeyDown
Alex,
Your script doesn't work properly if:
Please check this:
local sExisting, sSelected, sSelected1
on openField
put the text of me into sExisting
end openField
on selectionChanged
put the selectedChunk into sSelected1
put "sSelected1: " & sSelected1 into line 1 of msg
end selectionChanged
on arrowKey
send "selectionChanged" to me in 0
pass arrowKey
end arrowKey
on textChanged
local tMinus, tDot
put empty into tDot
put empty into tMinus
--
put the selectedChunk into sSelected
put "sSelected: " & sSelected into line 2 of msg
--
get matchChunk (me, "^(-?)[0-9]*(\.)?([0-9]*)$", tMinus, tMinus, tDot, tDot)
if it then
switch tDot
case 2
if tMinus = 1 then put "-0." & char 3 to -1 of me into me
put (word 2 of sSelected) + 1 into word 2 of sSelected
put (word 4 of sSelected) + 1 into word 4 of sSelected
break
case 1
put "0." & char 2 to -1 of me into me
put (word 2 of sSelected) + 1 into word 2 of sSelected
put (word 4 of sSelected) + 1 into word 4 of sSelected
break
default
end switch
send "selectionChanged" to me in 0
put me into sExisting
else
if not (me is empty) then
put sExisting into me
put sSelected1 into sSelected
end if
end if
select sSelected
end textChanged
It's probably not perfect, but selection after paste and any character typing (even not allowed) should be correct. You can start typing with "-" or "." also, with "autocorrection" - if you type ".34" or "-.34" you will be corrected to "0.34" or "-0.34".
You can change cursor position by arrows and after paste not allowed string it doesn't change the cursor position. After paste proper string, new cursor position is at the end of pasted string.
Known fault I don't like there is missing remove leading zeros (and maybe trailing also should be removed).
Please let me know if you find some errors, so I'll try to repair it (with my pleasure). The script is little bit long, yesterday I have seen some bug, but will have not time in next few days so decided to put it there to play by somebody.
This is actually trickier than it looks. But this works:
on keyDown pKey
if pKey = "-" and me <> "" then exit keyDown
if pKey = "." and "." is in me then exit keyDown
if pKey is in "-0123456789." then pass keydown
end keyDown
this can also work:
on KeyDown pKey if pKey is among the characters of "0123456789." and (the length of me) < 15 then pass keyDown end Keydown