scale9Grid – When it works and when it does not
I think everyone with some actionscript knowledge tried at some point to use this feature, however ended up dissappointed. Looking on Adobe help won’t help you, because there’s nothing there.
So you kept on receiving the infamous #2004 ArgumentError: “One of the parameters is invalid.”.
You double checked the parameters of the Rectangle object you passed in and the values are within the bounding box of the symbol, but still the error is there.
In this post, I’ll try to bring some light on why sometimes scale9Grid works, and why it fails sometimes.
This article is on AS3 but the principles also apply on AS2 also, only the syntax might deffer.
First of all we should say that scale9Grid property of the flash.display.DisplayObject class receives a flash.geom.Rectangle object. The values of this rectangle must fall within the bounding box of the display object you’re trying to set the property on. The coordinates of the rectangle object are relative to the coordinate system of the display object, and not it’s parent!
Let’s see an example:
We have this Sprite object, mySprite, situated at x=100, y=100, being 200px in width and 200px in height.
We would set the scale9Grid property to a Rectangle object that is situated at x>=0 and y>=0, and let it have it’s width <= 200 and height <= 200. But we must make sure that x+width<=200 and y+height<200, this way we make sure or Rectangle falls within the bounds of the display object.
What we said so far is available on Adobe’s help also. But read forward, because from now on we’ll look at concrete examples of when it works and when it fails.
When it works?!
The scale9Grid will always work correctly when the DisplayObject doesn’t have any other symbols inside it, only graphics. That is, it doesn’t have any children.
Example:
mySprite.graphics.beginFill(0xff0000);
mySprite.graphics.lineStyle(2, 0x00ff00);
mySprite.graphics.drawRoundRect(0, 0, 200, 200, 50);
mySprite.graphics.endFill();
mySprite.x = 100;
mySprite.y = 100;
this.addChild(mySprite);
// Set the x and y of the rectangle bigger than the cornerRadius of our roundedRect,
// otherwise it the corner will look stretched
mySprite.scale9Grid = new Rectangle(60, 60, 100, 100);
// Test the movie with the next line commented and uncommented so you can see
// that event the sprite is resized, the corners keep their shapes
mySprite.width = 400;
Copy and paste the code above into the first frame of a fla file (AS3) and test the app. You should see the rounded rectangle preserves it’s beautiful corners.
It will also always work if the Rectangle that you set will not fall outside the bounds of the graphics object, even if the display object contains other children.
Let’s see an example:
mySprite.graphics.beginFill(0xff0000);
mySprite.graphics.lineStyle(2, 0x00ff00);
mySprite.graphics.drawRoundRect(0, 0, 200, 200, 50);
mySprite.graphics.endFill();
mySprite.x = 100;
mySprite.y = 100;
var mySprite2 : Sprite = new Sprite();
mySprite2.graphics.beginFill(0x0000ff);
mySprite2.graphics.drawRoundRect(0, 0, 50, 50, 20);
mySprite2.graphics.endFill();
mySprite2.x = 80;
mySprite2.y = 80;
mySprite.addChild(mySprite2);
this.addChild(mySprite);
mySprite.scale9Grid = new Rectangle(60, 60, 100, 100);
mySprite.width = 400;
Make note of the of the second Sprite we built, and added it as a child of the first Sprite object.
Now test your movie, with and without resizing the sprite, and notice that scale9Grid apply only to the current display object, and not to it’s children. (the second Sprite is stretched, doesn’t keep it’s rounded corner shape)
If you don’t have any drawings in the graphics object of the display object, but the display object has children, if you try to set the scale9Grid, and you set it right, you won’t get the #2004 error, but as I said above, the scale grid will not apply to the children, they will be stretched, like in the next example:
mySprite.x = 100;
mySprite.y = 100;
var mySprite2 : Sprite = new Sprite();
mySprite2.graphics.beginFill(0x0000ff);
mySprite2.graphics.drawRoundRect(0, 0, 50, 50, 20);
mySprite2.graphics.endFill();
mySprite2.x = 10;
mySprite2.y = 10;
mySprite.addChild(mySprite2);
this.addChild(mySprite);
mySprite.scale9Grid = new Rectangle(35, 35, 10, 10);
mySprite.width = 300;
If you think that setting scale9Grid property on the children will do the trick, that will not work. Like in the next example:
mySprite.x = 100;
mySprite.y = 100;
var mySprite2 : Sprite = new Sprite();
mySprite2.graphics.beginFill(0x0000ff);
mySprite2.graphics.drawRoundRect(0, 0, 50, 50, 20);
mySprite2.graphics.endFill();
// Set scale9Grid on the child
mySprite2.scale9Grid = new Rectangle(25,25, 10, 10);
mySprite2.x = 10;
mySprite2.y = 10;
mySprite.addChild(mySprite2);
this.addChild(mySprite);
mySprite.scale9Grid = new Rectangle(35, 35, 10, 10);
mySprite.width = 300;
When it fails?!
As I said above, if your display object does not have anything in it’s graphics object, setting scale9Grid might not throw the #2004 error, but it will certainly not have the expected result.
It will always fail if you set the rectangle beyond the bounds of the display object.
Like in this example:
mySprite.graphics.beginFill(0xFF0000);
mySprite.graphics.lineStyle(2, 0x00ff00);
mySprite.graphics.drawRoundRect(0, 0, 200, 200, 50);
mySprite.graphics.endFill();
mySprite.x = 100;
mySprite.y = 100;
this.addChild(mySprite);
mySprite.scale9Grid = new Rectangle(60, 60, 150, 150);
mySprite.width = 300;
Note that although I’ve set the width and height of the rectangle to 150, which is lower than the width of the sprite, 200, scale9Grid fails with #2004 error. That is because 60+150>200, the rectangle falls beyond the bounds of the display object.
Setting scale9Grid also fails if the rectangle is within the bounds of the display object, but falls beyond the bounds of the graphics object. See the next example:
mySprite.graphics.beginFill(0xFF0000);
mySprite.graphics.lineStyle(2, 0x00ff00);
mySprite.graphics.drawRoundRect(0, 0, 200, 200, 50);
mySprite.graphics.endFill();
var mySprite2 : Sprite = new Sprite();
mySprite2.graphics.beginFill(0x0000FF, 0.5);
mySprite2.graphics.drawRoundRect(0, 0, 200, 200, 30);
mySprite2.graphics.endFill();
mySprite2.x = 140;
mySprite.addChild(mySprite2);
mySprite.x = 100;
mySprite.y = 100;
this.addChild(mySprite);
mySprite.scale9Grid = new Rectangle(60, 60, 150, 100);
mySprite.width = 500;
As you can see the rectangle is within the bounds of the display object, but falls outside the bounds of the graphics object. So scale9Grid fails with error “ArgumentError: Error #2004: One of the parameters is invalid.
at flash.display::DisplayObject/set scale9Grid()”
As a bottom line, you should scale9Grid if the display object has drawings in it’s graphics object, and set the Rectangle you pass to the scale9Grid property to fall inside the bounds of the graphics.
Hope I was clear enough and it will help anyone.
Any comments are very welcome.

Good write up, it inspired me to write a class that will scale anything, check it out and tell me what you think: http://ahmednuaman.com/blog/2009/06/26/scale-any-displayobject-with-my-scaleobject-class/
Holy crap!
This is awesome, Ovidiu! Thanks, man!
Well, congratulations! This is the only useful information on this (non) feature anywhere! The Adobe examples and documentation are horrendous.
Thank you!
I’ll another failure point that might not be obvious and isn’t really documented (at least I couldn’t find it…)
Let’s say you want to use actionscript to apply scale9Grid to a loaded swf that has vector art on the timeline. Seems like a sensible use case…. It won’t work! Vector drawings are not drawn into graphics instances. For AS scale9Grid to work, it needs to be operating on a movieclip with a non-empty graphics instance that is larger than the applied rectangle.
So, you think, maybe I’ll get cute and draw into a graphics instance in the loaded swf. That won’t work either. As soon as you include both your vector art and code drawing, scale9Grid will barf. Basically, AS scale9Grid, as opposed to the library variety, can’t be applied to a movieclip that contains vector drawings on the timeline.
For me, this makes the feature almost useless. If I can’t easily apply it to a loaded swf, well…
Anyway, giving up. Thanks again for supplying some useful information. The Adobe docs mention none of these limitations. They should go into detail on them, but alas…
You are right about one thing: the vector drawings drawn in the editor are not stored in the graphics object that you can manipulate with as. That’s just to keep the graphics “safe”. But you can still apply successfully scale9Grid in code to a movieclip created and draw in IDE, as long as you follow the guidelines: make sure all drawing is directly inside the movieclip and not inside any other child, the movieclip shouldn’t contain children (or if contains be even more careful and still apply scale9Grid to only the graphics object, the children won’t be affected by the scale9Grid setting on their parent)..
The movieclip will even resize correctly if you put drawings on more keyframes. – in the zip file, check scale9GridEx1 for example
You can also apply successfully scale9Grid to loaded content (actually this is how Flex is setting scale9Grid to skins created in flash), but you must make sure to not apply scale9Grid to the Loader object but rather to the actual content, and make sure the graphics are actually drawn on the stage of the loaded swf, and not in any other symbol that is placed on the stage (or you can draw in other symbols but you then have to apply scale9Grid to those) – in the zip file, check scale9GridEx2 for how the swf is loaded and applied scale9Grid, and check scale9GridLoading to see how the loading swf is drawn – very simple actually
scale9GridEx.zip – You will need Flash CS4 or newer to be able to open the fla files