从XML创建Flex组件

时间:2010-02-04 10:06:17

标签: xml flex actionscript-3 dynamic

我有一个XML,它有一个属性选项或组合框,解析我需要动态地在我的flex中创建组件。

Viatropos给出了一个很棒的代码,但是我无法执行它...任何人都可以生成它...谢谢

2 个答案:

答案 0 :(得分:10)

您可以使用以下内容动态创建Flex中的组件:

示例数据

<?xml version="1.0" encoding="UTF-8"?>
<components type="array">
    <component type="mx.controls.ComboBox">
        <width>100</width>
        <height>100</height>
        <color isStyle="true">0xff0000</color>
        <prompt>Im a Combo Box!</prompt>
    </component>
    <component type="mx.controls.Button">
        <width>100</width>
        <height>100</height>
        <color isStyle="true">0xff0000</color>
        <label>Im a Button!</label>
    </component>
</components>

示例应用

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    creationComplete="creationCompleteHandler()">

    <mx:Script>
        <![CDATA[

            import flash.display.DisplayObject;
            import mx.core.UIComponent;
            import mx.controls.ComboBox; ComboBox;

            protected function creationCompleteHandler():void
            {
                var components:Array = getComponentsFromXML(xml.component);
                var i:int = 0;
                var n:int = components.length;
                for (i; i < n; i++)
                {
                    panel.addChild(components[i] as DisplayObject);
                }
            }

            /**
             *  Parses an XML string, returns array of new components.
             */
            public function getComponentsFromXML(components:XMLList):Array
            {
                var result:Array = [];
                var child:Object;
                var component:UIComponent;
                var type:String;
                var clazz:Class;
                var i:int = 0;
                var n:int = components.length();
                for (i; i < n; i++)
                {
                    child = components[i];
                    type = child.@type;
                    try {
                        clazz = flash.utils.getDefinitionByName(type) as Class;
                    } catch (error:ReferenceError) {
                        traceImportError(type);
                    }

                    component = new clazz(); // dynamic

                    var properties:XMLList = child.elements();
                    var property:XML;
                    var name:String;
                    var value:Object;

                    // for each child node
                    for each (property in properties)
                    {
                        name = property.localName();
                        value = property.toString();
                        // create a more generic method to convert
                        // strings to numbers and whatnot
                        // this is a regular expression matching any digit
                        // check out rubular.com
                        if (/\d+/.test(value.toString()))
                            value = Number(value);

                        if (property.attribute("isStyle") == "true")
                            component.setStyle(name, value);
                        else
                            component[name] = value;
                    }
                    result.push(component);
                }
                return result;
            }

            protected function traceImportError(type:String):void
            {
                trace("Please include the class '" + type + "' in the swf.");
                var names:Array = type.split(".");
                var last:String = names[names.length - 1];
                trace("import " + type + "; " + last + ";");
            }

        ]]>
    </mx:Script>

    <!-- sample data -->
    <mx:XML id="xml" source="components.xml" />

    <!-- sample container -->
    <mx:Panel id="panel" width="100%" height="100%"/>

</mx:Application>

只要你有一个XML的定义结构,就可以创建一个XMLUtil来一般地处理xml(例如,获取所有属性,或者将字符串转换为正确的类型),以及一个带有XML文件的ComponentManifest类并将其转换为组件。

您还需要确保将XML中定义的所有类都导入到swf中,否则会抛出该错误。你可以这样做:

import mx.controls.ComboBox; ComboBox;

直接导入,没有第二个ComboBox将无法执行此操作。

这应该让你开始,根据需要填写它!

如果您想要更好/高级的xml值解析,请查看Rubular以便使用Regular Expressions。)

答案 1 :(得分:2)

以下是@ viatropos解决方案的修改版本:

示例数据:

<?xml version="1.0" encoding="UTF-8"?>
<components type="array">
    <component type="mx.controls::ComboBox">
        <width>100</width>
        <height>100</height>
        <color isStyle="true">"0xff0000"</location>
        <label>"Im a Combo Box!"</label>
    </component>
    <component type="mx.controls::Button">
        <width>100</width>
        <height>100</height>
        <color isStyle="true">"0xff0000"</location>
        <label>"Im a Button!"</label>
    </component>
</components>

显然有一个错误用于结束标记。

我还在所有字符串值周围添加了引号,以便更容易识别它们。

示例(伪)方法: createComponentsFromXML(xml.components)

public function createComponentsFromXML(components:XMLList):void
{
    var child:Object;
    var component:UIComponent;
    var i:int = 0;
    var n:int = components.length();
    for (i; i < n; i++)
    {
        child = components[i];
        var clazz:Class = flash.utils.getDefinitionByName(child.@type);
        component = new clazz(); // dynamic
        var property:Object;
        var value:Object;
        var useIntVal:Boolean;
        var intVal:int;
        // for each child node
        for (property in child.children())
        {
            useIntVal = false;
            value = property.toString();
            if(!(value.substr(1, 2) == '"' AND value.substr(-1, value.length()) == '"')) {
                useIntVal = true;
                intVal = parseInt(value);
            }
            // button["width"] = 100;
            if (property.attribute("isStyle") == "true")
                if(useIntVal) {
                    component.setStyle(property.localName(), intVal);
                } else {
                    component.setStyle(property.localName(), value);
                }
            else {
                if(useIntVal) {
                    component[property.localName()] = intVal;
                } else {
                    component[property.localName()] = value;
                }
            }
        }
    }
}

我实现了转换为int,确保我检查属性是字符串还是int。

PS:我现在没有安装Flex,因此您可能会发现需要纠正的一些错误。

在这种情况下,您可能希望像这样使用XML:

<?xml version="1.0" encoding="UTF-8"?>
<components type="array">
    <component type="mx.controls::ComboBox">
        <properties>
            <width>100</width>
            <height>100</height>
            <color isStyle="true">"0xff0000"</location>
            <label>"Im a Combo Box!"</label>
        </properties>
    </component>
    <component type="mx.controls::Button">
        <properties>
            <width>100</width>
            <height>100</height>
            <color isStyle="true">"0xff0000"</location>
            <label>"Im a Button!"</label>
        </properties>
        <children>
            <!--other children here-->
        </children>
    </component>
</components>

因为我怀疑你可以用手风琴中的一层嵌套来做很多事情。

我将把这个功能留给你。