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:
var mySprite
: Sprite =
new Sprite();
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:
var mySprite
: Sprite =
new Sprite();
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:
var mySprite
: Sprite =
new Sprite();
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:
var mySprite
: Sprite =
new Sprite();
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:
var mySprite
: Sprite =
new Sprite();
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:
var mySprite
: Sprite =
new Sprite();
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.
Actionscript 3.0
Actionscript 3.0, as3, scale9Grid