2008-11-06 15 views
8

Estoy usando un procesador de elementos personalizado en un cuadro combinado para mostrar un dibujo personalizado en lugar de la etiqueta de texto predeterminada.Representador de elemento personalizado de Flex para el elemento mostrado en el cuadro combinado

Esto funciona bien para la lista desplegable, pero el elemento mostrado (cuando la lista está cerrada) sigue siendo la representación textual de mi objeto.

¿Hay alguna manera de que el elemento mostrado se represente de la misma manera que el del menú desplegable?

Respuesta

9

Por defecto no puede hacer esto. Sin embargo, si extiende ComboBox, puede agregar esta funcionalidad fácilmente. Aquí hay un ejemplo rápido, es una versión aproximada y probablemente necesite pruebas/ajustes, pero muestra cómo se puede lograr esto.

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; 
      } 
     } 
    } 
} 
5

Probé la solución anterior, pero se encontró que el selectedItem no se muestra cuando el cuadro combinado se cerró. Se requirió una línea adicional de código para enlazar la propiedad data itemRenderer a la 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); 
        } 
      } 
0

Gracias maclema y Maurits de Boer. He añadido un par de cosas más a esta clase para que se ajuste a mis necesidades:

  • me hizo caso omiso puse itemRenderer para que esto funcionará si se establece la itemRenderer través de AS en lugar de mxml. Moví el código de reemplazo de entrada de texto a su propia función para evitar la duplicación.

  • Agregué setters para 'increaseW' y 'increaseH' para cambiar el tamaño del combobox si es necesario porque mi renderizador era demasiado grande para el combobox al principio.

  • Restamos 25 del ancho textInputReplacement para que no se superponga nunca al botón desplegable ... puede ser mejor usar algo más proporcional para acomodar diferentes máscaras y tal.

Código:

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); 

         } 
       } 
     } 
    } 
} 
+0

¿me pueden ayudar: // eliminar el defecto textInput \t \t \t \t \t removeChild (textInput); Coerción implícita de un valor de tipo mx.core: ITextInput en un tipo no relacionado flash.display: DisplayObject. –

-1

Esto se puede lograr mucho más simple si usted está en busca de algún tipo de encargo de texto con atributos CSS. Reemplaza la función "get selectedLabel(): String" para devolver cualquier cadena que se muestre en el cuadro de texto. Si necesita algún tipo de CSS, establezca el estilo en su TextInput (this.textInput) en el método seleccionado Label().

0

Estaba buscando una manera de hacer esto con el Spark ComboBox.

Este hilo fue muy útil para mí, pero hasta ahora solo ha habido respuestas sobre cómo hacerlo usando un mx: ComboBox. Pensé que debería agregar mi respuesta sobre cómo hacerlo usando una chispa ComboBox.

  1. crear un nuevo aspecto de la ComboBox
  2. Ocultar y desactivar la textInput
  3. Inserte su propio componente

Esto es lo que la piel se vería así:

<s:SparkSkin> 

    <... Lots of other stuff/> 

    <s:BorderContainer height="25"> 
     <WHATEVER YOU NEED HERE!/> 
    </s:BorderContainer> 

    <!-- Disable the textInput and hide it --> 
    <s:TextInput id="textInput" 
     left="0" right="18" top="0" bottom="0" 
     skinClass="spark.skins.spark.ComboBoxTextInputSkin" 

     visible="false" enabled="false"/> 


</s:SparkSkin> 

Con Spark ComboBox, este proceso es muy fácil y no requiere extender ComboBox.

3

He extendido el código de Dane un poco más. En algunos casos, al hacer clic no abrí el cuadro desplegable con mi procesador de imagen y noté que las máscaras Flex ComboBox normales no se activaban. Por lo tanto, en replaceTextInput(), agregué algunos detectores de eventos adicionales y guardo una referencia al botón ComboBox usado para mostrar las máscaras. Ahora se comporta como el ComboBox normal.

Aquí está el código:

 
    package 
    { 
    import flash.events.Event; 
    import flash.events.KeyboardEvent; 
    import flash.events.MouseEvent; 

    import mx.binding.utils.BindingUtils; 
    import mx.controls.Button; 
    import mx.controls.ComboBox; 
    import mx.core.IFactory; 
    import mx.core.UIComponent; 
    import mx.events.DropdownEvent; 

    /** 
    * Extension of the standard ComboBox that will use the assigned 'itemRenderer' 
    * for both the list items and the selected item. 
    * 
    * Based on code from: 
    * http://stackoverflow.com/questions/269773/flex-custom-item-renderer-for-the-displayed-item-in-the-combobox 
    */ 
    public class ComboBoxFullRenderer extends ComboBox 
    { 
    protected var textInputReplacement:UIComponent; 
    private var _increaseW:Number = 0; 
    private var _increaseH:Number = 0; 


    /** 
    * Keeps track of the current open/close state of the drop down list. 
    */ 
    protected var _isOpen:Boolean = false; 

    /** 
    * Stores a reference to the 'Button' which overlays the ComboBox. Allows 
    * us to pass events to it so skins are properly triggered. 
    */ 
    protected var _buttonRef:Button = null; 


    /** 
    * Constructor. 
    */ 
    public function ComboBoxFullRenderer() { 
     super(); 
    } 


    /** 
    * Sets a value to increase the width of our ComboBox to adjust sizing. 
    * 
    * @param val Number of pixels to increase the width of the ComboBox. 
    */ 
    public function set increaseW(val:Number):void { 
     _increaseW = val; 
    } 

    /** 
    * Sets a value to increase the height of our ComboBox to adjust sizing. 
    * 
    * @param val Number of pixels to increase the height of the ComboBox. 
    */ 
    public function set increaseH(val:Number):void { 
     _increaseH = val; 
    } 


    /** 
    * Override the 'itemRenderer' setter so we can also replace the selected 
    * item renderer. 
    * 
    * @param value The renderer to be used to display the drop down list items 
    * and the selected item. 
    */ 
    override public function set itemRenderer(value:IFactory):void { 
     super.itemRenderer = value; 
     replaceTextInput(); 
    } 


    /** 
    * Override base 'createChildren()' routine to call our 'replaceTextInput()' 
    * method to replace the standard selected item renderer. 
    * 
    * @see #replaceTextInput(); 
    */ 
    override protected function createChildren():void { 
     super.createChildren(); 
     replaceTextInput(); 
    } 


    /** 
    * Routine to replace the ComboBox 'textInput' child with our own child 
    * that will render the selected data element. Will create an instance of 
    * the 'itemRenderer' set for this ComboBox. 
    */ 
    protected function replaceTextInput():void { 
     if (!textInputReplacement) { 
      if (this.itemRenderer != null && textInput != null) { 
       //remove the default textInput 
       removeChild(textInput); 

       //create a new itemRenderer instance to use in place of the text input 
       textInputReplacement = this.itemRenderer.newInstance(); 
       // Listen for clicks so we can open/close the drop down when 
       // renderer components are clicked. 
       textInputReplacement.addEventListener(MouseEvent.CLICK, _onClick); 
       // Listen to the mouse events on our renderer so we can feed them to 
       // the ComboBox overlay button. This will make sure the button skins 
       // are activated. See ComboBox::commitProperties() code. 
       textInputReplacement.addEventListener(MouseEvent.MOUSE_DOWN, _onMouseEvent); 
       textInputReplacement.addEventListener(MouseEvent.MOUSE_UP, _onMouseEvent); 
       textInputReplacement.addEventListener(MouseEvent.ROLL_OVER, _onMouseEvent); 
       textInputReplacement.addEventListener(MouseEvent.ROLL_OUT, _onMouseEvent); 
       textInputReplacement.addEventListener(KeyboardEvent.KEY_DOWN, _onMouseEvent); 

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

       // Add our renderer as a child. 
       addChild(textInputReplacement); 

       // Listen for open close so we can maintain state. The 
       // 'isShowingDropdown' property is mx_internal so we don't 
       // have access to it. 
       this.addEventListener(DropdownEvent.OPEN, _onOpen); 
       this.addEventListener(DropdownEvent.CLOSE, _onClose); 

       // Save a reference to the mx_internal button for the combo box. 
       // We will need this so we can call its dispatchEvent() method. 
       for (var i:int = 0; i < this.numChildren; i++) { 
        var temp:Object = this.getChildAt(i); 
        if (temp is Button) { 
         _buttonRef = temp as Button; 
         break; 
        } 
       } 
      } 
     } 
    } 


    /** 
    * Detect open events on the drop down list to keep track of the current 
    * drop down state so we can react properly to a click on our selected 
    * item renderer. 
    * 
    * @param event The DropdownEvent.OPEN event for the combo box. 
    */ 
    protected function _onOpen(event:DropdownEvent) : void { 
     _isOpen = true; 
    } 


    /** 
    * Detect close events on the drop down list to keep track of the current 
    * drop down state so we can react properly to a click on our selected 
    * item renderer. 
    * 
    * @param event The DropdownEvent.CLOSE event for the combo box. 
    */ 
    protected function _onClose(event:DropdownEvent) : void { 
     _isOpen = false; 
    } 


    /** 
    * When we detect a click on our renderer open or close the drop down list 
    * based on whether the drop down is currently open/closed. 
    * 
    * @param event The CLICK event from our selected item renderer. 
    */ 
    protected function _onClick(event:MouseEvent) : void { 
     if (_isOpen) { 
      this.close(event); 
     } else { 
      this.open(); 
     } 
    } 


    /** 
    * React to certain mouse/keyboard events on our selected item renderer and 
    * pass the events to the ComboBox 'button' so that the skins are properly 
    * applied. 
    * 
    * @param event A mouse or keyboard event to send to the ComboBox button. 
    * 
    */ 
    protected function _onMouseEvent(event:Event) : void { 
     if (_buttonRef != null) { 
      _buttonRef.dispatchEvent(event); 
     } 
    } 
    } // end class 
    } // end package 
0

He encontrado una manera más fácil de cambiar el procesador para el elemento seleccionado. Este solo funciona si su elemento hereda de la clase TextInput, en Flex 4.0 o superior.

En Flex v4.5, en ComboBase.createChildren en la línea 1177, se encuentra que la clase definible para la textInput puede transmitirse utilizando el estilo clave textInputClass:

// Mechanism to use MXFTETextInput. 
var textInputClass:Class = getStyle("textInputClass");    
if (!textInputClass || FlexVersion.compatibilityVersion < FlexVersion.VERSION_4_0) 
{ 
    textInput = new TextInput(); 
} 
else 
{ 
    textInput = new textInputClass(); 
} 

Sólo cambia el valor de esta clave en el constructor de tu combo y ahora tienes tu propio procesador para el selectedItem.

public function ComboAvailableProfessor() 
{ 
    super(); 

    itemRenderer = new ClassFactory(ProfessorAvailableListItemRenderer); 
    setStyle('textInputClass', ProfessorAvailableSelectedListItemRenderer); 
} 

Por último se debe enlazar la propiedad data a la propiedad selectedItem en su combo con el fin de obtener datos que se muestran.

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

    BindingUtils.bindProperty(textInput, 'data', this, 'selectedItem', true); 
} 
Cuestiones relacionadas