2006年12月29日 星期五

12 枚硬幣秤重 - 公式解推導方式 (2)   [+/-]

Ticore's Blog

之前提出的公式推法
由於需要列舉所有組合,篩選掉鏡像等步驟
計算時間一下就超過電腦的負荷

以下歸納得到的規則

以秤重三次的公式來說

硬幣代號 A B C D E F G H I J K L
第一次
第二次
第三次

經過調整之後可以得到

硬幣代號 A B C D E F G H I J K L
第一次 > < = = > < > < = < = >
第二次 = > < > < = > < = > < =
第三次 = > < = > < = > < = > <

 

剛好是由 =、>、<隨機排列組合中取出三組互不為鏡像排列組合而成

  互為鏡像
Set 1 = > < = < >
Set 2 > < = < > =
Set 3 < = > > = <

再根據上表重新整理

硬幣代號 A B C D E F G H I J K L
第一次 ﹝Set 2﹞ ﹝Set 1﹞ ﹝Set 2﹞ ﹝Set 3﹞
第二次 ﹝Set 1﹞ ﹝Set 2﹞ ﹝Set 2﹞ ﹝Set 2﹞
第三次 ﹝Set 1﹞ ﹝Set 1﹞ ﹝Set 1﹞ ﹝Set 1﹞

最後將 Set 1 ~ 3 以 1、2、3 簡化

可得數列

第一次
第二次
第三次

同理,秤四次的數列為

第一次
第二次
第三次
第三次

這樣便有了規則可循
只要根據秤重的次數
根據以上的規則產生數列
將數字替換成對應的 Set 1 ~ 3
即可得到秤重的公式

以下是根據上述規則寫成 ActionScript 程式:

//
//====================================================================
//
function genSupPattern(base:Number, radix:Number):Array {
 var reaAry:Array = [];
 var max:Number = 1;
 for (var i:Number = 0; i < radix - 1; ++i) {
  for (var j:Number = 0; j < max; ++j) {
   reaAry.push(j + max);
  }
  max *= base;
 }
 return reaAry;
}
function expendPattern(base:Number, radix:Number,
 superPattern:Array, setAry:Array):Array {
 var formulaAry:Array = [];
 for (var i:Number = 0; i < radix; ++i) {
  formulaAry[i] = [];
 }
 for (var i:Number = 0; i < superPattern.length; ++i) {
  var x:Number = superPattern[i];
  var q:Number = x;
  var r:Number = 0;
  for (var j:Number = 0; j < radix; ++j) {
   r = q % base;
   q = Math.floor(q / base);
   formulaAry[j] = formulaAry[j].concat(setAry[r]);
  }
 }
 return formulaAry;
}
function genPattern(base:Number, radix:Number, setAry:Array):Array {
 var superPattern:Array = genSupPattern(base, radix);
 return expendPattern(base, radix, superPattern, setAry);
}
//
//====================================================================
//
// 秤重次數
var radix:Number = 3;
var base:Number = 3;
// 三種基本互相為非鏡像組合
var setAry:Array = [["=", ">", "<"], [">", "<", "="], ["<", "=", ">"]];
//
var formulaAry:Array = genPattern(base, radix, setAry);
//
// 輸出公式字串
for (var i:Number = 0; i < radix; ++i) {
 trace(formulaAry[i]);
}
//
//====================================================================
//

相關連結:
12 枚硬幣秤重 - 公式解推導方式 (1)
硬幣問題
C 語言的解法

Read more...

2006年12月26日 星期二

AS3 Weakly Referenced Listener 錯誤的使用方式   [+/-]

Ticore's Blog

Weak Reference 是 ActionScript 3.0 新增的特色之一
不過使用者只能透過 Dictionary、EventDispatcher.addEventListener 兩種方式
才能享受到 Weak Reference 的好處

Dictionary 的使用方式很簡單,參考文件上範例即可
而 EventDispatcher.addEventListener 使用起來問題比較多
主要是因為 AS3 function 的特性以及 bug 所造成

先來看 EventDispatcher.addEventListener 參數

addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

listener 參數物件型別是 Function
表示我們可以用一個 function 當作物件傳進去
這在 ActionScript 1.0、2.0 早已被廣泛使用
只是那時候沒有 weak reference 可以用

AS 3 的 function 有分 bound method 與 unbound function
差異在於 function 使用 this 參考對象是否會被綁定
當然最重要的還有是否能夠回收的問題

以下為 weakly referenced listener 錯誤的使用示範

 

錯誤用法一、不可以把類別的方法當作 weakly referenced listener 來用

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

 public class Main extends MovieClip {
  public function Main() {
   this.addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
  }
  public static function onEnterFrame(event:Event):void{
   trace("static bound method as weakly listener.");
  }
 }
}
第一個程式把類別的方法當作弱引用 listener 來用
類別在 application 沒有 unload 以前是不可能會被回收的
類別方法與類別是綁在一起的
所以 listener 會不斷的執行下去

 

錯誤用法二、使用物件實體的方法當作 weakly referenced listener 來用,務必確保該物件會被回收

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

 public class Main extends MovieClip {
  public function Main() {
   this.addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
  }
  public function onEnterFrame(event:Event):void{
   trace("non-static bound method as weakly listener.");
  }
 }
}
第二個程式把 Main 物件實體的方法當作弱引用 listener 來用
Main 物件實體的方法與 Main 實體綁在一起
在關閉 Flash Player 以前是不會被回收的

 

錯誤用法三、不可用第一次產生的 function closure 當作 weakly referenced listener

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

 public class Main extends MovieClip {
  public function Main() {
   this.addEventListener(Event.ENTER_FRAME, getListener(), false, 0, true);
  }
  public function getListener():Function{
   return function(event:Event):void{
    trace("function closure as weakly listener.");
   };
  }
 }
}

由於 AS3 function closure 回收有 Bug
第一次取得的 function closure 物件無法被回收

 

錯誤用法四、你的 weakly referenced listener 不要被 function closure shapshot 掃到

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

 public class Main extends MovieClip {
  
  public var snapshot:Function;
  
  public function Main() {
   
   snapshot = function():void{};
   
   var listenerObj:ListenerObj = new ListenerObj();
   this.addEventListener(Event.ENTER_FRAME, listenerObj.onEnterFrame, false, 0, true);
  }
 }
}

import flash.events.*;
class ListenerObj {
 public function onEnterFrame(event:Event):void{
  trace("onEnterFrame();");
 }
}
由於 as3 function closure 會建立環境的快照
只要被快照掃到視同被參考到
上面的 listenerObj 被 snapshot 掃到了
只要 snapshot 還在,listenerObj 就不會被回收

 

 

AS 3 Function 相關線上文件:

Programming ActionScript 3.0 > Overview of ActionScript Programming > ActionScript Language and Syntax > Functions

Programming ActionScript 3.0 > Overview of ActionScript Programming > Object-Oriented Programming in ActionScript > Classes > Methods

相關參考資料:

ActionScript 3.0 - Function Closure GC Bug

相關連結:
AS2 以 LocalConnection 實作 WeakReference 的方式

Read more...

2006年12月24日 星期日

Flex 2 AS 3 Metadata Tag - Transient   [+/-]

Ticore's Blog

ActionScript 3 中加入對於物件序列化 (Object Serialization) 的支持
常見的便是用 ByteArray.writeObject、readObject 讀寫物件

假如遇到資料欄欄位不想被保存下來怎麼辦?
很簡單,用 transient 這個字
跟 Java 很像,只不過對於 AS3 來說 transient 是一個 Metadata Tag
而不是修飾子 (Modifier)

以下是簡單的測試

Main.as:
package {
 import flash.display.*;
 import flash.utils.*;
 import flash.net.*;

 public class Main extends Sprite {
  public function Main() {
   
   registerClassAlias("SerialObj", SerializableObj);
   
   var obj1:SerializableObj = new SerializableObj();
   obj1.field = ("NO Transient Field.");
   obj1.transField = ("Transient Field.");
   
   var ba:ByteArray = new ByteArray();
   ba.writeObject(obj1);
   ba.position = 0;
   
   var obj2:Object = ba.readObject();
   
   trace("obj1.field : " + obj1.field);
   trace("obj1.transField : " + obj1.transField);
   
   trace("obj2.field : " + obj2.field);
   trace("obj2.transField : " + obj2.transField);
   
   /*
   output:
   
   obj1.field : NO Transient Field.
   obj1.transField : Transient Field.
   obj2.field : NO Transient Field.
   obj2.transField : null
   */
   
  }
 }
}
SerializableObj.as
package {
 import flash.display.*;
 
 public class SerializableObj {
  
  public var field:String;
  
  [Transient]
  public var transField:String;
  
 }
}

 

Transient 也可以用於 get、set accessor:

Main.as 同前

SerializableObj.as

package {
 import flash.display.*;
 
 public class SerializableObj {
  
  private var _field:String;
  
  public function get field():String{
   return _field;
  }
  public function set field(p:String):void{
   _field = p;
  }
  
  private var _transField:String;
  
  [Transient]
  public function get transField():String{
   return _transField;
  }
  public function set transField(p:String):void{
   _transField = p;
  }
  
 }
}

利用 describeType 也可以看到 transient metadata tag 資訊確實被加入類別定義中

Read more...

2006年12月23日 星期六

ActionScript 3 靜態初始子   [+/-]

Ticore's Blog

AS3 文件上並沒有說明類別靜態初始化區塊用法

不過還是有人發現了 Daniel R. - Static Initializers in AS3

package {
 public class MyClass {
  {
   trace("static initialize block.");
  }
 }
}

再配合 AS3 Decompiler 看初始化區塊到底編譯成怎樣

  class MyClass extends Object
  {

    function MyClass():* /* disp_id -1*/
    {
      // local_count=1 max_scope=1 max_stack=1 code_len=6
      0     getlocal0      
      1     pushscope      
      2     getlocal0      
      3     constructsuper (0)
      5     returnvoid     
    }

    static function MyClass$cinit():* /* disp_id 0*/
    {
      // local_count=1 max_scope=1 max_stack=2 code_len=10
      0     getlocal0      
      1     pushscope      
      2     findpropstrict trace
      4     pushstring     "static initialize block."
      6     callpropvoid   trace (1)
      9     returnvoid     
    }
  }

原來每個 Class 的 il 都會自動產生一個 classname$cinit 的方法
而類別的靜態初始子被編譯到這裡來了

需要注意的是在靜態初始子裡面不能使用 this
因為還沒有產生實體,無法取得參考

靜態初始區塊並不會在 swf 被載入時馬上執行
而是當有程式使用到該類別
才會進行初始化動作

相關連結:
AS3 global, package 程式碼區塊初始化順序
AS3 Class 靜態程式碼區塊使用其它 Class 順序

Read more...

2006年12月22日 星期五

IE 記憶體洩漏 引起 Flash Movie 無法關閉的問題   [+/-]

Ticore's Blog

最近工作上又遇到奇怪的問題
據說客戶的電腦用 Internet Explorer 瀏覽器
撥放含有 Flash Media Server (FMS) 即時連線的 Flash 內容
該 IE 視窗關閉之後
連線無法終止
一直在背景與 FMS 連線
直到客戶把全部的 IE 視窗關閉才中斷

網頁中的 Flash Movie 是使用 SWFObject 來載入的
SWFObject 也更新到 1.4.4 版

在我自己的電腦上用了 Firefox 2.0 與 IE 6 一直都測不出來
只好像無頭蒼蠅一樣搜尋 Google 谷歌大神

的確也有人發生類似的的情況
像是 IE 視窗關閉之後
Flash 的音樂還繼續在背景撥放等等

不過卻找不到實際有問題的頁面以及有效的解決方式

隔了幾天之後,跟上次一樣索性把矛頭指向 IE Memory Leak Bug
果然又有斬獲!!

大致上好像是因為 IE 瀏覽器內記憶體回收 (GC) 的演算方式有瑕疵
遇到 Dom Object 與 JavaScript Object 反覆循環參照 (circular reference) 的情況無法有效回收記憶體

我也實際按照此原理測試
以下是用來建立 Flash Dom Object 與 JavaScript Object 反覆循環參照的程式碼:

Flash 內的 AS 只有單純的與 FMS 連線而已
(假如沒有安裝 FMS,改成撥放 Mp3 也可以)

假如在 window.onbeforeunload 事件內
沒有清除循環參照的話
一直重新整理網頁
Flash Movie 便會一直建立連線無法關閉
從 FMS Admin Console 就會看到連線數不斷增加

 

IE 記憶體洩漏 (memory leak) 相關參考資料:

[Mishoo] IE where's my memory

QuirksBlog - Javascript memory leaks

Schlueterica - Memory Leaks in Microsoft Internet Explorer

Novemberborn - Event Cache

talideon.com - Fixing JavaScript memory leaks for good

youngpup.net - DHTML leaks ... not so much, actually


其它相關參考資料:

重複引用 SWFObject JavaScript 衝突

Read more...

2006年12月20日 星期三

12 枚硬幣秤重 - 公式解推導方式 (1)   [+/-]

Ticore's Blog

關於 12 枚硬幣問題 早有人提出公式解
但是不知道怎樣推出來的
以下是個人的推導方式


特徵值:

特徵值是用來區分兩件東西不同的重要依據,特徵值不同,代表兩件東西不同
也可以依據特徵值找出符合的東西

天秤秤重的時候,共有三種可能發生狀況:左邊重、右邊重、等重,分別以>、<、=代替
假設只有秤一次,3 的一次方 = 3,也就是可以得到 3 種特徵值

 

Eg. 1

假設題目是 3 枚硬幣,其中有一個比較重,秤一次要找出來

將三枚硬幣編號為 A、B、C
A 不拿出來秤重,B 放在天秤左邊,C 放在天秤右邊

擺放位置 不秤 天秤左邊 天秤右邊
第一次 A B C

結果只有三種對應三種特徵值
可以得到這張表

硬幣編號 A B C
特徵值
結果 A重 B重 C重

依據這張表來秤重
特徵值 >、<、= 同時代表著秤重時硬幣擺放位置
以及秤重結果對照

假設是A比較重,那一定可以得到天秤兩邊是等重的結果
查表找出 = 的特徵值,即可得是A比較重

 

特徵值組合:

光是從一次測試,得到可能發生的幾種特徵值
能夠用來區分的種類數目有限
可以增加測試的次數,得到一特徵值組合
這樣便可以區分更多的種類

 

鏡像:

由於硬幣可能是比標準重,或是比標準輕
天秤秤出來的結果變成左邊重,或是右邊重
也就是兩種互為『鏡像』的狀況
當使用特徵值來做區分的時候
如果特徵值中也有兩種互為鏡像的狀況
就無法用來區分了

現在把 Eg. 1 改成硬幣比較重、或是比較輕都有可能發生
而這張表中 B、C 特徵值互為鏡像

  A B C
第一次

假設是 B 比較重,查表可以得到是 B 比較重
但是假如是 B 比較輕,查表卻是得到是 C 比較重
這樣這兩種情況就無法區分了
所以>、<兩種鏡像特徵值,只能取一種出來用
就只剩下兩種特徵值可以用,只秤一次產生的特徵值不足以用來區分三枚硬幣了

 

接下來,考慮秤重兩次的狀況

Eg. 2

假設題目是 3 個硬幣,其中有一個比較重或是比較輕,秤兩次要找出來

先列出秤重兩次可得到的所有特徵值
並將鏡像特徵值加以配對

  特徵值組合
第一次        
第二次

可以得到 4 對鏡像 + 1 非鏡像特徵值
理論上,可以區分 5 枚硬幣
但是,天秤左邊與天秤右邊的硬幣數目必須要一樣
就是每次秤重時,>與<出現的數目要一樣
基於以上限制,最多可以取出 3 組互為非鏡像特徵值來使用

硬幣編號 A B C
第一次
第二次

也就是最多只能從 3 枚硬幣找出哪個比較重或是比較輕

擺放位置 天秤左邊 天秤右邊 不秤
第一次 C B A
第二次 A C B

假設是C輕
可以得到兩次秤重結果分別是<、>
但是我們發現這結果在特徵值表中找不到
其實不是找不到
而是當初採用的特徵值是<、>結果的鏡像
<、>的鏡像是>、<

答案是"C比較重"的鏡像 => "C比較輕"

 

Eg. 3

最後,秤三次可以用來區分多少個硬幣呢?

秤三次,3 的三次方 = 27,可以得到 27 種特徵值

  特徵值組合
第一次
第二次
第三次

>、<兩種互為鏡像,而 = 本身無鏡像
把 27 種特徵值依據『鏡像』整理之後
可以得到 13 組鏡像 + 1 種非鏡像 特徵值
理論上,可以用來區分 14 個硬幣

  特徵值組合
第一次              
第二次
第三次
  特徵值組合
第一次              
第二次
第三次

但是,天秤兩邊的硬幣數量必須要一樣
又不能取到互為鏡像的特徵值
篩選出來的組合最多只能包含 12 組特徵值
最多可以區分 12 枚硬幣

           
           
硬幣代號 A B C D E F G H I J K L
第一次
第二次
第三次

硬幣擺放位置

    天秤左邊   天秤右邊   不秤
第一次   C D E K   F G H L   A B I J
第二次 B D F J E G I K A C H L
第三次 A E F L D H I J B C G K

結果對照表

結果 A重 A輕 B重 B輕 C重 C輕 D重 D輕 E重 E輕 F重 F輕
第一次
第二次
第三次
結果 G重 G輕 H重 H輕 I重 I輕 J重 J輕 K重 K輕 L重 L輕
第一次
第二次
第三次

 

相關連結:
12 枚硬幣秤重 - 公式解推導方式 (2)
39 Coins Puzzle 系統性解法
12 枚硬幣問題

Read more...

2006年12月18日 星期一

文件翻譯 - AS3 ApplicationDomain Class   [+/-]

Ticore's Blog

ActionScript 3.0 加入了類別定義域的管理功能
可以做到執行期動態加載外部類別定義(RSL)、外部模組的加載卸載...等
不像 AS 2 的 RSL 是定死的

對於開發 application 來說,是不可或缺的功能之一
這全靠 ApplocationDomain Class
以下便是文件上的翻譯


Flex 2 Live Docs - ApplicatonDomain Class

ApplicationDomain 類別的目的是用來儲存 ActionScript 3.0 類別定義,swf 檔案內所有的程式碼都定義在一個既存的 application domain 內。你可以使用 application domain 分隔在同一個 security domain 下的類別,這樣可以允許一個既存類別具有多重定義也可以讓子程式重複使用父程式的定義。

當你用 ActionScript 3.0 Loader 類別 API 讀取一個外部的 SWF 檔案時可以使用 application domains (當讀取一個圖片或是 ActionScrip 1.0、2.0 SWF 檔案時無法使用 application domain) 。當讀取 SWF 檔案時,你可以藉由設定 LoaderContext.applicationDomain 使該檔案被包含進入與 Loader 物件相同的 application domain,將 SWF 檔案放入相同的 application domain 之後,你便可以直接存取它的類別。

這是很有用處的,假如當你讀取一個包含媒體的 SWF 檔案,你可以透過關聯的類別名稱存取,或者你想要存取 SWF 檔案的方法,如下所示:

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

    public class ApplicationDomainExample extends Sprite {
        private var ldr:Loader;
        public function ApplicationDomainExample() {
            ldr = new Loader();
            var req:URLRequest = new URLRequest("Greeter.swf");
            var ldrContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
            ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
            ldr.load(req, ldrContext);    
        }
        private function completeHandler(event:Event):void {
            ApplicationDomain.currentDomain.getDefinition("Greeter");
            var myGreeter:Greeter = Greeter(event.target.content);
            var message:String = myGreeter.welcome("Tommy");
            trace(message); // Hello, Tommy
        }
    }
}

當你使用 application domain 時需要記住的事情:

  • 在一個 SWF 檔案內所有的程式存在一個 application domain。current domain 是你主要程式執行位置。system domain 包含所有的 application domain,包含 current domain,這意味它包含所有的 Flash Player 類別。
  • 所有的 application domain,除了 system domain,都有一個關聯的 parent domain。你的主要程式的 application domain 的 parent domain 便是 system domain。已讀取完的類別只有在父程式沒有該定義時才可以被定義,你不能用一個新的定義覆寫一個已讀取的類別定義。

以下的圖片表示一個應用程式從幾個不同的 SWF 檔案讀取到一個單獨的 domain, domain1.com。依據讀取的內容,使用不同的 application domain。

主應用程式是 application1.swf,包含 Loader 物件,從其它 SWF 檔案讀取內容。current domain 是 Application domain 1。使用方式 A、B、C 表示不同的技巧用來對每個 SWF 檔案設定適當的 aplication domain。

使用方式 A:藉由建立一個 system domain 的子域分隔子 SWF 檔案。

在此圖,application domain 2 是由 system domain 建立的子域。 application2.swf 被讀取進入 application domain 2,並且它的類別定義因此與 application1.swf 的類別分隔開來。

這技巧的使用方式之一便是一個舊的應用程式動態讀取一個新的相同應用程式而不會發生衝突。雖然類別名稱相同但是不會衝突,因為它們被不同的 application domain 分隔。

以下的程式建立一個 system domain 的子 application domain:

request.url = "application2.swf";
request.applicationDomain = new ApplicationDomain();

使用方式 B :加入新的類別定義到目前的類別定義中。

module1.swf 的 application domain 被設定為 current domain (application domain 1) ,這讓你在目前的應用程式的類別定義中加入一個新的類別定義,可以用於主程式的執行期共享庫,被讀取的 SWF 被當作一個遠端共享庫 (RSL)。使用此技巧可以在應用程式開始前用 preloader 讀取 RSLs。

以下的程式設定一個 application domain 到 current domain:

request.url = "module1.swf";
request.applicationDomain = ApplicationDomain.currentDomain;

使用方式 C : 藉由建立一個 current domain 的子域使用父類別的定義。

module3.swf 的 application domain 是 current domain 的子域,而子程式使用父程式的版本。這種技巧的使用方式之一可以是成為多重視窗 RIA 的模組,被讀取作為主程式的子程式,而子程式使用主程式的型別。假如你可以確認所有的類別更新總是向下相容,並且讀取程式總是比被讀取的新,子程式將會使用父程式的版本。假如後續沒有任何的參考指向子 SWF,擁有一個新的 application domain 也可以讓你移除所有的類別定義,是為垃圾收集。

以下的程式建立一個 current domain 的子 application domain:

request.url = "module3.swf";
request.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);

PS. 實際上 AS3 URLRequest 並沒有 applicationDomain 屬性
真正用來指定 ApplicationDomain 還是需要透過 LoaderContext
文件上的應該只是 Pseudo Code~

相關參考資料:
Roger Gonzalez - ApplicationDomain
Roger Gonzalez - Modular Applications (part 1)
Roger Gonzalez - Modular Applications (part 2)
Roger Gonzalez - Multi-SWF Applications
Claus Wahlers - w3blog - AS3 Loading Class Libraries at Runtime
Jesse Warden dot Kizz-om - Modular ActionScript Development
WDDJ - Working with Large Applications

Read more...

2006年12月17日 星期日

ActionScript 3.0 - Function Closure GC Bug   [+/-]

Ticore's Blog

依照文件上的定義

ActionScript 3.0 function closure 是一個物件,包含一個函式與詞彙環境的快照
函式的詞彙環境包含函式範圍鏈內所有的變數、屬性、方法、物件....

既然是一個物件,應該是可以被回收的

以下是一個測試程式

每 1 ms 執行一次函式 (已經測試過了,不用擔心電腦會當掉啦)
產生一個 function closure 物件並編上流水號
存到弱引用 (weak reference) 的 Dictionary 集合內
並且計算 Dictionary 內 key 的數量
假如 key 數量小於 4 ( 避免 trace 太多訊息出來)
列出所有的 function closure 編號

package {
 import flash.display.*;
 import flash.events.*;
 import flash.utils.*;
 import flash.system.System;
 
 public class FunctionClosure extends Sprite {
  
  public var dict:Dictionary = new Dictionary(true);
  
  public static var index:Number = 0;
  
  public static function getFun():Function{
   var fun:Function = function():void{

    trace("anonymous function");
   };
   fun.prototype.index = index++;
   return fun;
  }
  
  public function countDict():Number{
   var count:Number = 0;
   for(var i:Object in dict) {
    count++;
   }
   return count;
  }
  
  public function doTest():void{
   
   var dictCount:Number = countDict();
   if (dictCount < 4) {
    trace("count : " + dictCount + "\t  totalMemory : " + System.totalMemory);
    
    for(var i:Object in dict) {
     trace("index : " + i.prototype.index);
    }
   }
   
   var fun:Function = getFun();
   dict[fun] = null;
   
  }
  
  public function FunctionClosure() {
   
   // 決定是否用第一個 function closure 當作 Listener
   // var fun:Function = getFun();
   
   setInterval(doTest, 1);
   
  }
 }
}

測試結果可以發現到
每隔一段時間
function closure 就會被回收一次
但是編號為 0 的 function closure 一直都存在 Dictionary 集合內
始終都不會消失

這意味著『第一次產生的 function closure 無法被回收
可以算是蠻嚴重的 Bug 了吧

將 function closure 改由 package function 產生
或是改成 static function 產生
也都是一樣

該 Bug 在以下版本 Flash Player 會發生
Flash Player 9.0.16.0
Flash Player 9.0.28.0
Flash Player 9.0.45.0
Flash Player 9.0.47.0

相關資料:
ActionScript 3.0 - Function Closure
AS 2.0 關於函式範圍鏈與垃圾回收的問題
AS 2.0 將參數與 function 綁在一起
Scope Chain and Memory waste in Flash MX
FlashPlayer 9.0.60.325 改正 Function Closure GC Bug

Read more...

2006年12月16日 星期六

Flash UIComponent 與 Button 混用焦點問題   [+/-]

Ticore's Blog

Flash 7、8 內建的 UIComponent 有一個小問題
在 fla 中使用了 TextInput 或是其它的 UIComponent 之後
撥放時,使用者只要點選了 TextInput 或是 TextFiled
再按 Button Symbol
(此處指的是 Flash 三大基本元件之一的 Button,並非 UIComponent Button)
常常會出現 Button 反應不靈敏的情況

原因是因為 UI Component 內的 FocusManager
一旦使用了任一個 UI Component
FocusManager 會自動被包含進來
並且會控制所有 Focus 的動作
而 基本元件 Button Symbol 並沒有繼承 UIComponent
FocusManager 便會將 Focus 退回
造成 Button 反應不靈敏的現象

解決方式很簡單
只要將 FocusManager Disable 即可

_root.focusManager.enabled = false;

Focus 問題示範:

2009/06/14 補充:
將 FocusManager Disable 之後,Tab Focus 都失效了也很不方便
此時可以特別針對需要 enable focus 的組件或是 Button、TextFiled
另外去設置 tabIndex 屬性就可以了

相關連結:
AS2 UIComponent FocusRect 小技巧

Read more...

2006年12月15日 星期五

Flex 2 Metadata Tag 應用 - 在 swf 檔案內包入額外的 Class   [+/-]

Ticore's Blog

假如想要在 swf 編譯時,包入額外的 Class
當作 lib 使用,或是希望在執行期動態取得

一般通常會直接程式裡面建立一個無用的 function
在 statement 裡面明確引用這些 Class

像這樣

package {
 import flash.display.*
 import flash.utils.*;
 public class Main extends Sprite {
  private function foo() {
   idv.ticore.MyClass1;
   idv.ticore.MyClass2;
   idv.ticore.MyClass3;
  }
 }
}

雖然可以用,但是總覺得有點怪怪的

下面介紹一個 Flex 2 的 Metadata Tag - Frame
Frame 有一個屬性是 extraClass
可以用來指定想要包入的 Class 名稱

譬如

[Frame(extraClass="idv.ticore.MyClass1")]

這樣就算在 Main Class 內都沒有用到 MyClass1
MyClass1 一樣會被編譯到 swf 內

示範

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

 [Frame(extraClass="idv.ticore.MyClass1")]
 [Frame(extraClass="idv.ticore.MyClass2")]
 [Frame(extraClass="idv.ticore.MyClass3")]
 public class Main extends Sprite {
  public function Main() {
   
   trace(getDefinitionByName("idv.ticore.MyClass1"));
   trace(getDefinitionByName("idv.ticore.MyClass2"));
   trace(getDefinitionByName("idv.ticore.MyClass3"));
   
  }
 }
}
Read more...

2006年12月14日 星期四

指定 MovieClip 中心點作旋轉   [+/-]

Ticore's Blog

在 Flash IDE 開發工具內
是可以移動中心點並且用自由變形工具作旋轉

但是在 ActionScript 內
每一個 MovieClip 內都是一個獨立的座標系
不能直接用 AS 移動座標系的中心點作旋轉

以下是利用旋轉座標的數學公式作補償
模擬指定 MovieClip 中心點作旋轉的功能

MovieClip.prototype.rotateByCenter = function(centerX, centerY, radian) {
 var newX:Number = (Math.cos(radian) * centerX) - (Math.sin(radian) * centerY);
 var newY:Number = (Math.sin(radian) * centerX) + (Math.cos(radian) * centerY);
 this._x -= (newX - centerX);
 this._y -= (newY - centerY);
 this._rotation = radian * 180 / Math.PI;
};

// 使用方式
mc.rotateByCenter(50, 50, Math.PI / 2);
Read more...

2006年12月13日 星期三

AS3 字串資料語系編碼轉換   [+/-]

Ticore's Blog

ActionScript 3.0 新增了對 Byte Array 處理能力

flash.utils.ByteArray class 內有兩個方法

writeMultiByte(value:String, charSet:String):void
readMultiByte(length:uint, charSet:String):String

利用這兩個方法便可以做到字串資料的編碼轉換功能

以下是 ActionScript 3 分別讀取 Big5、GB2312 編碼的外部文字檔案

 

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

 public class Main extends Sprite {
  public function Main() {
   
   loadFile("big5", "big5.txt");
   loadFile("gb2312", "gb.txt");
   
  }
  
  public function loadFile(charset:String, fileName:String):void{
   
   var loader:URLLoader = new URLLoader();
   
   var completeHandler:Function =
    function completeHandler(event:Event):void{
     var ba:ByteArray = ByteArray(URLLoader(event.target).data);
     var utf8Str:String = ba.readMultiByte(ba.length, charset);
     trace(fileName + " : " + utf8Str);
    };
   
   loader.addEventListener(Event.COMPLETE, completeHandler);
   
   var request:URLRequest = new URLRequest(fileName);
   loader.dataFormat = URLLoaderDataFormat.BINARY;
   loader.load(request);
   
  }
 }
}

Flex Builder 2 輸出結果:

(Flex Builder 2 輸出結果內有一個 ? ,可能是由於 Eclipse 顯示字型的問題)

Flash Tracer 輸出結果:

Read more...

2006年12月12日 星期二

Flash Player for Firefox Plugin 本機路徑 Bug   [+/-]

Ticore's Blog

在本機硬碟上用 Firefox 瀏覽器播放含有中文路徑的 Flash Movie 時
用 NetStream.play 或是 Sound.loadSound 命令讀取外部檔案失敗
但是改用絕對路徑卻是OK

後來發現 Flash Player for Firefox Plugin 的 _url 有 Bug

以下分別用 IE、Firefox 撥放中文路徑下的 Flash Movie
測試 ActionScript _url 屬性

IE:

Firefox:

在 Firefox 上,_url 中文部分為亂碼
是編碼錯誤

ActionScript 1.0、2.0 雖然無法做到各種編碼轉換
但是利用 System.useCodepage、escape、unescape
至少可以做到 UTF-8 與 OS Default Charset 之間的轉碼

以下便是利用 AS 轉碼,修正中文路徑的問題

ActionScript Class:

class idv.ticore.as2.utils.URLFix {
 public static function encodeUtf8(s:String):String {
  var useCodepage:Boolean = System.useCodepage;
  System.useCodepage = true;
  var escapeStr:String = escape(s);
  System.useCodepage = false;
  var resultStr:String = unescape(escapeStr);
  System.useCodepage = useCodepage;
  return escapeStr;
 }
 public static function encodeOSCharset(s:String):String {
  var useCodepage:Boolean = System.useCodepage;
  System.useCodepage = false;
  var escapeStr:String = escape(s);
  System.useCodepage = true;
  System.useCodepage = useCodepage;
  return escapeStr;
 }
 public static function fixUrl(s:String):String {
  var useCodepage:Boolean = System.useCodepage;
  System.useCodepage = false;
  var result:String = unescape(encodeUtf8(s));
  System.useCodepage = useCodepage;
  return result;
 }
 public static function getFixedUrl(s:String):String {
  if (System.security.sandboxType == "remote") {
   return s;
  }
  if (System.capabilities.playerType != "PlugIn") {
   return s;
  }
  var useCodepage:Boolean = System.useCodepage;
  System.useCodepage = false;
  var url:String = fixUrl(unescape(_url));
  System.useCodepage = useCodepage;
  var urlToken:Array = url.split("/");
  urlToken.pop();
  return urlToken.join("/") + "/" + s;
 }
}

使用方式:

import idv.ticore.as2.utils.*;

var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
var video:Video;
video.attachVideo(ns);

ns.play(URLFix.getFixedUrl("video.flv"));

相關參考資料:
Flash 獨立撥放器中文路徑問題

2007/01/04 updated

經 kumas 測試,此方式只對部分中文字有效
某些中文路徑,還是會有解碼問題。
例如:c:\test\多國語言路徑
URLFix.getFixedUrl("video.flv");
回傳 c:\test\video.flv
查出在 URLFix.fixUrl(unescape(_url)); 解成亂碼。
註:測試版本 Firefox 2.0 + Flash player 9

Read more...

2006年12月11日 星期一

用 AS3 連 FMS 播放串流影片測試   [+/-]

Ticore's Blog

以下是用 ActionScript 3.0 測試與 Flash Media Server 連線
並且以 Streaming 的方式撥放影片

除了 AS 3 的寫法比較囉唆以外
要注意 ObjectEncoding 要設為 AMF0
才可以與 FMS、FCS 連線
package {
 import flash.display.*;
 import flash.net.*;
 import flash.events.*;
 import flash.media.*;

 public class FMSTest extends Sprite{
  
  public var fmsAppUrl:String = "rtmp:/simple_video";
  public var videoName:String = "video";
  
  public var nc:NetConnection;
  public var ns:NetStream;
  public var video:Video;
  
  public function FMSTest(){
   init();
  }
  
  public function init():void{
   nc = new NetConnection();
   video = new Video();
   this.addChild(video);
   
   nc.objectEncoding = ObjectEncoding.AMF0;
   
   nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
   nc.connect(fmsAppUrl);
  }
  
  public function playStreamVideo():void{
   ns = new NetStream(nc);
   ns.addEventListener(NetStatusEvent.NET_STATUS, playStatusHandler);
   ns.client = {};
   
   video.attachNetStream(ns);
   ns.play(videoName);
  }
  
  public function netStatusHandler(event:NetStatusEvent):void{
   trace(event.info.code);
   switch(event.info.code) {
    case "NetConnection.Connect.Success" :
      playStreamVideo();
      break;
   }
  }
  
  public function playStatusHandler(event:NetStatusEvent):void{
   trace(event.info.code);
  }
  
 }
}
Read more...

2006年12月9日 星期六

Flex 2.0 Metadata Tags   [+/-]

Ticore's Blog

Flex 2.0 裡面有許多的 Metadata
有些是給 AS 編譯器看的
有些是給 MXML 編譯器看的
使用者也可以自行定義 Metadata

官方文件內只有說明一部分的 Metadata Tag
還有很多不知道其功能為何

以下是粗略的整理,包含 Metadata Tag 名稱與幾個簡單的例子

文件上有記載的

http://livedocs.macromedia.com/flex/2/docs/00001651.html

 [ArrayElementType]
  [ArrayElementType("mx.states.Transition")]
  [ArrayElementType("mx.states.State")]
 
 [Bindable]
  [Bindable("errorStringChanged")]
  [Bindable("toolTipChanged")]
  [Bindable("currentStateChange")]
  [Bindable("verticalScrollPolicyChanged")]
 
 [DefaultProperty]
  [DefaultProperty("dataProvider")]
  [DefaultProperty("children")]
 
 [Effect]
  [Effect(name="hideDataEffect", event="hideData")]
  [Effect(name="moveEffect", event="move")]

 [Embed]
  [Embed(source="Beep.mp3")]
 
 [Event]
  [Event(name="itemClick", type="mx.charts.events.LegendMouseEvent")]
  [Event(name="hide", type="mx.events.FlexEvent")]
 
 [IconFile]
  [IconFile("Repeater.png")]
  [IconFile("AreaChart.png")]
 
 [Inspectable]
  [Inspectable(defaultValue="true")]
  [Inspectable(environment="none")]
  [Inspectable(category="Data")]
  [Inspectable(category="General", enumeration="overlaid,stacked,100%", defaultValue="overlaid")]

 
 [InstanceType]
  [InstanceType("mx.controls.Label")]
  public var topRow:IDeferredInstance;
 
 [NonCommittingChangeEvent]
  [NonCommittingChangeEvent("change")]
 
 [Style]
  [Style(name="axisStroke", type="mx.graphics.IStroke", inherit="no")]
  [Style(name="fontWeight", type="String", enumeration="normal,bold", inherit="yes")]
  [Style(name="barWidthRatio", type="Number", inherit="no")]


文件上沒記載的
 [SWF]
  [SWF(width="300", height="200", frameRate="18", backgroundColor="#FFFFFF")]
 
 [RemoteClass]
  [RemoteClass(alias="flex.messaging.io.ArrayCollection")]
  [RemoteClass(alias="flex.messaging.io.ArrayList")]
 
 [Frame]
  [Frame(factoryClass="mx.managers.SystemManager")]
  [Frame(factoryClass="mx.core.FlexApplicationBootstrap")]

  [Frame(extraClass="Obj")]
 


 [ExcludeClass]
 
 [DefaultBindingProperty]
  [DefaultBindingProperty(destination="dataProvider")]
 
 [DefaultTriggerEvent]
  [DefaultTriggerEvent("itemClick")]
  [DefaultTriggerEvent("scroll")]

 [Exclude]
  [Exclude(name="defaultButton", kind="property")]
  [Exclude(name="horizontalScrollPolicy", kind="property")]
  [Exclude(name="icon", kind="property")]
  [Exclude(name="label", kind="property")]
  [Exclude(name="tileHeight", kind="property")]

 [ResourceBundle]
  [ResourceBundle("validators")]
  [ResourceBundle("SharedResources")]
  [ResourceBundle("foo")]

 [PercentProxy]
  [PercentProxy("percentHeight")]

 [RequiresDataBinding]
  [RequiresDataBinding(true)]
 
 [CollapseWhiteSpace]

 [MaxChildren]
  [MaxChildren(0)]

 [AccessibilityClass]
  [AccessibilityClass(implementation="mx.accessibility.PanelAccImpl")]
  [AccessibilityClass(implementation="mx.accessibility.TitleWindowAccImpl")]


 [Transient]
Read more...

2006年12月8日 星期五

Flash 8 半透明輸入、動態文字欄位   [+/-]

Ticore's Blog

Flash 8 以前,假如要做半透輸入文字欄位
必須要嵌入字型

但是中文字型隨便都好幾 mb
會讓 swf 檔案大小暴增
這樣便不適合在網路上使用

拜 Flash 8 新增的功能所賜 - 點陣圖快取、濾鏡、混合模式...
已經不需要嵌入字型
就可以做到半透明輸入、動態文字欄位

方式很多種
原理都是讓 Flash Player 底層將文字欄位預先以點陣圖方式處理過
這樣就可以套用 alpha 屬性了

當然你也可以自己用 ActionScript 將文字欄位做點陣圖處理
不過比較麻煩一點

強迫 Flash Player 預先以點陣圖渲染的方式:

  1. 使用混合模式 (Blend Mode)
  2. 使用點陣圖快取 (MovieClip.cacheAsBitmap)
  3. 套用濾鏡

以下是用 AS 動態建立輸入文字欄位
利用濾鏡強迫輸入文字欄位預先以點陣圖渲染
再對文字欄位設定 _alpha 屬性達到半透明的效果

var txt:TextField = this.createTextField("txt", 100, 0, 0, 160, 160);
txt.type = "INPUT";
txt.border = true;
txt.multiline = true;
txt.wordWrap = true;
var tf:TextFormat = new TextFormat();
tf.size = 24;
tf.bold = true;
txt.setNewTextFormat(tf);
//
import flash.filters.*;
var bf:DropShadowFilter = new DropShadowFilter(1, 45, 1, 1);
var txtFilters:Array = txt.filters;
txtFilters.push(bf);
txt.filters = txtFilters;
//
txt._alpha = 50;

另外一種方式比較簡單

直接將文字欄位包覆一層 MovieClip
對外層 MovieClip 設定混合模式為 "layer",以及 alpha 值即可

 

示範

相關連結:
Flex Label, TextField 半透明小技巧

Read more...

2006年12月7日 星期四

Flex 2.0 - List 透明背景 + Alpha Image   [+/-]

Ticore's Blog

有人問到怎樣用 Flex List 作透明背景
但是又要在 List 背景嵌入 alpha channel image
原本也是想到用 backgroundAlpha 來作
不過這樣背景圖也會受到影響

最後終於找到 List 背景
原來是在 Super Class - ScrollControlBase
用 RectangularBorder 實現
只要 backgroundColor、borderStyle 為 null
ScrollControlBase 便不會 draw 向量背景

直接在 List MXML 屬性 backgroundColor、borderStyle 設為 null
並沒有效果,MXML Compiler 會自動轉換為非 null 值
只得用 ActionScript 強制設為 null

以下是效果擷圖與 MXML 程式碼:

Read more...

Flash 8 另一種 Alpha Mask 設置方法   [+/-]

Ticore's Blog

Flash 8 支援 alpha mask

有兩種設定方式

第一種是遮罩物(masker)與被遮罩物(maskee)都設為點陣圖快取
然後用遮罩圖層或是用 ActionScript setMask 命令即可

第二種方式是利用混合模式(blend mode)來作

先將遮罩物與被遮罩物包成一個 MovieClip
遮罩物混合模式設成 "alpha"
外層 MovieClip 混合模式設成 "layer" 即可
(或是將外層 MovieClip 設為點陣圖快取)

└MovieClip (blendMode = "layer")
 ├Masker (blendMode = "alpha")
 └Maskee

或是

└MovieClip (cacheAsBitmap = true)
 ├Masker (blendMode = "alpha")
 └Maskee

第二種的好處是可以在 Flash 工作區域上直接看到 alpha mask 呈現效果

 

Flash 8 LiveDoc - Blend Mode

2 ways to set alpha mask
Read more...

2006年12月6日 星期三

ActionScript 3.0 - Function Closure   [+/-]

Ticore's Blog

ActionScript 3.0 function closure 行為有很大的改變
如文件上所述

function closures A function closure is an object that contains a snapshot of a function and its lexical environment. A function's lexical environment includes all the variables, properties, methods, and objects in the function's scope chain, along with their values. Function closures are created any time a function is executed apart from an object or a class. The fact that function closures retain the scope in which they were defined creates interesting results when a function is passed as an argument or a return value into a different scope.
http://livedocs.macromedia.com/flex/2/docs/00001836.html

一個 function closure 是一個物件,包含一個函式與詞彙環境的快照,
函式的詞彙環境包含函式範圍鏈內所有的變數、屬性、方法、物件....

 

以下是一個測試程式

每 100 ms 執行一次函式
產生一個 function closure 物件,存到陣列內
同時在 function closure scope 產生 BitmapData
而 function closure 並沒有任何參考指向 BitmapData 物件

當然,也可以使用我之前提出利用 NetConnection 活動來測試記憶體回收

 

package {
 import flash.display.*;
 import flash.events.*;
 import flash.utils.*;
 import flash.system.System;
 
 public class AS3Test extends Sprite {
  
  public var ary:Array = [];
  
  public function getFun():Function{
   var bitmap:BitmapData = new BitmapData(100, 100);
   trace(System.totalMemory);
   return function():void{
    trace("this : " + this);
   };
  }
  
  public function doTest():void{
   ary.push(getFun());
  }
  
  public function AS3Test() {
   setInterval(doTest, 100);
  }
 }
}

測試結果可以發現到
記憶體使用量隨時間暴增,絲毫沒有回收的跡象

即便 function closure 沒有明確引用範圍鏈內其它的物件
該物件仍然無法被回收
ActionScript 2.0 的行為有很大的差異
這應該是 function closure scope 完整快照功能造成的結果

假如從 Scope Chain and Memory waste in Flash MX 的觀點來看
這是很嚴重的記憶體浪費!?

其實不一定
完整快照功能,可以賦予 function closure 更大的彈性與功能
只是相對的開發者也要注意 function closure 使用時機

 

相關資料:

ActionScript 3.0 - Function Closure GC Bug

AS 2.0 關於函式範圍鏈與垃圾回收的問題

AS 2.0 將參數與 function 綁在一起

Scope Chain and Memory waste in Flash MX

Read more...

2006年12月5日 星期二

新版 Firebug 1.0 beta   [+/-]

Ticore's Blog

Firebug 1.0 beta 公開了
新增好多功能

介面更美觀
動態調校 CSS、HTML
CSS 尺規顯示輔助
網路活動監看
Dom 檢視
JavaScript 除錯
......

趕快去下載來測試吧
Read more...

2006年12月4日 星期一

重複引用 SWFObject JavaScript 衝突   [+/-]

Ticore's Blog

最近在使用 SWFObject 的時候
遇到個一個問題
IE 瀏覽器出現『記憶體不足、堆疊錯誤』的警告

仔細探究

原來是因為在一個 HTML 頁面內重複引用 swfobject.js 達三次以上
SWFObject 1.4.2 ~ 1.4.4 內均會覆寫 window.onBeforeUnload 事件
並且將舊的事件指定給 oldBeforeUnload 變數
用意是在關閉視窗、跳頁的時候用來清除資料

重複引用 SWFObject 的結果
造成 oldBeforeUnload 變數名稱衝突
window.onBeforeUnload 事件無窮遞迴執行

雖然說對同一個 js file 重複引用是不良的習慣
可是有些情況卻難以避免
尤其像是 SWFObject,幾乎是只要有 Flash 就會用到的東西

類似的事情也有可能發生在不同 javascript 來源
解決方式便是要避免變數名稱衝突
譬如,用 function scope 暫存變數:

function wrapFunctionCall(innerExecute){
 return function(){
  alert("innerExecute();");
  innerExecute != null ? innerExecute() : null;
 };
}
window.onbeforeunload = wrapFunctionCall(window.onbeforeunload);

或者用 anonymous function 虛擬 block scope

(function(){
 var oldOnbeforeunload = window.onbeforeunload;
 window.onbeforeunload = function(){
  oldOnbeforeunload != null ? oldOnbeforeunload() : null;
 }
})();

相關參考資料

SWFObject
UserJS.org - Avoiding User JavaScript conflicts
AS 2.0 將參數與 function 綁在一起
利用function scope 暫存變數
Scope Chain and Memory waste in Flash MX

2007.02.28 更新

SWFObject 1.5 已經修正此問題
不過又發現其它的問題
swfobject.js 與 json.js 同時使用
由於 json.js 替 Object 加入 prototype function
造成 swfobject.js 輸出錯誤的 Flash HTML 標籤
連那些 prototype function 都跑出來了~

Read more...

2006年12月3日 星期日

AS 2.0 移除 Mouse、Key... Listener 小技巧   [+/-]

Ticore's Blog

有用過 Mouse、Key 類別的事件的人
可能會到一個問題
加入 Mouse 事件的 Listener 物件移除不乾淨
結果裡面的函式跑不停,甚至多跑了好幾次

像這樣
var lisObj:Object = {};
lisObj.onMouseDown = function() {
 trace("onMouseDown");
};
Mouse.addListener(lisObj);
delete lisObj;
遺失 lisObj 物件參考
再也無法自 Mouse 移除事件了

下面介紹一個小技巧
可以讓你確實移除事件
var lisObj:Object = {};
lisObj.onMouseDown = function() {
 trace("onMouseDown");
};
Mouse.addListener(lisObj);
delete lisObj;
//
ASSetPropFlags(Mouse, null, 0, 7);
Mouse["_listeners"] = [];
看到了吧
重點是後面那兩行

Mouse 本身會用一個陣列去紀錄 Listener 物件
該陣列是 private 屬性
正常情況下,是無法存取的

ActionScript 2.0 語言沒有那麼嚴謹
所以才可以用上述的方式偷改

以後到了 ActionScript 3.0 可就不能這樣做了
最好還是養成良好習慣為妙~~

除了 Mouse 以外
還有好幾個 Class 都可以這樣用

Mouse、Key、Stage、Selection、TextField、MovieClipLoader、System.IME、FileReference、AsBroadcaster...等都可以喔
Read more...

2006年12月2日 星期六

Flex 2.0 - 以 ActionScript 3.0 動態設置 Data Binding   [+/-]

Ticore's Blog

Flex 有一個很好用的 DataBinding 的功能
只要在 MXML 中使用大括號以點語法指定來源資料

像這樣

<mx:textinput id="txt1">
<mx:textinput text="{txt1.text}" id="txt2" /></mx:textinput>

即可輕鬆建立資料繫結

其它可以參考官方文件 Flex 2 - Binding Data

若想要用動態建立 Data Binding,或是動態改變繫結屬性
文件上卻沒有詳細相關資料

在 Flex 2.0 Language Reference 裡面
有兩個 Class 與 Data Binding 有關

mx.binding.utils.BindingUtils
mx.binding.utils.ChangeWatcher

不過沒有使用範例

以下示範使用這兩個 Class 動態建立 Data Binding

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="init();">
 <mx:Script>
  <![CDATA[

    import mx.binding.utils.*;
    public var watcher:ChangeWatcher;
    public function init():void{
      watcher = BindingUtils.bindProperty(txt2, "text", txt1, ["text"], true);
    }

  ]]>
 </mx:Script>
 <mx:TextInput id="txt1" />
 <mx:TextInput id="txt2" />
 <mx:TextInput id="txt3" />
</mx:Application>

這樣就可以建立單向 txt1.text 到 txt2.text 的 Data Binding

其它相關的操作方式

※停止資料繫結

watcher.unwatch();

※繫結到其它物件

watcher.reset(txt3);

※更改目標物件

watcher.setHandler(
 function(event:*):void{
  txt3["text"] = watcher.getValue();
 }
);

相關連結:
Flex 4 Gumbo 雙向資料繫結測試
Flex 技巧 - 將資料綁定封裝起來
Flex - 純手工設定 DataBinding 的方式
Flex 技巧 - BindingManager 使用方式
Flex 技巧 - 觀察 Data Binding 資料變化
Flex Tip - 在 Data Binding 內使用 [...] 運算子
Flex 2 Bindable Metadata Tag 背後實際作用

Read more...

2006年12月1日 星期五

利用 window.prompt 解決 Flash 透明模式下無法輸入中文的問題   [+/-]

Ticore's Blog

由於 Flash 在瀏覽器中以透明模式執行時 (wmode="transparent")
輸入文字欄位,以中文或是其它需要選字的輸入法打字會有問題

MasoBlog - 文字框中文輸入問題
Firefox wmode=transparent is completely screwy and breaks textfields

於是想到利用 ExternalInerface 與 JavaScript window.prompt 來解決
雖然會變的比較不 User Friendly
但是起碼可以用~~

Flash ActionScript:

import flash.external.*;

// 將 js function 宣告出去
ExternalInterface.call("eval",
    "function getInput(hint){return window.prompt(hint, '');}");

// 利用 ExternalInterface 呼叫 JS function,並取得 User 輸入文字
function doInput() {
 inputTxt.text = ExternalInterface.call("getInput", "請輸入文字");
}

示範:

下載檔案

相關連結:
Flash 技巧 - 利用 ExternalInterface 完全暫停 Flash Movie 程序

Read more...