【问题标题】:Flex custom item renderer for the displayed item in the combobox组合框中显示项目的 Flex 自定义项目渲染器
【发布时间】:2008-11-06 18:30:10
【问题描述】:

我在组合框中使用自定义项渲染器来显示自定义绘图而不是默认文本标签。

这适用于下拉列表,但显示的项目(当列表关闭时)仍然是我的对象的文本表示。

有没有办法让显示的项目以与下拉列表中的相同的方式呈现?

【问题讨论】:

    标签: apache-flex actionscript-3 combobox mxml itemrenderer


    【解决方案1】:

    默认情况下您不能这样做。但是,如果您扩展 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;
                }
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      我尝试了上面的解决方案,但发现关闭组合框时,selectedItem没有显示。需要一行额外的代码将 itemRenderer 数据属性绑定到 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);
                          }
                  }
      

      【讨论】:

        【解决方案3】:

        我进一步扩展了 Dane 的代码。在某些情况下,单击并没有用我的渲染器打开下拉框,我注意到正常的 Flex ComboBox 皮肤没有触发。因此,在 replaceTextInput() 中,我添加了一些额外的事件侦听器,并保存了对用于显示皮肤的 ComboBox 按钮的引用。现在它的行为就像普通的 ComboBox 一样。

        代码如下:

        包裹 { 导入 flash.events.Event; 导入 flash.events.KeyboardEvent; 导入 flash.events.MouseEvent; 导入 mx.binding.utils.BindingUtils; 导入 mx.controls.Button; 导入 mx.controls.ComboBox; 导入 mx.core.IFactory; 导入 mx.core.UIComponent; 导入 mx.events.DropdownEvent; /** * 标准组合框的扩展,将使用分配的“itemRenderer” * 用于列表项和选定项。 * * 基于以下代码: * http://stackoverflow.com/questions/269773/flex-custom-item-renderer-for-the-displayed-item-in-the-combobox */ 公共类 ComboBoxFullRenderer 扩展 ComboBox { 受保护的 var textInputReplacement:UIComponent; 私人 var _increaseW:Number = 0; 私有变量 _increaseH:Number = 0; /** * 跟踪下拉列表的当前打开/关闭状态。 */ 受保护的 var _isOpen:Boolean = false; /** * 存储对覆盖组合框的“按钮”的引用。允许 * 我们将事件传递给它,以便正确触发皮肤。 */ 受保护的 var _buttonRef:Button = null; /** * 构造函数。 */ 公共函数 ComboBoxFullRenderer() { 极好的(); } /** * 设置一个值来增加我们的 ComboBox 的宽度以调整大小。 * * @param val 增加组合框宽度的像素数。 */ 公共函数集增加W(val:Number):void { _increaseW = val; } /** * 设置一个值来增加我们的 ComboBox 的高度来调整大小。 * * @param val 增加组合框高度的像素数。 */ 公共函数集增加H(val:Number):void { _increaseH = 值; } /** * 覆盖 'itemRenderer' 设置器,这样我们也可以替换选定的 * 项目渲染器。 * * @param value 用于显示下拉列表项的渲染器 * 和所选项目。 */ 覆盖公共函数集 itemRenderer(value:IFactory):void { super.itemRenderer = 值; 替换文本输入(); } /** * 覆盖基本的 'createChildren()' 例程来调用我们的 'replaceTextInput()' * 替换标准选定项渲染器的方法。 * * @see #replaceTextInput(); */ 覆盖受保护的函数 createChildren():void { super.createChildren(); 替换文本输入(); } /** * 用我们自己的孩子替换 ComboBox 'textInput' 孩子的例程 * 这将呈现选定的数据元素。将创建一个实例 * 为这个 ComboBox 设置的 'itemRenderer'。 */ 受保护的函数replaceTextInput():void { 如果(!textInputReplacement){ if ( this.itemRenderer != null && textInput != null ) { //删除默认的文本输入 removeChild(textInput); //创建一个新的 itemRenderer 实例来代替文本输入 textInputReplacement = this.itemRenderer.newInstance(); // 监听点击,以便我们可以在何时打开/关闭下拉菜单 // 渲染器组件被点击。 textInputReplacement.addEventListener(MouseEvent.CLICK, _onClick); // 在我们的渲染器上监听鼠标事件,以便我们可以将它们提供给 // ComboBox 覆盖按钮。这将确保按钮皮肤 // 被激活。请参阅 ComboBox::commitProperties() 代码。 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); // 将 textInputReplacement 的数据绑定到选中项 BindingUtils.bindProperty(textInputReplacement, "data", this, "selectedItem", true); // 将我们的渲染器添加为子级。 addChild(textInputReplacement); // 监听打开关闭,这样我们就可以保持状态。这 // 'isShowingDropdown' 属性是 mx_internal 所以我们不 // 可以访问它。 this.addEventListener(DropdownEvent.OPEN, _onOpen); this.addEventListener(DropdownEvent.CLOSE, _onClose); // 保存对组合框的 mx_internal 按钮的引用。 // 我们需要这个,所以我们可以调用它的 dispatchEvent() 方法。 for (var i:int = 0; i

        【讨论】:

          【解决方案4】:

          感谢 maclema 和 Maurits de Boer。我在这个类中添加了一些东西来满足我的需要:

          • 我覆盖了 set itemRenderer,因此如果您通过 AS 而不是 mxml 设置 itemRenderer,这将起作用。我将文本输入替换代码移到了自己的函数中以避免重复。

          • 我为“increaseW”和“increaseH”添加了设置器,以便在必要时调整组合框的大小,因为起初我的渲染器对于组合框来说太大了。

          • 我从 textInputReplacement 宽度中减去了 25,因此它不会与下拉按钮重叠...可能会更好地使用更成比例的东西来适应不同的皮肤等。

          代码:

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

          【讨论】:

          • 你能帮帮我吗://删除默认的textInput removeChild(textInput);将 mx.core:ITextInput 类型的值隐式强制转换为不相关的类型 flash.display:DisplayObject。
          【解决方案5】:

          我正在寻找一种使用 Spark ComboBox 的方法。

          这个帖子对我来说非常有用,但到目前为止,只有关于如何使用 mx:ComboBox 的答案。我认为我应该附加关于如何使用 spark ComboBox 执行此操作的答案。

          1. 创建 ComboBox 的新外观
          2. 隐藏和禁用文本输入
          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。

          【讨论】:

            【解决方案6】:

            我找到了一种更简单的方法来更改所选元素的渲染器。仅当您的元素继承自 Flex 4.0 或更高版本中的 TextInput 类时,此选项才有效。

            在 Flex v4.5 中,在第 1177 行的 ComboBase.createChildren 中,您会发现为 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 );
            }
            

            【讨论】:

              猜你喜欢
              • 2010-09-11
              • 1970-01-01
              • 2014-01-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多