Средство визуализации настраиваемых элементов Flex для отображаемого элемента в поле со списком

Я использую настраиваемое средство визуализации элементов в поле со списком для отображения настраиваемого рисунка вместо текстовой метки по умолчанию.

Это отлично работает для раскрывающегося списка, но отображаемый элемент (когда список закрыт) по-прежнему является текстовым представлением моего объекта.

Есть ли способ, чтобы отображаемый элемент отображался так же, как и элемент в раскрывающемся списке?


person pbreault    schedule 06.11.2008    source источник


Ответы (6)


По умолчанию вы не можете этого сделать. Однако, если вы расширите ComboBox, вы сможете легко добавить эту функциональность. Вот краткий пример, это грубая версия и, вероятно, требует тестирования / настройки, но она показывает, как вы можете этого добиться.

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;
            }
        }
    }
}
person Matt MacLean    schedule 11.11.2008

Я попробовал вышеуказанное решение, но обнаружил, что selectedItem не отображается при закрытии поля со списком. Для привязки свойства данных itemRenderer к выбранному элементу потребовалась дополнительная строка кода:

            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);
                    }
            }
person Maurits de Boer    schedule 23.11.2009

Я немного расширил код Дэйна. В некоторых случаях щелчок не открывал выпадающее меню в моем рендерере, и я заметил, что обычные скины Flex ComboBox не срабатывают. Таким образом, в replaceTextInput () я добавил несколько дополнительных прослушивателей событий и сохранил ссылку на кнопку ComboBox, используемую для отображения обложек. Теперь он ведет себя так же, как обычный ComboBox.

Вот код:

    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
person John    schedule 26.07.2012

Спасибо, Maclema и Морис де Бур. Я добавил в этот класс еще пару вещей, чтобы он соответствовал моим потребностям:

  • Я переопределил set itemRenderer, так что это будет работать, если вы установите itemRenderer через AS вместо mxml. Я переместил код замены ввода текста в его собственную функцию, чтобы избежать дублирования.

  • Я добавил сеттеры для «УвеличитьW» и «УвеличитьH», чтобы при необходимости изменить размер поля со списком, потому что сначала мой модуль рендеринга был слишком большим для поля со списком.

  • Я вычел 25 из ширины textInputReplacement, чтобы она никогда не перекрывала раскрывающуюся кнопку ... может быть лучше использовать что-то более пропорциональное, чтобы разместить разные скины и тому подобное.

Код:

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

                        }
                }
        }
    }
}
person Dane    schedule 15.03.2010
comment
Можете ли вы мне помочь: // удалите значение по умолчанию textInput removeChild (textInput); Неявное приведение значения типа mx.core: ITextInput к несвязанному типу flash.display: DisplayObject. - person Kumaresan K; 25.08.2016

Я искал способ сделать это с помощью Spark ComboBox.

Эта тема была для меня очень полезной, но пока были ответы только о том, как это сделать с помощью mx: ComboBox. Я подумал, что должен добавить свой ответ о том, как это сделать, используя искру ComboBox.

  1. Создайте новый скин ComboBox
  2. Скрыть и отключить textInput
  3. Вставьте свой собственный компонент

Вот как будет выглядеть скин:

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

С Spark ComboBox этот процесс очень прост и не требует расширения ComboBox.

person sixtyfootersdude    schedule 12.10.2011

Я нашел более простой способ изменить средство визуализации для выбранного элемента. Этот работает, только если ваш элемент наследуется от класса TextInput во Flex 4.0 или выше.

В Flex v4.5 в ComboBase.createChildren в строке 1177 вы обнаружите, что класс, определяемый для textInput, может быть передан с помощью ключа стиля 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();
}

Просто измените значение этого ключа в конструкторе вашего комбо, и теперь у вас есть собственный рендерер для selectedItem.

public function ComboAvailableProfessor()
{
    super();

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

Наконец, вы должны привязать свойство data к свойству selectedItem в вашем комбо, чтобы данные отображались.

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

    BindingUtils.bindProperty( textInput, 'data', this, 'selectedItem', true );
}
person Paulo Enmanuel    schedule 10.09.2015