如何将一个工作s:TextInput添加到s:Datagrid HeaderRenderer?

时间:2012-05-07 17:15:47

标签: flex flex4 itemrenderer flex-spark

我需要/想要在我的某些数据网格的标题中添加s:TextInput,以便为表格提供过滤功能(其思路是:“在输入字段中键入文本,按Enter键,数据网格过滤”)。目前我正在使用s:TextInput处理HeaderRenderer,但也会有使用s:CheckBoxess:DropDownLists的渲染器。

我正在尝试使用自定义RendererSkin,但我遇到了几个问题:

  1. 您无法输入s:TextInput(虽然鼠标悬停时光标会变为工字梁,但控件会获得焦点边框。)
  2. 与标题进行了几次交互后,s:TextInputs似乎“泄漏”了某种白色矩形(见截图)。
  3. verticalAlign="bottom"似乎没有像我认为的那样工作。

  4. 到目前为止,我的HeaderRenderer看起来像这样:

    <?xml version="1.0" encoding="utf-8"?>
    <s:DefaultGridHeaderRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx"
        mouseEnabledWhereTransparent="true">
        <fx:Script>
            <![CDATA[
                import spark.components.DataGrid;
                import spark.components.GridColumnHeaderGroup;
                import spark.components.TextInput;
                import spark.components.gridClasses.GridColumn;
                import spark.components.gridClasses.IGridVisualElement;
                import spark.primitives.supportClasses.GraphicElement;
    
                import mx.collections.ArrayCollection;
                import mx.core.IFactory;
                import mx.core.IVisualElement;
                import mx.events.FlexEvent;
    
                // chrome color constants and variables
                private static const DEFAULT_COLOR_VALUE:uint = 0xCC;
    
                private static const DEFAULT_COLOR:uint = 0xCCCCCC;
    
                private static const DEFAULT_SYMBOL_COLOR:uint = 0x000000;
    
                private static var colorTransform:ColorTransform = new ColorTransform();
    
                private function dispatchChangeEvent(type:String):void {
                    if (hasEventListener(type))
                        dispatchEvent(new Event(type));
                }
    
                // ----------------------------------
                // maxDisplayedLines
                // ----------------------------------
                private var _maxDisplayedLines:int = 1;
    
                [Bindable("maxDisplayedLinesChanged")]
                [Inspectable(minValue="-1")]
                override public function get maxDisplayedLines():int {
                    return _maxDisplayedLines;
                }
    
                /**
                 *  @private
                 */
                override public function set maxDisplayedLines(value:int):void {
                    if (value == _maxDisplayedLines)
                        return;
    
                    _maxDisplayedLines = value;
                    if (labelDisplay)
                        labelDisplay.maxDisplayedLines = value;
    
                    invalidateSize();
                    invalidateDisplayList();
    
                    dispatchChangeEvent("maxDisplayedLinesChanged");
                }
    
                // ----------------------------------
                // sortIndicator
                // ----------------------------------
                private var _sortIndicator:IFactory;
    
                private var sortIndicatorInstance:IVisualElement;
    
                [Bindable("sortIndicatorChanged")]
                override public function get sortIndicator():IFactory {
                    return (_sortIndicator) ? _sortIndicator : defaultSortIndicator;
                }
    
                override public function set sortIndicator(value:IFactory):void {
                    if (_sortIndicator == value)
                        return;
    
                    _sortIndicator = value;
                    if (sortIndicatorInstance) {
                        sortIndicatorGroup.includeInLayout = false;
                        sortIndicatorGroup.removeElement(sortIndicatorInstance);
                        sortIndicatorInstance = null;
                    }
    
                    invalidateDisplayList();
                    dispatchChangeEvent("sortIndicatorChanged");
                }
    
                override public function prepare(hasBeenRecycled:Boolean):void {
                    super.prepare(hasBeenRecycled);
    
                    if (labelDisplay && labelDisplayGroup && (labelDisplay.parent != labelDisplayGroup)) {
                        labelDisplayGroup.removeAllElements();
                        labelDisplayGroup.addElement(labelDisplay);
                    }
    
                    if (labelDisplayGroup.numChildren < 2) {
                        var filter:TextInput = new TextInput();
                        filter.percentWidth = 100;
                        filter.addEventListener(FlexEvent.ENTER, filter_handleEnter);
                        filterDisplayGroup.addElement(filter);
                    }
    
                    const column:GridColumn = this.column;
                    if (sortIndicator && column && column.grid && column.grid.dataGrid && column.grid.dataGrid.columnHeaderGroup) {
                        const dataGrid:DataGrid = column.grid.dataGrid;
                        const columnHeaderGroup:GridColumnHeaderGroup = dataGrid.columnHeaderGroup;
    
                        if (columnHeaderGroup.isSortIndicatorVisible(column.columnIndex)) {
                            if (!sortIndicatorInstance) {
                                sortIndicatorInstance = sortIndicator.newInstance();
                                sortIndicatorGroup.addElement(sortIndicatorInstance);
                                chromeColorChanged = true;
                                invalidateDisplayList();
                            }
    
                            // Initialize sortIndicator
                            sortIndicatorInstance.visible = true;
                            const gridVisualElement:IGridVisualElement = sortIndicatorInstance as IGridVisualElement;
                            if (gridVisualElement)
                                gridVisualElement.prepareGridVisualElement(column.grid, -1, column.columnIndex);
    
                            sortIndicatorGroup.includeInLayout = true;
                            sortIndicatorGroup.scaleY = (column.sortDescending) ? 1 : -1;
                        } else {
                            if (sortIndicatorInstance) {
                                sortIndicatorGroup.removeElement(sortIndicatorInstance);
                                sortIndicatorGroup.includeInLayout = false;
                                sortIndicatorInstance = null;
                            }
                        }
                    }
                }
    
                private var chromeColorChanged:Boolean = false;
    
                private var colorized:Boolean = false;
    
                override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
                    // Apply chrome color
                    if (chromeColorChanged) {
                        var chromeColor:uint = getStyle("chromeColor");
    
                        if (chromeColor != DEFAULT_COLOR || colorized) {
                            colorTransform.redOffset = ((chromeColor & (0xFF << 16)) >> 16) - DEFAULT_COLOR_VALUE;
                            colorTransform.greenOffset = ((chromeColor & (0xFF << 8)) >> 8) - DEFAULT_COLOR_VALUE;
                            colorTransform.blueOffset = (chromeColor & 0xFF) - DEFAULT_COLOR_VALUE;
                            colorTransform.alphaMultiplier = alpha;
    
                            transform.colorTransform = colorTransform;
    
                            var exclusions:Array = [labelDisplay, sortIndicatorInstance];
    
                            // Apply inverse colorizing to exclusions
                            if (exclusions && exclusions.length > 0) {
                                colorTransform.redOffset = -colorTransform.redOffset;
                                colorTransform.greenOffset = -colorTransform.greenOffset;
                                colorTransform.blueOffset = -colorTransform.blueOffset;
    
                                for (var i:int = 0; i < exclusions.length; i++) {
                                    var exclusionObject:Object = exclusions[i];
    
                                    if (exclusionObject && (exclusionObject is DisplayObject || exclusionObject is GraphicElement)) {
                                        colorTransform.alphaMultiplier = exclusionObject.alpha;
                                        exclusionObject.transform.colorTransform = colorTransform;
                                    }
                                }
                            }
    
                            colorized = true;
                        }
    
                        chromeColorChanged = false;
                    }
    
                    super.updateDisplayList(unscaledWidth, unscaledHeight);
                }
    
                override public function styleChanged(styleProp:String):void {
                    var allStyles:Boolean = !styleProp || styleProp == "styleName";
    
                    super.styleChanged(styleProp);
    
                    if (allStyles || styleProp == "chromeColor") {
                        chromeColorChanged = true;
                        invalidateDisplayList();
                    }
                }
    
                private function filter_handleEnter(event:FlexEvent):void {
                    if (this.grid.dataProvider is ArrayCollection) {
                        (this.grid.dataProvider as ArrayCollection).refresh();
                    }
                }
            ]]>
        </fx:Script>
    
        <fx:Declarations>
            <fx:Component id="defaultSortIndicator">
                <s:Path data="M 3.5 7.0 L 0.0 0.0 L 7.0 0.0 L 3.5 7.0" implements="spark.components.gridClasses.IGridVisualElement">
                    <fx:Script>
                        <![CDATA[
                            import spark.components.DataGrid;
                            import spark.components.Grid;
    
                            public function prepareGridVisualElement(grid:Grid, rowIndex:int, columnIndex:int):void {
                                const dataGrid:DataGrid = grid.dataGrid;
                                if (!dataGrid)
                                    return;
    
                                const color:uint = dataGrid.getStyle("symbolColor");
                                arrowFill1.color = color;
                                arrowFill2.color = color;
                            }
                        ]]>
                    </fx:Script>
    
                    <s:fill>
                        <s:RadialGradient rotation="90" focalPointRatio="1">
                            <s:GradientEntry id="arrowFill1" color="0" alpha="0.6"/>
    
                            <s:GradientEntry id="arrowFill2" color="0" alpha="0.8"/>
                        </s:RadialGradient>
                    </s:fill>
                </s:Path>
            </fx:Component>
    
            <s:Label id="labelDisplay" verticalCenter="1" left="0" right="0" top="0" bottom="0" textAlign="start"
                fontWeight="bold" verticalAlign="bottom" maxDisplayedLines="1" showTruncationTip="true"/>
        </fx:Declarations>
    
        <s:states>
            <s:State name="normal"/>
            <s:State name="hovered"/>
            <s:State name="down"/>
        </s:states>
    
        <!-- layer 1: shadow -->
    
        <s:Rect id="shadow" left="-1" right="-1" top="-1" bottom="-1" radiusX="2">
            <s:fill>
                <s:LinearGradient rotation="90">
                    <s:GradientEntry color="0x000000" color.down="0xFFFFFF" alpha="0.01" alpha.down="0"/>
    
                    <s:GradientEntry color="0x000000" color.down="0xFFFFFF" alpha="0.07" alpha.down="0.5"/>
                </s:LinearGradient>
            </s:fill>
        </s:Rect>
    
        <!-- layer 2: fill -->
    
        <s:Rect id="fill" left="0" right="0" top="0" bottom="0">
            <s:fill>
                <s:LinearGradient rotation="90">
                    <s:GradientEntry color="0xFFFFFF" color.hovered="0xBBBDBD" color.down="0xAAAAAA" alpha="0.85"/>
    
                    <s:GradientEntry color="0xD8D8D8" color.hovered="0x9FA0A1" color.down="0x929496" alpha="0.85"/>
                </s:LinearGradient>
            </s:fill>
        </s:Rect>
    
        <!-- layer 3: fill lowlight -->
    
        <s:Rect id="lowlight" left="0" right="0" top="0" bottom="0">
            <s:fill>
                <s:LinearGradient rotation="270">
                    <s:GradientEntry color="0x000000" ratio="0.0" alpha="0.0627"/>
    
                    <s:GradientEntry color="0x000000" ratio="0.48" alpha="0.0099"/>
    
                    <s:GradientEntry color="0x000000" ratio="0.48001" alpha="0"/>
                </s:LinearGradient>
            </s:fill>
        </s:Rect>
    
        <!-- layer 4: fill highlight -->
    
        <s:Rect id="highlight" left="0" right="0" top="0" bottom="0">
            <s:fill>
                <s:LinearGradient rotation="90">
                    <s:GradientEntry color="0xFFFFFF" ratio="0.0" alpha="0.33" alpha.hovered="0.22" alpha.down="0.12"/>
    
                    <s:GradientEntry color="0xFFFFFF" ratio="0.48" alpha="0.33" alpha.hovered="0.22" alpha.down="0.12"/>
    
                    <s:GradientEntry color="0xFFFFFF" ratio="0.48001" alpha="0"/>
                </s:LinearGradient>
            </s:fill>
        </s:Rect>
    
        <!-- layer 5: highlight stroke (all states except down) -->
    
        <s:Rect id="highlightStroke" left="0" right="0" top="0" bottom="0" excludeFrom="down">
            <s:stroke>
                <s:LinearGradientStroke rotation="90" weight="1">
                    <s:GradientEntry color="0xFFFFFF" alpha.hovered="0.22"/>
    
                    <s:GradientEntry color="0xD8D8D8" alpha.hovered="0.22"/>
                </s:LinearGradientStroke>
            </s:stroke>
        </s:Rect>
    
        <!-- layer 6: highlight stroke (down state only) -->
    
        <s:Rect id="hldownstroke1" left="0" right="0" top="0" bottom="0" includeIn="down">
            <s:stroke>
                <s:LinearGradientStroke rotation="90" weight="1">
                    <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.0"/>
    
                    <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.001"/>
    
                    <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.0011"/>
    
                    <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.965"/>
    
                    <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.9651"/>
                </s:LinearGradientStroke>
            </s:stroke>
        </s:Rect>
    
        <s:Rect id="hldownstroke2" left="1" right="1" top="1" bottom="1" includeIn="down">
            <s:stroke>
                <s:LinearGradientStroke rotation="90" weight="1">
                    <s:GradientEntry color="0x000000" alpha="0.09" ratio="0.0"/>
    
                    <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.0001"/>
                </s:LinearGradientStroke>
            </s:stroke>
        </s:Rect>
    
        <s:VGroup bottom="5" left="7" right="7" top="5" gap="2" verticalAlign="bottom">
            <s:Group id="filterDisplayGroup" width="100%"/>
    
            <s:HGroup bottom="5" left="7" right="7" top="5" gap="2" verticalAlign="bottom">
                <s:Group id="labelDisplayGroup" width="100%" left="8" right="8"/>
    
                <s:Group id="sortIndicatorGroup" includeInLayout="false"/>
            </s:HGroup>
        </s:VGroup>
    </s:DefaultGridHeaderRenderer>
    

    所以基本上,我想要的是这个(基本上是一种更简单的this $800 datagrid component形式):

    enter image description here

    我目前拥有的是(带有上述问题):

    enter image description here enter image description here

    • “Longname”列显示鼠标悬停在白色“泄漏”
    • “短名称”列中的s:TextInput似乎有焦点,但您无法输入
    • “Id”列的标签仍然垂直居中,但它应位于底部

    任何人都可以给我一个暗示我的渲染器出了什么问题(主要是为什么我不能输入输入字段的freck以及这个白色东西来自哪里)?

3 个答案:

答案 0 :(得分:1)

的Datagrid:

<mx:DataGrid id="myGrid" dataProvider="{initDG}" variableRowHeight="true"> 
    <mx:columns>
        <mx:DataGridColumn headerText="col1"/>
        <mx:DataGridColumn headerText="col2"/>
        <mx:DataGridColumn headerText="col3"/>
        <mx:DataGridColumn headerRenderer="col4DGheaderRenderer"/>
    </mx:columns>       
</mx:DataGrid>

然后是col4DGheaderRenderer的完整代码:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:s="library://ns.adobe.com/flex/spark">
    <s:TextInput/>
    <mx:Label text="label text"/>
</mx:VBox>

答案 1 :(得分:1)

正如我们在评论中所讨论的那样,您的代码中有很多内容可能成为不当行为的可能来源。我碰巧有一个标题渲染器,其功能非常相似,完美无缺。所以我只是将代码转储到这里,你可以开始解决这个问题了。

一些注意事项:

  • 此渲染器具有简化的图形:您可以将默认Spark渲染器的图形粘贴回来并替换我的fill组件
  • 它扩展了GridItemRenderer而不是DefaultGridHeaderRenderer(如评论中所述)
  • 它通过mxml添加了TextInput,而不是通过ActionScript动态添加,这降低了复杂性

<s:GridItemRenderer minWidth="21" minHeight="21"
                xmlns:fx="http://ns.adobe.com/mxml/2009" 
                xmlns:s="library://ns.adobe.com/flex/spark" 
                xmlns:vmm="library://ns.vmm.be/flex/components">

<fx:Declarations>
    <fx:Component id="defaultSortIndicator">
        <s:Path data="M 3.5 7.0 L 0.0 0.0 L 7.0 0.0 L 3.5 7.0" implements="spark.components.gridClasses.IGridVisualElement">

            <s:fill>
                <s:RadialGradient rotation="90" focalPointRatio="1">    
                    <s:GradientEntry id="arrowFill1" color="0" alpha="0.6" />
                    <s:GradientEntry id="arrowFill2" color="0" alpha="0.8" />
                </s:RadialGradient>
            </s:fill>
        </s:Path>
    </fx:Component>

    <s:Label id="labelDisplay" verticalCenter="1" left="0" right="0" top="0" bottom="0"
             textAlign="start" verticalAlign="middle" maxDisplayedLines="1" showTruncationTip="true"
             color.normal="0x555555" color="0x90a938" fontWeight="bold" />
</fx:Declarations>

<fx:Script>
    <![CDATA[
        import spark.components.gridClasses.IGridVisualElement;
        import mx.core.IVisualElement;

        import spark.components.DataGrid;
        import spark.components.GridColumnHeaderGroup;
        import spark.components.gridClasses.GridColumn;
        import spark.primitives.supportClasses.GraphicElement;


        private function dispatchChangeEvent(type:String):void {
            if (hasEventListener(type)) dispatchEvent(new Event(type));
        }            

        //----------------------------------
        //  maxDisplayedLines
        //----------------------------------

        private var _maxDisplayedLines:int = 1;

        [Bindable("maxDisplayedLinesChanged")]
        [Inspectable(minValue="-1")]
        public function get maxDisplayedLines():int {
            return _maxDisplayedLines;
        }

        public function set maxDisplayedLines(value:int):void {
            if (value == _maxDisplayedLines) return;

            _maxDisplayedLines = value;
            if (labelDisplay) labelDisplay.maxDisplayedLines = value;

            invalidateSize();
            invalidateDisplayList();

            dispatchChangeEvent("maxDisplayedLinesChanged");
        }

        //----------------------------------
        //  sortIndicator
        //----------------------------------

        private var _sortIndicator:IFactory;
        private var sortIndicatorInstance:IVisualElement;

        [Bindable("sortIndicatorChanged")]
        public function get sortIndicator():IFactory {
            return (_sortIndicator) ? _sortIndicator : defaultSortIndicator;
        }

        public function set sortIndicator(value:IFactory):void {
            if (_sortIndicator == value) return;

            _sortIndicator = value;
            if (sortIndicatorInstance) {
                sortIndicatorGroup.includeInLayout = false;
                sortIndicatorGroup.removeElement(sortIndicatorInstance);
                sortIndicatorInstance = null;
            }

            invalidateDisplayList();
            dispatchChangeEvent("sortIndicatorChanged");
        }

        override public function prepare(hasBeenRecycled:Boolean):void {
            super.prepare(hasBeenRecycled);

            if (labelDisplay && labelDisplayGroup && (labelDisplay.parent != labelDisplayGroup)) {
                labelDisplayGroup.removeAllElements();
                labelDisplayGroup.addElement(labelDisplay);
            }

            const column:GridColumn = this.column;
            if (sortIndicator && column && column.grid && column.grid.dataGrid && column.grid.dataGrid.columnHeaderGroup) {
                const dataGrid:DataGrid = column.grid.dataGrid;
                const columnHeaderGroup:GridColumnHeaderGroup = dataGrid.columnHeaderGroup;

                if (columnHeaderGroup.isSortIndicatorVisible(column.columnIndex)) {
                    if (!sortIndicatorInstance) {
                        sortIndicatorInstance = sortIndicator.newInstance();
                        sortIndicatorGroup.addElement(sortIndicatorInstance);
                        invalidateDisplayList();
                    }

                    // Initialize sortIndicator
                    sortIndicatorInstance.visible = true;
                    const gridVisualElement:IGridVisualElement = sortIndicatorInstance as IGridVisualElement;
                    if (gridVisualElement)
                        gridVisualElement.prepareGridVisualElement(column.grid, -1, column.columnIndex);

                    sortIndicatorGroup.includeInLayout = true;
                    sortIndicatorGroup.scaleY = (column.sortDescending) ? 1 : -1;
                }
                else if (sortIndicatorInstance) {
                    sortIndicatorGroup.removeElement(sortIndicatorInstance);
                    sortIndicatorGroup.includeInLayout = false;
                    sortIndicatorInstance = null;
                }
            }
        }

        override public function styleChanged(styleProp:String):void {
            var allStyles:Boolean = !styleProp || styleProp == "styleName";
            super.styleChanged(styleProp);
            if (allStyles) invalidateDisplayList();
        }
    ]]>
</fx:Script>

<s:states>
    <s:State name="normal" />
    <s:State name="hovered" />
    <s:State name="down" />
</s:states>      

<s:Rect id="fill" left="0" right="0" top="0" bottom="0">
    <s:fill>
        <s:LinearGradient rotation="90">
            <s:GradientEntry color.normal="0xf9f9f9" color.hovered="0xfcfdfa" 
                             color.down="0xdceac2" alpha="0.85" />
            <s:GradientEntry color.normal="0xeaeaea" color.hovered="0xdceac2"
                             color.down="0xd2e1b5" alpha="0.85" />
        </s:LinearGradient>
    </s:fill>
</s:Rect>

<s:VGroup left="7" right="7" top="5" bottom="5" gap="6" verticalAlign="middle">
    <s:TextInput width="100%" />
    <s:HGroup width="100%">
        <s:Group id="labelDisplayGroup" width="100%" />
        <s:Group id="sortIndicatorGroup" includeInLayout="false" />
    </s:HGroup>
</s:VGroup>

</s:GridItemRenderer>

答案 2 :(得分:0)

下面的代码显示了如何使用Header Renderer将输入框放入Header。我希望这可以解决问题。

<fx:Script>
    <![CDATA[
        import mx.controls.Alert;
        protected function button1_clickHandler(event:MouseEvent):void
        {
            Alert.show(s.headerText);

        }
    ]]>
</fx:Script>

<fx:Declarations>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>

<mx:DataGrid id="myGrid" x="-4" y="0" width="528" horizontalScrollPolicy="off"
             variableRowHeight="true" verticalScrollPolicy="off"> 
    <mx:columns>
        <mx:DataGridColumn headerText="col1"/>
        <mx:DataGridColumn headerText="col2"/>
        <mx:DataGridColumn headerText="col3"/>
        <mx:DataGridColumn  id="s">
        <mx:headerRenderer>
            <fx:Component>
                    <mx:VBox >
                        <s:TextInput width="{outerDocument.s.width}" id="p" change="{outerDocument.s.headerText=p.text}"/>
                        <s:Label text="col4"/>
                    </mx:VBox>  
            </fx:Component>
        </mx:headerRenderer>
        </mx:DataGridColumn>
    </mx:columns>       
</mx:DataGrid>
<s:Button x="10" y="150" label="click" click="button1_clickHandler(event)"/>