Sizing in the IDE pt.1

To kick it all off I thought I’d post some information about getting your component to size properly in the IDE when you use the Free Transform Tool (Q key). Now components don’t really like transforms so we’ll leave that till later on, but we will deal with setting the component to the correct size when you use the transform tool….

For the sake of this example I am going to extend the ExampleBox component from UIComponent – although we won’t be utilizing any of UIComponents main properties or methods at this time. Below you can see the component class in its entirety

/*
*	@package:	com.flashgen.examples.components
*	@component:	ExampleBox
*	@author:	Mike Jones
*	@url:					http://www.flashgen.com
*	@email:	mikej@flashgen.com
*
*	@version:	1.0
*	@summary:	A component to illustrate the ability to size the component correctly via
*			the Free Transform Tool (Q key) in the Flash IDE.
*
*	@license:	Released under the GNU PUBLIC LICENSE (GPL)
*/
 
import mx.core.UIComponent;
 
class com.flashgen.examples.components.ExampleBox extends UIComponent
{
// Components must declare these to be proper
// components in the components framework.
public static var symbolName:String = "ExampleBox";
public static var symbolOwner:Object = com.flashgen.examples.components.ExampleBox;
public var className:String = "ExampleBox";
 
private var boundingBox_mc:MovieClip;
private var _resizeableSquare:MovieClip;
 
private var _lineStart, _lineEnd:Number = 0;
private var _lineWeight	:Number = 2;
private var _lineColor:Number = 0x000000;
private var _lineAlpha:Number = 100;
 
private function init():Void
{
super.init();
useHandCursor = false;
boundingBox_mc._visible = false;
boundingBox_mc._width = 0;
boundingBox_mc._height = 0;
}
 
private function createChildren():Void
{
_resizeableSquare = createEmptyMovieClip('_resizeableSquare', getNextHighestDepth());
}
 
/**
*	The size method is invoked when the component's size
*	changes. This is an opportunity to resize the children,
*	and the graphics / components it contains.
*/
private function size():Void
{
invalidate();
}
 
/**
*	This is an overridden method so we can have a finer control
*	over what we need to trigger on an invalidate() call.
*/
private function draw() :Void
{
var w:Number = this._lineWeight;
var c:Number = this._lineColor;
var a:Number = this._lineAlpha;
var lx:Number = this._lineStart;
var ly:Number = this._lineEnd;
var lw:Number = this.width;
var lh:Number = this.height;
 
var rs:MovieClip = this._resizeableSquare;
 
rs.clear();
 
with(rs)
{
lineStyle(w, c, a);
moveTo(lx, ly);
lineTo(lx, lh);
lineTo(lw, lh);
lineTo(lw, ly);
lineTo(lx, ly);
}
}
}

So what does all of this actually do in our component, well lets start at the top. Here we have our declared variables, note they are almost all private, except the top three, these are used in the component framework as well as our toString() method at the bottom of the class, more on that later on.

// Components must declare these to be proper
// components in the components framework.
public static var symbolName:String = "ExampleBox";
public static var symbolOwner:Object = com.flashgen.examples.components.ExampleBox;
public var className:String = "ExampleBox";
 
private var boundingBox_mc:MovieClip;
private var _resizeableSquare:MovieClip;
 
private var _lineStart, _lineEnd:Number = 0;
private var _lineWeight	:Number = 2;
private var _lineColor:Number = 0x000000;
private var _lineAlpha:Number = 100;

Below those public static variables are our main asset declarations. We’ll talk more about the boundingBox_mc when we get to the actual component clip, but for now you have all the information you need on it.

  • boundingBox_mc – an actual movieClip within the component clip
  • _resizeableSquare – the main visual asset of our component

Below our asset declarations are the internal variables we are going to use to create our ExampleBox, as you may have already worked out from reading the entire class – we’re just going to draw a box that has a black keyline around it. We store these values in our declaration for a few reasons, but primarily it stops us falling into the trap of ‘magic values’, i.e. littering your code with repetative string or numeric values making alteration and maintenance of those initial defaults nye on impossible. As opposed to storing them once in a variable and using that in your methods and processing instead.

private var _lineStart, _lineEnd:Number = 0;
private var _lineWeight	:Number = 2;
private var _lineColor:Number = 0x000000;
private var _lineAlpha:Number = 100;

Now we have our variables declared we can concentrate on our methods. Notice I skipped over the constructor, this is because in most cases you won’t need to add anything to the constructor and can therefore let the compiler create a ‘default’ empty constructor for you. A component has four destinct methods, although not all four are required to be instantiated or overridden unless needed.
The first of these is the init() method. This deals with the initialization of the component and is invoked by the constructor when the component is initialized on the stage. Its sole purpose it to start in motion the creation, management and storage of elements in our component.

The steps most init() methods are generally to call our parents init() method, via super.init(), this sets the values required to allow us to respond to the enabling or disabling of oour component amongst other things. We’ll look at that in another article. Next we set the ‘hand cursor’ so that it doesn’t show when we moe over our component even if there is an area that we can interact with; and finally we set our ‘boundingBox_mc’ movieClip so that its width and height are both zero – effectively hidding it, just to make double sure we set it to invisible too.

private function init():Void
{
super.init();
useHandCursor = false;
boundingBox_mc._visible = false;
boundingBox_mc._width = 0;
boundingBox_mc._height = 0;
}

Next our createChildren() method gets called – now not all components override this method, so have a createChild() method, but we will deal with those at a later date. This method is used to instatiate our visual assets and assign them to our internal variables we declared in the beginning.

private function createChildren():Void
{
_resizeableSquare = createEmptyMovieClip('_resizeableSquare', getNextHighestDepth());
}

As you can see from this method all we are doing is creating an empty movieClip assigning it the same name as our declared variable* we are going to store it in and set its depth via getNextHighestDepth().

* I tend to name instantiated visual elements identically to the variables that will store them so as not to confuse or inadvertedly obfuscate in my code what I am actually interacting with.

Next in the set is the size() method, as its name implies it deals with sizing our component, in all honesty this is only in this specific class to illustrate the methods used in a component, I could have quite easily left it out, however as we are dealing with sizing in this article I thought it pertinent to add it in. As you can see it invokes the invalidate() method which is a public method for initializing a redraw of the component by invoking the draw() method. The size method is very important though when resizing a component within the IDE as it receives a call informing it that the size has altered and updates the components width and height properties, (more on that below).

Finally we have the draw() method, and as size() its function is pretty much self explainatory, this method directly or indirectly deals with the rendering of our assets to the screen and is the last in our chain of component methods that you will use most often. Inside his specific draw() method is where we actually draw our square via the Drawing API, note I have declared a set of function scoped variables that hold the variables that we declared at the top of our class.

/**
*	This is an overridden method so we can have a finer control
*	over what we need to trigger on an invalidate() call.
*/
private function draw() :Void
{
var w:Number = this._lineWeight;
var c:Number = this._lineColor;
var a:Number = this._lineAlpha;
var lx:Number = this._lineStart;
var ly:Number = this._lineEnd;
var lw:Number = this.width;
var lh:Number = this.height;
 
var rs:MovieClip = this._resizeableSquare;
 
rs.clear();
 
with(rs)
{
lineStyle(w, c, a);
moveTo(lx, ly);
lineTo(lx, lh);
lineTo(lw, lh);
lineTo(lw, ly);
lineTo(lx, ly);
}
}
}

I suspect you are thinking that this is a bit overkill, and if you are using MX 2004 then you’d be right it is overkill. However Flash 8 is very hot on visibility of variables and as all of our declared variables are private our new instance of an empty movieClip cannot directly access them as it is a violation of scope. Therefore we pop a copy of them into our locally scoped variables and all is well and we can use them within our movieClip.

The two important properties to look out for here are:

  • this.width, (var lw:Number = this.width;)
  • this.height, (var lh:Number = this.height;)

Now we haven’t seen these properties in our class until now, these values exist based on the ACTUAL size of our ‘boundingBox_mc’ movieClip in our component clip when it is first instanciated. Therefore if we made that clip 100 x 100 in our component then these values would both be 100 also. After this point when we resize the component it takes its new width and height based upon its own new width and height – think of the ‘boundingBox_mc’ as a width and height jump start. So if we set these values in our lineTo code, as we do, when we resize the component our size() method is invoked, storing the new width and height, then fires of a call to the draw() method informing it to redraw making our component size correctly based on the Free Transform Tool size.

Simple really :P

Grab the files here: ExampleBox Component

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *