显示具有 ActionScript 标签的文章。 显示所有文章
显示具有 ActionScript 标签的文章。 显示所有文章

2008年9月16日 星期二

Flash 技巧 - 字体资料转换与解析方式   [+/-]

相信大家应该都看过 fontpark 2.0 网站了吧
基本上,它是透过后端程序取得 font glyphs 矢量资料的
才能够做到随意缩放不失真

至于该如何从 TTF 取出资料呢?
资料格式又该使用哪一种呢?

其实网络上有不少工具可将 TTF 转为 PostScript、SVG、... 等等
相较起来,PostScript 语法需要自行去解析
而且 PostScript 有些绘图动作可能是 Flash 做不到的

AS3 有支持 E4X,同时 SVG 绘图的资料语法与 AS graphics API 比较相近
解析起来也更容易些
可以使用的工具有 Java Batik SVG ToolKit

不过后来又发现还有更好用的方式
那就是 ActionScript Viewer
千万不要以为它只是反编译程序的工具喔
它还可以将嵌入的字体输出 TTF、SWF、ActionScript Data
看到 ActionScript Data 了吧,意思就是连解析都不用!

那么事情就变得很简单了,只要制作一个 SWF
里面嵌入想要用的字体,输出 SWF,丢到 ASV 内
取出 Font Glyphs 资料
实际输出的资料格式如下:

利用 AS 将 Font Glyphs 资料重新画出来:

Ticore's Blog

因为是用标楷体,所以笔画重叠的地方会反白
相对有好有坏,这样可以做到把每一个笔画都拆成独立的对象呢!

最后,还有一个可能的方式,连 font glyphs 资料都不用转出来
请参考本 Blog 第一篇
利用 Flash Javascript API 作批次输出静态文字 swf
利用 Flash JavaScript API,多做一些动作:
打散文字、全选、分布到不同图层去、将每个图层的对象转为单独的 Sprite、....
到时候只要将这些 SWF 直接读入,就有分好的 Sprite 对象可以用
是不是更方便呢!

Read more...

2008年9月15日 星期一

Flash CS3 Compiler Bug   [+/-]

Ticore's Blog

这个问题其实去年就遇到了,只是最近又有人遇到类似的问题
再仔细探讨发生原因,顺便做的纪录

Bug 重现步骤如下:

  1. 使用 Flash CS3 创建一空白的 fla (as3) 文档
  2. 与 Cairngorm.swc (Cairngorm 2.2.1 or 2.2) 放在同一个资料夹下
  3. 影格一写一行 trace(123); 程序
  4. 编译测试影片就会得到以下的错误消息
1046: Type was not found or was not a compile-time constant: WebService.
1046: Type was not found or was not a compile-time constant: RemoteObject.
1046: Type was not found or was not a compile-time constant: HTTPService.

这个实在蛮诡异的,fla 文档内完全没有用到 Cairngorm 的类别
甚至连 ActionScript Classpath 都没设
Flash IDE 就自动去查找 Cairngorm.swc
然后自己挂在那边~~

Read more...

2008年9月9日 星期二

觉得 AS3 太困难?不妨试试看 SimpleAS3!   [+/-]

Ticore's Blog

SimpleAS3 提供了很简单的 function
让你可以做到读取外部资料、图片、跳页等等..

eg.

 var loader = this.loadChild( "images/button.png" );

loader.onClick(function()
{
        getURL( "http://www.example.com/", "_self" );

}); 

SimpleAS3 简介
SimpleAS3: It Doesn’t Get Any Easier Than This!
http://flashspeaksactionscript.com/simpleas3-it-doesnt-get-any-easier...

SimpleAS3 网站
http://simpleas3.com/

SimpleAS3 Documentation
http://simpleas3.com/documentation/

Read more...

2008年9月4日 星期四

Flex 技巧 - 将 NumericStepper 上下按钮变灰   [+/-]

Ticore's Blog

Flex 内的 NumericStepper 组件,在遇到 Value 等于 Maximun or Minimum 时
NextButton, PrevButton 仍然是 Enable 状态
这样很容易让使用者混淆,多按了好几下才知道已经到底了
以下分享一个简单的做法,可以让 NumericStepper 到底时
自动将 NextButton, PrevButton Disable

MXML Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   layout="horizontal" verticalAlign="middle" backgroundColor="#FFFFFF" fontSize="12">
 <mx:Script>
  <![CDATA[
   import mx.core.mx_internal;
   import mx.controls.NumericStepper;
  ]]>
 </mx:Script>
 <mx:Label text="Before Disable Btn:" />
 <mx:NumericStepper />
 
 <mx:VRule height="100%" />
 
 <mx:Label text="After Disable Btn:" />
 <mx:NumericStepper>
  <mx:creationComplete>
   <![CDATA[
    var target:NumericStepper = event.target as NumericStepper;
    target.mx_internal::nextButton.enabled = target.value < target.maximum;
    target.mx_internal::prevButton.enabled = target.value > target.minimum;
   ]]>
  </mx:creationComplete>
  <mx:change>
   <![CDATA[
    var target:NumericStepper = event.target as NumericStepper;
    target.mx_internal::nextButton.enabled = target.value < target.maximum;
    target.mx_internal::prevButton.enabled = target.value > target.minimum;
   ]]>
  </mx:change>
 </mx:NumericStepper>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

线上示范:

Read more...

2008年8月5日 星期二

八月最后消暑日、神魂与 RiS 合办网聚啰!   [+/-]

Ticore's Blog

时间:8/24(日)下午2:00到5:00
地点:味子SAUCE - 台北市光复南路260巷28号 (国父纪念馆站2号出口,右前方直走50公尺第二条巷子旁,争鲜回转寿司、骑楼义大利面旁)
每人费用:新台币200块 (会场提供高级水果、蛋糕、饮料,并且无限供应,再加上主题新知、赠品等内容,绝对物超所值喔!)

报名网址:http://event.flash2u.com.tw/default.aspx?eventid=E2008071500001&comefrom=1
详情:http://bbs.flash2u.com.tw/dispbbs_177_86814.html

Read more...

2008年7月19日 星期六

Kaspersky Firewall Bug   [+/-]

Ticore's Blog

昨天测试 Flash AS3 Socket 联机时,意外的让 Windows VISTA 直接进入蓝画面!

后来经过反覆测试,似乎与 Windows 无关,XP、VISTA SP 几都会发生
主要问题是发生在 Kaspersky Internet Security 7.0.1.325
而 ActionScript 3.0 作的事情也很简单,每隔 10 ms 尝试 Socket 联机到 127.0.0.1:80 而已

Kaspersky Internet Security 7.0.0.325 似乎没有这个问题

使用 Flash Player 测试时,需要注意一下要在本机上跑
不然会被 Flash Player Sandbox 挡下来的
另外机器上也不要在 80 port 开 HTTP Server

ActionScript 3.0 Socket 测试程序:

package {
 import flash.display.MovieClip;
 import flash.events.IOErrorEvent;
 import flash.events.TimerEvent;
 import flash.net.Socket;
 import flash.utils.Timer;

 [SWF(width="300", height="200", backgroundColor="#FFFFFF", frameRate="30")]
 public class AS3SocketCrash extends MovieClip {
  
  protected var timer:Timer = new Timer(10);
  protected var socket:Socket = new Socket();
  
  public function AS3SocketCrash() {
   socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
   timer.addEventListener(TimerEvent.TIMER, onTimerHandler);
   timer.start();
  }
  
  private function onTimerHandler(evtObj:TimerEvent):void{
   socket.connect("127.0.0.1", 80);
  }
  
  private function onIOError(evtObj:IOErrorEvent):void{
   trace(evtObj);
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

以下则是使用 VMWare 测试得到蓝画面

Read more...

2008年7月5日 星期六

AS3 - BitmapText 程序分享   [+/-]

Ticore's Blog

由于 Flash Player 一直以来都无法对系统字体的文字作旋转与不规则形状遮罩
可是到了 Flash Player 9 AS3,可以将文字绘制成位图
也可以自行继承内建类别 Sprite, TextField 等
于是想到做一个 TextField Wrapper,提供系统文字的点阵化功能
藉以达到文字可旋转、套用不规则遮罩

其实这个 BitmapText 程序去年就已经写了
主要是出于研究目的
专案一次也没有用到过
没想到最近新出的 Flash Player 10 beta 文字引擎
已经可以使用系统字体作旋转了
倘若再不把这程序拿出来使用一下,恐怕就这样永不见天日了~~><>

主要是包含两个类别 TextWrapper, BitmapText
TextWrapper 只是 TextField 的外覆类别
真正在做点阵绘图的是 BitmapText
由于 AS3 TextField 成员属性与方法相当多
我已经很尽量的复写大部分的方法了

TextWrapper Class:

/*
TextWrapper AS3 v0.0.2
 
Date: 2007.04.25
作者: Ticore Shih
Blog:http://ticore.blogspot.com
EMail: swl@ms53.url.com.tw
 
v0.0.1
继承 Sprite 包覆一个 TextField
 
v0.0.2
增加 TextField 一般性方法
*/

package com.ticore.text {
 
 import flash.geom.*;
 import flash.display.*;
 import flash.text.*;
 import flash.events.*;
 
 public class TextWrapper extends Sprite {
  //
  // Protected Property
  //
  protected var _txt_:TextField;
  //
  // Constructor
  //
  public function TextWrapper() {
   init();
  }
  protected function init():void {
   _txt_ = new TextField();
   this.addChild(_txt_);
  }
  //
  // Override DisplayObject Property and Method
  //
  public override function set width(w:Number):void {
   _txt_.width = w;
  }
  public override function get width():Number {
   return _txt_.width;
  }
  
  public override function set height(h:Number):void {
   _txt_.height = h;
  }
  public override function get height():Number {
   return _txt_.height;
  }
  //
  // Proxy Common TextField Property
  //
  public function set antiAliasType(value:String):void {
   _txt_.antiAliasType = value;
  }
  public function get antiAliasType():String {
   return _txt_.antiAliasType;
  }
  
  public function set autoSize(value:String):void {
   _txt_.autoSize = value;
  }
  public function get autoSize():String {
   return _txt_.autoSize;
  }
  
  public function set gridFitType(value:String):void {
   _txt_.gridFitType = value;
  }
  public function get gridFitType():String {
   return _txt_.gridFitType;
  }
  
  public function set htmlText(value:String):void {
   _txt_.htmlText = value;
  }
  public function get htmlText():String {
   return _txt_.htmlText;
  }
  
  public function set restrict(value:String):void {
   _txt_.restrict = value;
  }
  public function get restrict():String {
   return _txt_.restrict;
  }
  
  public function set text(txt:String):void {
   _txt_.text = txt;
  }
  public function get text():String {
   return _txt_.text;
  }
  
  public function set type(type:String):void {
   _txt_.type = type;
  }
  public function get type():String {
   return _txt_.type;
  }
  
  
  public function set backgroundColor(value:uint):void {
   _txt_.backgroundColor = value;
  }
  public function get backgroundColor():uint {
   return _txt_.backgroundColor;
  }
  
  public function set borderColor(value:uint):void {
   _txt_.borderColor = value;
  }
  public function get borderColor():uint {
   return _txt_.borderColor;
  }
  
  public function set textColor(value:uint):void {
   _txt_.textColor = value;
  }
  public function get textColor():uint {
   return _txt_.textColor;
  }
  
  
  public function get bottomScrollV():int {
   return _txt_.bottomScrollV;
  }
  
  public function get caretIndex():int {
   return _txt_.caretIndex;
  }
  
  public function get length():int {
   return _txt_.length;
  }
  
  public function get maxChars():int {
   return _txt_.maxChars;
  }
  
  public function get maxScrollH():int {
   return _txt_.maxScrollH;
  }
  
  public function get maxScrollV():int {
   return _txt_.maxScrollV;
  }
  
  public function get numLines():int {
   return _txt_.numLines;
  }
  
  public function get selectionBeginIndex():int {
   return _txt_.selectionBeginIndex;
  }
  
  public function get selectionEndIndex():int {
   return _txt_.selectionEndIndex;
  }
  
  
  public function set sharpness(value:Number):void {
   _txt_.sharpness = value;
  }
  public function get sharpness():Number {
   return _txt_.sharpness;
  }
  
  public function set thickness(value:Number):void {
   _txt_.thickness = value;
  }
  public function get thickness():Number {
   return _txt_.thickness;
  }
  
  public function get textHeight():Number {
   return _txt_.textHeight;
  }
  public function get textWidth():Number {
   return _txt_.textWidth;
  }
  
  
  public function set alwaysShowSelection(value:Boolean):void {
   _txt_.alwaysShowSelection = value;
  }
  public function get alwaysShowSelection():Boolean {
   return _txt_.alwaysShowSelection;
  }
  
  public function set border(value:Boolean):void {
   _txt_.border = value;
  }
  public function get border():Boolean {
   return _txt_.border;
  }
  
  public function set condenseWhite(value:Boolean):void {
   _txt_.condenseWhite = value;
  }
  public function get condenseWhite():Boolean {
   return _txt_.condenseWhite;
  }
  
  public function set displayAsPassword(value:Boolean):void {
   _txt_.displayAsPassword = value;
  }
  public function get displayAsPassword():Boolean {
   return _txt_.displayAsPassword;
  }
  
  public function set embedFonts(value:Boolean):void {
   _txt_.embedFonts = value;
  }
  public function get embedFonts():Boolean {
   return _txt_.embedFonts;
  }
  
  public function set mouseWheelEnabled(value:Boolean):void {
   _txt_.mouseWheelEnabled = value;
  }
  public function get mouseWheelEnabled():Boolean {
   return _txt_.mouseWheelEnabled;
  }
  
  public function set multiline(value:Boolean):void {
   _txt_.multiline = value;
  }
  public function get multiline():Boolean {
   return _txt_.multiline;
  }
  
  public function set selectable(value:Boolean):void {
   _txt_.selectable = value;
  }
  public function get selectable():Boolean {
   return _txt_.selectable;
  }
  
  public function set useRichTextClipboard(value:Boolean):void {
   _txt_.useRichTextClipboard = value;
  }
  public function get useRichTextClipboard():Boolean {
   return _txt_.useRichTextClipboard;
  }
  
  public function set wordWrap(value:Boolean):void {
   _txt_.wordWrap = value;
  }
  public function get wordWrap():Boolean {
   return _txt_.wordWrap;
  }
  //
  // Proxy Common TextField Method
  //
  public function appendText(text:String):void {
   _txt_.appendText(text);
  }
  
  public function getCharBoundaries(charIndex:int):Rectangle {
   return _txt_.getCharBoundaries(charIndex);
  }
  
  public function getCharIndexAtPoint(x:Number, y:Number):int {
   return _txt_.getCharIndexAtPoint(x,y);
  }
  
  public function getFirstCharInParagraph(charIndex:int):int {
   return _txt_.getFirstCharInParagraph(charIndex);
  }
  
  public function getImageReference(id:String):DisplayObject {
   return _txt_.getImageReference(id);
  }
  
  public function getLineIndexAtPoint(x:Number, y:Number):int {
   return _txt_.getLineIndexAtPoint(x,y);
  }
  
  public function getLineIndexOfChar(charIndex:int):int {
   return _txt_.getLineIndexOfChar(charIndex);
  }
  
  public function getLineLength(lineIndex:int):int {
   return _txt_.getLineLength(lineIndex);
  }
  
  public function getLineMetrics(lineIndex:int):TextLineMetrics {
   return _txt_.getLineMetrics(lineIndex);
  }
  
  public function getLineOffset(lineIndex:int):int {
   return _txt_.getLineOffset(lineIndex);
  }
  
  public function getLineText(lineIndex:int):String {
   return _txt_.getLineText(lineIndex);
  }
  
  public function getParagraphLength(charIndex:int):int {
   return _txt_.getParagraphLength(charIndex);
  }
  
  public function replaceSelectedText(value:String):void {
   _txt_.replaceSelectedText(value);
  }
  
  public function replaceText(beginIndex:int, endIndex:int, newText:String):void {
   _txt_.replaceText(beginIndex,endIndex,newText);
  }
  
  public function setTextFormat(format:TextFormat, beginIndex:int = -1, endIndex:int = -1):void {
   _txt_.setTextFormat(format,beginIndex,endIndex);
  }
  public function getTextFormat(beginIndex:int = -1, endIndex:int = -1):TextFormat {
   return _txt_.getTextFormat(beginIndex,endIndex);
  }
  
  public function set defaultTextFormat(format:TextFormat):void {
   _txt_.defaultTextFormat = format;
  }
  public function get defaultTextFormat():TextFormat {
   return _txt_.defaultTextFormat;
  }
  
 }
}

BitmapText Class:

/*
BitmapText AS3 v0.0.4
 
Date: 2007.04.25
作者: Ticore Shih
Blog:http://ticore.blogspot.com
EMail: swl@ms53.url.com.tw
 
v0.0.1
利用 BitmapData draw TextFIeld
达到可以呈现旋转文字的效果
 
v0.0.2
增加 TextField 一般性方法与属性控制
增加 validate 属性,减少不必要 draw 次数
 
TextField.autoSize 功能会有一些问题
TextField 大小会一直跳动,重复 draw 会发生多重图象
 
v0.0.3
增加 TextField 一般性方法与属性控制
 
v0.0.4
重构将 TextWrapper 功能独立为单一 Class
*/

package com.ticore.text {
 
 import flash.geom.*;
 import flash.display.*;
 import flash.text.*;
 import flash.events.*;
 import flash.filters.*;
 
 public class BitmapText extends TextWrapper {
  
  // Private Property
  private var _validate_:Boolean = true;
  private var magniFactor:Number = 3;
  private var blurFilter:BlurFilter;
  private var _useBitmapText_:Boolean = true;
  
  private var bmpData:BitmapData;
  private var bmp:Bitmap;
  
  public function BitmapText() {
   init();
  }
  protected override function init():void {
   super.init();
   _txt_.addEventListener(Event.CHANGE, onChange);
   bmp = new Bitmap();
   bmp.smoothing = true;
   bmp.scaleX = bmp.scaleY = 1 / magniFactor;
   this.addChild(bmp);
   _txt_.visible = false;
   this.addChild(_txt_);
   blurFilter = new BlurFilter(1 + magniFactor / 6, 1 + magniFactor / 6, BitmapFilterQuality.MEDIUM);
   validate = false;
   addEventListener(Event.ENTER_FRAME, onEnterFame);
  }
  //
  // Private Method
  //
  private function updateBmpData():void {
   if (bmpData) {
    bmpData.dispose();
   }
   bmpData = new BitmapData((width + 1) * magniFactor, (height + 1) * magniFactor, true, 0x00000000);
   bmp.bitmapData = bmpData;
   bmp.smoothing = true;
   validate = false;
  }
  
  private function onChange(eventObj:Event):void {
   validate = false;
  }
  
  private function onEnterFame(eventObj:Event):void {
   if (!validate) {
    draw();
   }
  }
  
  private function draw():void {
   if (bmpData == null) {
    updateBmpData();
   }

   if (bmpData.width < (width + 1) * magniFactor || bmpData.height < (height + 1) * magniFactor) {
    updateBmpData();
   }
   var rect:Rectangle = new Rectangle(_txt_.x, _txt_.y, _txt_.width, _txt_.height);
   bmpData.fillRect(bmpData.rect, 0x00000000);
   var xOffset:Number = -_txt_.x;

   var dev:Number = magniFactor / 3;
   bmpData.draw(_txt_, new Matrix(magniFactor, 0, 0, magniFactor, xOffset * magniFactor + 0, 0));
   bmpData.draw(_txt_, new Matrix(magniFactor, 0, 0, magniFactor, xOffset * magniFactor + dev, 0));
   bmpData.draw(_txt_, new Matrix(magniFactor, 0, 0, magniFactor, xOffset * magniFactor + 0, dev));
   bmpData.applyFilter(bmpData, bmpData.rect, new Point(0, 0), blurFilter);
   bmpData.draw(_txt_, new Matrix(magniFactor, 0, 0, magniFactor, xOffset * magniFactor + dev / 2, dev / 2));

   bmp.x = _txt_.x;
   bmp.y = _txt_.y;
   validate = true;
  }
  
  //
  // Public Method
  //
  public function set validate(value:Boolean):void {
   _validate_ = value;
  }
  public function get validate():Boolean {
   return _validate_;
  }
  
  public function set useBitmapText(value:Boolean):void {
   _useBitmapText_ = value;
   _txt_.visible = !value;
   bmp.visible = value;
  }
  public function get useBitmapText():Boolean {
   return _useBitmapText_;
  }
  //
  // Override Method
  //
  public override function set width(w:Number):void {
   super.width = w;
   validate = false;
  }
  public override function set height(h:Number):void {
   super.height = h;
   validate = false;
  }
  public override function appendText(text:String):void {
   super.appendText(text);
   validate = false;
  }
  public override function replaceSelectedText(value:String):void {
   super.replaceSelectedText(value);
   validate = false;
  }
  public override function replaceText(beginIndex:int, endIndex:int, newText:String):void {
   super.replaceText(beginIndex,endIndex,newText);
   validate = false;
  }
  public override function setTextFormat(format:TextFormat, beginIndex:int = -1, endIndex:int = -1):void {
   super.setTextFormat(format,beginIndex,endIndex);
   validate = false;
  }
  public override function set defaultTextFormat(format:TextFormat):void {
   super.defaultTextFormat = format;
   validate = false;
  }
  
  public override function set antiAliasType(value:String):void {
   super.antiAliasType = value;
   validate = false;
  }
  public override function set autoSize(value:String):void {
   super.autoSize = value;
   validate = false;
  }
  public override function set gridFitType(value:String):void {
   super.gridFitType = value;
   validate = false;
  }
  public override function set htmlText(value:String):void {
   super.htmlText = value;
   validate = false;
  }
  public override function set restrict(value:String):void {
   super.restrict = value;
   validate = false;
  }
  public override function set text(value:String):void {
   super.text = value;
   validate = false;
  }
  
  public override function set backgroundColor(value:uint):void {
   super.backgroundColor = value;
   validate = false;
  }
  public override function set borderColor(value:uint):void {
   super.borderColor = value;
   validate = false;
  }
  public override function set textColor(value:uint):void {
   super.textColor = value;
   validate = false;
  }
  
  public override function set sharpness(value:Number):void {
   super.sharpness = value;
   validate = false;
  }
  public override function set thickness(value:Number):void {
   super.thickness = value;
   validate = false;
  }
  
  public override function set alwaysShowSelection(value:Boolean):void {
   super.alwaysShowSelection = value;
   validate = false;
  }
  public override function set border(value:Boolean):void {
   super.border = value;
   validate = false;
  }
  public override function set condenseWhite(value:Boolean):void {
   super.condenseWhite = value;
   validate = false;
  }
  public override function set displayAsPassword(value:Boolean):void {
   super.displayAsPassword = value;
   validate = false;
  }
  public override function set embedFonts(value:Boolean):void {
   super.embedFonts = value;
   validate = false;
  }
  public override function set multiline(value:Boolean):void {
   super.multiline = value;
   validate = false;
  }
  public override function set selectable(value:Boolean):void {
   super.selectable = value;
   validate = false;
  }
  public override function set wordWrap(value:Boolean):void {
   super.wordWrap = value;
   validate = false;
  }
  
 }
}

测试程序如下:

import com.ticore.text.*;

var bmpTxt:BitmapText = new BitmapText();
this.addChild(bmpTxt);
bmpTxt.border = true;
bmpTxt.multiline = true;
bmpTxt.rotation = 0;
bmpTxt.wordWrap = true;
bmpTxt.rotation = 15;
bmpTxt.width = 320;
bmpTxt.height = 250;
bmpTxt.x = 170;
bmpTxt.y = 30;

var format:TextFormat = bmpTxt.getTextFormat();
format.font = "新细明体";
format.align = "center";

for (var i:Number = 6; i <= 22; format.size=i; bmpTxt.defaultTextFormat=format; bmpTxt.appendText("Font Size format.size 新细明体\n");>

原始文件下载

实际运行效果撷图:

看起来应该还不错吧!
即使在旋转状态下也没有很严重的锯齿
我特别在绘制位图步骤提升了分辨率
并且作了偏移绘制,套用滤镜
当然这些动作是会消耗效能的
所以只有在必要时才会进行重绘的动作

Read more...

2008年6月27日 星期五

Flex 技巧 - 将资料绑定封装起来   [+/-]

Ticore's Blog

之前介绍了 纯手工设置 Flex DataBinding 的方式
不过那挺麻烦的
假如想要将 DataBinding 封装起来,保留部分弹性
又不想要那么麻烦的设置方式
不妨可以试试看以下的方式

在这个例子中,完全的将 DataBinding 封装在一个 MXML Component 中
必须要指定好目标物,Component 内的 DataBinding 才会发生作用
想要停止 DataBinding 也很简单,只要将目标属性设为 null 就好

甚至可以对一份资料,准备多个 DataBinding Component
只要在运行期动态替换 Component,就能达到切换 DataBinding 行为的目的
其实还挺方便的

Main.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  verticalAlign="middle" backgroundColor="#FFFFFF"
  creationComplete="init();" fontSize="12">
 <mx:Script>
  <![CDATA[
   public var comp:BindingComp;
   
   public function init():void{
    comp = new BindingComp();
    comp.initialize();
   }
  ]]>
 </mx:Script>
 <mx:HBox>
  <mx:Label text="No 1:" />
  <mx:NumericStepper id="no1" maximum="100" />
 </mx:HBox>
 <mx:HBox>
  <mx:Label text="No 2:" />
  <mx:NumericStepper id="no2" maximum="100" />
 </mx:HBox>
 <mx:CheckBox id="chk" label="DataBinding Enabled"
   change="comp.target = chk.selected ? this : null;" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

BindingComp.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:UIComponent xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:Script>
  <![CDATA[
   [Bindable]
   public var target:Main;
   
   public function doBinding1(... args:*):void{
    if (target) target.no2.value = target.no1.value;
   }
   public function doBinding2(... args:*):void{
    if (target) target.no1.value = target.no2.value;
   }
  ]]>
 </mx:Script>
 <mx:Model>
  {doBinding1(target.no1.value)}
 </mx:Model>
 <mx:Model>
  {doBinding2(target.no2.value)}
 </mx:Model>
</mx:UIComponent>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

线上测试示范:

相关连结:
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 观察 Data Binding 资料变化
Flex Tip - 在 Data Binding 内使用 [...] 运算子
Flex 2 Bindable Metadata Tag 背后实际作用
Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding

Read more...

2008年6月18日 星期三

Flex SDK 马歇尔计画   [+/-]

Ticore's Blog

Marshall Plan 原文有点长,主要只有两件事情:

  • 不同版本交互支持 (Cross-Versioning):
    不同版本 Flex 编译的 SWFs 可以被放在相同的 SecurityDomain 运行
    但是却可以有不同的 ApplicationDomain

  • 不信任的应用程序支持 (Untrusted Application):
    被装入到不同 SecurityDomain 的 SWFs 将不能访问主应用程序或是 Stage 与其它受限的资源

这个计画将可能会在 Flex 3.1 开始支持
未来不同版本的 Flex 应用程序可以做混搭了
个人猜测,这计画背后更重要的意义是 Flash 与 Flex 应用程序混搭

不过在那之前,Adobe 可能要先把 ApplicationDomain 的 Bug 处理掉吧~

Read more...

2008年6月14日 星期六

AS 技巧 - Layer BlendMode 的用处   [+/-]

Ticore's Blog

Flash Player 8 新增的混合模式功能中的图层模式 (Layer)
一般使用起来或许觉得没有什么特别的用处
说明文档上写得更是令人雾茫茫
简单的说,只是让 DisplayObject 子对象预先混和颜色而已

基本上,除了 Normal 之外的混合模式,都会强迫预先混和子对象颜色
但是其它混合模式都是有特殊效果的
假如不需要那些效果,但是又要强迫预先混合颜色时
就要用 Layer 混合模式了

对于像是 Flex 这样由大量的 DisplayObject 组合而成的组件
遇到需要淡入、淡出效果时
即使是在最外层设置 Alpha 透明度
每个子对象仍会先被单独套用 Alpha 效果再叠合成一张图
这样就会有某些位置颜色特别突兀不透明

此时 Layer 混合模式就非常好用了
它可以让整个表单先叠合成一张图再进行 Alpha 效果
可以确保组件颜色看起来不会特别突兀

以下是用 Flex 作的简单测试
可以容易观察到多层嵌套组件在不同 Alpha, BlendMode 的效果

<?xml version="1.0"?>
<mx:Application layout="vertical" fontSize="12" backgroundColor="#FFFFFF"
   xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:Style>
  HBox.whiteBox {
   paddingTop: 15px;
   paddingBottom: 15px;
   paddingLeft: 15px;
   paddingRight: 15px;
   backgroundColor: #000000;
  }
 </mx:Style>
 <mx:HBox styleName="whiteBox" alpha="{alphaSlider.value}"
    blendMode="{blendModeCb.value ? blendModeCb.value : 'normal'}">
  <mx:HBox styleName="whiteBox">
   <mx:HBox styleName="whiteBox">
    <mx:HBox styleName="whiteBox" />
   </mx:HBox>
  </mx:HBox>
 </mx:HBox>
 
 <mx:HRule width="100%" />
 <mx:HBox verticalAlign="middle">
  <mx:Label text="BlendMode: " />
  <mx:ComboBox id="blendModeCb">
   <mx:dataProvider>
    ["normal", "layer", "darken", "invert", "hardlight"]
   </mx:dataProvider>
  </mx:ComboBox>
 </mx:HBox>
 <mx:HBox verticalAlign="middle">
  <mx:Label text="Alpha: " />
  <mx:HSlider id="alphaSlider" value="0.5"
    tickValues="[0, 0.5, 1]" labels="[0, 0.5, 1]"
    minimum="0" maximum="1" liveDragging="true" />
 </mx:HBox>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

线上测示示范:

相关连结:
Flex Label, TextField 半透明小技巧
Flash 8 半透明输入、动态文字字段

Read more...

2008年6月8日 星期日

Flex 技巧 - BindingManager 使用方式   [+/-]

Ticore's Blog

Flex 的 mx.binding.*; 内有许多未公开的类别
主要都是给 MXML Compiler 使用的
其中 mx.binding.BindingManager 便是负责管理所有的 DataBinding 运作
BindingManager 内有一些静态函式还蛮有用的
列举如下:

  • BindingManager.setEnabled(document:Object, isEnabled:Boolean):void;
    用来 停止/启动 Flex Application/Component 内 Data Binding

  • BindingManager.executeBindings(document:Object, destStr:String, destObj:Object):void;
    运行被指定 Data Binding Expression

  • BindingManager.debugBinding(destinationString:String):void;
    对指定的 Data Binding Expression 进行除错

以下是简单的 BindingManager 使用示范程序:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" layout="vertical" fontSize="12"
   creationComplete="onCreateComplete();">
  <mx:Script>
   <![CDATA[
    import mx.binding.*;
    public function onCreateComplete():void{
     BindingManager.debugBinding("slider2.value");
    }
   ]]>
  </mx:Script>
  
  <mx:Label text="Binding Source:" />
  <mx:HSlider id="slider1" snapInterval="1" maximum="100" value="50" />

  <mx:Label text="Binding Destination:" />
  <mx:HSlider id="slider2" snapInterval="1" maximum="100" value="{slider1.value}" />
  
  <mx:CheckBox id="chk" label="Binding Enabled" selected="true"
    change="BindingManager.setEnabled(this, chk.selected); btn.enabled = chk.selected;" />
    
  <mx:Button id="btn" label="Execute DataBinding"
    click="BindingManager.executeBindings(this, 'slider2.value', null);" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

测试输出结果:

Binding: destString = slider2.value, srcFunc result = 54
Binding: destString = slider2.value, srcFunc result = 59
Binding: destString = slider2.value, srcFunc result = 81
Binding: destString = slider2.value, srcFunc result = 41

相关连结:
Flex 技巧 - 将资料绑定封装起来
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - 观察 Data Binding 资料变化
Flex Tip - 在 Data Binding 内使用 [...] 运算子
Flex 2 Bindable Metadata Tag 背后实际作用
Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding

Read more...

2008年6月6日 星期五

Flex 技巧 - 观察 Data Binding 资料变化   [+/-]

Ticore's Blog

Flex Data Binding 功能让开发者不用写太多的程序码
就能做到资料系结功能
但是要除错的时候就比较不太方便
Data Binding Expression 区块内很多语法都不能使用
当 Data Binding 被触发时,想要观察资料变化就不太方便

以下分享一个小技巧,可以很简单的观察 Data Binding 前后资料的变化

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" layout="vertical" fontSize="12">
  
  <mx:Label text="Binding Source:" />
  <mx:HSlider id="slider1" snapInterval="1" maximum="100" />

  <mx:Label text="Binding Destination:" />
  <mx:HSlider id="slider2" snapInterval="1" maximum="100"
    value="{trace('Before :', slider2.value),
    setTimeout(function():void{trace('After :', slider2.value);}, 0), slider1.value}"/>
  
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

由于 Data Binding Expression 内不能使用 ";" 结尾的陈述式
所以使用 "," 作区隔,只有最后一个 Expression 会被当作值指定给目标
这样在前面就可以 trace 到变化之前的值
配合 setTimeout 又可以观察到变化之后的值

相关连结:
Flex 技巧 - 将资料绑定封装起来
Flex - 纯手工设置 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex Tip - 在 Data Binding 内使用 [...] 运算子
Flex 2 Bindable Metadata Tag 背后实际作用
Flex 2.0 - 以 ActionScript 3.0 动态设置 Data Binding

Read more...

2008年6月3日 星期二

Flash 内嵌动态文字与样式的问题   [+/-]

Ticore's Blog

问题出处:动态文字字段的问题

问题描述:

于 Flash 舞台上
放置两个动态文字字段,选择相同的字体
第一个不嵌入任何字集,样式设为 regular
第二个嵌入数字字符集,样式设为 bold
于运行期动态重设第二个文字字段内容
该文字字段将无法表现新的文字内容

简化过后的问题 Demo 程序如下:

注意,测试的时候不要先选定 txt2 内的文字
只要一选定过,就不过出现问题了

原始文件下载

这个问题其实还挺复杂的,由许多的特性共同影响,分述如下~

Flash TextField 与 Embed Font 特性:

特性 1.
基本上,Flash 的内嵌字体,即使是相同的字体名称
不同的样式 (regular, bold, italic) 会被当作完全不同的字体处理

特性 2.
Flash 内所有时间轴预置 TextField 内嵌字体都是可以共用的

依据特性 1. 2.,可以做一个简单的测试
于 Flash 舞台上放置两个动态文字字段
第一个文字字段仅嵌入 Airal regular 数字字集
第二个文字字段仅嵌入 Airal bold 英文字母字集
动态将第二个文字字段样式设为 regular 之后
那么该文字字段只能表现数字了~~

特性 3.
一个 SWF 内仅嵌入单一字体样式 (eg. Arial regular) 时
动态使用同一字体但是不同样式 (eg. Arial bold) 的文字字段
将会使用该字体唯一嵌入样式 (eg. Arial regular) 作为替代字体

特性 4.
将 TextField.text 内容重设时
TextField 内的文字样式 bold, italic 也会被重设为默认的样式
AS3 TextField.appendText 则不会重设样式

ActionScript 3.0 测试程序:

package {
 import flash.display.*;
 import flash.text.*;

 public class Main1 extends MovieClip {

  public function Main1() {

   var txt:TextField = new TextField();
   var tf:TextFormat = new TextFormat();
   tf.bold = true;
   tf.italic = true;


   // TextField 内不含文字内容时,无法套用 bold, italic 样式
   txt.text = "";
   txt.setTextFormat(tf);
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : null , tf.italic : null

   txt.text = "123";
   txt.setTextFormat(tf);
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : true , tf.italic : true


   // 改变 TextField.text 内容时,bold, italic 样式被重设
   txt.text="123";
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : false , tf.italic : false

   tf.bold = true;
   tf.italic = true;
   txt.setTextFormat(tf);
   txt.text += "123";
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : false , tf.italic : false


   // 使用 appendText 改变 TextField.text 内容时,bold, italic 样式会被保留
   tf.bold = true;
   tf.italic = true;
   txt.setTextFormat(tf);
   txt.appendText("456");
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : true , tf.italic : true
   
   
   // 指定 TextField.text 内容前,调用 setSelection,bold, italic 样式会被保留
   tf.bold = true;
   tf.italic = true;
   txt.setTextFormat(tf);
   txt.setSelection(0, 1);
   txt.text = "456";
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : true , tf.italic : true
   
   
   // 改变 TextField.text 内容时,bold, italic 会被重设为 defaultTextFormat
   tf.bold = true;
   tf.italic = false;
   txt.setTextFormat(tf);
   tf.bold = false;
   tf.italic = true;
   txt.defaultTextFormat = tf;
   txt.text = "456";
   tf = txt.getTextFormat();
   trace("tf.bold :",tf.bold,", tf.italic :",tf.italic);
   // tf.bold : false , tf.italic : true
   
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

了解上述特性之后,答案就很明显了~~

解决方式:
1. 对于同一字体不同的样式,均嵌入相同的字集
2. 当 TextField.text 内容重设时,自行回设正确的 Bold, Italic 样式
3. 利用 TextField.defaultTextFormat 设置 Bold, Italic 设置样式
4. 于 TextField.text 内容重设之前,调用 TextField.setSelection(0, 1);

相关连结:
Flash 技巧 - 预先编译嵌入字体

Read more...

2008年5月31日 星期六

Flash 技巧 - 利用 ExternalInterface 完全暂停 Flash Movie 程序   [+/-]

Ticore's Blog

最近在 review 一年半以前发现的技巧时
『利用 window.prompt 解决 Flash 透明模式下无法输入中文的问题』
又有了新的发现

透过 ExternalInterface 调用 window.prompt 时
完全是同步的
在浏览器对话框关闭以前
Flash Movie 就像是被暂停了一样

忽然想到 Flash ActionScript 到现在没有直接提供过全面暂停的功能
(PS. Flash Player 9 debug 版可以使用 flash.system.System.pause(); 暂停)
不光是只调用 _root.stop(); 那样
要连 _root 下面所有子 MovieClip 也一并暂停啊

于是更进一步测试
发现透过 ExternalInterface 调用 JavaScript alert, prompt, confirm 时
能够将 Flash Player 几乎全面暂停

能够暂停的项目:

  1. MovieClip Timeline
  2. Video play head
  3. Timer, setInterval, setTimeout
  4. for, while 回圈
  5. 影格上的 Stream Sound

无法暂停的项目:

  1. Event Sound, 串流下载播放的 Sound
  2. Network Activity

这样一来就很方便了
除了声音对象要自行暂停以外
几乎大部分 Flash Player 内的活动都能够用 ExternalInterface 加以暂停

而且会比自行实作的更省效能
因为它连回圈, Timer 都停住了
其实已经很接近运行绪 (Threading) 的睡眠 (sleep) 功能

声音播放、网络活动等之所以无法暂停
原因可能与 Flash Player 内部运行绪配置方式有关
声音播放、网络活动都是非同步的
很可能是在主运行绪之外配置了副运行绪来处理的

未来 Flash Player 可能会支持运行绪的功能
在那之前,就先用这个小技巧
暂停 Flash Player 主运行绪吧!

ActionScript 测试程序:

import flash.external.*;

function doPause() {
 trace("Before call alert.");
 ExternalInterface.call("alert", "Flash Movie 已暂停, 按下确定继续");
 trace("After call alert.");
}

setInterval(function(){trace("onTimer: " + getTimer());}, 1000);

// Ticore's Blog - http://ticore.blogspot.com/

线上测试页面

测试程序下载

相关连结:
利用 window.prompt 解决 Flash 透明模式下无法输入中文的问题

PS. 上述功能主要是以 AS2.0 测试的
后来邦邦告知可能会引发 Script Timeout 问题
测试之后发现 AS3.0 上运行类似的动作
只要 JS Alert, Prompt 对话框超过默认 15 秒没有关闭
便会引发 Script Timeout 问题

Read more...

2008年5月28日 星期三

Flex - RemoteObject 与 ApplicationDomain 问题   [+/-]

Ticore's Blog

问题出处:SWFLoader装入问题,当要装入的swf有使用DataServices...
在 Flex App 内,以新的 ApplicationDomain 装入另一个 Flex App 之后
被读入的 Flex App 使用 RemoteObject 调用会出现问题

重新把问题程序码简化如下
因为这问题发生于 HTTP 请求之前,不必配置后端

LoadeeApp.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:Button label="Submit" click="remoteObj.test(123);"/>
 <mx:RemoteObject id="remoteObj" destination="xxx" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

LoaderApp.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
 <mx:SWFLoader id="swfLdr" width="100%" height="100%">
  <mx:creationComplete>
   <![CDATA[
    swfLdr.loaderContext = new LoaderContext();
    swfLdr.loaderContext.applicationDomain = new ApplicationDomain();
    swfLdr.source = "LoadeeApp.swf";
   ]]>
  </mx:creationComplete>
 </mx:SWFLoader>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

编译之后,运行 LoaderApp,按下按钮就会得到错误消息

ArgumentError: Error #1063:
 Object/http://adobe.com/AS3/2006/builtin::hasOwnProperty()
 上的引数个数不相符。需要 0 个,当前为 2 个。
 at LoadeeApp/___LoadeeApp_Button1_click()

假如改成 remoteObj.test(); 还会得到堆栈溢位错误呢

Error: Error #1023: 发生堆栈溢位。
 at Object$/_hasOwnProperty()
 at Object/http://adobe.com/AS3/2006/builtin::hasOwnProperty()
 at Object$/_hasOwnProperty()
 at Object/http://adobe.com/AS3/2006/builtin::hasOwnProperty()
 ...

从错误消息看起来,其实与 Flex 无关
问题很可能是出在 Flash ActionScript 3.0 内建 Class 上
由于 RemoteObject 是继承 Proxy
再将问题简化,剔除 Flex 相关的因素
仅使用 Flash ActionScript 3.0 以 new ApplicationDomain(); 装入另一个 Flash App
于被装入的 Flash App 调用自订的 MyProxy 方法

LoaderFlash Class:

package {
 import flash.display.Loader;
 import flash.display.Sprite;
 import flash.net.URLRequest;
 import flash.system.ApplicationDomain;
 import flash.system.LoaderContext;

 public class LoaderFlash extends Sprite {
  
  protected var ldr:Loader;
  protected var ldrCxt:LoaderContext;
  protected var req:URLRequest;
  
  public function LoaderFlash() {
   ldr = new Loader();
   ldrCxt = new LoaderContext(false, new ApplicationDomain());
   req = new URLRequest("LoadeeFlash.swf");
   
   ldr.load(req, ldrCxt);
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

LoadeeFlash Class:

package {
 import flash.display.Sprite;

 public class LoadeeFlash extends Sprite {
  public function LoadeeFlash() {
   var proxy:MyProxy = new MyProxy();
   proxy.test(123);
   //proxy.prop++;
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

MyProxy Class:

package {
 import flash.utils.Proxy;
 import flash.utils.flash_proxy;

 public dynamic class MyProxy extends Proxy {
  public function MyProxy() {
   super();
  }
  override flash_proxy function callProperty(methodName:*, ... args):* {
   trace("callProperty :", methodName, args);
   return;
  }
  override flash_proxy function getProperty(name:*):* {
   trace("getProperty :", name);
   return;
  }
  override flash_proxy function hasProperty(name:*):Boolean{
   trace("hasProperty :", name);
   return true;
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

下载测试程序码

运行 LoaderFlash.swf,结果还是会得到一样的错误消息
所以 flash.utils.Proxy 无法在 new ApplicationDomain(); 方式装入的 SWF 内使用

变通方式,大概只能避免使用到 Proxy 的功能了
改以 NetConnection 等比较低阶的方式使用 Remoting 功能

以上的 Bug 至少会发生在以下版本的 Flash Player
Flash Player 9.0.115.0
Flash Player 9.0.124.0
Flash Player 10.0.0.525
Flash Player 10.0.1.218
Flash Player 10.0.12.10

Read more...

2008年5月23日 星期五

Flash Player 10 beta - 新的影格事件   [+/-]

Ticore's Blog

Flash Player 10 beta 文档出来了
要观察新的 API 更方便一些

新的 AS3 API 多了两个影格事件
分别是 Event.FRAME_CONSTRUCTED, Event.EXIT_FRAME
看起来有点像 Director 的影格事件
以往 Flash 从来没有离开影格的相关事件

Event.FRAME_CONSTRUCTED 事件按照文档上所述
是发生在影格上的 DisplayObject 创建之后
运行影格程序之前

看起来像是用来补足 Flash Player 9 影格事件的不足
之前听到不少人抱怨 AS3 作影格跳跃之后
无法直接取用该影格的时间轴预置对象 (Timeline-Placed Object)
必须要等一个影格左右的时间...
非常不方便!

不过新的 frameConstructed 事件也只是将等待一个影格的时间缩短而已
好像没有方便到哪去
至于正式版情况怎样,就拭目以待了!

以下为 Flash Player 10 beta 新影格事件测试程序:
(需要自行准备一个具有三个影格的空白 fla 文档)

package {
    import flash.display.*;
    import flash.text.*;
    import flash.events.*;

    public class Main extends MovieClip {

        public function Main() {
            this.addEventListener(Event.ENTER_FRAME, onEvent);
            this.addEventListener(Event.EXIT_FRAME, onEvent);
            this.addEventListener(Event.FRAME_CONSTRUCTED, onEvent);
            this.addFrameScript(0, onFrame, 1, onFrame, 2, onFrame);
        }

        private function onFrame():void {
            trace(currentFrame, "FrameAction");
        }

        private function onEvent(evtObj:Event):void {
            trace(currentFrame, evtObj.type);
        }

    }
}
// Ticore's Blog - http://ticore.blogspot.com/

以下是输出结果:

1 frameConstructed
1 FrameAction
1 exitFrame
2 enterFrame
2 frameConstructed
2 FrameAction
2 exitFrame
3 enterFrame
3 frameConstructed
3 FrameAction
3 exitFrame
1 enterFrame
1 frameConstructed
1 FrameAction
1 exitFrame
..
.

除了第一影格之外,大致上可以看得出来运行顺序是
enterFrame, frameConstructed, FrameAction, exitFrame

相关连结:
Flash Player 10 beta - MouseCursor 功能
Flash Player 10 beta - JPEGLoaderContext 介绍
Flash 9 AS3 时间性事件混合测试
Flash Player 8 AS2 影格程序运行顺序

Read more...