2007年6月30日 星期六

ActionScript "with" Block Scope 遮蔽效應   [+/-]

Ticore's Blog

ActionScript 有一種 with(obj) {...} 用法
需要對相同物件大量呼叫時,可以節省不少程式碼
不過 with 的使用也會帶來其它的效應
像是遮蔽外層 Scope 變數

ActionScript 2、3 - "with" 遮蔽變數 i:

var i:Number = 1;
trace(i); // 1
with ({i: 2}) {
 trace(i); // 2
}
trace(i); // 1

上述的例子祇有遮蔽一個變數而已
假如把 Object.__resolve 拿進來

ActionScript 2 - "with" & Object.__resolve:

var i:Number = 1;
trace(i); // 1
with ({__resolve: function(){}}) {
 trace(i); // undefined
 trace(_root); // undefined
 trace(_global); // undefined
 trace(_url); // undefined
}

可以發現 with 區塊內所有外層 Scope 變數都會被遮蔽
ActionScript 3.0 也有類似的情況
只是要改用 flash.utils.Proxy

ActionScript 3 - "with" & Proxy Object:

package {
 import flash.display.*;
 public class main extends MovieClip {
  public function main ():*{
   
   with(new ProxyObj()) {
    trace(name);
    // getProperty : name
    // callProperty : trace
   }
   
  }
 }
}

import flash.utils.*;
class ProxyObj extends Proxy {
 
 flash_proxy override function hasProperty(name:*):Boolean{
  return true;
 }
 flash_proxy override function getProperty(name:*):*{
  trace("getProperty : " + name);
  return null;
 }
 flash_proxy override function callProperty(name:*,... rest):*{
  trace("callProperty : " + name);
  return null;
 }
 
}

上面的例子可以看得出來
AS3 with 甚至連 trace 呼叫都可以遮蔽

相關連結:
AS3 利用 with, Proxy 選擇性替換 Scope Variables
AS2 利用 with, Object.__resolve 選擇性替換 Scope Variables
AS3 技巧 - 利用 with 跳過編譯器 Strict Mode 檢查


Read more...

2007年6月29日 星期五

AS3 Number 與 int 預設初始值   [+/-]

Ticore's Blog

又是一個 ActionScript 3.0 神奇之處
原文請參考 quick FYI: Number & int

另外再進一步測試,int 型別參考無法指定為 NaN

var n:Number;
trace(isNaN(n)); // true
var i:int;
trace(isNaN(i)); // false
i = NaN;
trace(isNaN(i)); // false
trace(i); // 0

Read more...

AS2 以 LocalConnection 實作 WeakReference 的方式   [+/-]

Ticore's Blog

這是去年簡報中介紹過的 AS2 實作 Weak Reference 的方式
利用 LocalConnection 可以不用透過參考呼叫
但是又可以被回收的特性來實作

不過由於 Flash Player 9 AS2 LocalConnction 回收有 Bug
使用上需要特別注意
這個程式實驗性遠大於實用性就是了

AS2 WeakReference Class:

/*//

AS2 WeakReference Class, version 0.1.1
(c) 2006 Shih, Wei-Lung
http://ticore.blogspot.com/

AS2 WeakReference Class is freely distributable under the terms of an GNU license.

Events:

onGetReferent
onReleaseReferent
onDispose
onCallback
onObjDead

//*/

import mx.events.EventDispatcher;

class WeakReference {
 
 //---------------------------------------------------------------------------------------------
 
 static var weakRefPrefix:String = "WeakRef";
 static var weakRefIndex:Number = 0;
 
 public var proxyObj:Object;
 public var referentObj:Object;
 public var alive:Boolean = true;
 public var connectionName:String;
 
 private var __lc_caller__:LocalConnection;
 
 //---------------------------------------------------------------------------------------------
 //
 var addEventListener:Function;
 var removeEventListener:Function;
 var dispatchEvent:Function;
 var dispatchQueue:Function;
 //
 //---------------------------------------------------------------------------------------------
 
 public function WeakReference(referent:Object) {
  
  EventDispatcher.initialize(this);
  
  //------------------------------------------------------------------------------------------
  
  this.connectionName = weakRefPrefix + weakRefIndex++;
  
  var weakRef:Object = this;
  
  this.__lc_caller__ = new LocalConnection();
  //this.__lc_caller__.weakRef = this;
  this.__lc_caller__.onStatus = function(infoObj:Object):Void{
   trace(weakRef.connectionName + " LC : " + infoObj.level);
   switch(infoObj.level){
    case "status":
     
     break;
    case "error":
     weakRef.alive = false;
     weakRef.dispatchEvent({type:"onReferentDead", target: weakRef});
     break;
   }
  }
  
  var resolve:Function = function (name):Object {
   if (name == "__name__") {
    return null;
   }
   //trace("name : " + name);   
   //trace("__name__ : " + this.__name__);
   var __name__:String = (this.__name__ == null ? "" : this.__name__ + ".") + name;
   var o:Object = function ():Object {
    //trace("o.__name__ : " + __name__ + "()");
    //callMethod(__name__ + "()");
    weakRef.callMethod(__name__ + "()");
    return __name__ + "()";
   };
   o.toString = function() {
    weakRef.callMethod(__name__);
    return __name__;
   };
   o.__name__ = __name__;
   o.__resolve = resolve;
   _global.ASSetPropFlags(o, null, 7, 0);
   return o;
  };
  this.proxyObj = {};
  this.proxyObj.__resolve = resolve;
  
  
  //------------------------------------------------------------------------------------------
  
  var __lc_callee__:LocalConnection = new LocalConnection();
  referent["__lc_callee__"] = __lc_callee__;
  //_global.ASSetPropFlags(referent, "__lc_callee__", 7, 0);
  
  __lc_callee__["referent"] = referent;
  __lc_callee__.weakRef = this;
  __lc_callee__.connectionName = connectionName;
  __lc_callee__.onStatus = function(infoObj:Object):Void{
   trace(infoObj.level);
  }
  
  __lc_callee__.getReferent = function():Void{
   trace(this.connectionName + " getReferent");
   weakRef.referentObj = this["referent"];
   weakRef.dispatchEvent({type:"onGetReferent", target: weakRef, referent: this["referent"]});
  }
  
  __lc_callee__.dispose = function():Void{
   trace(this.connectionName + " dispose");
   var referent:Object = this["referent"];
   delete this["referent"];
   
   _global.ASSetPropFlags(referent, "__lc_callee__", 0, 7);
   delete referent["__lc_callee__"];
   this.close();
   
   weakRef.dispatchEvent({type:"onDisposed", target: weakRef, referent: referent});
   delete referent;
  }
  
  __lc_callee__.callMethod = function(path:String):Void{
   //trace(this.connectionName + " callMethod()");
   var key:String = "referent";
   var resultObj:Object = WeakReference.evalPath(this["referent"], path);
   weakRef.dispatchEvent({type:"onCallback", target: weakRef, result: resultObj});
  }
  
  __lc_callee__.traceObj = function():Void{
   trace(this.connectionName + " traceObj");
   for(var i:String in this["referent"]){
    trace("referent[" + i + "] : " + this["referent"][i]);
   }
  }
  
  __lc_callee__.connect(connectionName);
  
  delete __lc_callee__;
  delete referent;
  
  //------------------------------------------------------------------------------------------
  
 }
 
 public function getReferent():Void{
  this.__lc_caller__.send(this.connectionName, "getReferent");
 }
 
 public function releaseReferent():Void{
  this.dispatchEvent({type:"onReleaseReferent", target: this, referent: this["referentObj"]});
  this["referentObj"] = null;
 }
 
 public function dispose():Void{
  this.__lc_caller__.send(this.connectionName, "dispose");
 }
 
 public function callMethod(method:String):Void{
  this.__lc_caller__.send(this.connectionName, "callMethod", method);
 }
 
 public function traceObj():Void{
  this.__lc_caller__.send(this.connectionName, "traceObj");
 }
 
 //---------------------------------------------------------------------------------------------
 
 
 public static function evalPath(o:Object, path:String) {
  var pathArray:Array = path.split(".");
  for (var i:Number = 0; i < pathArray.length; ++i) {
   if (pathArray[i].indexOf("()") > 0) {
    o = o[pathArray[i].split("()")[0]]();
   } else {
    o = o[pathArray[i]];
   }
  }
  return o;
 }

 //---------------------------------------------------------------------------------------------
 
}

使用方式:

var obj:Object = {name: "Referent Object"};
obj.getName = function(){
 return this.name;
};
var weakRef:WeakReference = new WeakReference(obj);
delete obj;
var lisObj:Object = {};
lisObj.onCallback = function(eventObj:Object):Void{
 trace("onCallback : " + eventObj.result);
};
weakRef.addEventListener("onCallback", lisObj);
weakRef.proxyObj.getName();

相關連結:
AS3 Weakly Referenced Listener 錯誤的使用方式


Read more...

2007年6月27日 星期三

FMS Client AS 自訂類別物件傳遞   [+/-]

Ticore's Blog

透過與 FMS 連線,可以共享 SharedObject 物件資料
但是資料內容僅限於 String、Number、Array 等基礎物件
不過可以使用 SharedObject.send 傳遞自訂類別的物件
以下是範例程式:

FMS SSAS:

application.onConnect = function() {
 return true;
};

自訂類別 MyClass.as:

class MyClass {
 public var name:String = "MyClass";
 public function MyClass() {
  trace("MyClass();");
 }
 public function fun():Void {
  trace("fun();");
 }
}

發布者 ActionScript:

Object.registerClass("MyClass",MyClass);
//
var nc:NetConnection = new NetConnection();
nc.onStatus = function(infoObj:Object):Void  {
 trace(infoObj.code);
 switch (infoObj.code) {
  case "NetConnection.Connect.Success" :
   so.send("getObj",new MyClass());
   break;
 }
};
nc.connect("rtmp:/so_app");
var so:SharedObject = SharedObject.getRemote("so", nc.uri);
so.connect(nc);

接受者 ActionScript:

Object.registerClass("MyClass",MyClass);
//
var nc:NetConnection = new NetConnection();
nc.onStatus = function(infoObj:Object):Void  {
 trace(infoObj.code);
 switch (infoObj.code) {
  case "NetConnection.Connect.Success" :
   break;
 }
};
nc.connect("rtmp:/so_app");
var so:SharedObject = SharedObject.getRemote("so", nc.uri);
so.getObj = function(obj) {
 trace("so.getObj();");
 trace(obj.name);
 obj.fun();
};
so.connect(nc);

最主要的關鍵步驟是 Object.registerClass("MyClass",MyClass);
同理也可以利用類似做法在 FMS SSAS 與 Client AS 之間共享類別物件


Read more...

AS3 E4X - XML 節點包覆   [+/-]

Ticore's Blog

全部子節點下移一層:

var xml:XML =
<xml>
 <node/>
</xml>;
var newNode:XML = <{"newNode"}/>;
newNode.* = xml.*;
xml.* = newNode;
trace(xml.toXMLString());

全部子節點下移一層:

var xml:XML =
<xml>
 <node/>
 text
</xml>;
var nodeName:String = "children";
xml.* = <{nodeName}>{xml.*}</{nodeName}>;
trace(xml.toXMLString());

個別子節點下移一層:

var xml:XML =
<xml>
 <node1/>
 text
 <node2/>
 <node3/>
</xml>;
var nodeName:String = "child";
xml.*.(parent().*[childIndex()] = <{nodeName}>{parent().*[childIndex()]}</{nodeName}>);
trace(xml.toXMLString());

相關連結:
AS3 - Inline 宣告 XMLList 物件方式
Flash CS3 jsfl 也支援 E4X, RegExp
AS3 E4X 互補方案 XPath
AS3 E4X - QName 相關操作
AS3 利用 QName 快速存取 Namespace Member
AS3 E4X 資料取出與計算
AS3 E4X - XML 節點交換
AS3 E4X - 插入 XML 節點
AS3 E4X - 刪除 XML 節點
AS3 E4X Tip - 你拿到的是 XML or XMLList?
AS3 E4X 技巧 - 替 XML 添加 prototype fnuction
AS3 E4X - XML Attribute 相關操作
用 @* 指定 Attributes 造成 Flash Player 9 Crash
AS3 E4X - XML、XMLList 物件內子節點參考指定與複製
AS3 E4X - XML 物件比較
AS3 E4X - 相關類別與物件建立
AS2、AS3 基礎型別物件一致性
原來 Firefox 1.5 就已經開始支援 E4X


Read more...

2007年6月26日 星期二

修改 FileReference 相對路徑依據方式   [+/-]

Ticore's Blog

之前介紹了三種截然不同 Flash Player Plugin 路徑行為
真是非常神奇,文件上居然都沒有提到

FileReference 這樣完全根據自身 Flash Movie 路徑的行為有時候很不方便
解決的方式很簡單,只要在主影片內宣告 function 讓其它載入的影片呼叫即可

再繼續研究影響路徑的因素...
可以發現到主要是由 FileReference 物件實體化位置所影響
這樣可以更彈性的只要動態依據參數在主影片內產生實體回傳就好
其它呼叫函式的動作都下放子影片內

http://www.dom1.com/swf1/movie1.swf
ActionScript:

System.security.allowDomain("http://www.dom2.com");

function getInstance(className:String):Object{
 return new [className]();
};

var mc:MovieClip = this.createEmptyMovieClip("mc", this.getNextHighestDepth());
mc.loadMovie("http://www.dom2.com/swf2/movie2.swf");

http://www.dom1.com/swf2/movie2.swf
ActionScript:

_parent.getInstance("flash.net.FileReference").download("file1.txt","file1.txt");

這樣 movie2.swf 會下載檔案 http://www.dom1.com/swf1/file1.txt

相關連結:
Flash Player Plugin 相關路徑行為實例
網頁上 Flash 路徑小技巧


Read more...

Flash Player Plugin 相關路徑行為實例   [+/-]

Ticore's Blog

Flash Player Plugin 在 HTML 上路徑相關的行為相當複雜
一般認知是 SWF 檔案會以 HTML 所在路徑為相對路徑起始
這只適用於大部分讀取外部資料 API 行為,loadMovie、LoadVars...

假如遇到了 NetStream 撥放外部 *.flv 檔案
或是 FileReference 便不適用了

以下分別挑選一般性的 LoadVars 以及 NetStream、FileReference 作測試
加入 Flash Object 標籤的 Base 屬性設定,以及跨網域 (cross-domain) 讀取等因素進行測試

HTML 部分不完整列出了,僅列出 Object Base、Object Src 而已
主要影片:指的是 HTML Object 明確指定路徑的 Flash Movie,非 loadMovie 讀入的影片
自身影片:指的是 ActionScript 執行所在 Flash Movie 位置,可能是主要影片或是外部讀入影片

LoadVars 相對起始路徑與依據主要影片位置相同,會受 Object Base 影響
http://localhost/html/index.html
[HTML Setting] object base:".." object src:"http://www.dom1.com/swf1/movie1.swf"
http://www.dom1.com/swf1/movie1.swf
[ActionScript] var loader:LoadVars = new LoadVars(); loader.load("swf1/file1.txt"); loadMovieNum("http://www.dom2.com/swf2/movie2.swf", 1);
http://www.dom2.com/swf2/movie2.swf
[ActionScript] var loader:LoadVars = new LoadVars(); loader.load("swf2/file2.txt"); loadMovieNum("http://www.dom3.com/swf3/movie3.swf", 2);
http://www.dom3.com/swf3/movie3.swf
[ActionScript] var loader:LoadVars = new LoadVars(); loader.load("swf3/file3.txt");
上述的程式會先讀取
http://localhost/crossdomain.xml

然後分別讀取以下路徑檔案:

http://localhost/swf1/file1.txt
http://localhost/swf2/file2.txt
http://localhost/swf3/file3.txt

*.flv 撥放相對起始位置相對起始路徑與主要影片位置相同,不受 Object Base 影響
http://localhost/html/index.html
[HTML Setting] object base:".." object src:"http://www.dom1.com/swf1/movie1.swf"
http://www.dom1.com/swf1/movie1.swf
[ActionScript] var nc:NetConnection = new NetConnection(); nc.connect(null); var ns:NetStream = new NetStream(nc); ns.play("video1.flv"); loadMovieNum("http://www.dom2.com/swf2/movie2.swf", 1);
http://www.dom2.com/swf2/movie2.swf
[ActionScript] var nc:NetConnection = new NetConnection(); nc.connect(null); var ns:NetStream = new NetStream(nc); ns.play("video2.flv"); loadMovieNum("http://www.dom3.com/swf3/movie3.swf", 2);
http://www.dom3.com/swf3/movie3.swf
[ActionScript] var nc:NetConnection = new NetConnection(); nc.connect(null); var ns:NetStream = new NetStream(nc); ns.play("video3.flv");

上述的程式分別讀取以下路徑檔案:

http://www.dom1.com/swf1/video1.flv
http://www.dom1.com/swf1/video2.flv
http://www.dom1.com/swf1/video3.flv

FileReference 相對起始路徑與自身影片位置相同,不受 Object Base 影響
http://localhost/html/index.html
[HTML Setting] object base:".." object src:"http://www.dom1.com/swf1/movie1.swf"
http://www.dom1.com/swf1/movie1.swf
[ActionScript] import flash.net.*; var file:FileReference = new FileReference(); var lisObj:Object = {}; lisObj.onComplete = function() { trace("onComplete"); loadMovieNum("http://www.dom2.com/swf2/movie2.swf", 1); }; file.addListener(lisObj); file.download("file1.txt", "file1.txt");
http://www.dom2.com/swf2/movie2.swf
[ActionScript] import flash.net.*; var file:FileReference = new FileReference(); var lisObj:Object = {}; lisObj.onComplete = function() { trace("onComplete"); loadMovieNum("http://www.dom3.com/swf3/movie3.swf", 1); }; file.addListener(lisObj); file.download("file2.txt","file2.txt");
http://www.dom3.com/swf3/movie3.swf
[ActionScript] import flash.net.*; var file:FileReference = new FileReference(); file.download("file3.txt", "file3.txt");

上述的程式分別讀取以下路徑檔案:

http://www.dom1.com/swf1/file1.txt
http://www.dom2.com/swf2/file2.txt
http://www.dom3.com/swf3/file3.txt

相關連結:
修改 FileReference 相對路徑依據方式
網頁上 Flash 路徑小技巧


Read more...

2007年6月25日 星期一

AS3 E4X 資料取出與計算   [+/-]

Ticore's Blog

使用 for 計算總合:

var xml:XML = 
<order>
 <item id='1' quantity='2'>
  <menuName>burger</menuName>
  <price>3.95</price>
 </item>
 <item id='2' quantity='2'>
  <menuName>fries</menuName>
  <price>1.45</price>
 </item>
</order>;
var total:Number = 0;
for (var pname:String in xml.item) {
 total += xml.item.@quantity[pname] * xml.item.price[pname];
}
trace(total);

使用 for each 計算總合:

var xml:XML = 
<order>
 <item id='1' quantity='2'>
  <menuName>burger</menuName>
  <price>3.95</price>
 </item>
 <item id='2' quantity='2'>
  <menuName>fries</menuName>
  <price>1.45</price>
 </item>
</order>;
var total:Number = 0;
for each (var prop:XML in xml.item) {
 total += prop.@quantity * prop.price;
}
trace(total);

使用篩選運算子 .(...) 計算總合:

var xml:XML = 
<order>
 <item id='1' quantity='2'>
  <menuName>burger</menuName>
  <price>3.95</price>
 </item>
 <item id='2' quantity='2'>
  <menuName>fries</menuName>
  <price>1.45</price>
 </item>
</order>;
var total:Number = 0;
xml.item.(total += @quantity * price);
trace(total);

兩個 XML 模擬關聯式 Table 計算總合:

var itemXML:XML =
<table>
 <entry id="0">
  <name>Item 0</name>
  <price>12</price>
 </entry>
 <entry id="1">
  <name>Item 1</name>
  <price>8</price>
 </entry>
 <entry id="2">
  <name>Item 2</name>
  <price>16</price>
 </entry>
 <entry id="3">
  <name>Item 3</name>
  <price>26</price>
 </entry>
</table>;

var recordXML:XML = 
<table>
 <entry id="0">
  <itemId>1</itemId>
  <no>22</no>
 </entry>
 <entry id="1">
  <itemId>2</itemId>
  <no>12</no>
 </entry>
 <entry id="2">
  <itemId>0</itemId>
  <no>8</no>
 </entry>
 <entry id="3">
  <itemId>3</itemId>
  <no>13</no>
 </entry>
</table>;
var total:Number = 0;
recordXML.entry.(total += (itemXML.entry.(@id == itemId).price * no));
trace(total);

相關連結:
AS3 - Inline 宣告 XMLList 物件方式
Flash CS3 jsfl 也支援 E4X, RegExp
AS3 E4X 互補方案 XPath
AS3 E4X - QName 相關操作
AS3 利用 QName 快速存取 Namespace Member
AS3 E4X - XML 節點包覆
AS3 E4X - XML 節點交換
AS3 E4X - 插入 XML 節點
AS3 E4X - 刪除 XML 節點
AS3 E4X Tip - 你拿到的是 XML or XMLList?
AS3 E4X 技巧 - 替 XML 添加 prototype fnuction
AS3 E4X - XML Attribute 相關操作
用 @* 指定 Attributes 造成 Flash Player 9 Crash
AS3 E4X - XML、XMLList 物件內子節點參考指定與複製
AS3 E4X - XML 物件比較
AS3 E4X - 相關類別與物件建立
AS2、AS3 基礎型別物件一致性
原來 Firefox 1.5 就已經開始支援 E4X


Read more...

2007年6月23日 星期六

網頁上 Flash 路徑小技巧   [+/-]

Ticore's Blog

一般製作 HTML 網頁內嵌 Flash SWF 時
為了管理方便,通常會把 *.html、*.swf 檔案放在不同資料夾下
假如 SWF 內還有需要動態讀取其它的檔案
預設情況下,Flash Player Plugin 會以 .html 所在路徑為起始預設路徑
這樣測試起來不太方便

其實 Flash Object 標籤有一個 Base Attribute 可用
可以用來設定起始路徑位置

像以下將 Base 設為 ".",Flash Player Plugin 就會以 .swf 檔案所在路徑為起始

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
 codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0"
    name="loader" width="300" height="200" align="middle" id="loader">
  <param name="allowScriptAccess" value="sameDomain" />
  <param name="allowFullScreen" value="false" />
  <param name="movie" value="swf/loader.swf" />
  <param name="quality" value="high" />
  <param name="bgcolor" value="#ffffff" />
  <param name="base" value=".">
  <embed src="swf/loader.swf" width="300" height="200" align="middle" quality="high"
   bgcolor="#ffffff" name="loader" allowScriptAccess="sameDomain"
    allowFullScreen="false" type="application/x-shockwave-flash"
    pluginspage="http://www.macromedia.com/go/getflashplayer" base="." />
</object>

或者也可以設為其它 domain,只是需要注意 Corssdomain Security

另外需要注意,這個方式對撥放外部 *.flv 路徑沒有效果喔!

相關連結:
Flash OBJECT and EMBED tag attributes
Flash Player Plugin 相關路徑行為實例
修改 FileReference 相對路徑依據方式


Read more...

2007年6月22日 星期五

Flash 9 AS3 移除 Render Event Bug   [+/-]

Ticore's Blog

最近在測試 AS3 時間性事件時,又發現了一個 Render Event Bug
當一個 DisplayObject 註冊多個 Render 事件後
使用 removeEventListener 移除一個 Render 事件
會造成該 DisplayObject 所有 Render 事件監聽器都失效
需要重新加入一個 Render 事件監聽器,才能讓其它監聽器恢復作用

以下是 Bug Demo 程式
main class:

package {
 import flash.display.*;
 import flash.events.*;
 import flash.utils.*;
 
 public class main extends MovieClip {
  
  var mc:MovieClip;
  
  public function main():* {
   stage.frameRate = 1;
   mc = new MC();
   mc.name = "MC";
   this.addChild(mc);
   setInterval(onInterval, 10);
  }
  
  public function onInterval():* {
   trace("onInterval:" + getTimer());
   stage.invalidate();
  }
  
 }
}

MC class:

package {
 import flash.display.*;
 import flash.events.*;
 
 public class MC extends MovieClip {

  public function MC():* {
   this.addEventListener(Event.ENTER_FRAME,enterFrameHandler1);
   this.addEventListener(Event.ENTER_FRAME,enterFrameHandler2);
   this.addEventListener(Event.RENDER,renderHandler1);
   this.addEventListener(Event.RENDER,renderHandler2);
   this.addEventListener(Event.RENDER,renderHandler3);
  }
  
  public function enterFrameHandler1(e:Event):void {
   var mc:MovieClip = e.target as MovieClip;
   trace("onEnterFame Event 1");
   e.target.removeEventListener(Event.ENTER_FRAME, e.target.enterFrameHandler1);
  }
  
  public function enterFrameHandler2(e:Event):void {
   var mc:MovieClip = e.target as MovieClip;
   trace("onEnterFame Event 2");
  }
  
  public function renderHandler1(e:Event):void {
   var mc:MovieClip = e.target as MovieClip;
   trace("onRender Event 1");
   e.target.removeEventListener(Event.RENDER, e.target.renderHandler1);
   // 重新加入一個 Render Event
   //e.target.addEventListener(Event.RENDER, function(e:Event):*{});
  }
  
  public function renderHandler2(e:Event):void {
   var mc:MovieClip = e.target as MovieClip;
   trace("onRender Event 2");
  }
  
  public function renderHandler3(e:Event):void {
   var mc:MovieClip = e.target as MovieClip;
   trace("onRender Event 3");
  }
 }
}

輸出結果:

onEnterFame Event 1
onEnterFame Event 2
onInterval:117
onRender Event 1
onRender Event 2
onRender Event 3
onInterval:206
onInterval:312
onInterval:406
onInterval:512
onInterval:607
onInterval:711
onInterval:806
onInterval:912
onInterval:1018
onEnterFame Event 2
onInterval:1113
onInterval:1207
onInterval:1315
onInterval:1406
onInterval:1512
onInterval:1606
onInterval:1706
onInterval:1807
onInterval:1906
onInterval:2006
onInterval:2106
onEnterFame Event 2
onInterval:2206
onInterval:2306
onInterval:2406
onInterval:2509
onInterval:2606

該 Bug 已經在以下 Flash Player 版本測試過確實會發生
Flash Player 9.0.45.0
Flash Player 9.0.60.120
Flash Player 9.0.60.235
Flash Player 9.0.64.0
Flash Player 9.0.115.0
Flash Player 9.0.124.0


Read more...

2007年6月21日 星期四

Flash 9 AS3 時間性事件混合測試   [+/-]

Ticore's Blog

這次將 Flash 9 AS3 與時間相關的事件一併納入測試
與 FPS 直接相關的 frameScript、enterFrame、render 事件
還有 setInterval 事件 (與 Timer 類似)
最後還有一個簡單的 Mouse Down 事件,主要是用來觀察與時間性事件之間的關係

開一 fla 文件,建立含有三個影格的 MovieClip,設定 Class Name 為 "MC"
套用以下 document class:

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

 public class main extends MovieClip {

  var mc1:MovieClip;
  var mc2:MovieClip;
  var mc3:MovieClip;
  var mcAry:Array = [];
  
  //
  //=================================================================================
  //
  
  public function main() {
   init();
  } 
  public function init() {
   
   for (var i:Number = 1 ; i <= 3 ; ++i) {
    var mc:MovieClip = new MC();
    this["mc" + i] = mc;
    mcAry.push(mc);
    mc.name = "MC" + i;
    mc.frameAction = frameAction;
    var fa:Function = createFrameAction(mc, "frameAction");
    mc.addFrameScript(0, fa, 1, fa, 2, fa);
    mc.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    mc.addEventListener(Event.RENDER, renderHandler);
    mc.gotoAndPlay(2);
   }
   
   reparent();
   setInterval(reparent, 6000);
   setInterval(onInterval, 1);
   stage.invalidate();
   stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
   
  }
  
  //
  //=================================================================================
  //
  
  public function reparent():void {
   
   mcAry.sort(sortOnRandom);
   trace("=> Reparent To:root > ", mcAry[0].name + " > " + mcAry[1].name + " > " + mcAry[2].name);
   
   for(var i:Number = 0 ; i < mcAry.length ; ++i) {
    if(mcAry[i].parent != null) {
     mcAry[i].parent.removeChild(mcAry[i]);
    }
   }
   
   this.addChild(mcAry[0]);
   mcAry[0].addChild(mcAry[1]);
   mcAry[1].addChild(mcAry[2]);
   
  }
  
  public function sortOnRandom(a:*, b:*):Number{
   return Math.floor(Math.random() * 3) - 1;
  }
  
  public function createFrameAction(mc:MovieClip, fun:String):Function {
   return function():void {
    mc[fun]();
   };
  }
  public function getFullPath(mc:DisplayObject):String {
   if (mc == null) { return ""; }
   var path:String = mc.name;
   var target:DisplayObjectContainer = mc.parent;
   while (target != stage) {
    path = target.name + "." + path;
    target = target.parent;
   }
   return path;
  }
  
  //
  //=================================================================================
  //
  
  public var mouseDownHandler:Function = function(e:Event):void {
   trace("Mouse Down");
  };
  
  public var frameAction:Function = function():void {
   trace("Frame Script " + this.currentFrame + ":" + getFullPath(this));
  };
  
  public var enterFrameHandler:Function = function(e:Event):void{
   var mc:MovieClip = e.target as MovieClip;
   trace("onEnterFame " + mc.currentFrame + ":" + getFullPath(mc));
  };
  
  public var renderHandler:Function = function(e:Event):void{
   var mc:MovieClip = e.target as MovieClip;
   trace("onRender " + mc.currentFrame + ":" + getFullPath(mc));
  };
  
  public var onInterval:Function = function():void{
   trace("onInterval:" + getTimer());
   stage.invalidate();
  };
  
  //
  //=================================================================================
  //
 }
}

輸出結果如下:

=> Reparent To:root >  MC1 > MC2 > MC3
Frame Script 2:root1.MC1
Frame Script 2:root1.MC1.MC2
Frame Script 2:root1.MC1.MC2.MC3
onEnterFame 2:root1.MC1
onEnterFame 2:root1.MC1.MC2
onEnterFame 2:root1.MC1.MC2.MC3
onInterval:1120
onRender 2:root1.MC1
onRender 2:root1.MC1.MC2
onRender 2:root1.MC1.MC2.MC3
onInterval:2053
onInterval:3078
onInterval:4266
onInterval:5125
=> Reparent To:root >  MC1 > MC2 > MC3
onInterval:6149
onInterval:7174
onInterval:8197
Mouse Down
onInterval:9221
onInterval:10246
onInterval:11270
onEnterFame 3:root1.MC1
onEnterFame 3:root1.MC1.MC2
onEnterFame 3:root1.MC1.MC2.MC3
=> Reparent To:root >  MC2 > MC1 > MC3
onInterval:12293
Frame Script 3:root1.MC2
Frame Script 3:root1.MC2.MC1
Frame Script 3:root1.MC2.MC1.MC3
onRender 3:root1.MC2.MC1
onRender 3:root1.MC2
onRender 3:root1.MC2.MC1.MC3
onInterval:13317

各位也可以調整參數反覆測試,可以觀察到一些特性:

  • 主要分為三種 Phase:Enter Frame Event Phase、Frame Script Phase、Render Event Phase, 三種階段也是按此順序執行
    (首輪 Frame Script Phase 優先可能又是例外)
  • Frame Script 執行順序受到階層順序的影響,上層較優先; Enter Frame Event 與 Render Event 則是依照建立順序執行
  • Interval Event 與 Mouse Event 似乎無法插入三種 Phase 任一執行期內, 僅能插入於 Phase 之間的空檔執行
  • FPS 越小 Render Event Phase 與 Enter Frame Event Phase 時間空隙越大

相關連結:
Flash Player 10 beta - 新的影格事件
Flash 9 AS3 FrameScript + Reparenting 惡搞測試
Flash Player 8 AS2 影格程式執行順序
AS3 Tip - 讓動態加入影格程式取得目前 MovieClip 參考


Read more...

AS3 E4X - XML 節點交換   [+/-]

Ticore's Blog

先把節點複製出來,再插入:

var xml:XML =
<xml>
 <node1>1</node1>
 <node2>2</node2>
</xml>;
var node1:XML = xml.*[0].copy();
var node2:XML = xml.*[1].copy();
xml.*[0] = node2;
xml.*[1] = node1;
trace(xml.toXMLString());

取得節點參考,刪除子節點後,再插入:

var xml:XML =
<xml>
 <node1>1</node1>
 <node2>2</node2>
</xml>;
var node1:XML = xml.*[0];
var node2:XML = xml.*[1];
delete xml.*;
xml.*[0] = node2;
xml.*[1] = node1;
trace(xml.toXMLString());
trace(xml.*[0].childIndex());
trace(xml.*[1].childIndex());
var xml:XML =
<xml>
 <node1>1</node1>
 <node2>2</node2>
 <node3>3</node3>
</xml>;
var node1:XML = xml.*[0];
var node2:XML = xml.*[1];
var node3:XML = xml.*[2];
xml.*[0] = <n />;
xml.*[2] = <n />;
trace(xml.toXMLString());
xml.*[0] = node3;
xml.*[2] = node1;
trace(xml.toXMLString());

交換失敗例子:

var xml:XML =
<xml>
 <node1>1</node1>
 <node2>2</node2>
 <node3>3</node3>
</xml>;

var node:XML = xml.*[0];
xml.*[0] = xml.*[2];
xml.*[2] = <n />;
trace(xml.toXMLString());

使用 replace 交換節點:

var xml:XML =
<xml>
 <node1>1</node1>
 <node2>2</node2>
 <node3>3</node3>
</xml>;
var node:XML = xml.*[0];
xml.replace(0, xml.*[2]);
xml.replace(2, node);
trace(xml.toXMLString());

使用 replace 交換節點:

var xml:XML =
<xml>
 <node1>1</node1>
 <node2>2</node2>
 <node3>3</node3>
</xml>;
var node1:XML = xml.*[0];
var node2:XML = xml.*[2];
xml.replace(0, "");
xml.replace(2, "");
xml.*[0] = node2;
xml.*[2] = node1;
trace(xml.toXMLString());
trace(xml.*[0].childIndex());
trace(xml.*[1].childIndex());
trace(xml.*[2].childIndex());

相關連結:
AS3 - Inline 宣告 XMLList 物件方式
Flash CS3 jsfl 也支援 E4X, RegExp
AS3 E4X 互補方案 XPath
AS3 E4X - QName 相關操作
AS3 利用 QName 快速存取 Namespace Member
AS3 E4X - XML 節點包覆
AS3 E4X 資料取出與計算
AS3 E4X - 插入 XML 節點
AS3 E4X - 刪除 XML 節點
AS3 E4X Tip - 你拿到的是 XML or XMLList?
AS3 E4X 技巧 - 替 XML 添加 prototype fnuction
AS3 E4X - XML Attribute 相關操作
用 @* 指定 Attributes 造成 Flash Player 9 Crash
AS3 E4X - XML、XMLList 物件內子節點參考指定與複製
AS3 E4X - XML 物件比較
AS3 E4X - 相關類別與物件建立
AS2、AS3 基礎型別物件一致性
原來 Firefox 1.5 就已經開始支援 E4X


Read more...

AS3 E4X - 插入 XML 節點   [+/-]

Ticore's Blog

利用 appendChild 插入節點:

XML.ignoreComments = false;
XML.ignoreProcessingInstructions = false;
var xml:XML = 
<xml attr1="1">
</xml>;
xml.appendChild(<node />);
xml.appendChild(<!-- comment -->);
xml.appendChild(<? instruction ?>);
xml.appendChild("text");
trace(xml.toXMLString());

利用 += 運算子插入節點:

XML.ignoreComments = false;
XML.ignoreProcessingInstructions = false;
var xml:XML = 
<xml attr1="1">
</xml>;
xml.* += <node />;
xml.* += <!-- comment -->;
xml.* += <? instruction ?>;
xml.* += XML("text");
trace(xml.toXMLString());

直接指定節點名稱與索引插入:

var xml:XML = 
<xml attr1="1">
 text
</xml>;
xml.node[0] = "node text 1";
xml.node[1] = "node text 2";
trace(xml.toXMLString());

插在子節點 0 之後:

var xml:XML = 
<xml attr1="1">
 text
</xml>;
xml.*[0] += <node>1</node>;
xml.*[0] += <node>2</node>;
xml.*[0] += <node>3</node>;
trace(xml.toXMLString());
var xml:XML = 
<xml attr1="1">
 text
</xml>;
xml.insertChildAfter(xml.*[0], <node>1</node>);
xml.insertChildAfter(xml.*[0], <node>2</node>);
xml.insertChildAfter(xml.*[0], <node>3</node>);
trace(xml.toXMLString());

插在子節點 0 之前:

var xml:XML = 
<xml attr1="1">
 text
</xml>;
xml.* = <node>1</node> + xml.*;
xml.* = <node>2</node> + xml.*;
xml.* = <node>3</node> + xml.*;
trace(xml.toXMLString());
var xml:XML = 
<xml attr1="1">
 text
</xml>;
xml.insertChildBefore(xml.*[0], <node>1</node>);
xml.insertChildBefore(xml.*[0], <node>2</node>);
xml.insertChildBefore(xml.*[0], <node>3</node>);
trace(xml.toXMLString());

相關連結:
AS3 - Inline 宣告 XMLList 物件方式
Flash CS3 jsfl 也支援 E4X, RegExp
AS3 E4X 互補方案 XPath
AS3 E4X - QName 相關操作
AS3 利用 QName 快速存取 Namespace Member
AS3 E4X - XML 節點包覆
AS3 E4X 資料取出與計算
AS3 E4X - XML 節點交換
AS3 E4X - 刪除 XML 節點
AS3 E4X Tip - 你拿到的是 XML or XMLList?
AS3 E4X 技巧 - 替 XML 添加 prototype fnuction
AS3 E4X - XML Attribute 相關操作
用 @* 指定 Attributes 造成 Flash Player 9 Crash
AS3 E4X - XML、XMLList 物件內子節點參考指定與複製
AS3 E4X - XML 物件比較
AS3 E4X - 相關類別與物件建立
AS2、AS3 基礎型別物件一致性
原來 Firefox 1.5 就已經開始支援 E4X


Read more...

AS3 Tip - 讓動態加入影格程式取得目前 MovieClip 參考   [+/-]

Ticore's Blog

當用 addFrameScript 動態指定 MovieClip 影格程式時
function 內的 this 一般都是指到原始宣告位置的 Class Instance
或者是指向 global 物件
這樣用起來實在不方便

以下使用 unbound function 加上一個公用函式
讓 this 可以取得目前 MovieClip 參考
首先建立公用函式:

package {
 import flash.display.*;
 public function delegate (mc:MovieClip, fun:String):Function {
  return function():*{
   mc[fun]();
  }
 }
}

宣告 document class:

package {
 import flash.display.*;
 public class main extends MovieClip {
  public function main () {
   
   var mc:MC = new MC();
   mc.frameAction = function ():void{
    trace(this.name, this.currentFrame);
   }
   var fun:Function = delegate(mc, "frameAction");
   mc.addFrameScript(0, fun, 1, fun);
   
  }
 }
}

建立 fla 文件,並且建立一個三個影格的 MovieClip,輸出為 "MC"

相關連結:
ActionScript 3.0 beta 2 Bound Function
ActionScript 3.0 beta 1 Global Object
AS 3.0 利用 function scope 暫存變數
AS 2.0 將參數與 function 綁在一起


Read more...

2007年6月20日 星期三

Flash 9 AS3 FrameScript + Reparenting 惡搞測試   [+/-]

Ticore's Blog

繼之前 Flash Player 8 AS2 影格程式執行順序
再來測試 Flash 9 AS3 影格程式執行順序
不過如 qop 測試結果,AS3 都改外層 Frame Script 優先執行

所以要加點料,把 AS3 新功能 Reparenting 加入測試條件
首先用 Flash CS3 建立空白文件
root 影格拉到三格,fps 設為 1
於 Library 建立一個 MovieClip,也是一樣影格拉到三格
然後設定輸出給 ActionScript 使用,Class 命名為 "MC"
最後將文件套用 document class:

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

 public class main extends MovieClip {

  var mc1:MovieClip;
  var mc2:MovieClip;
  var mc3:MovieClip;
  var mcAry:Array = [];
  
  public function main() {
   var obj:Object = {};
   init();
  } 
  public function init() {
   
   for (var i:Number = 1 ; i <= 3 ; ++i) {
    var mc:MovieClip = new MC();
    this["mc" + i] = mc;
    mcAry.push(mc);
    mc.name = "MC" + i;
    mc.frameAction = frameAction;
    var fa:Function = createFrameAction(mc, "frameAction");
    mc.addFrameScript(0, fa, 1, fa, 2, fa);
    mc.gotoAndPlay(2);
   }
   
   var fa0:Function = createFrameAction(this, "frameAction");
   this.addFrameScript(0, fa0, 1, fa0, 2, fa0);
   this.gotoAndPlay(2);
   
   reparent();
   
   setInterval(reparent, 3000);
  }
  
  public function reparent():void {
   
   mcAry.sort(sortOnRandom);
   trace("\nReparent To:root > ", mcAry[0].name + " > " + mcAry[1].name + " > " + mcAry[2].name);
   
   this.numChildren > 0 ? this.removeChildAt(this.numChildren - 1) : null;
   mc1.numChildren > 0 ? mc1.removeChildAt(0) : null;
   mc2.numChildren > 0 ? mc2.removeChildAt(0) : null;
   mc3.numChildren > 0 ? mc3.removeChildAt(0) : null;
   
   this.addChild(mcAry[0]);
   mcAry[0].addChild(mcAry[1]);
   mcAry[1].addChild(mcAry[2]);
   
  }
  
  public function sortOnRandom(a:*, b:*):Number{
   return Math.floor(Math.random() * 3) - 1;
  }
  
  public function createFrameAction(mc:MovieClip, fun:String):Function {
   return function():void {
    mc[fun]();
   };
  }
  
  public var frameAction:Function = function():void {
   var path:String = this.name;
   var target:DisplayObjectContainer = this.parent;
   while (target != stage) {
    path = target.name + "." + path;
    target = target.parent;
   }
   trace("Frame " + this.currentFrame + " Running:" + path);
  }
 }
}

上述程式會動態建立三個 MC
並且會以亂數順序加入到 root 之下
測試影格程式是否會受到加入順序影響
每三秒鐘還會重新洗牌一次,夠惡搞了吧!

測試影片,可以看到輸出結果:

Reparent To:root >  MC1 > MC3 > MC2
Frame 2 Running:root1
Frame 2 Running:root1.MC1
Frame 2 Running:root1.MC1.MC3
Frame 2 Running:root1.MC1.MC3.MC2
Frame 3 Running:root1
Frame 3 Running:root1.MC1
Frame 3 Running:root1.MC1.MC3
Frame 3 Running:root1.MC1.MC3.MC2
Frame 1 Running:root1
Frame 1 Running:root1.MC1
Frame 1 Running:root1.MC1.MC3
Frame 1 Running:root1.MC1.MC3.MC2

Reparent To:root >  MC3 > MC1 > MC2
Frame 2 Running:root1
Frame 2 Running:root1.MC3
Frame 2 Running:root1.MC3.MC1
Frame 2 Running:root1.MC3.MC1.MC2
Frame 3 Running:root1
Frame 3 Running:root1.MC3
Frame 3 Running:root1.MC3.MC1
Frame 3 Running:root1.MC3.MC1.MC2
Frame 1 Running:root1
Frame 1 Running:root1.MC3
Frame 1 Running:root1.MC3.MC1
Frame 1 Running:root1.MC3.MC1.MC2

果然不負眾望,依照期望方式執行~

接下來,再調整洗牌時間間隔為 300 ms
可以看到輸出結果:

Reparent To:root >  MC1 > MC2 > MC3
Frame 2 Running:root1
Frame 2 Running:root1.MC1
Frame 2 Running:root1.MC1.MC2
Frame 2 Running:root1.MC1.MC2.MC3

Reparent To:root >  MC1 > MC2 > MC3

Reparent To:root >  MC1 > MC2 > MC3

Reparent To:root >  MC1 > MC2 > MC3
Frame 3 Running:root1
Frame 3 Running:root1.MC1
Frame 3 Running:root1.MC1.MC2
Frame 3 Running:root1.MC1.MC2.MC3

Reparent To:root >  MC1 > MC2 > MC3

Reparent To:root >  MC1 > MC2 > MC3

Reparent To:root >  MC1 > MC2 > MC3
Frame 1 Running:root1
Frame 1 Running:root1.MC1
Frame 1 Running:root1.MC1.MC2
Frame 1 Running:root1.MC1.MC2.MC3

Reparent To:root >  MC1 > MC2 > MC3

Reparent To:root >  MC1 > MC3 > MC2

Reparent To:root >  MC3 > MC1 > MC2

Reparent To:root >  MC3 > MC1 > MC2
Frame 2 Running:root1
Frame 2 Running:root1.MC3
Frame 2 Running:root1.MC3.MC1
Frame 2 Running:root1.MC3.MC1.MC2

Frame Script 與 setInterval 函式的執行階段似乎是井水不泛河水
不管 interval 多小,都無法插入 Frame Script 執行階段內

相關連結:
Flash Player 10 beta - 新的影格事件
Flash 9 AS3 時間性事件混合測試
Flash Player 8 AS2 影格程式執行順序
AS3 Tip - 讓動態加入影格程式取得目前 MovieClip 參考


Read more...

2007年6月19日 星期二

Flash Player 8 AS2 影格程式執行順序   [+/-]

Ticore's Blog

看到 qop 的文章,也稍微測試一下影格程式的執行順序
在 Flash 8 AS2 的測試結果出人意料之外!

只有在 MovieClip 實體預先放在 stage 上
且目標 Frame Script 都是放在影格 1
第一次 loop 才是外層 Frame Script 先執行
跑第二次 loop 時,就會變成最內層 Frame Script 先執行

簡單的輸出範例:

// loop 1
_level0.mc
_level0.mc.mc
_level0.mc.mc.mc
// loop 2
_level0.mc.mc.mc
_level0.mc.mc
_level0.mc
// loop 3
_level0.mc.mc.mc
_level0.mc.mc
_level0.mc
// loop 4
_level0.mc.mc.mc
_level0.mc.mc
_level0.mc

其它以 AS 動態建立 MovieClip 實體測試條件
則完全都是內層 Frame Script 先執行

測試檔案下載

相關連結:
Flash Player 10 beta - 新的影格事件
Flash 9 AS3 時間性事件混合測試
Flash 9 AS3 FrameScript + Reparenting 惡搞測試
AS3 Tip - 讓動態加入影格程式取得目前 MovieClip 參考


Read more...

AS3 E4X - 刪除 XML 節點   [+/-]

Ticore's Blog

刪除單一子節點:

var xml:XML =
<xml>
 <node>1</node>
 <node>2</node>
 <node>3</node>
 <node>4</node>
 <node>5</node>
 <node>6</node>
</xml>;
delete xml.*[0];
trace(xml.toXMLString());
delete xml.node[0];
trace(xml.toXMLString());
delete xml["node"][0];
trace(xml.toXMLString());

刪除全部子節點:

var xml:XML =
<xml>
 <node>1</node>
 <node>2</node>
 <node>3</node>
 <node>4</node>
 <node>5</node>
 <node>6</node>
</xml>;
delete xml.*;
trace(xml.toXMLString());
var xml:XML =
<xml>
 <node>1</node>
 <node>2</node>
 <node>3</node>
 <node>4</node>
 <node>5</node>
 <node>6</node>
</xml>;
delete xml["node"];
trace(xml.toXMLString());

用篩選運算子刪除所有 Text 節點:

XML.ignoreComments = false;
XML.ignoreProcessingInstructions = false;
var xml:XML =
<xml>
 <node>
  <n />
  <? ins ?>
  text1
  <node>text2</node>
 </node>
 text3
</xml>;
var texts:XMLList = xml..*.(nodeKind() == "text" ?
    delete parent().*[childIndex()] : false);
trace(xml.toXMLString());
trace(texts.toXMLString());

利用 prototype function 刪除所有 Text 節點:

XML.ignoreComments = false;
XML.ignoreProcessingInstructions = false;
var xml:XML =
<xml>
 <node>
  <n />
  <? ins ?>
  text
  <node>text</node>
 </node>
 text
</xml>;
XML.prototype.process = function():void{
 if (this.nodeKind() == "text") {
  delete this.parent().*[this.childIndex()];
 }
};
xml..*.(process());
trace(xml.toXMLString());

刪除第一層、第二層 Text 子節點:

XML.ignoreComments = false;
XML.ignoreProcessingInstructions = false;
var xml:XML =
<xml>
 <node>
  <n />
  <? ins ?>
  text
  <node>text</node>
 </node>
 text
</xml>;
XML.prototype.process = function():void{
 if (this.nodeKind() == "text") {
  delete this.parent().*[this.childIndex()];
 }
};

xml.*.(process());
xml.*.*.(process());
trace(xml.toXMLString());

相關連結:
AS3 - Inline 宣告 XMLList 物件方式
Flash CS3 jsfl 也支援 E4X, RegExp
AS3 E4X 互補方案 XPath
AS3 E4X - QName 相關操作
AS3 利用 QName 快速存取 Namespace Member
AS3 E4X - XML 節點包覆
AS3 E4X 資料取出與計算
AS3 E4X - XML 節點交換
AS3 E4X - 插入 XML 節點
AS3 E4X Tip - 你拿到的是 XML or XMLList?
AS3 E4X 技巧 - 替 XML 添加 prototype fnuction
AS3 E4X - XML Attribute 相關操作
用 @* 指定 Attributes 造成 Flash Player 9 Crash
AS3 E4X - XML、XMLList 物件內子節點參考指定與複製
AS3 E4X - XML 物件比較
AS3 E4X - 相關類別與物件建立
AS2、AS3 基礎型別物件一致性
原來 Firefox 1.5 就已經開始支援 E4X


Read more...

2007年6月18日 星期一

自製 Flash、Flex、FMS LvieDocs 搜尋引擎外掛   [+/-]

Ticore's Blog

Ticore's Search Plugins

Add Flex 2.01 Search Plugin
Add Flash 8 Search Plugin
Add Flash CS3 Search Plugin
Add FMS 2 Search Plugin
Add Flash CS3 AS 3 Ref. Search Plugin
Add Flex 2.01 AS 3 Ref. Search Plugin
Add Flash CS3 TW Search Plugin
Add Flash CS3 AS 3 Ref. TW Search Plugin


Read more...

AS3 E4X Tip - 你拿到的是 XML or XMLList?   [+/-]

Ticore's Blog

在 AS3 E4X 四個相關 Class 中
XML、XMLList 非常相近,容易讓人混淆
XML 主要是用來描述單一 XML 物件,具有一個 root node
XMLList 則是 XML 物件集合,沒有 root node,有點類似陣列
許多的 XML 相關的操作,都是回傳 XMLList

以下做一些測試,看看拿到的是什麼型別:

var xml:XML =
<xml attr1="A1" attr2="A2">
 text
 <node/>
 <node/>
 <node/>
</xml>;
trace((describeType(xml)).@name);               // XML
trace((describeType(xml.name())).@name);        // QName
trace((describeType(xml.@*)).@name);            // XMLList
trace((describeType(xml.@*[0])).@name);         // XML
trace((describeType(xml.attributes())).@name);  // XMLList
trace((describeType(xml.*)).@name);             // XMLList
trace((describeType(xml.children())).@name);    // XMLList
trace((describeType(xml.node)).@name);          // XMLList
trace((describeType(xml.node[0])).@name);       // XML
trace((describeType(xml.node.(true))).@name);   // XMLList
trace((describeType(xml.child("node"))).@name); // XMLList

XMLList 還有一個很重要特性
當 XMLList 物件內元素數量為 1 時,可以直接當作 XML 來進行操作

var xml:XML =
<xml>
 <node name="Node"/>
</xml>;
trace(xml.node.(true).@name); // Node
trace((describeType(xml.child("node"))).@name); // XMLList

當 XML、XMLList 同時具有相同名稱 prototype function 時
上述的自動轉換功能又有些不一樣

XML.prototype.foo = function():*{
 trace("XML.foo();");
}
XMLList.prototype.foo = function():*{
 trace("XMLList.foo();");
}

var xml:XML =
<xml>
 <node/>
</xml>;
(xml.node as Object).foo(); // XMLList.foo();
delete XMLList.prototype.foo;
(xml.node as Object).foo(); // XML.foo();

由 output 可以發現
對單一元素 XMLList 物件呼叫 prototype function 時
AVM 會先檢查 XMLList.prototype
假如沒有,才會轉成 XML 呼叫

相關連結:
AS3 - Inline 宣告 XMLList 物件方式
Flash CS3 jsfl 也支援 E4X, RegExp
AS3 E4X 互補方案 XPath
AS3 E4X - QName 相關操作
AS3 利用 QName 快速存取 Namespace Member
AS3 E4X - XML 節點包覆
AS3 E4X 資料取出與計算
AS3 E4X - XML 節點交換
AS3 E4X - 插入 XML 節點
AS3 E4X - 刪除 XML 節點
AS3 E4X 技巧 - 替 XML 添加 prototype fnuction
AS3 E4X - XML Attribute 相關操作
用 @* 指定 Attributes 造成 Flash Player 9 Crash
AS3 E4X - XML、XMLList 物件內子節點參考指定與複製
AS3 E4X - XML 物件比較
AS3 E4X - 相關類別與物件建立
AS2、AS3 基礎型別物件一致性
原來 Firefox 1.5 就已經開始支援 E4X


Read more...