views:

6705

answers:

5

I am using a custom item renderer in a combobox to display a custom drawing instead of the default text label.

This works fine for the dropdown list but the displayed item ( when the list is closed) is still the textual representation of my object.

Is there a way to have the displayed item rendered the same way as the one in the dropdown?

+5  A: 

By default you cannot do this. However, if you extend ComboBox you can add this functionality easily. Here is a quick example, it is a rough version and probably needs testing / tweaking but it shows how you could accomplish this.

package
{
    import mx.controls.ComboBox;
    import mx.core.UIComponent;

    public class ComboBox2 extends ComboBox
    {
     public function ComboBox2()
     {
      super();
     }

     protected var textInputReplacement:UIComponent;

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

      if ( !textInputReplacement ) {
       if ( itemRenderer != null ) {
        //remove the default textInput
        removeChild(textInput);

        //create a new itemRenderer to use in place of the text input
        textInputReplacement = itemRenderer.newInstance();
        addChild(textInputReplacement);
       }
      }
     }

     override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
      super.updateDisplayList(unscaledWidth, unscaledHeight);

      if ( textInputReplacement ) {
       textInputReplacement.width = unscaledWidth;
       textInputReplacement.height = unscaledHeight;
      }
     }
    }
}
maclema
+2  A: 

I tried the above solution, but found that the selectedItem did not display when the combobox was closed. A extra line of code was required to bind the itemRenderer data property to the selectedItem:

            if ( !textInputReplacement ) {
                    if ( itemRenderer != null ) {
                            //remove the default textInput
                            removeChild(textInput);

                            //create a new itemRenderer to use in place of the text input
                            textInputReplacement = itemRenderer.newInstance();

                            // ADD THIS BINDING:
                            // Bind the data of the textInputReplacement to the selected item
                            BindingUtils.bindProperty(textInputReplacement, "data", this, "selectedItem", true);

                            addChild(textInputReplacement);
                    }
            }
Maurits de Boer
A: 

thanks. This is what I need

binhdocco
this should be placed in the comments section, not as an answer
asawilliams
A: 

Thank you maclema and Maurits de Boer. I added a couple more things to this class to make it fit my needs:

-I overrode set itemRenderer so that this will work if you set the itemRenderer through AS instead of mxml. I moved the text input replacement code to its own function to avoid duplication.

-I added setters for 'increaseW' and 'increaseH' to resize the combobox if necessary because my renderer was too big for the combobox at first.

-I subtracted 25 from the textInputReplacement width so it doesn't ever overlap the dropdown button... may be better to use something more proportional to accommodate different skins and such.

package
{
 import mx.binding.utils.BindingUtils;
 import mx.controls.ComboBox;
 import mx.core.IFactory;
 import mx.core.UIComponent;

    public class ComboBox2 extends ComboBox
    {
        public function ComboBox2()
        {
                super();
        }

        protected var textInputReplacement:UIComponent;
        private var _increaseW:Number = 0;
        private var _increaseH:Number = 0;

  public function set increaseW(val:Number):void
  {
   _increaseW = val;
  }

  public function set increaseH(val:Number):void
  {
   _increaseH = val;
  }

  override public function set itemRenderer(value:IFactory):void
  {
   super.itemRenderer = value;
   replaceTextInput();
  }

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

        }

        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {

          unscaledWidth += _increaseW;
          unscaledHeight += _increaseH;

                super.updateDisplayList(unscaledWidth, unscaledHeight);

                if ( textInputReplacement ) {
                        textInputReplacement.width = unscaledWidth - 25;
                        textInputReplacement.height = unscaledHeight;
                }
        }

        protected function replaceTextInput():void
        {
         if ( !textInputReplacement ) {
                        if ( this.itemRenderer != null ) {
                                //remove the default textInput
                                removeChild(textInput);

                                //create a new itemRenderer to use in place of the text input
                                textInputReplacement = this.itemRenderer.newInstance();
                                addChild(textInputReplacement);

                                // ADD THIS BINDING:
                             // Bind the data of the textInputReplacement to the selected item
                             BindingUtils.bindProperty(textInputReplacement, "data", this, "selectedItem", true);

                             addChild(textInputReplacement);

                        }
                }
        }
    }
}
Dane
A: 

This can be much more simply achieved if you're just looking for some sort of custom formatted text with CSS attributes. Override the "get selectedLabel():String" function to return any string to be dispalyed in the text box. If you need some sort of CSS, then set the style on your textInput (this.textInput) in the selectedLabel() method.

davidemm