ActionScript 3.0 TextField Style and Event gotchas
Yesterday I ported some experimental syntax tree code I’d written in C# over to Flash and ActionScript. It’s a tribute of the richness of ActionScript 3.0 that such code could be ported so easily.
To test the code out I needed to be able to input text. No worries. Add a TextField.
It’d been a while since I’d done this in ActionScript, and I hit a couple of “noob” gotchas that can even get an old dog like this one. So in case you’ve hit the same problems, and are being misled by the documentation, here are a couple of pointers…
GOTCHA #1: TextField Styling
Problem
setTextFormat() doesn’t seem to work no matter what you try!
Solution
Assign to the defaultTextFormat property instead of calling the setTextFormat() method.
Discussion
It’s a common scenario, you want to change the font, point size or text colour in your input text field. You’d think it’d be intuitive. It can be done with css and all sorts of fangled HTML methods, But you just want to change the font in the simplest possible way. You refer to the docs. They helpfully instruct you that:
The following example applies one TextFormat object to an entire TextField object and applies a second TextFormat object to a range of text within that TextField object:
var tf:TextField = new TextField(); tf.text = "Hello Hello"; var format1:TextFormat = new TextFormat(); format1.color = 0xFF0000; var format2:TextFormat = new TextFormat(); format2.font = "Courier"; tf.setTextFormat(format1); var startRange:uint = 6; tf.setTextFormat(format2, startRange); addChild(tf);
Looks straightforward enough doesn’t it? But, whilst the docs aren’t technically wrong, there’s a lot they’re not telling you.
setTextFormat() sets the format for the text or a range of text already in the TextField. However, if you have a TextField whose type is TextFieldType.INPUT or you want to dynamically update the TextField, then the format set by setTextFormat won’t apply to the changed text. If you want all future text within a TextField to be styled, then what you need to do is set the defaultTextFormat for the TextField.
Once you realise your noobish error you immediately change your code:
var format1:TextFormat = new TextFormat(); format1.color = 0xFF0000; tf.defaultTextFormat(format1);
Only this doesn’t work. The interface Adobe have created for TextFields is a little inconsistent. setTextFormat() is a method, but defaultTextFormat is a property. So, the correct code is:
var format1:TextFormat = new TextFormat(); format1.color = 0xFF0000; tf.defaultTextFormat = format1;
Conclusion
I’d wager that 9 times out of 10 setting the default format for the TextField is your intention rather than just performing a one-off styling of a section of text. This snippet should be the first thing they put in the Formatting Text section of the ActionScript reference docs.
GOTCHA #2: TextField OnChanged Event Handling
Problem
You’ve followed the docs and have set up an event Handler to handle whenever a user changes the text in their TextField. However, inside the handler, the TextField.text is missing the last character entered.
Solution
Instead of adding a TextEvent.TEXT_INPUT event handler, use the more general Event.CHANGE handler.
Discussion
It’s pretty common to want to respond to the user entering input as they type. Say you want to have the text that the user has entered appear elsewhere as they’re typing it. You want to add an event handler that gets called every time the user inputs text, and within the handler access the TextField’s text property, and assign the same text to another TextField. Simple? Should be, but the helpful docs are lacking again. They say:
By default, a text field’s type property is set to dynamic. If you set the type property to input using the TextFieldType class, you can collect user input and save the value for use in other parts of your application. Input text fields are useful for forms and any application that wants the user to define a text value for use elsewhere in the program.
For example, the following code creates an input text field called myTextBox. As the user enters text in the field, the textInput event is triggered. An event handler called textInputCapture captures the string of text entered and assigns it a variable. Flash Player or AIR displays the new text in another text field, called myOutputBox.
package { import flash.display.Sprite; import flash.display.Stage; import flash.text.*; import flash.events.*; public class CaptureUserInput extends Sprite { private var myTextBox:TextField = new TextField(); private var myOutputBox:TextField = new TextField(); private var myText:String = "Type your text here."; public function CaptureUserInput() { captureText(); } public function captureText():void { myTextBox.type = TextFieldType.INPUT; myTextBox.background = true; addChild(myTextBox); myTextBox.text = myText; myTextBox.addEventListener(TextEvent.TEXT_INPUT, textInputCapture); } public function textInputCapture(event:TextEvent):void { var str:String = myTextBox.text; createOutputBox(str); } ...
That enormous example looks like it handles the exact situation we need to solve doesn’t it? It’s perfect except for one serious problem. The TextEvent.TEXT_INPUT event is triggered BEFORE a user’s changes occur to the TextField’s text property. Presumably this is so that you can validate input data and possibly veto it? I don’t know the reason for sure, but I do that 9 times out of 10 this isn’t the behaviour you’re expecting.
The solution is just to not handle the TextEvent.TEXT_INPUT event, but instead handle the general Event.CHANGE event. This event does what you’d expect. The TextField.text property reflects the current state of the text control after the user makes a change to it.
myTextBox.addEventListener(Event.CHANGE, textInputCapture);
Summary
These scenarios are common activities when working with Flash. Both of them are made more confusing by inadequate documentation: The more common use-cases aren’t given in the docs, and the examples given seem to be authoritative explanations of how things work, when they don’t clearly explain the nuances. Of course, if you’re an experienced Flash hacker these quirks will be second nature, but if you’re reading this article there’s a good chance you’ve hit the exact same snags, either as a noob to ActionScript 3.0, or because you’ve had a hiatus from Flash development like I have.
Hope this has helped someone!
Thanks for the post. I don’t know actionscript very well and had just been struggling with your gotcha #2, then I found this post.
It might be worth mentioning that if you handle the Event.CHANGE event, you’ll also need to change textInputCapture’s argument type to be Event instead of TextEvent, in order for Adobe’s example to work.
I know that probably goes without saying for most actionscript folks, but if you’re a beginner like me and you’re tripping over this stuff, maybe it’ll help.