Figured Out 1009 Error with Focus Manager
Resolving Error 1009 with Focus Manager in Actionscript 3
The FocusManager class allows custom focus management for all display objects that impliment the fl.managers.IFocusManagerComponent interface. This includes text fields, and a few additional display object classes. There is one caveat with the focus manager class. You must pass the constructor a display object that exists on the stage when you call it. If the display object like a movie clip on which you want to control focus has not been instantiated on the stage (i.e. added to the display list) using the addChild, or addChildAt method, the FocusManager constructor returns a 1009 Error stating you are passing the constructor a null parameter. It is null because it is not yet part of the display list. I kept running into this 1009 error and it took me a while to figure it out so I thought I would share.
Setting up custom focus management on a movie clip at run time.
You can also set up focusManagement for a movie in a custom class definition file. Remember that movie clips in AS 3 all have a class definition of movie clip. You can customize any movie clip you have in the library by creating a custom .as and declaring your custom .as file as the class definition for the movie clip using the properties panel. The only requirement is that your custom .as class file must extend the MovieClip class. One nice thing is that you can also use the childAdded or addedToStage event within your extended class definition to determine when the movie clip has been added to the stage and then create a FocusManager as a custom property on the extended movie clip class. Here is an example:
You add a movie clip to your library in your main .fla file. In the linkage menu name the symbol "CustomMovie". Add two text fields in the movie clip. In the properties panel make sure they are of type "Input Text" and name the instances on in your movie clip "txtBoxOne" and "txtBoxTwo" respectively so you can use them in your actionscript file. You may want to put a border on these in the properties panel so you can easily see them on the stage when you run the movie. Write a custom class file that extends the movie clip we just put in the library. Go to file and open and start a new actionscript 3.0 file. We will use this file to create a custom class definition for our new "CustomMovie" movie clip that we just put in our library. This file should be saved in the same folder as your .fla file.
package{
import flash.display.MovieClip;
import fl.managers.FocusManager;
import flash.text.TextField;
public class CustomMovie extends MovieClip
{
private var thisFocusManager:FocusManager;
private var txtBoxOneProperty: TextField;
private var txtBoxTwoProperty:TextField;
public function CustomMovie extends MovieClip()
{
/*
Add and event listener to the class instance to call a handler function when this
Movie clip instance is added to the stage
*/
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
/*
Two text fields are already added to the movie clip in your library, but we need to be able to refer to them in our class definition so we set up private properties here called "txtBoxOneProperty" and "txtBoxTwoProperty and we point these to the text fields we created on the stage. You could just refer to them by using the path reference this.txtBoxOne for example, but then you don't get any code hinting when you refer to them in your class definition.
*/
this. txtBoxOneProperty = this.txtBoxOne;
this. txtBoxOneProperty.tabIndex = 1;
this.txtBoxTwoProperty = this.txtBoxTwo;
this. txtBoxTwoProperty.tabIndex = 2;
}
private function addedToStageHandler (e:Event)
{
trace("Event Type: " + e.type + " Event Target: " + e.target);
thisFocusManager = new FocusManager(this);
thisFocusManager.setFocus(txtBoxOneProperty);
trace(thisFocusManager.getFocus());
}
}
}
Save this file in the same folder as your .fla file and call it CustomMove.as. This is your custom class definition that we will use for the CustomMovie clip in the library. You have to tell Flash that you want to use the CustomMovie.as file we created as the class definition for your movie clip in your library. Go back to your .fla file and open the properties for the CustomMovie clip in your library. You can right click and choose properties. Leave the base class as flash.display.MovieClip. In the Class box type in CustomMovie. Don't add the .as extension. Flash knows it is a .as file. You custom class file can be in any location, but if you put it some place other than the folder where your main .fla file resides you have to modify the path in the Class box, and you have to modify the path in your package declaration in the CustomMovie.as file. For simplicity we are putting our CustomMovie.as file in the same folder as our main .fla file so just type in CustomMovie. Make sure you check "export for Actionscript" and "Export in first frame".
Now the last thing to do is to tell the main .fla file to add your new CustomMovie clip to the stage.
In the main .fla file create a new layer and name it actions. Select the first frame of the new layer and from the Window Menu select Actions. In the actions panel type the following:
/*This creates instance of movie in library but in actionscript 3 all movies are classes so you have to use the new key word with the constructor like when you instantiate objects
*/
var myCustomMovie:MovieClip = new CustomMovie();
//Now add it to the display list
addChild(CustomMovie);
Now save your .fla file and run it by pressing Control Enter or Debug/Debug Movie. What you say? You got an error?
1046: Type was not found or was not a compile-time constant: FocusManager.
I got this too. I solved it by adding a component to my library. Any component will work. I just added a button. I am not sure what this is adding to the file, but it is apparently adding some class that is required and that we failed to import in any of our other files. I tried a bunch like UIComponent, InteractiveObject etc, but I can't seem to determine what it is. The FocusManager inherits directly from the Object class so beats me, but it works if you have any component in your library at all.
Once you add a component to the library and run it you should see the two text boxes you placed on the stage and a cursor should be blinking in the one you named txtBoxOne. You should also get two trace statements as follows:
Event type: addedToStage Event target: [object CustomMovie]
current focus [object TextField]
Now try tabbing through the text boxes and you will see they tab back and forth. You will also see that when the movie clip is instantiated the focus is set to txtBoxOne. Wow big deal. Well it was for me. I spent a long time trying to understand why this didn't work. Although this example is simple the trace statements clearly show that the FocusManager has been created and that focus controls are working to set focus on the component I want as soon as the movie clip instance is added to the stage. I haven't said anything about the tabIndex property on the text boxes. This is important because when you set a tab index for even one interactive component on the stage, in this case the text fields, all default tabbing is disabled so you have full custom control over both your tab order and your focus management for a given movie clip as soon as you instantiate it on the stage. If you have any interactive components that you don't want in the tab list just set the tabEnabled property equal to false for that component like
txtBoxOneProperty.tabEnabled = false;
Hope that helps.
Last edited by ggerstein; 01-09-2008 at 07:02 PM.
|