0

HBox内にあるキャンバスでサイズの問題が発生しています。「_graphic」、「_ border」、および「_fill」キャンバス(com.example.ThingRenderer.mxml内)は、レンダラー内の他のすべての測定と同時に測定されないようです。ただし、この問題は最初のパススルーでのみ観察されます。ビジュアルについては画像を参照してください...最初の画像は、アプリの読み込みが完了した後のアプリの状態を示しています。Populate2番目の画像は、ボタンがクリックされた後の画面の外観を表しています。3番目の画像は、ステッパーがインクリメントされたときに何が起こるかを示しています。問題は、データがテーブルに入力された後、3番目の画像の図面がレンダリングされないのはなぜですか?

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

com.exampleThingRenderer.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas
    xmlns:mx="http://www.adobe.com/2006/mxml"

    width="100%"
    horizontalScrollPolicy="off" verticalScrollPolicy="off"
>
    <mx:Script>
        <![CDATA[
            import mx.binding.utils.ChangeWatcher;

            private var _thing:Thing;
            private var _ratioWatcher:ChangeWatcher;

            private var _doClearContent:Boolean;
            private var _doDrawBorder:Boolean;
            private var _doUpdateFill:Boolean;

            override public function set data(value:Object):void {
                if(value && value is Thing) {
                    _thing = Thing(value);
                    if(_ratioWatcher) {
                        _ratioWatcher.unwatch();
                    }
                    _ratioWatcher = ChangeWatcher.watch(_thing, "ratio", handleRatioChanged);

                    _doClearContent = false;
                    _doDrawBorder = true;
                    _doUpdateFill = true;
                    _graphic.invalidateSize();
                    _border.invalidateSize();
                }
                else {
                    _doClearContent = true;
                    _doDrawBorder = false;
                    _doUpdateFill = false;
                }
                super.data = value;
            }

            private function handleRatioChanged(event:Event):void {
                _doUpdateFill = true;
                invalidateDisplayList();
            }

            override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
                if(_doClearContent) {
                    _container.visible = false;
                    _container.includeInLayout = false;
                    _doClearContent = false;
                }

                super.updateDisplayList(unscaledWidth, unscaledHeight);

                if(_doDrawBorder) {
                    trace("_thingContainer.width="+_container.width, "_thingGraphic.width="+_graphic.width, "_thingBorder.width="+_border.width);
                    _border.graphics.clear();
                    _border.graphics.moveTo(0, 0);
                    _border.graphics.lineStyle(1, _thing.color);
                    _border.graphics.lineTo(_border.width, 0);
                    _border.graphics.lineTo(_border.width, _border.height);
                    _border.graphics.lineTo(0, _border.height);
                    _border.graphics.lineTo(0, 0);

                    _doDrawBorder = false;
                }

                if(_doUpdateFill) {
                    _percentage.text = Math.round(_thing.ratio * 100.0) + "%";
                    _fill.graphics.clear();
                    _fill.graphics.beginFill(_thing.color);
                    _fill.graphics.drawRect(0, 0, _fill.width * _thing.ratio, _fill.height);

                    _doUpdateFill = false;
                }
            }
        ]]>
    </mx:Script>

    <mx:HBox id="_container" width="100%" paddingLeft="5" paddingTop="5" paddingRight="5" paddingBottom="5">
        <mx:Label id="_percentage" width="45" />
        <mx:Canvas id="_graphic" width="100%" height="15">
            <mx:Canvas id="_border" x="0" y="0" width="100%" height="100%" />
            <mx:Canvas id="_fill" x="0" y="0" width="100%" height="100%" />
        </mx:Canvas>
    </mx:HBox>
</mx:Canvas>

com.example.Thing.as

package com.example {
    public class Thing {
        [Bindable] public var name:String;
        [Bindable] public var color:uint;
        [Bindable] public var ratio:Number;

        public function Thing(name:String, color:uint, ratio:Number) {
            this.name = name;
            this.color = color;
            this.ratio = ratio;
        }
    }
}

アプリの読み込みが完了したときの初期外観

ポピュレートボタンがクリックされた後

ステッパーが0.30から0.40にインクリメントされた後

4

1 に答える 1

2

updateDisplayListでwidthプロパティとheightプロパティを使用できないため、これはすべて発生します。これらはまだ更新されていません。別のコンポーネント(ThingProgressBarなど)を作成し、その中に描画ロジックを配置すると、すべてが解決されます。

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>
  1. ウォッチャーを削除しました。ウォッチャーによるバインドは悪い習慣と見なされます。代わりにmxmlバインディングまたはイベントを使用してください。
  2. 境界線と塗りつぶしが分離された2つのキャンバスを削除しました。これらは一緒に組み合わせることができます。
  3. Canvasの代わりにUIComponentを使用しました。レイアウトが必要でない限り、コンテナは使用しないでください。コンテナは重いです。
  4. ボックスが好きなので、レンダラーでCanvasの代わりにHBoxを使用しました:)しかし、カスタムスタイルが必要な場合は、リストがレンダラーのスタイルシートを上書きするため、レンダラーで2番目のコンテナーを使用することを避けられません。
于 2012-05-10T14:31:30.733 に答える