15 Replies Latest reply on Apr 26, 2010 10:07 AM by Flex harUI

    Extending UIComponent, createChildren question

    danbucholtz1

      All,

       

      I'm trying to make some simple components.  For the sake of making this exercise very simple, I'm using a callout control from Adobe posted here.

      http://www.adobe.com/devnet/flex/samples/fig_callout/

       

      The source of that component can be viewed here:

      http://www.adobe.com/devnet/flex/samples/fig_callout/srcview/index.html

       

      More specifically, I'm looking at the src/AirportCallout.mxml file.

       

      I'm looking at making a class that extends UIComponent.

       

      public class AlertWrapper extends UIComponent

      {

              private var callout : Callout;
              public function AlertWrapper(){
                  super();
                  this.buttonMode = true;
                  //this.addEventListener(MouseEvent.CLICK, alertClicked);

                  this.graphics.drawCircle(25, 25, 5);
              }

       

             override protected function createChildren():void{
                  super.createChildren();

                  this.callout = new Callout();
                  this.callout.x = 25
                  this.callout.y = 25;
                  this.addChild(this.callout);
              }
             
              override protected function measure():void{
                  super.measure();
              }

      }

       

       

      This is obviously a very simple example dumbed down for the sake of figuring out what's going on.  I'm drawing a circle at point (25, 25) with a radius of 5.  I'm then trying to place a callout component (something that adobe made and works well) onto this component as a child.

       

      When I add an instance of the AlertWrapper class to the display list (In the real world situation, I add it to a container using the addChild method), it does not render the callout correctly (it's the wrong size, much smaller than it should be).  I'm stumped trying to figure out why this is.  If I look at the AirportCallout.mxml class, I see that it isn't given a size by default.  If I give it a size of 200, it does render correctly (albeit the wrong size).

       

      Can anyone shed any light of this?  I'm new to designing my own controls that extend UIComponent.

       

      Thanks,

      Dan

        • 1. Re: Extending UIComponent, createChildren question
          Flex harUI Adobe Employee

          You need to set measuredWidth/Height in your measure method, or set

          width/height in the constructor.

          • 2. Re: Extending UIComponent, createChildren question
            danbucholtz1 Level 1

            What if I don't know those values?

             

            Say the Callout has a width of 20 and a height of 20.

             

            What if the the circle drawn in the AlertWrapper is is a radius of 25 (so a diameter of 50).

             

            What does the size have to be for the AlertWrapper component then?  Does the AlertWrapper UIComponent's size have to be greater than the size of it's graphics object?

             

            Thanks,

            Dan

            • 3. Re: Extending UIComponent, createChildren question
              Flex harUI Adobe Employee

              The component will be sized to an explicit width if the width/height

              properties are set, or the measuredWidth/Height that should be set via an

              override of measure().  The measure method can ask the callout for its

              width/height by using getExplicitOrMeasuredWidth()/Height() and set

              measuredWidth/Height to those values.

               

              If you draw a circle with the diameter of 50 you can set

              measuredWidth/Height to 50.

               

              If you supply a larger measuredWidth/Height there will be extra space

              awarded to the component, if too small, the next component may sit on it.

              • 4. Re: Extending UIComponent, createChildren question
                danbucholtz1 Level 1

                public class AlertWrapper extends UIComponent

                {

                         private var callout : Callout;
                        public function  AlertWrapper(){
                            super();
                            this.buttonMode =  true;
                            //this.addEventListener(MouseEvent.CLICK,  alertClicked);

                            this.graphics.drawCircle(25, 25, 5);
                         }

                 

                        override protected function createChildren():void{
                             super.createChildren();

                            this.callout = new Callout();
                             this.callout.x = 25
                            this.callout.y = 25;
                             this.addChild(this.callout);
                        }
                       
                         override protected function measure():void{
                             super.measure();

                            this.measuredHeight = this.callout.getExplicitOrMeasuredHeight();
                            this.measuredWidth = this.callout.getExplicitOrMeasuredWidth();
                        }

                }

                 

                Doing something like this does not render correctly.  It looks cut off like this.

                var alertWrapper : AlertWrapper = new AlertWrapper();

                var canvas : Canvas = new Canvas();

                canvas.addChild(alertWrapper);

                 


                When debugging, the alertWrapper measuredHeight and measuredWidth are set to 35 and 32.

                 

                It looks like this

                 

                bad.png

                 

                 

                If I change the code in alertWrapper and change the createChildren and measure functions to as follows, I can hack my way through it:

                 

                override protected function createChildren():void{
                             super.createChildren();

                            this.callout = new Callout();
                             this.callout.x = 25
                            this.callout.y = 25;
                            //  this.addChild(this.callout);
                        }
                       
                         override protected function measure():void{
                             super.measure();

                            // this.measuredHeight =  this.callout.getExplicitOrMeasuredHeight();
                             // this.measuredWidth =  this.callout.getExplicitOrMeasuredWidth();
                        }

                 

                 

                 

                Then, if I add it to my container as such, it renders correctly but I don't understand why.  When I debug with this second method, the measuredWidth and measuredHeight of the alertWrapper are both 0 (which is weird since the circle is being drawn).

                 

                var alertWrapper : AlertWrapper = new AlertWrapper();

                var canvas : Canvas = new Canvas();

                canvas.addChild(alertWrapper);

                canvas.addChild(alertWrapper.callout);

                 

                good.png

                 

                 

                This second method seems very hacky and I would like to understand what I have to do to make it work so I only have to add the alertWrapper to the container to get it to render correctly.  Please help!

                • 5. Re: Extending UIComponent, createChildren question
                  Flex harUI Adobe Employee

                  In the second case, you took the callout out of the ALertWrapper and put it

                  in the container as a sibling.  If you remove the AlertWrapper the callout

                  will not be removed.

                   

                  The problem in the first case is that the callout is positioned at 25,25 so

                  you need to add that to your measurements.

                  • 6. Re: Extending UIComponent, createChildren question
                    danbucholtz1 Level 1

                    So looking at the first case, if I add do as follows it doesn't change anything with the rendering.  It still does not render correctly.  What my end goal of this discussion is to get this component coded correctly so I can add one AlertWrapper object and once that's add to the display list, I want the AlertWrapper to automatically create it's children (which will be a callout), and get it to render properly, like it does if I add the two components to the container separately.

                     

                            override protected function createChildren():void{
                                super.createChildren();
                                this.callout = new AlertCallout();
                                this.callout.x = alert.location.x;
                                this.callout.y = alert.location.y;
                                this.addChild(this.callout);
                            }
                           
                            override protected function measure():void{
                                super.measure();
                                this.measuredHeight = 25 + this.callout.getExplicitOrMeasuredHeight();
                                this.measuredWidth = 25 + this.callout.getExplicitOrMeasuredWidth();
                            }

                     

                    So, in theory this should work because the UIComponent now has a width of 25 + width/height of callout (so it should be within the UIComponent rectangle).  I don't understand why it does not.

                     

                    What is the relationship between the UIComponent and Graphics object?  I can do something like this (for the AlertWrapper) for the measure function of my extended UIComponent but the graphics drawing still render a proper cricle with radius 25.

                     

                           override protected function measure():void{
                                super.measure();
                                //this.measuredHeight = this.alert.location.y + this.callout.getExplicitOrMeasuredHeight();
                                //this.measuredWidth = this.alert.location.x + this.callout.getExplicitOrMeasuredWidth();
                                this.measuredHeight = 0;
                                this.measuredWidth = 0;
                            }

                     

                     

                    Update:

                     

                    Even if I do something like this and make the AlertWrapper huge (200 by 200 pixels), it still does not render correctly.  I don't understand what the problem is.

                     

                    override protected function createChildren():void{
                                super.createChildren();
                                this.callout = new AlertCallout();
                                this.callout.x = 25;
                                this.callout.y = 25;
                                this.addChild(this.callout);
                            }
                           
                            override protected function measure():void{
                                super.measure();
                                //this.measuredHeight = 25 + this.callout.getExplicitOrMeasuredHeight();
                                //this.measuredWidth = 25 + this.callout.getExplicitOrMeasuredWidth();
                                this.measuredHeight = 200;
                                this.measuredWidth = 200;
                            }

                     

                    I appreciate your help!

                     

                    Dan

                    • 7. Re: Extending UIComponent, createChildren question
                      Flex harUI Adobe Employee

                      Every time you supply code, you are changing it.  In the previous post you

                      had callout.x = 25,  now you are setting it to some variable.

                      • 8. Re: Extending UIComponent, createChildren question
                        danbucholtz1 Level 1

                        Sorry, I forgot to wipe my code from the example.

                         

                        If I use the following code, it doesn't work.  I don't understand why.

                         

                        override protected function createChildren():void{
                                    super.createChildren();
                                    this.callout = new AlertCallout();
                                    this.callout.x = 25;
                                    this.callout.y = 25;
                                    this.addChild(this.callout);
                                }
                               
                                override protected function measure():void{
                                    super.measure();
                                    this.measuredHeight = 25 + this.callout.getExplicitOrMeasuredHeight();
                                    this.measuredWidth = 25 + this.callout.getExplicitOrMeasuredWidth();
                                }

                        • 9. Re: Extending UIComponent, createChildren question
                          Flex harUI Adobe Employee

                          What is AlertCallout returning when you call

                          getExplicitMeasuredWidth/Height?  Are you getting expected values?

                          • 10. Re: Extending UIComponent, createChildren question
                            danbucholtz1 Level 1

                            Yes, the values returned by getExplicitMeasuredWidth() and getExplicitMeasuredHeight   () are 32 and 35.

                            • 11. Re: Extending UIComponent, createChildren question
                              Flex harUI Adobe Employee

                              How are you positioning and sizing the child in updateDisplayList?

                               

                              There is documentation on how to use the measure() and updateDisplayList()

                              methods.  I suggest you read the chapters on creating custom components.

                              • 12. Re: Extending UIComponent, createChildren question
                                danbucholtz1 Level 1

                                updateDisplayList is not overridden.  None of the properties are changing so I don't see why I would have to make any changes to that function.  I have read the documentation, but it isn't working as described (also in the way you're describing).

                                 

                                Still a work in a progress...

                                • 13. Re: Extending UIComponent, createChildren question
                                  danbucholtz1 Level 1

                                  This is the measure function of the CalloutContainer that AlertCallout extends.

                                   

                                  override protected function measure():void
                                      {
                                          super.measure()
                                          _layoutObject.measure();
                                         
                                          measuredWidth = measuredWidth+getStyle("calloutOffsetX");
                                          measuredHeight = measuredHeight+getStyle("calloutOffsetY");
                                          //trace("explicitWidth: "+explicitWidth);
                                          measuredMinWidth     = 80;
                                          measuredMinHeight     = 24;
                                      }

                                   

                                   

                                  I'm not sure what that gets me.

                                   

                                  I'm handling the creation complete event from the AlertCallout object and executing the following code:

                                  private function init():void{
                                     Alert.show(this.getExplicitOrMeasuredHeight() + " height " + this.getExplicitOrMeasuredWidth() + " width");
                                  }

                                   

                                  This prints out the height of 35, and the width of 32.  If I declare the height and width to be these values (in mxml), the component renders properly for the initial event, but the resizing on mouse over does not work correctly, so it in effect does not work.

                                   

                                  Any thoughts on how I can quickly get this thing to render correctly?

                                  • 14. Re: Extending UIComponent, createChildren question
                                    Flex harUI Adobe Employee

                                    If the component resizes on rollover, the measure method probably has to

                                    factor that in.

                                    • 15. Re: Extending UIComponent, createChildren question
                                      Flex harUI Adobe Employee

                                      Depending on your application, a component may not always be given its

                                      measured size.  UpdateDisplayList is where you react to that.