2008-11-06 11 views
8

Ich verwende einen benutzerdefinierten Elementrenderer in einer Combobox, um eine benutzerdefinierte Zeichnung anstelle der Standardbeschriftung anzuzeigen.Flexibler benutzerdefinierter Elementrenderer für das angezeigte Element in der Combobox

Dies funktioniert gut für die Dropdown-Liste, aber das angezeigte Element (wenn die Liste geschlossen ist) ist immer noch die textliche Darstellung meines Objekts.

Gibt es eine Möglichkeit, das angezeigte Element auf die gleiche Weise wie das im Dropdown-Menü darzustellen?

Antwort

9

Standardmäßig können Sie dies nicht tun. Wenn Sie jedoch ComboBox erweitern, können Sie diese Funktionalität problemlos hinzufügen. Hier ist ein kurzes Beispiel, es ist eine grobe Version und muss wahrscheinlich getestet/optimiert werden, aber es zeigt, wie Sie dies erreichen können.

5

Ich habe die obige Lösung versucht, aber festgestellt, dass das selectedItem nicht angezeigt wurde, wenn die Combobox geschlossen wurde. Eine zusätzliche Zeile Code wurde erforderlich, um die itemRenderer Daten-Eigenschaft auf den selectedItem zu binden:

  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

Danke maclema und Maurits de Boer. Ich habe noch ein paar Dinge zu dieser Klasse, um es meine Bedürfnisse fit zu machen:

  • I itemRenderer gesetzt overrode so dass dies funktionieren wird, wenn Sie die itemRenderer durch AS statt mxml eingestellt. Ich habe den Texteingabeersetzungscode in seine eigene Funktion verschoben, um eine Duplizierung zu vermeiden.

  • Ich habe Setter für 'erhöhenW' und 'erhöhenH' hinzugefügt, um die Größe der Combobox zu ändern, falls nötig, weil mein Renderer zu groß für die Combobox war.

  • Ich subtrahierte 25 von der textInputReplacement Breite, so dass es nie die Dropdown-Schaltfläche überlappt ... ist es besser, etwas proportional zu verwenden, um verschiedene Skins und dergleichen unterzubringen.

Code:

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

können Sie mir helfen: // entfernen Sie die Standardtextinput \t \t \t \t \t removeChild (textinput); Implizite Koerzition eines Werts vom Typ mx.core: ITextInput auf einen nicht verwandten Typ flash.display: DisplayObject. –

-1

Dies kann viel mehr erreicht werden, einfach, wenn Sie gerade für irgendeine Art von benutzerdefinierten formatierten Text mit CSS-Attribute suchen. Überschreiben Sie die Funktion "get selectedLabel(): String", um eine beliebige Zeichenfolge, die im Textfeld angezeigt werden soll, zurückzugeben. Wenn Sie irgendeine Art von CSS benötigen, dann legen Sie den Stil für Ihren textInput (this.textInput) in der selectedLabel() -Methode fest.

0

Ich suchte nach einer Möglichkeit, dies mit der Spark ComboBox zu tun.

Dieser Thread war sehr nützlich für mich, aber bisher gab es nur Antworten darauf, wie man es mit einer mx: ComboBox macht. Ich dachte, dass ich meine Antwort anfügen sollte, wie man es mit einer Funken ComboBox macht.

  1. Erstellen Sie eine neue Haut des ComboBox
  2. ausblenden, und deaktivieren Sie die Textinput
  3. Legen Sie Ihre eigene Komponente

Dies ist, was die Haut aussehen würde:

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

Mit der Spark ComboBox ist dieser Prozess sehr einfach und erfordert keine Erweiterung der ComboBox.

3

Ich habe Dane's Code ein bisschen weiter ausgebaut. In einigen Fällen hat das Klicken auf die Drop-Box mit meinem Renderer nicht geöffnet und ich habe bemerkt, dass die normalen Flex ComboBox-Skins nicht ausgelöst wurden. Also in replaceTextInput() Ich habe einige zusätzliche Ereignis Listener hinzugefügt und speichern Sie einen Verweis auf die Schaltfläche ComboBox zum Anzeigen der Skins. Jetzt verhält es sich genau wie die normale ComboBox.

Hier ist der Code:

 
    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

ich eine einfachere Möglichkeit der Änderung der Renderer für das ausgewählte Element gefunden. Dies funktioniert nur, wenn Ihr Element von der Klasse TextInput in Flex 4.0 oder höher erbt.

In Flex v4.5, in ComboBase.createChildren in Zeile 1177, werden Sie feststellen, dass die Klasse definierbar für die textInput kann Schlüssel mit dem Stil textInputClass übergeben werden: ändern

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

einfach den Wert dieses in Schlüssel der Konstruktor Ihrer Combo und jetzt haben Sie Ihren eigenen Renderer für die selectedItem.

public function ComboAvailableProfessor() 
{ 
    super(); 

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

Schließlich müssen Sie die data Eigenschaft auf die selectedItem Eigenschaft in Ihrer Combo um binden zu erhalten angezeigten Daten.

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

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