代码之家  ›  专栏  ›  技术社区  ›  Adam Tuttle

flex itemrenderer防止在文本输入之间使用制表符

  •  7
  • Adam Tuttle  · 技术社区  · 17 年前

    我有一个习俗 项目渲染器 在3个面板中的每个面板中显示5个文本输入:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:VBox 
        xmlns:mx="http://www.adobe.com/2006/mxml"
        height="300"
        width="800"
        creationComplete="onCreationComplete()"
    >
        <!-- code-behind -->
        <mx:Script source="ChainListRenderer.mxml.as" />
    
        <mx:Label text="{data.title}" fontSize="25" fontWeight="bold" width="100%" textAlign="center" />
        <mx:HBox>
            <mx:Panel id="triggerPanel" title="Trigger" width="260">
                <mx:VBox id="tpBoxes" width="100%" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
                    <mx:TextInput id="trigger1" width="100%" textAlign="left" tabIndex="0" tabEnabled="true" />
                    <mx:TextInput id="trigger2" width="100%" textAlign="left" tabIndex="1" tabEnabled="true" />
                    <mx:TextInput id="trigger3" width="100%" textAlign="left" tabIndex="2" tabEnabled="true" />
                    <mx:TextInput id="trigger4" width="100%" textAlign="left" tabIndex="3" tabEnabled="true" />
                    <mx:TextInput id="trigger5" width="100%" textAlign="left" tabIndex="4" tabEnabled="true" />
                </mx:VBox>
            </mx:Panel>
            <mx:Panel id="linkPanel" title="Link" width="260">
                <mx:VBox id="lpBoxes" width="100%" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
                    <mx:TextInput id="link1" width="100%" textAlign="left" tabIndex="5" tabEnabled="true" />
                    <mx:TextInput id="link2" width="100%" textAlign="left" tabIndex="6" tabEnabled="true" />
                    <mx:TextInput id="link3" width="100%" textAlign="left" tabIndex="7" tabEnabled="true" />
                    <mx:TextInput id="link4" width="100%" textAlign="left" tabIndex="8" tabEnabled="true" />
                    <mx:TextInput id="link5" width="100%" textAlign="left" tabIndex="9" tabEnabled="true" />
                </mx:VBox>
            </mx:Panel>
            <mx:Panel id="answerPanel" title="Answer" width="260">
                <mx:VBox id="apBoxes" width="100%" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
                    <mx:TextInput id="answer1" width="100%" textAlign="left" tabIndex="10" tabEnabled="true" />
                    <mx:TextInput id="answer2" width="100%" textAlign="left" tabIndex="11" tabEnabled="true" />
                    <mx:TextInput id="answer3" width="100%" textAlign="left" tabIndex="12" tabEnabled="true" />
                    <mx:TextInput id="answer4" width="100%" textAlign="left" tabIndex="13" tabEnabled="true" />
                    <mx:TextInput id="answer5" width="100%" textAlign="left" tabIndex="14" tabEnabled="true" />
                </mx:VBox>
            </mx:Panel>
        </mx:HBox>
    </mx:VBox>
    

    不幸的是,当用作项呈现器时,文本输入之间的制表符不起作用,即使使用上面的tabindex值也是如此。如果我将此代码复制到自己的MXML应用程序中,文本输入之间的制表符将按预期工作。

    有人知道如何在这种情况下恢复tabbing吗?如果我不得不在没有简单可用性元素的情况下发布这个应用程序,那将是一个遗憾。

    我想我可能需要实施 mx.managers.IFocusManagerComponent 但是我找不到任何关于如何做到这一点的例子, FocusManager docs 也没有帮助。

    9 回复  |  直到 14 年前
        1
  •  3
  •   datico    17 年前

    我使用一个mx:vbox作为自定义项呈现器,其中renderReseditor=“true”用于我的数据报,我也遇到了标签顺序问题。

    我发现itemRenderer需要实现ifocusManagerComponent,以便主应用程序的focusManager()能够正确地标记到它。我尝试实现这个接口:

    <?xml version="1.0"?>
    <mx:VBox implements="mx.managers.IFocusManagerComponent" ...>
     [the rest of my itemRenderer code]
    </mx:VBox>
    

    …而且要实现的接口函数太多了。

    但是,在我的例子中,我很幸运;我的itemrenderer中只有一个textInput元素(其余都是自定义代码、验证器和格式化程序),因此我将itemrenderer从mx:vbox转换为mx:textInput(它已经实现了ifocusManagerComponent):

    <?xml version="1.0"?>
    <mx:TextInput ...>
     [the rest of my itemRenderer code]
    </mx:TextInput>
    

    哇!我的标签订单问题已解决。

    我想对于那些拥有更复杂itemrenders的人来说,结论是您需要在类中完全实现ifocusManagerComponent接口……这可能很好,因为看起来它会告诉flex如何通过itemrenderer字段自定义选项卡。或者您可以将顶级标记更改为已经实现接口的内容,例如:可以将mx:vbox嵌套在类似以下内容的内容中吗?

    <mx:Container focusIn="FocusManager.setFocus(trigger1)">
    

    …也许还能用?一个拥有比我更复杂代码的人应该尝试一下看看会发生什么。

        2
  •  3
  •   typix    15 年前

    我在“listbase-derived”组件中使用的itemRender遇到了同样的问题。 我发现所有“listbase派生的”组件都将所有项目呈现器包装在listbaseContentHolder中。

    从ListBase源:

    /**
     *  An internal display object that parents all of the item renderers,
     *  selection and highlighting indicators and other supporting graphics.
     *  This is roughly equivalent to the <code>contentPane</code> in the 
     *  Container class, and is used for managing scrolling.
     */
    protected var listContent:ListBaseContentHolder;
    

    这个 表孩 表格化的 默认情况下,此类的属性设置为false。我唯一能找到的解决方法是创建一个从列表派生的MyList组件,并通过以下方式重写CreateChildren方法(其中ListContent是初始化的):

    import flash.display.DisplayObject;
    import mx.controls.List;
    
    public class MyList extends List {
        override protected function createChildren():void {
                super.createChildren();
                this.listContent.tabChildren = this.tabChildren
                this.listContent.tabEnabled = this.tabEnabled
            }
        }
    

    然后使用“<mylist tabchildren=”true“/>”而不是“<mx:list/>”组件返回了itemprender中的选项卡功能。

    希望它有帮助,

        3
  •  0
  •   Adam Tuttle    17 年前

    我想我可能朝着正确的方向前进,但我还没有完全做到。

    我有我的主要应用程序,Horizontallist使用自定义项渲染器:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application 
        xmlns:mx="http://www.adobe.com/2006/mxml" 
        xmlns:com="ventures.view.component.*"
        layout="absolute"
        backgroundColor="#ffffff"
        preinitialize="onPreInitialize()"
        click="onClick(event)"
    >
        <!-- code-behind -->
        <mx:Script source="ConsumptionChain.as" />
    
        <!-- show chain links -->
        <mx:HorizontalList
            id="ChainList"
            direction="horizontal"
            dataProvider="{chainData}"
            rollOverColor="#ffffff"
            selectionColor="#ffffff"
            horizontalScrollPolicy="off"
            left="20"
            right="20"
            top="20"
            height="300"
            minWidth="802"
            rowHeight="300"
            columnWidth="800"
            tabChildren="false"
            itemRenderer="ventures.view.ItemRenderer.ChainListRenderer"
        />
    
    </mx:Application>
    

    我更新了原始问题中的代码示例,以包含整个项呈现器MXML(适用部分);下面是操作脚本代码:

    /*
     * ChainListRenderer.mxml.as -- code-behind for ChainListRenderer.mxml
     */
    
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;
    
    //used to combine all textboxes in a single array to make looping through them with the TAB key easier
    private var allBoxes:Array;
    
    public function expandPanel(e:Event):void {
        trace(e.currentTarget);                
        var state : String = e.currentTarget.parent.parent.id;                
        if (state != this.currentState)
            this.currentState = state;
    }
    
    private function onCreationComplete():void{
        //this function will be run on each object via the map function
        function forEach(o:Object, index:int, ar:Array):void{
            o.addEventListener(FocusEvent.FOCUS_IN, expandPanel)
            o.addEventListener(MouseEvent.CLICK, stopBubble);           //don't propagate click events (which return to base state)
            o.addEventListener(KeyboardEvent.KEY_DOWN, customTabbing);  //fix tabbing between text fields
        }
    
        this.addEventListener(KeyboardEvent.KEY_DOWN, customTabbing);
    
        //loop over textboxes and add the focusIn event listener
        tpBoxes.getChildren().map(forEach);
        lpBoxes.getChildren().map(forEach);
        apBoxes.getChildren().map(forEach);
    
        //create an "allBoxes" array that is used by the customTabbing function
        allBoxes = tpBoxes.getChildren();
        function forEachTabbing(o:Object, index:int, ar:Array):void {
            allBoxes.splice(allBoxes.length, 0, o);
        }
        lpBoxes.getChildren().map(forEachTabbing);
        apBoxes.getChildren().map(forEachTabbing);
    }
    
    //this function is used to prevent event bubbling
    private function stopBubble(e:Event):void {
        e.stopPropagation();
    }
    
    //this function re-implements tabbing between text fields, which is broken when inside an itemRenderer
    public function customTabbing(e:KeyboardEvent):void {
        trace('keyCode: ' && e.keyCode.toString());
        if (e.keyCode == flash.ui.Keyboard.TAB){
            trace(focusManager.getFocus());
            //loop over array of all text-boxes
            for (var i:int = 0; i < allBoxes.length; i++){
                trace(i.toString());
                //if event (keypress) current target is the current TextInput from the array
                if (e.currentTarget == allBoxes[i]){
                    //then focus the NEXT TextInput, and wrap if at last one
                    allBoxes[((i+1) % allBoxes.length)].setFocus();
                    //break out of the loop
                    break;
                }
            }
    
            //prevent arrow keys from navigating the horizontal list
            e.stopPropagation();
        }
    }
    

    实际上,我在这里要做的是通过检查每个文本字段的tab key on key_down事件重新实现tabbing,并使用它将焦点移动到下一个文本输入(从上一个到第一个文本输入)。不过,这并没有预期的效果,焦点仍然会跳到这个水平仪之外的下一个控件。

    你知道从这里到哪里去吗?

        4
  •  0
  •   Shua    17 年前

    你为什么这么做tabchildren=“false”?你不想把霍齐安塔利斯特的孩子们当标签吗?因为itemrenderer是列表的子级…

        5
  •  0
  •   Adam Tuttle    17 年前

    我用的方法似乎不可能做到这一点。我没有使用带有自定义项渲染器的列表,而是切换到单个项视图组件和单独的列表来显示所有项的摘要,这让我解决了我的问题。

        6
  •  0
  •   sth    16 年前

    我有同样的问题,通过尝试重新实现选项卡按钮的行为来解决它。成功的线索就是 event.preventdefault() 方法。使用的代码显示在前面。

    private function initFocusMap():void {
        focusMap = {
            InNom:benefPersona.InApePat,
            InApePat:benefPersona.InApeMat,
            InApeMat:benefPersona.InFecNacimiento,
            InFecNacimiento:benefPersona.InRFC,
            InRFC:benefPersona.InCURP,
            InCURP:benefPersona.InIdSexo,
            InIdSexo:benefPersona.InIdParentesco,
            InIdParentesco:benefPersona.InPorc,
            InPorc:domBeneficiario.InCalle,
            InCalle:domBeneficiario.InNumExterior,
            InNumExterior:domBeneficiario.InNumInterior,
            InNumInterior:domBeneficiario.InCP,
            InCP:domBeneficiario.InColonia,
            InColonia:domBeneficiario.InIdPais,
            InIdPais:domBeneficiario.InIdEdo,
            InIdEdo:domBeneficiario.InIdCiudad,
            InIdCiudad:benefPersona.InNom                   
        }
    }
    
    private function kfcHandler(event:FocusEvent):void {
        var id:String = ""
        if (event.target is AperClsDateField || event.target is AperClsCombo) {
            id = event.target.id;
        } else {
            id = event.target.parent.id;
        }
        if (id != "InIdDelegacionMunic") {
            event.preventDefault();             
            focusManager.setFocus(focusMap[id]);
        }
    }
    
        7
  •  0
  •   thargenediad    16 年前
        8
  •  0
  •   handitan    15 年前

    我在advancedDataGrid中有一个项呈现器的tabbing问题(顺便说一句,我使用的是flex sdk 3.5),但是这篇文章非常有帮助,让我可以使我的选项卡友好的项呈现器,所以我也愿意做出贡献:)

    要使其正常工作,还需要更改网格和GridColumn上的一些属性。

    我们先来谈谈网格和网格列。

    众所周知,当您将网格的“可编辑”属性设置为“真”时,您可以在每个列单元格中进行制表(假设您没有将列的“可编辑”属性设置为“假”)。

    第1步 ,使网格的“可编辑”属性设置为“真”

    第2步 ,使网格的列“可编辑”属性也设置为“真”,“renderReseditor”设置为“真”

    将数据字段设置为假字段很重要,因为我们将渲染器设置为编辑器,这意味着在项渲染器中更新的任何内容都将分配给数据字段,即将数据字段设置为“foo”,该字段具有int类型,并且有非基元对象填充组合框项渲染器。当您进行选择时,该对象将被分配给“foo”

    第3步 使网格的列“datafield”属性也设置为假字段。

    现在,让我们来做一件事情,使tabbing能够在itemrenderer上工作。

    我知道这不是一个优化版本,但这将在第一次通过。

    import mx.core.mx_internal;
    import mx.managers.IFocusManagerComponent;
    use namespace mx_internal;
    
    public class FriendlyItemRendererContainer extends HBox implements IFocusManagerComponent
    {
    
        public function FriendlyItemRendererContainer ()
        {
        super();
        addEventListener(FocusEvent.KEY_FOCUS_CHANGE, keyFocusChangeHandler);       
        }
    
        private var _listData:DataGridListData;
        //This is required to make it work as itemEditor
        public var text:String;
    
        private function keyFocusChangeHandler(event:FocusEvent):void
        {
                if (event.keyCode == Keyboard.TAB &&
                    ! event.isDefaultPrevented() &&
                    findNextChildToFocus(event.shiftKey))
                {
    
                    event.preventDefault();
    
                }
    
        }
    
        private function findNextChildToFocus(shiftKey:Boolean):Boolean
        {
              var myChildrenAry:Array = getChildren();
          var incr:int = shiftKey ? -1 : 1;
          var index:int = shiftKey ? myChildrenAry.length : 0;
          var focusChildIndex:int = 0;
          var found:Boolean = false;
    
             for (focusChildIndex = 0; focusChildIndex < myChildrenAry.length; ++focusChildIndex)
         {
            if (!(myChildrenAry[focusChildIndex] as UIComponent).visible ||
                (myChildrenAry[focusChildIndex] is Container))
            {
                //If it's an invisible UIComponent or a container then just continue
                continue;
            }
    
                if (myChildrenAry[focusChildIndex] is TextInput)
            {
                        if (systemManager.stage.focus == (myChildrenAry[focusChildIndex] as TextInput).getTextField())
                        {
                            (myChildrenAry[focusChildIndex] as UIComponent).drawFocus(false);
                            found = true;
                            break;
                        }
            }
            else
            {
                        if (systemManager.stage.focus == myChildrenAry[focusChildIndex])
                        {
                            (myChildrenAry[focusChildIndex] as UIComponent).drawFocus(false);
                            found = true;
                            break;
                        }
           }
             }
    
             if (!found)
         {
            focusChildIndex = 0;
          }
    
          while (true)
          {
                    focusChildIndex = focusChildIndex + incr;
    
                    if ((focusChildIndex < 0) || (focusChildIndex >= myChildrenAry.length))
                    {
                        UIComponentGlobals.nextFocusObject = null;
                        return false;
                    }
                    else
                    if (myChildrenAry[focusChildIndex] is UIComponent)
                    {
                    (myChildrenAry[focusChildIndex] as UIComponent).setFocus();
                    (myChildrenAry[focusChildIndex] as UIComponent).drawFocus(true);
    
                        break;
                    }
            }
    
    
            return true;
        }
    
        override public function setFocus():void
        {
           var myChildrenAry:Array = getChildren();
           if (myChildrenAry.length > 0)
           {
            for (var i:int = 0; i < myChildrenAry.length; ++i)
            {
                if ((myChildrenAry[i] is UIComponent) && (myChildrenAry[i] as UIComponent).visible)
                {
                   (myChildrenAry[i] as UIComponent).setFocus();
                       (myChildrenAry[i] as UIComponent).drawFocus(true);
                   break;
                }
           }
        }
    
        }
    
        public function get listData():BaseListData
        {
                return _listData;
        }
    
        public function set listData(value:BaseListData):void
        {
                _listData = DataGridListData(value);
        }  
    }
    

    关于如何在项渲染器上使用它的示例:

    <FriendlyItemRendererContainer xmlns:mx="http://www.adobe.com/2006/mxml">
    
    <mx:TextInput/>
    <mx:Button label="Boo"/>
    <mx:RadioButton/>
    <<mx:TextInput/>
    <mx:Button label="Baa"/>
    
    </FriendlyItemRendererContainer>
    

    然后把它放在网格列中就行了。

    享受。

        9
  •  0
  •   Cocu_1012    14 年前

    基本上,您希望删除焦点更改事件的默认行为。我认为你需要这样做:

    1. yourRenderer.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, onKeyFocusChange);
    2. since you want to stop tab key, in the handler, do this: 
            if (event.keyCode == Keyboard.TAB)
                event.preventDefault()
    3. in your keyDown handler, catch TAB, then you can manually move your focus.
    
    推荐文章