`
smithfox
  • 浏览: 55074 次
  • 性别: Icon_minigender_1
  • 来自: hf
社区版块
存档分类
最新评论

[译]从Flex中owner和parent的区别来说Flex API设计思路

阅读更多

英文原文: Flex 4 Gumbo DOM Tree API - Functional and Design Specification

翻译的原创链接:  http://www.smithfox.com/?e=36  转载请注明, 文中如果有什么错误的地方或是讲的不清楚的地方,欢迎大家留言.

这是一篇难得的Flex功能和架构技术SPEC, 耐心看完绝对有收获.

为了振作你看这个文章的兴趣, 假设你应聘Flex工作被问到了下面的几个问题:

1. Flex中owner和parent有什么区别?

2. addChild和addElement两套函数有什么不同,(不是指怎么使用不同, 而是指框架内部的设计有什么不同)?

3. <s:Rect>是GraphicElement吗, 他们为什么可以放在<s:Group>内?

4. SkinnableComponent, SkinnableContainer, Group, DataGroup以及SkinnableDataContainer有什么区别?

5. 最关键的是: 你知道smithfox吗?(哈哈)

 

目的

在Flex 4中有许多DOM(Document Object Model)树。他们到底是怎么组织和呈现的?

定义

图形元素(graphic element) - 就象是矩形, 路径, 或是图片. 这些元素不是DisplayObject的子类; 但是它们还是需要一个DisplayObject来渲染到屏幕. (smithfox注: "多个图形元素可以只用一个DisplayObject来渲染")

视觉元素(visual element) - (英文有时简称为 - "element"). 可以是一个halo组件, 或是一个gumbo组件, 或是一个图形元素. 视觉元素实现了接口 IVisualElement.

数据项 (英文有时简称为 - "item") - 本质上Flex中的任何事物都可以被看着数据项. 通常是指非可视化项,比如 String, Number, XMLNode, 等等. 一个视觉元素也能作为数据项 -- 这要看他是怎么被看待的.

组件树 - 组件树表现了MXML文档结构. 举个简单例子, 一个 Panel 包含了一个 Label. 这个例子中, Panel 和 Label 都在组件树中, 但是 Panel的皮肤却不是.

布局树 - 布局树呈现了运行时的布局. 在这个树中, 父亲负责呈现和布局对象, 孩子则是被布局的视觉元素.  举个简单例子, 一个 Panel 包含了一个 Label.  这个例子中, Panel 和 Label 都在布局树中, 同样Panel皮肤和皮肤中的contentGroup也是.

显示树 - Flash 底层 DisplayObject 树.

本文中的全部图的图例如下:

背景:

当你用MXML创建应用程序时, 幕后发生了许多的事情,会将MXML转换成Flash显示对象. 后台有三个主要因素: 皮肤,项渲染和显示对象sharing. 前两个对开发人员是非常重要的概念; 最后一个只需要框架开发人员关注, 但仍然比较重要.

皮肤:

当你初始化一个 Button, 其实创建了不止一个对象. 例如:

<s:Button />

 在布局树中的结果是:


(注: TextBox 已经更名为 Label)

一个皮肤文件被实例化了,并且加入到Button的显示列表中.Button的皮肤文件如下:

 

<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"  minWidth="23" minHeight="23">

    <fx:Metadata>
    	[HostComponent("mx.components.Button")]
    </fx:Metadata>

    <s:states>
        <s:State name="up" />
        <s:State name="over" />
        <s:State name="down" />
        <s:State name="disabled" />
    </s:states>

    <!-- background -->
    <s:Rect left="0" right="0" top="0" bottom="0"
    	  width="70" height="23"
    	  radiusX="2" radiusY="2">
        <s:stroke>
            <s:SolidColorStroke color="0x5380D0" color.disabled="0xA9C0E8" />
        </s:stroke>
        <s:fill>
            <s:SolidColor color="0xFFFFFF" color.over="0xEBF4FF" color.down="0xDEEBFF" />
        </s:fill>
    </s:Rect>

    <!-- label -->
    <s:Label id="labelDisplay" />

</s:Skin>
 尽管Button看上去是一个叶子结点, 但因为皮肤的存在, 实际上他包含了孩子. 为访问这些元素,所有SkinnableComponent对象都定义了skin属性. 这样就可以通过Button.Skin实例来访问Rectangle 和Label. 如要访问Label, 你可以写成:myButton.skin.getElementAt(2)或是 myButton.skin.labelDisplay.由于labelDisplay是 Button 的 skin part, 所以你可可以直接写成 myButton.labelDisplay.

同样的原则也一样适用在SkinnableContainerSkinnableContainer是容器所以天然就有孩子, 但同时他们也是SkinnableComponent,所以也有一个皮肤以及来自皮肤的孩子.

(smithfox注: SkinnableContainer的确是继承自SkinableComponent, 见图)

还是以Panel为例:

<s:Panel>
    <s:Button />
    <s:Label />
    <s:CheckBox />
</s:Panel>
 panel有三个孩子:一个button,一个label,和一个checkbox.用定义在SkinnableContainer上的content APIs可以访问他们. 这些content APIs很像flash DisplayObjectContainer 的 APIs, 包括addElement(), addElementAt(), getElementAt(), getElementIndex(), 等等.... 所有方法的完整列表在稍后文档中列出.

因为 panel有3个孩子, 它的组件树象这样:


(注: TextBox 已经更名为 Label)

但是, 这只是组件树. 因为皮肤的原因, Panel真正布局树是这样的:


(注: TextBox 已经更名为 Label)

在上面这张图上有许多箭头. 需要注意的有:

  • Panel的组件孩子有: button, label, 和checkbox.
  • button, label, 和checkbox的组件父亲(owner 属性) 是 Panel.
  • button, label, and checkbox的布局父亲 (parent 属性) 是 Panel皮肤的contentGroup.

这意味着即使看上去Panel的孩子应该是一个button, 一个label, 和一个checkbox; 但实际上真正的孩子是一个panel皮肤实例. button, label, 和 checkbox 向下变成了皮肤中contentGroup的孩子. 有几种方法可以访问panel中的ButtonmyPanel.getElementAt(0) or myPanel.contentGroup.getElementAt(0) or myPanel.skin.contentGroup.getElementAt(0).

所有 SkinnableComponent 都有 skin 属性. 在 SkinnableContainer中组件的孩子实际上下推成为skin的 contentGroup的孩子组件树 指向编译自MXML的语义树.Panel 例子中, 只包括Panel 和他的孩子: 一个 button, 一个 label, 和一个checkbox. 由于皮肤, 布局树 是布局系统所实际看到的树.Panel 例子中,包括 这个panel, panel的皮肤, 以及这个皮肤的所有孩子(皮肤中的contentGroup的孩子).

布局树无需和所见的Flash显示列表有什么相关性. 这是因为 GraphicElement 不是天然的显示对象. 因为考虑效率的原因, 他们最小化了显示对象数目(smithfox注: 多个GraphicElement可以在一个DisplayObject上渲染, 这样DisplayObject的总数就可以大大减少).

(smithfox注: GraphicElement是spark的类, 确实是少有继承层次非常少的对象, 如图:)

IVisualElementContainer 定义了content APIs. 在Spark中, SkinGroup, 和 SkinnableContainer 实现了这个接口,持有着可视化元素. 为保持一致性, MX的 Container 也实现了这个接口, 不过只是对addChild(), numChildren, 等函数的封装....

package mx.core
{

public interface IVisualElementContainer
{

//----------------------------------
//  Visual Element iteration
//----------------------------------

/**
 *  The number of elements in this group.
 * 
 *  @return The number of visual elements in this group
 */
public function get numElements():int;

/**
 *  Returns the visual element that exists at the specified index.
 *
 *  @param index The index of the element to retrieve.
 *
 *  @return The element at the specified index.
 * 
 *  @throws RangeError If the index position does not exist in the child list.
 */ 
public function getElementAt(index:int):IVisualElement

//----------------------------------
//  Visual Element addition
//----------------------------------

/**
 *  Adds a visual element to this visual container. The element is 
 *  added after all other elements and on top of all other elements.  
 *  (To add a visual element to a specific index position, use 
 *  the <code>addElementAt()</code> method.)
 * 
 *  <p>If you add a visual element object that already has a different
 *  container as a parent, the element is removed from the child 
 *  list of the other container.</p>  
 *
 *  @param element The element to add as a child of this visual container.
 *
 *  @return The element that was added to the visual container.


 * 
 *  @event elementAdded ElementExistenceChangedEvent Dispatched when 
 *  the element is added to the child list.
 * 
 *  @throws ArgumentError If the element is the same as the visual container.
 */   
public function addElement(element:IVisualElement):IVisualElement;

/**
 *  Adds a visual element to this visual container. The element is 
 *  added at the index position specified.  An index of 0 represents   
 *  the first element and the back (bottom) of the display list, unless
 *  <code>layer</code> is specified.
 * 
 *  <p>If you add a visual element object that already has a different
 *  container as a parent, the element is removed from the child 
 *  list of the other container.</p>  
 *
 *  @param element The element to add as a child of this visual container.
 * 
 *  @param index The index position to which the element is added. If 
 *  you specify a currently occupied index position, the child object 
 *  that exists at that position and all higher positions are moved 
 *  up one position in the child list.
 *
 *  @return The element that was added to the visual container.
 * 
 *  @event elementAdded ElementExistenceChangedEvent Dispatched when 
 *  the element is added to the child list.
 * 
 *  @throws ArgumentError If the element is the same as the visual container.
 * 
 *  @throws RangeError If the index position does not exist in the child list.
 */
public function addElementAt(element:IVisualElement, index:int):IVisualElement;

//----------------------------------
//  Visual Element removal
//----------------------------------

/**
 *  Removes the specified visual element from the child list of 
 *  this visual container.  The index positions of any elements 
 *  above the element in this visual container are decreased by 1.
 *
 *  @param element The element to be removed from the visual container.
 *
 *  @return The element removed from the visual container.
 * 
 *  @throws ArgumentError If the element parameter is not a child of 
 *  this visual container.
 */
public function removeElement(element:IVisualElement):IVisualElement;

/**
 *  Removes a visual element from the specified index position 
 *  in the visual container.
 *
 *  @param index The index of the element to remove.
 *
 *  @return The element removed from the visual container.
 * 
 *  @throws RangeError If the index does not exist in the child list.
 */
public function removeElementAt(index:int):IVisualElement;

//----------------------------------
//  Visual Element index
//----------------------------------

/**
 *  Returns the index position of a visual element.
 *
 *  @param element The element to identify.
 *
 *  @return The index position of the element to identify.
 * 
 *  @throws ArgumentError If the element is not a child of this visual container.
 */ 
public function getElementIndex(element:IVisualElement):int;

/**
 *  Changes the position of an existing visual element in the visual container.
 * 
 *  <p>When you call the <code>setElementIndex()</code> method and specify an 
 *  index position that is already occupied, the only positions 
 *  that change are those in between the elements's former and new position.
 *  All others will stay the same.</p>
 *
 *  <p>If a visual element is moved to an index 
 *  lower than its current index, the index of all elements in between increases
 *  by 1.  If an element is moved to an index
 *  higher than its current index, the index of all elements in between 
 *  decreases by 1.</p>
 *
 *  @param element The element for which you want to change the index number.
 * 
 *  @param index The resulting index number for the element.
 * 
 *  @throws RangeError - If the index does not exist in the child list.
 *
 *  @throws ArgumentError - If the element parameter is not a child 
 *  of this visual container.
 */
public function setElementIndex(element:IVisualElement, index:int):void;

//----------------------------------
//  Visual Element swapping
//----------------------------------

/**
*  Swaps the index of the two specified visual elements. All other elements
*  remain in the same index position.
*
*  @param element1 The first visual element.
*  @param element2 The second visual element.
*/
public function swapElements(element1 :IVisualElement, element2 :IVisualElement):void;

/**
 *  Swaps the visual elements at the two specified index 
 *  positions in the visual container.  All other visual 
 *  elements remain in the same index position.
 *
 *  @param index1 The index of the first element.
 * 
 *  @param index2 The index of the second element.
 * 
 *  @throws RangeError If either index does not exist in 
 *  the visual container.
 */
public function swapElementAt(index1:int, index2:int):void;

}
}
 

这个接口使访问树变得容易了. 本质上, 这个接口为容器对外暴露有它哪些孩子提供了方法. 例如, FocusManager就是这样. 该接口使得 focus manager不依赖于Group 或是其它 Spark代码(除了这个接口), MX也不必增加太多代码. 我们讨论过要不要增加这些变异的(mutation) APIs,要不要MX也实现这些接口, 但我们认为这将有助有开发人员(框架开发人员) 实现所有容器(MX和Spark). 当我们看 DataGroup and SkinnableDataContainer 代码时, 你会发现他们并没有实现IVisualElementContainer接口, 尽管DataGroup有几个相似的 "只读的" 方法, 比如 numElements 和 getElementAt().

(smithfox注: 从Spark最终SDK中的代码可以验证, 如图)


IVisualElementContainer 持有 IVisualElementsIVisualElement 是可视化元素的一个新接口. 它包含了一些必要的属性和方法以使容器可以增加element. 他继承自 ILayoutElement 并增加了一些其它属性.

////////////////////////////////////////////////////////////////////////////////
//
//  ADOBE SYSTEMS INCORPORATED
//  Copyright 2003-2008 Adobe Systems Incorporated
//  All Rights Reserved.
//
//  NOTICE: Adobe permits you to use, modify, and distribute this file
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////
package mx.core
{

/**
 *  The IVisualElement interface defines the minimum properties and methods 
 *  required for a visual element to be laid out and displayed in a Spark container.
 */
public interface IVisualElement extends ILayoutElement
{

    /**
     *  The owner of this IVisualElement object. 
     *  By default, it is the parent of this IVisualElement object.
     *  However, if this IVisualElement object is a child component that is
     *  popped up by its parent, such as the drop-down list of a ComboBox control,
     *  the owner is the component that popped up this IVisualElement object.
     *
     *  <p>This property is not managed by Flex, but by each component.
     *  Therefore, if you use the <code>PopUpManger.createPopUp()</code> or
     *  <code>PopUpManger.addPopUp()</code> method to pop up a child component,
     *  you should set the <code>owner</code> property of the child component
     *  to the component that popped it up.</p>
     *
     *  <p>The default value is the value of the <code>parent</code> property.</p>
     */
    function get owner():DisplayObjectContainer;
    function set owner(value:DisplayObjectContainer):void;
    
    /**
     *  The parent container or component for this component.
     *  Only visual elements should have a <code>parent</code> property.
     *  Non-visual items should use another property to reference
     *  the object to which they belong.
     *  By convention, non-visual objects use an <code>owner</code>
     *  property to reference the object to which they belong.
     */
    function get parent():DisplayObjectContainer;
    
    ...OTHER STUFF NOT DISCUSSED HERE...
}
}

(smithfox注: IVisualElement接口为什么是放在mx.core包内,确实有点怪, 但这是事实, 如图)

视觉元素的parent, 也就是容器, 直接负责布局. 视觉元素的owner是视觉元素的逻辑持有组件. 如果一个 Button在一个SkinnableContainer里, 它的parent是contentGroup而它的owner 是这个 SkinnableContainer.

请注意  parent 和 owner 属性类型是 DisplayObjectContainer 而不是 IVisualElementContainer. 这是因为在MX内, 这些属性就是 
DisplayObjectContainer. 此外, 因为 parent 属性是继承自 Flash的 DisplayObject, 我们无法改变他. 我们曾讨论过为这个属性起个新名字, 但最后我们认为这样不值得.

(smithfox注: DisplayObjectContainer是flash.display.Sprite的父类)

未完,javaeye截断了

分享到:
评论

相关推荐

    Flex4 中文API

    Flex4中文API文档详细记录了AS3的各种类库、方法、属性和事件,帮助开发者理解和利用这些功能。 1. **Flex Framework**:Flex框架包括一系列组件、服务和工具,用于构建用户界面。它提供了MXML,一种声明式语言,让...

    Flex4.0中文API

    总的来说,Flex 4.0中文API文档是开发者学习Flex 4.0框架的关键资源,它详细解释了如何使用Flex组件、事件、服务以及如何利用Spark组件模型来创建高度定制化的用户界面。通过查阅这个CHM文档,开发者可以快速掌握...

    Flex 中文API以及开发指南链接

    在本压缩包中,重点是Flex的中文API和开发指南,这对于初学者和有经验的开发者来说都是宝贵的资源。 首先,让我们来了解一下Flex API。API,全称Application Programming Interface,是一系列预先定义的函数,允许...

    flex 中文API

    这个"flex 中文API"是针对初学者的中文版文档,旨在帮助开发者快速理解并掌握Flex编程的核心概念和API用法。 1. **Flex SDK与Flex Builder** Flex SDK是一个开源工具集,包含了编译Flex应用所需的编译器、库和...

    flex_api (FLEX接口)

    在本文中,我们将深入探讨Flex API的核心概念、主要特点以及如何使用它来开发动态、互动的Web应用。 1. **Flex SDK与Flex API** Flex SDK(Software Development Kit)是一套免费的开发工具,包含编译Flex应用程序...

    flex4中文API帮助文档

    总的来说,Flex4中文API帮助文档是Flex开发者不可或缺的工具,它覆盖了Flex4的所有核心功能,包括组件、MXML、ActionScript、布局、动画、服务集成等多个方面,对于学习和掌握Flex4开发技术至关重要。无论你是初学者...

    ArcGIS Flex API和SuperMap Flex API实现的军标箭头库

    在军标箭头库的实现中,开发者可能利用了ArcGIS Flex API的图形对象和符号系统来绘制各种军标箭头,这些箭头可以表示战术动作、方向或兵力部署等。 另一方面,SuperMap Flex API则是SuperMap公司为Flex开发者提供的...

    Flex4.0API中文手册完整版

    总的来说,Flex 4.0 API中文手册是开发者深入学习Flex开发不可或缺的资源,它详尽地涵盖了从基础概念到高级特性的各个方面,帮助开发者熟练掌握Flex 4.0框架,创造出功能丰富、交互性强的RIA应用。

    flex4.6-api.chm

    我见到过的最好用的flex4 chm api,非常完整,超级帮 最新Flex4.6中文API,离线帮助文档,无js错误

    Flex4.0中文API.rar

    这个版本的Flex引入了全新的设计和编程模型,极大地增强了开发者创建复杂、动态且具有高度交互性的Web应用的能力。Flex 4.0中文API文档是为中文开发者提供的官方参考手册,帮助他们理解和运用Flex 4.0的各类功能和...

    Flex中文API

    Flex中文API文档是学习和使用Flex的关键资源,它详尽地解释了每个类、方法、属性和事件,对于初学者和经验丰富的开发者来说都是不可或缺的工具。通过深入研究这个文档,开发者可以熟练掌握Flex的各个方面,构建出...

    flex4.5.1.chm flex4API文档

    在Flex 4.5.1版本中,引入了一系列改进和新特性,为开发者提供了更强大的功能和更好的用户体验设计。这个"flex4.5.1.chm"文件是一个完整的Flex 4 API文档,它是开发人员的重要参考资料,包含了大量的类库、函数、...

    Flex 4 中文API

    Flex 4 中文API 绝对的好东西 不是损坏的

    Adobe Flex 3 API

    总的来说,Adobe Flex 3 API为开发者提供了一个全面的框架,帮助他们构建功能强大、视觉吸引人的RIA。通过学习和掌握这个API,开发者可以创建出高度交互、响应迅速的Web应用程序,同时利用Adobe的技术栈实现广泛的...

    flex的资料 api

    1. **Flex API**:Flex API是Flex框架的核心组成部分,提供了大量的类库和接口,用于创建和管理组件、处理事件、进行数据绑定、网络通信等。例如,`mx.controls`包下的Button、Label、TextInput等控件,以及`mx....

    Flex中文API,类方法说明

    综上所述,“Flex中文API”是一份宝贵的资源,对于想要理解和掌握Flex框架的开发者来说,无论英语水平如何,都能从中受益。通过深入学习这些文档,开发者将能够熟练地运用Flex构建高效、美观的RIA。

    Flex_API.rar_flex_flex api

    中文版的Flex API 文档对于中国开发者来说是一份非常有价值的参考资料,它可以帮助开发者更方便地理解和使用Flex框架。 Flex是Adobe公司开发的一个开源框架,基于ActionScript编程语言,用于构建跨平台的、基于...

    flex3-cn-api..zip_flex_flex 3 api_flex3 api_flex3 a_flex3 api

    在“flex3-cn-api..zip_flex_flex 3 api_flex3 api_flex3 a_flex3 api”这个压缩包中,包含了Flex 3 API的中文文档,这对于Flex开发者来说是一个非常宝贵的资源。文档名为“Flex3拞暥API..chm”,其中的“拞暥”可能...

    Flex 4.5 API

    Flex 4.5 API 是Adobe Flex框架的一个重要版本,它为开发者提供了丰富的工具和技术来创建交互式的、基于Web的应用程序。这个API集成了ActionScript 3.0,使得开发人员可以利用面向对象的编程能力来构建高效且动态的...

Global site tag (gtag.js) - Google Analytics