Link to home
Start Free TrialLog in
Avatar of SkySigal
SkySigal

asked on

Help with compiled Component that has attachMovie() to internal movie. Sizing not consistent!

Help with compiled Component that has attachMovie() to internal movie. Sizing not consistent!



After hours and hours trying to debug this (notice the debug var for testing), I'm reaching out for more experienced help/advice as to what I am doing wrong.

Basic issue:
I'm trying to make a v2 component, that includes within it an optional MC as background.
The internal MC has to be sized to fill in the full width/height of the control.

The problem:
As it stands, I get different results depending on whether I view the compiled component in the designer (looks ok) or whether I press ctrl-Enter and view it in the player -- when it doesn't work correctly. The internal MC (background image) is bigger than it should be!

What I thought i was suppossed to do:
In the resize method, the code that is setting up the sizing is currently done by the following (seems right in IDE, bug ignores it in runtime and makes it too big):

            background_mc._height = height;
            background_mc._width = width;


More Description of control in case you've read this far:
Basically its just a label that draws an rounded rectangle frame if no MC name is provided. If an MC name is provided, it does not draw the border, and just displays the MC as the background... other parameters are background color, borderColor, borderthickness, etc.  
Its meant to be half useful, half force me to learn v2 component design in flash.


Description of code:
I started from the tutorial at:
//See: http://www.ultrashock.com/ff.htm?http://www.ultrashock.com/tutorials/flashmx2004/components.php
And basically only did two major changes: added more parameters at the bottom, and rewrote the draw() method to handle the border and if/else clause to draw the border or resize the background MC. And added a debug var to add stuff to the text to see what was going on...

Note that if textSize=0, it sets the fontsize to 2/3 size of the control (I mention this because for seeing the debug output, this is too big to read...)




Finally, the code:
//See: http://www.ultrashock.com/ff.htm?http://www.ultrashock.com/tutorials/flashmx2004/components.php


import mx.core.UIComponent;

// We declare our class fully qualified. Also we
// make this class a child of the UIComponent class
// by using the extends keyword
class XAct.AS.Controls.LabelBox extends UIComponent{

      // These are required for createClassObject()
      static var symbolName:String = "XAct.AS.Controls.LabelBox";
      static var symbolOwner:Object = XAct.AS.Controls.LabelBox;

      // we declare our Bounding Box here so that we can
      // reference it in our code
      private var boundingbox_mc:MovieClip;
      private var background_mc:MovieClip;

      // this will be our TextField that we will use to display the text
      private var dynamicTextField:TextField = null;


      // private fields behind get/set parameters:
      private var _debug:Boolean = false;
      private var _backgroundMCName:String = null;
      private var _backColor:Number = 0x0F0FFF;
      private var _labelText:String = null;
      private var _textBold:Boolean = true;
      private var _textBorder:Boolean = true;
      private var _textSize:Number = 0;
      private var _textColor:Number;
      private var _borderThickness:Number=2;
      private var _borderRadius:Number = 8;
      private var _borderColor:Number=0;


      private var _depth:Number = 0;




      // This is our constructor. Most of the time you will
      // just leave this blank when developing UIComponents.
      // Instead we use the init() function to set up our component
      function TextBox(){};





      // This function is automatically called when our component
      // extends the UIComponent class.
      private function init():Void     {

            // we call the superclass' init function which is required
            // when subclassing UIComponent
            super.init();

            // Since we have a bounding box, we need to hide it and make sure
            // that its width and height are set to 0. Notice that we are not using
            // "this" as we used to in AS1. In AS2 the compiler automatically
            // references the class members.
            boundingbox_mc._visible = false;
            boundingbox_mc._width = 0;
            boundingbox_mc._height = 0;

  _xscale = 100;
  _yscale = 100;

      }

      // This function is also called automatically when our component
      // extends the UIComponent class.
      private function createChildren():Void     {
            // This method is useful for when you want to create/attach sub-objects.
            // This method only gets called once.

            // In our component the only child object we need to create
            // is the TextField. The rest
            // is handled by the draw function as we will see below.
            // createLabel() is a method provided by UIObject that we can use
            // when we want to create a TextField. This is recommended
            // over the use of createTextField() method we are accustomed to.


            //Stick background Image In:
//            if (_backgroundMCName){
//                  this.attachMovie(_backgroundMCName, "background_mc", _depth++);
//            }


            //Create Text Field, and set its Filters
                  dynamicTextField = createLabel("dynamicTextField",_depth++);
            dynamicTextField.setTextFormat(new TextFormat());
            dynamicTextField.autoSize = "center";

                 var _filter = new flash.filters.DropShadowFilter();
            var _filtersCollection : Array = dynamicTextField.filters;
            _filtersCollection.push(_filter);
            dynamicTextField.filters = _filtersCollection;




            };


      // This function is called every time our component is invalidated.
      private function draw():Void    {
            // We get the appropriate background color from the style manager
            // the getStyle() method is provided to us by the framework. Make
            // sure to review the list of styles that the Macromedia components
            // support from the help as you will want your component to use the same
            // styleNames.

            this.clear();

            var W : Number = this._width;
            var H : Number = this._height;
            //this._xscale = 0;
            //this._yscale =0;
            //this.setSize(W,H);

            //HANDLE BACKGROUND COLOR OR MC:
            var tmpBackColor:Number;
            if(getStyle("backgroundColor")) {
                  tmpBackColor = getStyle("backgroundColor");
            }
            else {
                  tmpBackColor = _backColor;
            }


            //Only draw rectangle if no background image...
            if (!_backgroundMCName){
                  this.lineStyle(_borderThickness, _borderColor, 100, true, null, "none", "miter", 2);
                  drawRoundedRectangle(this, width, height, _borderThickness, _borderRadius, tmpBackColor, 100);
            }




            //HANDLE LABEL TEXT:

            var tmpTextSize:Number = _textSize;
                 var tmpTextFormat : TextFormat = dynamicTextField.getTextFormat();

                 if(!tmpTextSize){tmpTextSize=height * (2/3);}

            //Set the style of the textfield:
                 tmpTextFormat.bold = _textBold;
                 tmpTextFormat.color = _textColor;
                 tmpTextFormat.size = tmpTextSize;
                 //dynamicTextField.setTextFormat(tmpTextFormat); //Doesn't work
                 dynamicTextField.setNewTextFormat(tmpTextFormat);

                 //Set the border on textfield:
            dynamicTextField.border = _textBorder;

            //Set the Text after having set the Style:
            var tmpText  = (_debug!=true)?Text:

                              (Text + "\n" +
                              "\n"+
                              "width\\height: " + width + "\\" + height + "\n" +
                              "_width\\_height: " + _width + "\\" + _height + "\n" +
                              "_xscale\\_yscale: " + _xscale + "\\" + _yscale + "\n" +
                              "mc._width\\mc._width: "+ background_mc._width + "\\" + background_mc._height + "\n" +
                              "mc._xscale\\mc._yscale: "+ background_mc._xscale + "\\" + background_mc._yscale + "\n" +
                              "");
                 dynamicTextField.text = tmpText;

                 // We set the size of the Label so that it is viewable:
                 dynamicTextField.setSize(dynamicTextField.textWidth+1,dynamicTextField.textHeight+1);

                 // now we center our Label in the middle of our box
                 var tWidth:Number = width/2 - dynamicTextField.width/2;
                 var tHeight:Number = height/2 - dynamicTextField.height/2;
                 dynamicTextField._x = tWidth;
                 dynamicTextField._y = tHeight;


            //SETUP BACKGROUND IMAGE:


            //background_mc._xscale = 100 * (width / background_mc._width );
            //background_mc._yscale = 100 * (height / background_mc._height);

            background_mc._height = height;
            background_mc._width = width;


            if (_debug){


/*
                  //versus the _width/_height: (RED)
                  this.moveTo(1,1);
                  this.lineStyle(1, 0xFF0000);
                  this.lineTo(_width-1,1);
                  this.lineTo(_width-1,_height-1);
                  this.lineTo(1,_height-1);
                  this.lineTo(1,1);
*/
                  //Let's see what the width/height looks like...(BLUE)
                  this.moveTo(1,1);
                  this.lineStyle(1, 0x0000FF);
                  this.lineTo(width-1,1);
                  this.lineTo(width-1,height-1);
                  this.lineTo(1,height-1);
                  this.lineTo(1,1);
            }

           }

      // The size function is automatically called whenever our component is
      // resized.
           private function size():Void      {
                 // Since we don't have any special implementation
                 // for sizing. We can just invalidate the component
                 // invalidating the component will cause the component's
                 // draw() function to be called.



                 invalidate();
           };



      // This is our setter for the text property.
      // This will set the value and invalidate() the component
      // by adding the [Inspectable] meta-tag, the Flash IDE will
      // add an available text property to the property inspector

      //-------------------------------------------------
      //-------------------------------------------------
      [Inspectable (type=Boolean, defaultValue=True)]
           function set Debug(x:Boolean):Void     {
                 _debug = x;
                 invalidate();
      };

           // This is a getter for the text property. Our user can
           // use this property to retrieve the current value of the text
           function get Debug():Boolean     {
                 return _debug;
           }
      //-------------------------------------------------
      //-------------------------------------------------
      [Inspectable (type=String, defaultValue="---"]
           function set Text(x:String):Void     {
                 _labelText = x;
                 invalidate();
      };

           // This is a getter for the text property. Our user can
           // use this property to retrieve the current value of the text
           function get Text():String {
                 return _labelText;
           }
      //-------------------------------------------------
      [Inspectable (type=Color , defaultValue=0x0F0FFF)]
      function set TextColor(x:Number):Void     {
            _textColor = x;
            invalidate();
      };

      // This is a getter for the text property. Our user can
      // use this property to retrieve the current value of the text
      function get TextColor(): Number     {
            return _textColor;
      }
      //-------------------------------------------------
      [Inspectable (type=Number, defaultValue=0)]
      function set TextSize(x:Number):Void     {
            _textSize = x;

            invalidate();
      };

      // This is a getter for the text property. Our user can
      // use this property to retrieve the current value of the text
      function get TextSize(): Number     {
            return _textSize;
      }
      //-------------------------------------------------
      [Inspectable (type=Boolean, defaultValue=True)]
           function set TextBold(x:Boolean):Void     {
                 _textBold = x;
                 invalidate();
      };

           // This is a getter for the text property. Our user can
           // use this property to retrieve the current value of the text
           function get TextBold():Boolean     {
                 return _textBold;
           }
      //-------------------------------------------------
      [Inspectable (type=Boolean, defaultValue=True)]
           function set TextBorder(x:Boolean):Void     {
                 _textBorder = x;
                 invalidate();
      };

           // This is a getter for the text property. Our user can
           // use this property to retrieve the current value of the text
           function get TextBorder():Boolean     {
                 return _textBorder;
           }
      //-------------------------------------------------
      [Inspectable (type=Color , defaultValue=0x0F0FFF)]
      function set BackColor(x:Number):Void     {
            _backColor = x;
            invalidate();
      };

      // This is a getter for the text property. Our user can
      // use this property to retrieve the current value of the text
      function get BackColor(): Number     {
            return _backColor;
      }
      //-------------------------------------------------
      //-------------------------------------------------
      [Inspectable (type=Number , defaultValue=2)]
      function set BorderThickness(x:Number):Void     {
            _borderThickness = x;
            invalidate();
      };

      // This is a getter for the text property. Our user can
      // use this property to retrieve the current value of the text
      function get BorderThickness(): Number     {
            return _borderThickness;
      }
      //-------------------------------------------------
      [Inspectable (type=Number , defaultValue=8)]
      function set BorderRadius(x:Number):Void     {
            _borderRadius = x;
            invalidate();
      };

      // This is a getter for the text property. Our user can
      // use this property to retrieve the current value of the text
      function get BorderRadius(): Number     {
            return _borderRadius;
      }
      //-------------------------------------------------
      [Inspectable (type=Color , defaultValue=0x0F0FFF)]
      function set BorderColor(x:Number):Void     {
            _borderColor = x;
            invalidate();
      };

      // This is a getter for the text property. Our user can
      // use this property to retrieve the current value of the text
      function get BorderColor(): Number     {
            return _borderColor;
      }
      //-------------------------------------------------
      //-------------------------------------------------
      [Inspectable (type=String, defaultValue=""]
      function set BackgroundMCName (x:String): Void{

            _backgroundMCName = x;
            if (_backgroundMCName){
                  this.attachMovie(_backgroundMCName, "background_mc", -1);
            }else{
                  background_mc.unloadMovie();
            }

            invalidate();
      }

      function get BackgroundMCName():String{
            return _backgroundMCName;
      }

      //-------------------------------------------------
      //-------------------------------------------------


      function drawRoundedRectangle(target_mc:MovieClip, boxWidth:Number, boxHeight:Number, lineThickness, cornerRadius:Number, fillColor:Number, fillAlpha:Number):Void {
          with (target_mc) {

                //public lineStyle(lineThickness, lineColor, alpha:Number, pixelHinting:Boolean, noScale:String, capsStyle:String, jointStyle:String, miterLimit:Number);

            if (lineThickness <0){lineThickness =0;}

                var OFF:Number = lineThickness/2;


            var RADIUS = cornerRadius + OFF;


            beginFill(fillColor, fillAlpha);

            moveTo(RADIUS, 0 + OFF);

            lineTo(width - RADIUS, 0 + OFF);
            curveTo(boxWidth-OFF, 0+OFF, boxWidth-OFF, 0 + RADIUS);

            lineTo(boxWidth-OFF, boxHeight - RADIUS);
            curveTo(boxWidth-OFF, boxHeight-OFF, boxWidth - RADIUS, boxHeight-OFF);

            lineTo(0 + RADIUS, boxHeight-OFF);
            curveTo(0+OFF, boxHeight-OFF, 0+OFF, boxHeight - RADIUS);

            lineTo(0+OFF, RADIUS);
            curveTo(0+OFF, 0+OFF, RADIUS, 0+OFF);

            endFill();
          }
}


};



Avatar of Aneesh Chopra
Aneesh Chopra
Flag of India image

How are you creating the instance of this class.

please show the code here....
also confirm, what all the parameters.....

Rgds
Aneesh
Avatar of SkySigal
SkySigal

ASKER

Hi Aneesh:

I'll try to summarize here.

The public parameters are:

Debug {get;set;} //Sets debugging on so that text shown shows dimensions of _x, _y, _xwidth, etc. to
try to figure out what is going on

Text {get;set;} //Sets the text to be displayed at center of component
TextColor {get;set;} //Sets color that text is rendered in
TextBold {get;set;} //Whether to render text in bold

BorderColor {get;set;} //Color of rectangle that is drawn around text, at full dimensions of control.
BorderThickness {get;set;}//Sets the thickness of the line for drawing the rounded corner rectangle.
BorderRadius{get;set;}//Sets the radius in pixels for rounded corner rectangle (0 for square edges).
BackColor {get;set;} //Sets the background color within the rounded corder rectangle.

BackgroundMC {get;set;} //(optional) set with name of a MC to be displayed as background of Component*
* Note that if a backgroundMC is specified, the Rectangle is not drawn...


The logic is broken down into two main groups -- startup and paint:

Startup Logic:
Constructor does nothing
Init() initializes control
CreateChildControls() creates the TextBox that is used to display text


RedrawLogic:   //triggered each time a property is changed, or if control is resized
draw(): // this is where all the work is done:
-- the canvas is cleared,
-- then the rectangle redrawn, or the MC background resized to be at 0,0, with full width, full height...
-- the text inputed and textfield resized


The problem:
And draw() appears to be where the problem is.
In the IDE, if I give a backgroundMCName parameter, it stops drawing the rectangle, and instead sizes background_mc to be full width, full height. And it looks about right in the IDE.
But in runtime player, it isn't.
For one, the background_mc seems to be at a position higher up the page than 0,0
For two, it is wider/deeper and extends beyond the limits of the component.

I don't understand why...

Maybe its an issue of the order in which to resize the mc ?

Can anyone help?
Hi SkySigal,

this all is clear, I can get this much only by looking into the code...

my requirement is how are  you creating an instance of this class...?

In simple word, can you send me a SAMPLE fla, with class file to my Email...

so that I can see the real issue on run time

(my Emal: aneeshchopra<AT>gmail<DOT>com)

Rgds
Aneesh
Oops -- wasn't sure what you meant :-)

I've just sent you the AS and FLA... Hope you see what I am missing!
Hi, got the code...

I have been going through it...

Can you also provide a FLA in which component movie hasn't been compiled..

Rgds
Aneesh
The source for the compiled component is in the same file.
If you really need to, just delete the TextLabelII SWF, and use the TextLabelII (non-compiled) component.
When ready to recheck the behavior of the compilation, right-click on TextLabelII and build Compiled Component.

Is that what you were looking for?
Any luck last night?
Sorry for the late reply....

sorry to say... but I feel that you have messed up alot....

I am doing a fresh sample exclusively for you....

Will be uploading within this hour..

Rgds
Aneesh
ASKER CERTIFIED SOLUTION
Avatar of Aneesh Chopra
Aneesh Chopra
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Morning Aneesh:

First of all -- thanks so much for your time involved. You obviously spent a lot of time on redoing the control.
Second -- didn't know about yousendit.com -- nice trick that might be useful for me in the future :-)

Third, looking at your code, I see that instead of painting the rectangle on the main canvas of the compiled component, you created a new mc within it which you painted on, in essence once. In other words, where I was doing

component
>preview_mc (hidden)
>drawn rectangle (directly drawn on component)
>background_mc

you did:
component
>preview_mc (hidden)
>rectangle_mc (visible)
  >drawn rectangle (on rectangle_mc rather than component).

For cleanliness/compartimentalization, this makes sense.
But...I had thought about investigating that direction as well...but considering I was having trouble already one mc within a compnent, I didn't see the reason to add another mc (rectangle_mc) until I figured out the sizing of the first mc (background_mc).

Because...I see you basically have the same problem as I: even though your component has a stated width of 100px, it draws the rectangle_mc at...120px wide. In other words, you too are outside the bounds of the component.width property...

Secondly:
I'm not sure why you made [Investigable] the height and width properties... Hum. Basically the Width/Height of the component should be either set by direct stretching/pulling the component rectangle, or setting the width/height in the IDE's x/y/width/height properties same as any other mc/component. To set up yet a 3rd way of setting width/height seems...like shoelaces and buckles, making it harder to sync the values (note that when you stretch your component, it does not update the Properties you have in the properties inspector...)

Thirdly:
Whatcha done with my background_mc??? :-)
The whole point of this control was to draw a label that  EITHER drew a rectangle around it, OR showed a backgrounnd image behind it... Oh well...

Anyway -
I think I have to now set up another test rig that diminishes the number of uncertainties -- has just one mc, with a filled background color, no text label, and one mc in it and see if I can I can get the inner mc to cover up the background exactly -- not bigger, not smaller. Maybe its the textfield sizing that is causing the resize dimensions to be not in sync.


Again, I thank you for your time.
I'll let you know what I come up with in the next coming hours...


Ok. As promised...results.

FINALLY got it to work...but not sure exactly why. Maybe someone knows?

The change was to ensure that the mc that I want to use for the background mc/image (whatever it is, a fish, an animated star, whatever) has to be set to _xscale=0, and _yscale=0....but at a specific location in the code.

Why? I have no idea. But without it, I noticed that after i set the _width and _height of the inner mc, the scale was something like 500.0034 whatever (big), which I could expect fine -- but what I didn't like is that it obviously is throwing the math because the inner mc's dimensions are stretched to outside the bounds of the control...
Whereas the outer container mc/component's scales were 100/100.

So ...what I decided to reset the scales.

I tried with 100/100 on the inner mc -- but that didn't work (if done before setting the _width/_height, it didn't do anything, and if done after, set it back to being 'original size' -- not the full size of the component.

I also tried setting them to 0 just before sizing...and that didn't work either.

//-------------------------------------------------
function _drawBackgroundImage(w:Number,h:Number):Void{
    //DOES NOT WORK HERE IN RUNTIME -- DOES IN DESIGN TIME ONLY
    background_mc._xscale=0;
    background_mc._yscale=0;

    background_mc._width = w;
    background_mc._height = h;
}
      

The ONLY way I got it to work was setting the vars when attaching the mc:


//-------------------------------------------------
//-------------------------------------------------
[Inspectable (type=String, defaultValue="")]
function set BackgroundMCName (x:String): Void{

  _backgroundMCName = x;

  if (_backgroundMCName != null){
    //Attach movie -- and set its scales to 0 here or it won't work.
    this.attachMovie(_backgroundMCName, "background_mc", -1,{_x:0, _y:0,_xscale:0,_yscale:0});
  }else{
    background_mc.unloadMovie();
}
invalidate();
}




So obviously, I'm not understanding _xscale/_yscale at all and have no idea why it works, but it does.

And I HATE not understanding... it ends up always biting me ...later.

So if anybody has new input as to why it works as is so dependent on _xscale/_yscale, you have the mike :-)


Thank you.



SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks both of you for your inputs!

Sorry for the long delay getting back to you both... real big event over here ... My daughter was born on the 7th, and basically, since then, I'm not in front of a keyboard, as I basically spend the day holding her, wondering how lucky I just got :-)

Got to run...and thanks both of you.