Apache flex 在Flex3的渲染器中,mx:Canvas是如何测量的?

Apache flex 在Flex3的渲染器中,mx:Canvas是如何测量的?,apache-flex,flex3,Apache Flex,Flex3,我在HBox内的画布上遇到了尺寸问题。看起来“_graphic”、“_border”和“_fill”画布(在com.example.ThingRenderer.mxml中)与渲染器内的所有其他测量值不同时进行测量。但是,此问题仅在第一次通过时观察到。请参阅图像以了解视觉效果。。。第一幅图显示应用程序完成加载后的状态。第二幅图像表示单击填充按钮后屏幕的外观。第三幅图显示了步进器递增时发生的情况。问题是,为什么在将数据填充到表中后,第三个图像中的图形不会被渲染 RenderTest.mxml <

我在HBox内的画布上遇到了尺寸问题。看起来“_graphic”、“_border”和“_fill”画布(在com.example.ThingRenderer.mxml中)与渲染器内的所有其他测量值不同时进行测量。但是,此问题仅在第一次通过时观察到。请参阅图像以了解视觉效果。。。第一幅图显示应用程序完成加载后的状态。第二幅图像表示单击
填充
按钮后屏幕的外观。第三幅图显示了步进器递增时发生的情况。问题是,为什么在将数据填充到表中后,第三个图像中的图形不会被渲染

RenderTest.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute"
    creationComplete="handleCreationComplete(event)"
>
    <mx:Script>
        <![CDATA[
            import com.example.Thing;

            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;
            import mx.events.NumericStepperEvent;

            private const _thingProvider:ArrayCollection = new ArrayCollection();
            private var _thing1:Thing;

            protected function handleCreationComplete(event:FlexEvent):void {
                _thing1 = new Thing("thingy", 0xff0000, 0.3);
                _stepper.value = _thing1.ratio;
            }

            protected function handlePopulateClick(event:MouseEvent):void {
                _thingProvider.addItem(_thing1);
            }

            protected function handleStepperChange(event:NumericStepperEvent):void {
                _thing1.ratio = event.value;
            }

        ]]>
    </mx:Script>
    <mx:VBox>
        <mx:Button label="Populate" click="handlePopulateClick(event)" />
        <mx:NumericStepper id="_stepper" minimum="0" maximum="1" stepSize="0.01" change="handleStepperChange(event)" />
        <mx:AdvancedDataGrid dataProvider="{_thingProvider}" variableRowHeight="true" width="100%" height="100%">
            <mx:columns>
                <mx:AdvancedDataGridColumn headerText="Name" dataField="name" />
                <mx:AdvancedDataGridColumn headerText="Display"
                    width="150" sortable="false"
                    itemRenderer="com.example.ThingRenderer"
                />
            </mx:columns>
        </mx:AdvancedDataGrid>
    </mx:VBox>
</mx:Application>


所有这些都是因为无法在updateDisplayList中使用宽度和高度属性,它们尚未更新。制作单独的组件(例如ThingProgressBar)并将drawing logick放入其中,这将解决所有问题:

package
{
import mx.core.UIComponent;

public class ThingProgressBar extends UIComponent
{
    private var _ratio:Number;
    public function get ratio():Number
    {
        return _ratio;
    }
    public function set ratio(value:Number):void
    {
        _ratio = value;
        invalidateDisplayList();
    }

    override protected function updateDisplayList(
                     unscaledWidth:Number, unscaledHeight:Number):void
    {
        super.updateDisplayList(unscaledWidth, unscaledHeight);
        graphics.clear();
        if (unscaledWidth > 0 && unscaledHeight > 0)
        {
            graphics.lineStyle(1, 0xFF0000);
            graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);

            graphics.beginFill(0xFF0000);
            graphics.drawRect(0, 0, unscaledWidth * ratio, unscaledHeight);
            graphics.endFill();
        }
    }
}
}
因此,渲染器可能如下所示:

<mx:HBox
xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:mx="library://ns.adobe.com/flex/mx"
horizontalScrollPolicy="off" verticalScrollPolicy="off" xmlns:local="*"
>
<fx:Script>
    <![CDATA[
        [Bindable] private var _thing:Thing;

        override public function set data(value:Object):void
        {
            _thing = value as Thing;
            super.data = value;
        }
    ]]>
</fx:Script>

<mx:HBox width="100%"
             paddingLeft="5" paddingTop="5"
             paddingRight="5" paddingBottom="5">
    <mx:Label text="{_thing.name}" width="45" />
    <local:ThingProgressBar width="100%" height="15"
                                    ratio="{_thing.ratio}"/>
</mx:HBox>
</mx:HBox>

  • 我移除了守望者。由观察者绑定被认为是一种不好的做法,请改用mxml绑定或事件
  • 我移走了两个有分开的边界和填充的画布——它们可以被放在一起
  • 我使用UIComponent而不是Canvas。除非需要布局,否则不要使用容器,因为它们很重
  • 我在渲染器中使用HBox而不是Canvas,因为我更喜欢框:),但若您需要自定义样式,则无法避免在渲染器中使用第二个容器,因为列表会覆盖渲染器的样式表

  • 我玩了大约30分钟,感到很沮丧。我认为,fill.width和border.width返回为0。我不知道它为什么会这样做。因为列表组件(和子类)明确地设置了宽度,而不是宽度(出于某种原因)。我可以看出您所说的是一个合法的解决方案,但是为什么在updateDisplayList函数中_容器(包装mx:Canvas的mx:HBox)的大小是正确的?这是混淆和误导-一些组件的大小和一些不。。。知道为什么吗?@Andrey,看看BoxLayout或Canvas内部,它们在更新期间使用两对函数和属性进行操作:getExplicitOrMeasuredWidth/Heights()和percentWidth/Height,而不是width/Heights本身。当容器布局它的子容器时,它不会影响它的子容器,相反,它们将在LayoutManager中排队等待布局,并将在以后更新(甚至可能在下一帧中)。所以,当您试图在updateDisplayList中检查孙子的大小时,它仍然是零或以前的值。这一切现在都有意义了。谢谢你的回答!
    package
    {
    import mx.core.UIComponent;
    
    public class ThingProgressBar extends UIComponent
    {
        private var _ratio:Number;
        public function get ratio():Number
        {
            return _ratio;
        }
        public function set ratio(value:Number):void
        {
            _ratio = value;
            invalidateDisplayList();
        }
    
        override protected function updateDisplayList(
                         unscaledWidth:Number, unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth, unscaledHeight);
            graphics.clear();
            if (unscaledWidth > 0 && unscaledHeight > 0)
            {
                graphics.lineStyle(1, 0xFF0000);
                graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
    
                graphics.beginFill(0xFF0000);
                graphics.drawRect(0, 0, unscaledWidth * ratio, unscaledHeight);
                graphics.endFill();
            }
        }
    }
    }
    
    <mx:HBox
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx"
    horizontalScrollPolicy="off" verticalScrollPolicy="off" xmlns:local="*"
    >
    <fx:Script>
        <![CDATA[
            [Bindable] private var _thing:Thing;
    
            override public function set data(value:Object):void
            {
                _thing = value as Thing;
                super.data = value;
            }
        ]]>
    </fx:Script>
    
    <mx:HBox width="100%"
                 paddingLeft="5" paddingTop="5"
                 paddingRight="5" paddingBottom="5">
        <mx:Label text="{_thing.name}" width="45" />
        <local:ThingProgressBar width="100%" height="15"
                                        ratio="{_thing.ratio}"/>
    </mx:HBox>
    </mx:HBox>