Page 1 of 1
Messaging Question
Posted: Sat Dec 03, 2011 9:01 pm
by tjm167us
Good afternoon everyone!
This is my first time on the LiveCode forums, but I am running into a problem I was hoping to get some help with. Because I may be WAY overcomplicating my problem, I will start by explaining what I'm trying to do, and then get to my actual question. For my application, I require my text fields to add formatting characters, and to also limit user input to specific things (like numbers, and "." for decimals) all as the user is inputting data into the text field. The following are the input requirements of my currency text fields:
In real time, limit the characters the user enters to be numbers or a decimal point.
The decimal point should only be added if the field is not empty, or if there is a decimal point already present.
Limit the user to adding a maximum of 2 characters after a decimal point is inserted.
Further, there are the '$' and ',' formatting characters that are programmatically added AS the user is entering the number. The ',' is to be added for readability (ex. 123456 --> 123,456 or 1234567 --> 1,234,567).
Now, my goal is to do this in a way that leverages the wonderful built-in default behaviors the RunRev developers have added. For example, I want to avoid updating the text field using a 'put' command when after determining theKey that the user pressed is valid if I could just pass the message along through the hierarchy.
So, now for my problem: I'm properly inhibiting incorrect button presses from the user (not passing the message if the above conditions aren't met) by checkingForValidInput in my keyDown handler for the text field. The code looks something like:
on keyDown TheKey
if(checkForValidKeyPress("MyField", TheKey) = true) then
pass keyDown
else
beep
end if
end keyDown
The formatting characters are dealt with in the keyUp handler for the text field (because by that point the previous valid key press has been entered in the text field. I properly strip off the old commas, determine the location of the new commas, and all I have left is adding my formatting characters. Now, I have written a routine to update the field WHILE maintaining the correct position of the insertion point (blinking cursor). However, writing the code to properly locate the cursor after I add/remove the formatting characters got me thinking: Why would I go through the hassle of writing that code, when the RunRev developers have done a beautiful job implementing this for me for key presses?
So, in my keyUp handler, after figuring out where to add my formatting characters, I send a message to the keyDown handler with the character I wish to add as a parameter. In code,
on keyUp
--Find the location to add a formatting character
--Add the character
call "keyDown ','"
end keyUp
I find my code properly calling the keyDown routine, and passing the message along in the hierarchy, but the text field not updating with the new formatting character. Can anyone help me figure out why?
Thanks for taking the time to ready my ridiculously long inquiry!
-Tom
Re: Messaging Question
Posted: Sat Dec 03, 2011 11:13 pm
by bn
Hi Tom,
welcome to the forum.
I find my code properly calling the keyDown routine, and passing the message along in the hierarchy, but the text field not updating with the new formatting character. Can anyone help me figure out why?
I see the same thing, the message watcher shows the message but no input into the field. I can not explain why but guess it is because only keyboard input really triggers the characters to come through.
But I would not go that route anyways because you would have to be careful of recursion.
If you want to trigger a true keydown message you would use the type command
But there is nothing wrong and a lot right about "putting" your character into the place you deem fit. That is what I would do.
In most other instances your technique of calling a handler / function with a parameter is definitely the way to go.
Kind regards
Bernd
Re: Messaging Question
Posted: Fri Dec 09, 2011 12:35 am
by tjm167us
Bernd, Thanks for the reply!
I went ahead and took your advice, and controlled the location of the insertion point myself.
My text field is now formatting as it should (in realtime), and I want to do cleanup in the textfield after the user is done entering stuff in the text field.
By cleanup I mean:
If the user enters $123, $123., or $123.1, and then clicked out of the text field, the text field should change to $123.00, $123.00, and $123.10, respectively.
By "after the user is done entering stuff" I mean:
The user clicks out of the text field or tabs out.
I have tried exitField and closeField, but they don't seem to work the way I expect them to. Can anyone provide me with a message handler that would work this way?
Thanks,
Tom
Re: Messaging Question
Posted: Fri Dec 09, 2011 1:17 am
by mwieder
they don't seem to work the way I expect them to.
What are you expecting to happen? The closeField handler *should* trigger when you move to a different field, and then your code should execute. There are a few exceptions, mostly os-specific, as when moving to a different app, but are you expecting something else? What's not working? Where do you have your closeField handler located?
Re: Messaging Question
Posted: Fri Dec 09, 2011 3:32 pm
by tjm167us
mwieder wrote:they don't seem to work the way I expect them to.
What are you expecting to happen?
I expect the text field to be cleaned up in the manner I described. I located the clean up code in the closeField handler of the text field (although, it will eventually be put into my text formatting library). When I test my code by forcing the closeField handler to be executed, I find that for all possible input types ($123, $123., $123.1, $123.15), my code does what it is supposed to. Please see the code below:
on closeField
put "MyField" into FieldName
--Make the number in the text field end with .XX where XX is 00 if the user didn't enter a decimal point
put offset(".", field FieldName) into tPeriodOffset
put the length of field FieldName into tFieldLength
put empty into tCharsToAdd
switch
case tPeriodOffset = 0
put ".00" into tCharsToAdd
break
case (tFieldLength - tPeriodOffset) = 0
put "00" into tCharsToAdd
break
case (tFieldLength - tPeriodOffset) = 1
put "0" into tCharsToAdd
break
end switch
if not(tCharsToAdd is empty) then
put tCharsToAdd after field FieldName
end if
end closeField
I also expect this to be done when the user stops editing the text field. As of this morning, despite my code working properly when I force the handler to be executed, the handler isn't called when I:
a) Click out of the text field by clicking the card
b) Click out of the text field by clicking the tool palette within livecode
c) Tab out of the text field into a new text field
That is why I concluded that I must be using the wrong handler...
Thanks for any help, because I'm stumped.
Tom
Re: Messaging Question
Posted: Fri Dec 09, 2011 7:09 pm
by bn
Hi Tom,
I tested your code when I put it into the script of a field I called "myField" and also if I put your code into the script of the card where the field "myField" is (instead of the field script).
It worked perfectly in both places.
And in all 3 conditions you listed:
a) Click out of the text field by clicking the card
b) Click out of the text field by clicking the tool palette within livecode
c) Tab out of the text field into a new text field
I would place the code into the field script. Or else if you want to place it higher in the message path (like in the card script) provide a way to bail out of the code if another field sends a "closeField" message.
Where did you place the script?
Kind regards
Bernd
Re: Messaging Question
Posted: Fri Dec 09, 2011 7:27 pm
by tjm167us
Bernd,
I was about to post an update and am glad you responded! At lunch, I tested the code I posted on another computer, and it also worked fine... Can you think of any reason why my closeField handler would not be working properly on my computer, but work fine on others?! The code I wrote I put in the field script, like you recommended. What the heck!
Tom
Re: Messaging Question
Posted: Fri Dec 09, 2011 7:37 pm
by bn
Hi Tom,
I have no idea why your code works on one computer and not on another. What is the difference between the two?
What I would do is to make a new stack with just the field "myField" and your scripts in that field and see if it works on your computer. Was it the exact same stack you tested on the two computers?
In theorie there could be something intercepting the closefield message (fronscript, maybe plugin) that is why I would test it on a new stack. But actually I have no idea.
Kind regards
Bernd
Re: Messaging Question
Posted: Fri Dec 09, 2011 7:47 pm
by tjm167us
My code is organized the following way:
In my text field:
Code: Select all
on keyDown theKey
--Do real time determination of valid key presses
if (checkForValidInput "MyField", theKey, "Currency" = true) then
pass keyDown
else
beep
end if
end keyDown
on rawKeyUp
--Do real time formatting (add '$' and commas for readability)
formatTextField "MyField", "Currency"
end rawKeyUp
on closeField
--Clean up decimal formatting ($123, $123. --> $123.00 and $123.2 --> $123.20)
tjm167us wrote:put "MyField" into FieldName
--Make the number in the text field end with .XX where XX is 00 if the user didn't enter a decimal point
put offset(".", field FieldName) into tPeriodOffset
put the length of field FieldName into tFieldLength
put empty into tCharsToAdd
switch
case tPeriodOffset = 0
put ".00" into tCharsToAdd
break
case (tFieldLength - tPeriodOffset) = 0
put "00" into tCharsToAdd
break
case (tFieldLength - tPeriodOffset) = 1
put "0" into tCharsToAdd
break
end switch
if not(tCharsToAdd is empty) then
put tCharsToAdd after field FieldName
end if
end closeField
checkForValidInput and FormatTextField are located in my FormatTextFieldLib library that I load in on preOpenStack of the whatever application I'm writing.
Can you think of any way my other textfield handlers could be affecting the closeField handler? I can't...
Re: Messaging Question
Posted: Fri Dec 09, 2011 7:58 pm
by bn
Hi Tom,
I don't see anything except of some typos that I think are not really in the code:
on mouseDown theKey -> probably on keyDown theKey
checkForValidKeyPress -> probably checkForValidInput
The easiest would be if you could reproduce the problem in a small stack with just your library handlers in the stack script and your field with scripts. Than you upload a zipped version of the stack to the forum.
Kind regards
Bernd
Re: Messaging Question
Posted: Fri Dec 09, 2011 8:15 pm
by tjm167us
Bernd,
It looks like I'll need to do a little of investigation and get back to you-- I'll repost my findings after I have a little more time to systematically identify the problem. Thanks for taking the time to help - You're awesome!
If anyone else has had a problem similar to this, please pipe up. Meanwhile, it's debugging time!
Tom
Re: Messaging Question
Posted: Fri Dec 09, 2011 8:24 pm
by mwieder
Tom-
Might depend on what your library routines are doing. The closeField message is sent if there's a change in the contents of the field. If your library routines are formatting the field and then you don't do anything else to change the contents of the field after that, the closeField message probably won't be triggered, i.e., just a tab won't do it. If that's the case, you might try trapping the tab char in your rawKeyUp handler and see if you can trigger the closeField message that way.
Re: Messaging Question
Posted: Sun Dec 11, 2011 6:51 pm
by tjm167us
All, I found my problem, and it is what mwieder alluded to. One of the functions I have in my library adds formatting characters while preserving the location of the insertion point (cursor). The function is executed after EVERY key press a user makes. The closeField handler is called when the textField loses focus AND the contents have changed. The Live Code documentation covers this with the following comments in the dictionary entry for closeField:
The closeField message is not sent when a handler changes the field's contents using the put command.
If a field is closing and its contents have not changed, the exitField message is sent instead of closeField.
In one of my earlier posts I mentioned that NEITHER the exitField or closeField were behaving as I was expecting, but I think I was just confused. Because I know a handler is always going to be called after a change to the text field is made by the user, adding an exitField handler to my text field will cause the code to be executed!
If there were any instances where only the user changes something, I would need to also put the code in the closeField to make it work properly.
Thanks mwieder and Bernd for the help,
Tom
Re: Messaging Question
Posted: Sun Dec 11, 2011 7:17 pm
by bn
Hi Tom,
glad you found the cause of this. I didn't think of this, only after Mark mentioned it. I have to admit I always mix-up closeField, exitField, focusOut...
If you want to execute your script that is inside the "on exitField" handler also on "closeField" you could just say:
Code: Select all
on closeField
exitField
end closeField
if they are both in the field script then a closeField message would trigger your script in the exitField handler.
Kind regards
Bernd