在Flex应用程序中ActionScript的最主要的用处大概就是使用可视化的控件和容器来开发了。Flex提供了几种技术来完成这样工作,包括了用ActionScript引用Flex控件以及操控控件和容器的实例的属性。
为了在ActionScript中使用组件,我们一般要在MXML标签中给组件定义一个id属性。例如,下面的代码中,我们设置了Button控件的id属性为”myButton”:
<mx:Button id="myButton" label="Click Me"/>
如果你并不像通过使用ActionScript来操控这个组件,那么这个属性是可有可无的。
这段代码使得MXML编译器自动生成一个包含了Button实例的引用的名字为myButton的公共变量。你可以在ActionScript中通过使用这个自动生成的变量来操控组件。你可以在任意的ActionScript类或代码块中通过组件的id来明确的引用Button控件的实例。通过引用组件的实例,你可以修改组件的属性并且调用组件的方法。
例如,下面的ActionScript代码块中,当用户点击了按钮的时候,程序就会改变Button控件的label属性的值:
<?xml version="1.0"?>
<!-- usingas/ButtonExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
private function setLabel():void {
if (myButton.label=="Click Me") {
myButton.label = "Clicked";
} else {
myButton.label = "Click Me";
}
}
]]></mx:Script>
<mx:Button id="myButton" label="Click Me" click="setLabel();"/>
</mx:Application>
所有的MXML组件的id属性,无论它们嵌套的有多深,生成的都是已经定义好的组件的公共变量。因此,在文档中所有的id属性必须是唯一的。这也意味着,如果你指定了组件实例的id属性,你就可以在程序的任意地方来操控组件:函数,外部的类文件,导入的ActionScript文件,或者内嵌代码。
如果Flex组件并没有id属性,你可以通过使用组件的容器的一些方法来引用该组件。比如getChildAt()和getChildByName()方法。
你可以参照目前内附文件或者当前对象来使用这样的关键字。
你也可以通过使用跟组件名称一样的字符来引用组件。要在程序中使用对象,你可以通过使用方括号,方括号内存放的就是跟组件名称一样的字符串。这样你就得到了该对象的引用。
下面的例子中,通过使用字符串来获取对象的引用,然后改变每个Button控件的样式:
<?xml version="1.0"?>
<!-- usingas/FlexComponents.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
private var newFontStyle:String;
private var newFontSize:int;
public function changeLabel(s:String):void {
s = "myButton" + s;
if (this[s].getStyle("fontStyle")=="normal") {
newFontStyle = "italic";
newFontSize = 18;
} else {
newFontStyle = "normal";
newFontSize = 10;
}
this[s].setStyle("fontStyle",newFontStyle);
this[s].setStyle("fontSize",newFontSize);
}
]]></mx:Script>
<mx:Button id="myButton1"
click="changeLabel('2')"
label="Change Other Button's Styles"
/>
<mx:Button id="myButton2"
click="changeLabel('1')"
label="Change Other Button's Styles"
/>
</mx:Application>
这个小技巧有着比较特殊的用处,当你在用Repeater控件或用ActionScript创建了一个对象的时候,你不必知道对象的名字你也可以在运行时来引用该对象。但是,当你用ActionScript实例化一个对象的时候,如果要添加该对象到应用程序的属性数组(按本人的理解:该数组为应用程序的数组,包含程序中定义的组件的实例)中去,你必须定义该变量为public并且要在整个的类的作用域范围定义,而不是在函数的内部定义。
下面的例子中,用ActionScript在整个程序作用域中定义了两个Label控件。在程序初始化的时候,label控件会被初始化并设置text属性值。在这个例子中,当用户点击Button控件的时候,我们可以通过附加的字符串来获取Label控件的引用。
<?xml version="1.0"?>
<!-- usingas/ASLabels.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initLabels()">
<mx:Script><![CDATA[
import mx.controls.Label;
public var label1:Label;
public var label2:Label;
// 对象必须定义在整个程序的作用域里。
// 并且将名称添加到程序的属性数组中去
public function initLabels():void {
label1 = new Label();
label1.text = "Change Me";
label2 = new Label();
label2.text = "Change Me";
addChild(label1);
addChild(label2);
}
public function changeLabel(s:String):void {
// 创建一个与Label控件的名字一样的字符串
s = "label" + s;
// 通过使用程序的属性数组来获取Label控件的引用.
this[s].text = "Changed";
}
]]></mx:Script>
<mx:Button id="b1" click="changeLabel('2')" label="Change Other Label"/>
<mx:Button id="b2" click="changeLabel('1')" label="Change Other Label"/>
</mx:Application>
在Flex应用程序中你可以使用点标记语法来调用组件实例的公共方法,如下所示:
componentInstance.method([parameters]);
在下面的例子中,当用户点击按钮的时候,程序为调用adjustThumb()方法,在这个方法中又会调用HSlider控件的公共方法setThumbValueAt():
<?xml version="1.0"?>
<!-- usingas/ComponentMethods.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
public function adjustThumb(s:HSlider):void {
var randomNumber:int = (Math.floor(Math.random() * 10));
s.setThumbValueAt(0, randomNumber);
}
]]></mx:Script>
<mx:HSlider id="slider1" tickInterval="1"
labels="[1,2,3,4,5,6,7,8,9,10]"
width="282"
/>
<mx:Button id="myButton"
label="Change Thumb Position"
click="adjustThumb(slider1);"
/>
</mx:Application>
你可以通过使用parentApplication, parentDocument, 或者 Application.application属性从子文本(如自定义的MXML组件)中调用方法,。
注意:由于Flex在绘制组件之前会调用初始化事件,所以你不能在初始化事件中操控组件的大小和位置等信息,除非在creationComplete事件中来实现。
通过使用ActionScript中的new 操作符你可以程序化的创建可视化的Flex组件,用同样的方式你也可以创建任何ActionScript类的实例。创建后的组件的属性都有默认的值,但是组件此时并没有父类和子类(包含各式各样的DisplayObject),而且此时组件并不在Flash Player或Adobe AIR的显示列表中,因此无法在界面看到该组件。当创建组件完成后,你可以使用标准的赋值语句来重新设置组件的属性的值。
如果你要把新创建的组件添加到容器中去,必须使用容器的addChild()和addChildAt()方法,通过这种方法可以使得组件变成Flex程序的显示层级的一部分。当组件第一次被添加到容器的时候,组件的子实例就被创建了。在组件的生命周期子实例创建的时候比较晚,因此你可以在子实例创建完成后设置它的属性。
当创建可视化组建的时候,你必须导入合适的包。在大多数情况下,这些包基本都在mx.controls包中,具体的你可以查阅Adobe Flex Language Reference
下面的例子中,创建了一个Button控件并田间到HBox中去:
<?xml version="1.0"?>
<!-- usingas/ASVisualComponent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.controls.Button;
public var button2:Button;
public function createObject():void {
button2 = new Button();
button2.label = "Click Me";
hb1.addChild(button2);
}
]]></mx:Script>
<mx:HBox id="hb1">
<mx:Button label="Create Object" click="createObject()"/>
</mx:HBox>
</mx:Application>
Flex容器中新创建的元素将会排在容器的最后。如果你并不像让新创建的元素排在容器的最后,可是使用addChildAt()方法来改变元素的顺序。你也可以在调用addChild()方法后使用setChildIndex()方法来实现,不过这样做的话效率会降低。
你应该为每个动态创建的组件定义实例变量并且将新创建的组件的实例存储在变量里,就像当你为组件的实例标签设置了id属性的时候MXML编译器所做的那样。然后你就可以访问你刚才动态创建的组件。
如果要在程序中移除一个组件,你需要使用removeChild()或removeChildAt()方法。你也可以使用removeAllChildren()方法来移除容器的所有组件。调用这些方法并不是真正的删除这些对象。如果你在程序没有这些对象的任何引用,那么Flash Player的垃圾回收机制就会在将来的某个时间点进行回收。如果在程序中存储了该对象的引用,那么系统将会不从内存中移除该对象。
在有些情况下,你是通过使用MXML标签来定义组件的。你可以设置容器的creationPolicy属性为none来延迟容器中组件的实例化。为了创建那些用标签定义了但没有实例化的组件,你可以使用createComponentFromDescriptor()和
createComponentsFromDescriptors()方法。使用这些方法可以让你程序化的创建组件而不是声明化的。
可以支持addChild()方法的组件是UIComponent。换句话说,如果你创建了一个并不是mx.core.UIComponent的子类的对象,在你将该对象添加到容器之前你必须用UIComponent封装该对象。下面的例子中,创建了并不是UIComponent子类的Sprite对象,在将该对象添加到Panel容器之前将对象添加为UIComponent的子对象:
<?xml version="1.0"?>
<!-- usingas/AddingChildrenAsUIComponents.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import flash.display.Sprite;
import mx.core.UIComponent;
private var xLoc:int = 20;
private var yLoc:int = 20;
private var circleColor:Number = 0xFFCC00;
private function addChildToPanel():void {
var circle:Sprite = new Sprite();
circle.graphics.beginFill(circleColor);
circle.graphics.drawCircle(xLoc, yLoc, 15);
var c:UIComponent = new UIComponent();
c.addChild(circle);
panel1.addChild(c);
xLoc = xLoc + 5;
yLoc = yLoc + 1;
circleColor = circleColor + 20;
}
]]></mx:Script>
<mx:Panel id="panel1" height="250" width="300" verticalScrollPolicy="off"/>
<mx:Button id="myButton" label="Click Me" click="addChildToPanel();"/>
</mx:Application>
ActionScript中的作用域指的是对this关键引用到某个特殊点的描述。在你的程序的核心的MXML文件中,你可以使用this关键字来访问程序中对象。在定义了MXML组件的文件中,this关键字是当前组件的实例的引用。
在一个ActionScript类文件中,this关键字是当前类的实例的引用。在下面的例子中,this关键字是myClass类的实例的引用。由于this是隐式的,你不需要使用this关键字,它也能显示出它所表达的意思。
class myClass {
var _x:Number = 3;
function get x():Number {
return this._x;
}
function set x(y:Number):void {
if (y > 0) {
this._x = y;
} else {
this._x = 0;
}
}
}
然而,在自定义的ActionScript和MXML组件或者外部的ActionScript类文件中,在Flex执行这些对象和类文件的背景下,this关键字指的是当前作用域而并不是应用程序对象的作用域。
你可以使用Flex的Application.application属性来访问根应用。你也可以使用parentDocument属性来访问Flex应用程序的文档链的下一级,或者当应用程序使用了SWFLoader组件来加载另外一个应用程序对象的时候通过使用parentApplication属性可以访问应用程序链的下一级。
如果你在组件的事件监听器中添加了ActionScript代码,作用域值得是不是组件本身而是应用程序。例如,下面的例子中,一旦Button组件被按下,组件的label属性的值会变为”Clicked”:
<?xml version="1.0"?>
<!-- usingas/ButtonScope.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Panel width="250" height="100" layout="absolute" x="65" y="24">
<mx:Button id="myButton"
label="Click Me"
click="myButton.label='Clicked'"
x="79.5"
y="20"
/>
</mx:Panel>
<mx:Button label="Reset"
x="158"
y="149"
click="myButton.label='Click Me'"
/>
</mx:Application>
将下面的代码与之前的代码进行比较:
<?xml version="1.0"?>
<!-- usingas/AppScope.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!—下面的代码执行后没做任何事情是因为应用程序没有label属性可以设置-->
<mx:Button id="myButton" label="Click Me" click="label='Clicked'"/>
</mx:Application>
上面的代码并没有做任何的动作是因为当事件执行的时候,this关键并不是Button按钮实例的引用。This关键是应用程序或者其他的顶级组件实例的引用。程序试图设置应用程序对象的label属性,而并不是设置Button按钮的label属性的值。
在函数中声明的变量的作用域就是在这个函数中。在函数的外部也可以定义相同名字的变量,并且函数内部定义的变量并不影响外部的以同样名字命名的变量。如果一个变量只是在函数中作临时用,那就定义该变量为函数内的变量而不要定义为实例变量。使用实例变量仅仅是为了存储实例的状态,因为每个实例变量在实例的整个生命周期中会占用内存。你可以通过使用this.前缀来引用外部的变量。