2007年11月30日 星期五

Flex Label, TextField 半透明小技巧   [+/-]

Ticore's Blog

在 Flex 內,預設是沒有嵌入字體的
所以假如想要對組件設定 alpha 半透明
就會發現到組件內 Label, TextField 無法表現半透明效果
如下所示:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 layout="horizontal" verticalAlign="middle">
 <mx:Fade id="fadeOut" duration="500" alphaFrom="1" alphaTo="0.2" />
 <mx:Fade id="fadeIn" duration="500" alphaFrom="0.2" alphaTo="1" />
 <mx:Button label="Tween Alpha Button" alpha="0.2"
  rollOverEffect="{fadeIn}" rollOutEffect="{fadeOut}" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

這時候只要利用 AS3 DisplayObject 的混合模式
將 BlendMode 設為 "layer" 就可以對 Label, TextField 作 alpha 效果了

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 layout="horizontal" verticalAlign="middle">
 <mx:Fade id="fadeOut" duration="500" alphaFrom="1" alphaTo="0.2" />
 <mx:Fade id="fadeIn" duration="500" alphaFrom="0.2" alphaTo="1" />
 <mx:Button label="Tween Alpha Button" alpha="0.2"
  blendMode="{flash.display.BlendMode.LAYER}"
  rollOverEffect="{fadeIn}" rollOutEffect="{fadeOut}" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

相關連結:
Flash 8 半透明輸入、動態文字欄位
Flex TextField Render Bug

Read more...

2007年11月29日 星期四

Linux Flash Player Bugs   [+/-]

Ticore's Blog

最近遇到一堆 Linux 版本上的 Flash Player Bug
常常莫名其妙 Crash,無從找起....
另外有一些 Bug 則是可以被釐清的:

  1. fscommand 後面的 AS3 程式會被忽略掉
  2. 利用組合鍵 [Ctrl] 加上 [A] or [X] or [C] or [V] 觸發的事件中
    會得到錯誤的 keyCode 4294967295 與 charCode 0
  3. Menu Key 的 keyCode, charCode 錯誤,變成與 [G] 鍵一樣 (2009.02.26)

Linux flash player bug demo code:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
 <mx:Script>
  <![CDATA[
  import flash.events.*;
  import flash.system.Capabilities;
  import flash.system.fscommand;
  
  protected function onKeySelectAllHandler(evtObj:KeyboardEvent):void{
   txt.text += "keyCode : " + evtObj.keyCode +
    ", charCode : " + evtObj.charCode + ", ctrlKey : " + evtObj.ctrlKey + "\n";
  }
  ]]>
 </mx:Script>
 <mx:creationComplete>
  <![CDATA[
   txt.text += "Version : " + Capabilities.version + "\n";
   addEventListener(KeyboardEvent.KEY_DOWN, onKeySelectAllHandler);
   txt.text += "begin AS3 fscommand.\n";
   fscommand("trapallkeys", "true");
   txt.text += "end AS3 fscommand.\n";
  ]]>
 </mx:creationComplete>
 <mx:Button label="Button" />
 <mx:TextArea id="txt" width="100%" height="100%" selectable="false" editable="false" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

上述程式拿到 Linux 測試擷圖

Keycode Bug 測試網頁
http://riafiles.googlepages.com/KeycodeBug.html

以上第 2. 3. 點 Bug 會在以下版本的 Linux Flash Player 發生
Flash Player 9.0.31.0
Flash Player 9.0.48.0
Flash Player 9.0.60.184
Flash Player 9.0.64.0
Flash Player 9.0.115.0
Flash Player 10.0.0.569
Flash Player 10.0.12.36
Flash Player 10.0.22.87

第 1. 點 fscommand Bug 似乎已經 Flash Player 10.0.0.569 左右版本修正了

Read more...

2007年11月28日 星期三

Flex ListBase selectedItems, selectedIndices 陷阱   [+/-]

Ticore's Blog

最近使用 Flex ListBase 系列組件做全選時,遇到奇怪的 Bug
後來才發現是由於 ListBase.selectedItems, selectedIndices 的陷阱

譬如以下的程式利用 ListBase.selectedItems 做全選功能

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
 <mx:Script>
  <![CDATA[
   [Bindable]
   public var dataAry:Array =
    [{label: "Item 01"},{label: "Item 02"},{label: "Item 03"},{label: "Item 04"}];
    
   public function selectAll():void{
    list1.selectedItems = dataAry;
    trace(list1.selectedIndices);
   }
  ]]>
 </mx:Script>
 <mx:List id="list1" width="100" height="100%" dataProvider="{dataAry}" />
 <mx:Button label="Select All" click="selectAll();"/>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

實際測試就會發現,非但無法做全選
List 資料還會發生錯亂
點一下,List Items 就消失一半

另一種陷阱是利用 ListBase.selectedIndices 作選擇
以下程式產生 Indices 陣列,同時指定給多個相同資料來源的 List 做全選功能

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
 <mx:Script>
  <![CDATA[
   [Bindable]
   public var dataAry:Array =
    [{label: "Item 01"},{label: "Item 02"},{label: "Item 03"},{label: "Item 04"}];
    
   public function selectAll():void{
    var indices:Array = [];
    for (var i:Number = 0 ; i < dataAry.length ; ++i) {
     indices.push(i);
    }
    list1.selectedIndices = indices;
    list2.selectedIndices = indices;
    list3.selectedIndices = indices;
   }
  ]]>
 </mx:Script>
 <mx:List id="list1" width="100" height="100%" dataProvider="{dataAry}" />
 <mx:List id="list2" width="100" height="100%" dataProvider="{dataAry}" />
 <mx:List id="list3" width="100" height="100%" dataProvider="{dataAry}" />
 <mx:Button label="Select All" click="selectAll();"/>
</mx:Application>

實際測試就會發現,只有第一個 List 可以正確作選擇
如下圖所示:

由於指定陣列資料給 ListBase.selectedItems, selectedIndices 時
ListBase 本身並不會另外複製一份陣列
造成程式多處同時修改或是排序陣列資料
List 組件錯亂

所以正確的做法應該是每次都要產生新的陣列指定給 selectedItems, selectedIndices
嫌麻煩的話,也可以從已經指定好資料的 List 組件取得 selectedItems, selectedIndices
再指定給下一個 List
因為 get selectedItems, selectedIndices 是會得到一份 clone

正確的 selectedIndices 使用方式:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
 <mx:Script>
  <![CDATA[
   [Bindable]
   public var dataAry:Array =
    [{label: "Item 01"},{label: "Item 02"},{label: "Item 03"},{label: "Item 04"}];
    
   public function selectAll():void{
    var indices:Array = [];
    for (var i:Number = 0 ; i < dataAry.length ; ++i) {
     indices.push(i);
    }
    list1.selectedIndices = indices;
    list2.selectedIndices = list1.selectedIndices;
    list3.selectedIndices = list2.selectedIndices;
   }
  ]]>
 </mx:Script>
 <mx:List id="list1" width="100" height="100%" dataProvider="{dataAry}" />
 <mx:List id="list2" width="100" height="100%" dataProvider="{dataAry}" />
 <mx:List id="list3" width="100" height="100%" dataProvider="{dataAry}" />
 <mx:Button label="Select All" click="selectAll();"/>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

相關連結:
Flex ListBase selectedIndices, selectedItems Bug

Read more...

AS3 - delete descendent property 陷阱   [+/-]

Ticore's Blog

一般情況下,可以使用 delete 刪除 XML 物件的 child nodes or attributes
像這樣:

var xml:XML =
 <xml>
  <node />
  <node>
   <node />
  </node>
 </xml>;
trace(delete xml.node); // true
trace(xml.toXMLString()); // <xml/>

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

或是

var xml:XML =
 <xml>
  <node />
  <node>
   <node />
  </node>
 </xml>;
trace(delete xml.*); // true
trace(xml.toXMLString()); // <xml/>

但是假如遇到 delete descendent child node
雖然一樣得到 true
但是 child node 卻沒有被刪除

var xml:XML =
 <xml>
  <node />
  <node>
   <node />
  </node>
 </xml>;
trace(delete xml..*); // true
trace(xml.toXMLString());
/*
<xml>
  <node/>
  </node>
    <node/>
  </node>
</xml>
*/

原因可能是因為 "xxx.*" 屬於物件的 property
而 "xxx..*" 只能算是呼叫物件 descendent function 捷徑
故無法刪除

假如將 trace(delete xml..*); 這行程式反編譯來看
結果更妙
只剩下 trace(true); 而已

pcode:

@11     pushtrue 
@12     callpropvoid trace, 1 args
@13     findpropstrict trace

表示 AS3 編譯器直接把 delete descendent property 動作忽略掉了

Read more...

2007年11月27日 星期二

網聚主題:機器人+AS3+Silverlight   [+/-]

Ticore's Blog

網聚主題:機器人+AS3+Silverlight

議程順序:
1.把玩 LEGO 互動機器人------------------by 林修禾
2.從 AS2 到 AS3.0 的美麗與哀愁 ----------by 林新德
3.閃亮亮的 Silverlight 結構與開發流程 ---by 迷克斯
4.交流與討論

重點:
年終超歡樂摸彩
Microsoft Expression Studio正式版(Microsoft 贊助提供)
名額1名,價值 599 美金

來就送:
1.Adobe 官方紀念品
2.Silverlight:ASP.NET與AJAX開發實務-悅知文化(Microsoft 贊助提供)

時間地點:
場地費用:NT.300元(當日現場繳交)
時間:2007年12月9日(日) 下午1:30~5:30
地點:恆逸資訊訓練教育中心 龐畢度國際會議中心
地址:台北市復興北路99號2樓

>>報名由此去(需先註冊論壇會員帳號)
Read more...

2007年11月24日 星期六

在 Flex 中使用 AS3 DisplayObject 方式   [+/-]

Ticore's Blog

Flex 所有組件的容器類別 UIComponent
將 addChild、addChildAt.... 覆寫過
以致於無法任意在 Flex Container 內直接加入非 IUIComponent 的 AS3 DisplayObject
像是 MovieClip、TextField.....
有些情況下,就不太方便

當然,可以透過繼承 Flex Component 的方式來直接使用 AS3 DisplayObject
不過同時也必須要自行管理 UIComponent 一堆與尺寸有關的屬性
否則無法被正確縮放與排列

其實 Flex Builder 3 有附帶一個 Flex Component Kit for Flash CS3
Flex Builder 3 plugin 的位置預設是在

C:\Program Files\Adobe\Flex Builder 3 Plug-in\
 sdks\3.0.0\frameworks\flash-integration\FlexComponentKit.mxp

該 Extension 內有兩個主要 Class
mx.flash.UIMovieClip、mx.flash.FlexContentHolder
原本是用來讓 Flash CS3 開發 Flex Controls、Container、Skins 等資源用的

由於 UIMovieClip 實做了IUIComponent
可以被加入 Flex Container 中,並且正確的被縮放排列
其本身又可以加入非 IUIComponent 的 DisplayObject Child
正好可以作為 Flex Container 與 AS3 DisplayObject 門戶

至於怎樣將 UIMovieClip 拿到 Flex 內
請參考
Flex 3 Developer's Guide Adobe® Flex™ 3
Chapter 34: Importing Flash CS3 Assets into Flex

以下是在 Flex 內,利用 UIMovieClip 加入 AS3 TextField 程式範例

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 layout="horizontal" horizontalAlign="center" verticalAlign="middle">
 <mx:initialize>
  <![CDATA[
   uiMovieClip.addChild(textField);
  ]]>
 </mx:initialize>
 <txt:TextField id="textField" xmlns:txt="flash.text.*"
  multiline="true" border="true" type="{TextFieldType.INPUT}"
  width="200" height="100" text="ActionScript 3.0 TextField" >
 </txt:TextField>
 <comp:UIMovieClip id="uiMovieClip" xmlns:comp="mx.flash.*" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->
Read more...

2007年11月22日 星期四

Flex MXML Inline 程式小技巧   [+/-]

Ticore's Blog

Flex MXML 的 inline 程式撰寫起來相當方便
不過當程式中遇到 "&"、"<" 等會與 XML 語法混淆的字元
Flex 編譯器就會出現錯誤訊息

The entity name must immediately follow the '&' in the entity reference.

解決方式很簡單,使用 HTML Entity 取代這些特殊字元就好
就像這樣:

<?xml version="1.0" encoding="utf-8"?>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  layout="vertical">
 <mx:CheckBox id="chk1" label="CheckBox 1" />
 <mx:CheckBox id="chk2" label="CheckBox 2" />
 <mx:Button label="Submit"
  enabled="{chk1.selected &amp;&amp; chk2.selected}" />
</mx:Application>

在 MXML 中使用斷行的方式

<?xml version="1.0" encoding="utf-8"?>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:TextArea text="Line 1&#10;Line 2" />
</mx:Application>
Read more...

2007年11月11日 星期日

Flex Builder 開發小技巧   [+/-]

Ticore's Blog

以下是個人使用 Flex Builder 開發時發現的小技巧
應該可以有效縮短反覆除錯測試的時間

  • 技巧 1. 加入 Flex Project 編譯參數 -compiler.debug=false

    由於新版 Flex Builder 預設不再同時生成 Release、Debug 版本的 SWF
    只有 Debug 版本 SWF
    而SWF Debug 版本在測試的時候,遇到 Flash Player Debug 就會跳出除錯連線對話方塊
    非常煩人!
    另外,Debug 版本的 SWF 還會多出 1/2 ~ 1/4 左右的容量
    執行效能也比較差

    只要加入 -compiler.debug=false 編譯參數
    就可以讓 Flex Builder 預設產生非 Debug 版本的 SWF
    此時只要配合 Flash Player Debug、Flash Tracer,trace 訊息一樣會被紀錄下來
    一般情況下,我認為這樣除錯功能已經足夠

  • 技巧 2. 不要使用 Flex Builder > Run 執行 Flex Application

    Flex Builder > Run 執行需要做額外選擇動作
    執行起來還會檢查一大堆東西,導致時間延遲
    假如不小心選到不想要編譯的 Flex App.
    還會再花更多時間進行無謂的編譯動作...
    假如又不小心改到 MXML 沒存檔,Run Flex 還會跳出對話方塊強迫選擇...
    這樣搞下來,等到 Flex App. 開始執行,已經過了好幾秒....Orz
    非常不好用!

    其實只要打開 Flex Project \ bin 目錄
    找到欲執行的 SWF of html,滑鼠左鍵雙擊執行是最快、最直覺的
    缺點是需要自行判定 SWF 是否已經編譯完成
    不過這應該是非常簡單的事情

PS. Flash Player 9.0.115.0 Debug 版本預設不會再跳出除錯連線的對話方塊了

Read more...

2007年11月10日 星期六

AS3 DisplayObjectProxy 改版   [+/-]

Ticore's Blog

DisplayObjectProxy 改版
主要是增加利用 Wildcard 取得或是刪除全部 Child 功能
目標物為 null 情況處理
DisplayObjectProxy 加入對 DisplayObjectProxy 處理

AS3 DisplayObjectProxy Class:

/*//

AS3 DisplayObjectProxy Class, version 0.0.2
(c) 2007 Shih, Wei-Lung <weilung_shih@hotmail.com>

AS3 DisplayObjectProxy Class is freely distributable
  under the terms of an GNU license.
For details, see the Prototype web site: http://ticore.blogspot.com/

//*/
package {

 import flash.display.*;
 import flash.utils.*;

 public dynamic class DisplayObjectProxy extends Proxy {
  
  protected var _target_:DisplayObject;
  protected var _keys_:Array;
  protected var _values_:Array;
  
  protected var _targetContainer_:DisplayObjectContainer;
  
  public function DisplayObjectProxy(target:DisplayObject):*{
   this._target_ = target;
   this._targetContainer_ = _target_ as DisplayObjectContainer;
  }
  
  flash_proxy override function hasProperty(propName:*):Boolean {
   //trace("hasProperty : " + propName);
   if (_target_ == null) {
    return false;
   }
   return propName in _target_;
  }
  
  flash_proxy override function getProperty(propName:*):* {
   //trace("getProperty : " + propName);
   
   if (_target_ == null) {
    return null;
   }
   
   // Taget is DisplayObjectContainer
   if (_targetContainer_ != null) {
    
    if (propName == "*") {
     var children:Array = new Array();
     for (var i:Number = 0 ; i < _targetContainer_.numChildren ; ++i) {
      children.push(new DisplayObjectProxy(_targetContainer_.getChildAt(i)));
     }
     return children;
    }
    
    var no:Number = parseInt(propName);
    var isUint:Boolean = (no as uint) == no;
    var child:DisplayObject = null;
    if (isUint) {
     if (_targetContainer_.numChildren > no) {
      child = _targetContainer_.getChildAt(no);
     }
     //trace("child : " + child);
     if (child != null) {
      return new DisplayObjectProxy(child);
     } else {
      return null;
     }
    }
    
    //trace("_targetContainer_ : " + _targetContainer_);
    child = _targetContainer_.getChildByName(propName);
    //trace("child : " + child);
    if (child != null) {
     return new DisplayObjectProxy(child);
    }
   }
   
   // Taget is DisplayObject
   var prop:* = _target_[propName];
   if (prop is DisplayObject) {
    return new DisplayObjectProxy(prop);
   } else {
    return prop;
   }
   
  }
  
  
  flash_proxy override function setProperty(propName:*, valueObj:*):void {
   //trace("setProperty : " + propName, valueObj, describeType(valueObj).@name);
   
   if (_target_ == null) {
    return;
   }
   
   // Taget is DisplayObjectContainer
   if (_targetContainer_ != null) {
    var no:Number = parseInt(propName);
    var isUint:Boolean = (no as uint) == no;
    if (valueObj is DisplayObject || valueObj is DisplayObjectProxy) {
     if (isUint) {
      if(_targetContainer_.numChildren > no) {
       _targetContainer_.removeChildAt(no);
      }
      _targetContainer_.addChildAt(valueObj.valueOf(), no);
     }
    }
    if (valueObj == null) {
     if (isUint) {
      if(_targetContainer_.numChildren > no) {
       _targetContainer_.removeChildAt(no);
      }
     }
    }
   }
   
   // Taget is DisplayObject
   if (_target_.hasOwnProperty(propName)) {
    _target_[propName] = valueObj;
    return;
   }
   
  }
  
  flash_proxy override function deleteProperty(propName:*):Boolean {
   //trace("deleteProperty : " + propName);
   
   if (_target_ == null) {
    return false;
   }
   
   // Taget is DisplayObjectContainer
   if (_targetContainer_ != null) {
    if (propName == "*") {
     while (_targetContainer_.numChildren > 0) {
      _targetContainer_.removeChildAt(0);
     }
    }
    
    var no:Number = parseInt(propName);
    var isUint:Boolean = (no as uint) == no;
    if (isUint) {
     if(_targetContainer_.numChildren > no) {
      _targetContainer_.removeChildAt(no);
      return true;
     }
    }
   }
   
   // Taget is DisplayObject
   return delete _target_[propName];
  }
  
  
  flash_proxy override function callProperty(propName:*, ... rest:Array):* {
   //trace("callProperty : " + propName);
   if (_target_ == null) {
    return null;
   }
   return _target_[propName].apply(_target_, rest);
  }
  
  override flash_proxy function nextNameIndex (index:int):int {
   //trace("nextNameIndex : " + index);
   if (_target_ == null) {
    return 0;
   }
   if (index == 0) {
    _keys_ = new Array();
    _values_ = new Array();
    if (_targetContainer_ != null) {
     var o:DisplayObject;
     for (var i:Number = 0 ; i < _targetContainer_.numChildren ; ++i) {
      o = _targetContainer_.getChildAt(i);
      _keys_.push(o.name);
      _values_.push(o);
     }
    }
   }
   if (index < _keys_.length) {
    return index + 1;
   } else {
    return 0;
   }
  }
  
  override flash_proxy function nextName(index:int):String {
   //trace("nextName : " + index);
   if (_target_ == null) {
    return null;
   }
   return _keys_[index - 1];
  }
  
  override flash_proxy function nextValue(index:int):* {
   //trace("nextValue : " + index);
   if (_target_ == null) {
    return null;
   }
   return _values_[index - 1];
  }
  
 }
}

DisplayObjectProxy Class 使用範例:

package {
 
 import flash.display.*;
 import flash.utils.*;
 import flash.text.*;
 
 public dynamic class main extends MovieClip {
  
  public function main():*{
   test();
  }
  
  public function test():*{
   
   
   // 將 Main 包覆為 DisplayObjectProxy
   var mainProxy:* = new DisplayObjectProxy(this);
   
   // 用 DisplayObjectProxy 加入四個 Child MovieClip
   mainProxy[0] = new MovieClip();
   mainProxy[1] = new MovieClip();
   mainProxy[2] = new MovieClip();
   mainProxy[3] = new MovieClip();
   
   
   trace(this.numChildren); // 4
   
   // 用 DisplayObjectProxy 指定四個 Child MovieClip Name
   mainProxy[0].name = "mc1";
   mainProxy[1].name = "mc2";
   mainProxy[2].name = "mc3";
   mainProxy[3].name = "mc4";
   
   
   // 利用 "*" 一次取出所有 Child
   var children:Array = mainProxy.*;
   for each (var c:* in children) {
    trace(c.name);
   }
   
   // 利用 "*" 一次移除所有 Child
   delete mainProxy.*;
   trace(this.numChildren); // 0
   
   
   
   // 判定 DisplayObject 一般屬性
   trace("name" in mainProxy); // true
   trace("getChildAt" in mainProxy); // true
   trace("transform" in mainProxy); // true
   
   
   mainProxy[0] = new MovieClip();
   mainProxy[1] = new MovieClip();
   mainProxy[2] = new MovieClip();
   mainProxy[3] = new MovieClip();
   mainProxy[0].name = "mc1";
   mainProxy[1].name = "mc2";
   mainProxy[2].name = "mc3";
   mainProxy[3].name = "mc4";
   
   
   // 用 DisplayObjectProxy 依據 Child Name 取出物件
   trace(mainProxy["mc4"].name); // mc4
   
   trace(this.getChildAt(0).name); // mc1
   trace(this.getChildAt(1).name); // mc2
   trace(this.getChildAt(2).name); // mc3
   trace(this.getChildAt(3).name); // mc4
   
   
   
   // 用 DisplayObjectProxy 移除 index 為 2 的 child 方式之一
   mainProxy[2] = null;
   
   // 用 DisplayObjectProxy 列舉所有的 children 方式之一
   for (var i:* in mainProxy) {
    trace(i);
   }
   // mc1
   // mc2
   // mc4
   
   
   // 用 DisplayObjectProxy 移除 index 為 2 的 child 方式之二
   delete mainProxy[2];
   
   // 用 DisplayObjectProxy 列舉所有的 children 方式之二
   for each(var o:* in mainProxy) {
    trace(o.name);
   }
   // mc1
   // mc2
   
   
   // 用 DisplayObjectProxy 對子物件容器再加入 Child
   mainProxy[0][0] = new MovieClip();
   mainProxy[0][0][0] = new MovieClip();
   mainProxy[0][0][0][0] = new MovieClip();
   mainProxy[0][0][0][0].name = "MC[0][0][0][0]";
   
   
   
   // 用 DisplayObjectProxy 取出四層之下的 Child
   trace(mainProxy[0][0][0][0].name);
   // MC[0][0][0][0]
   
   
   // 相較之下,AS3 正規方式相當複雜
   trace(
   (
    (
     (
      (
          this.getChildAt(0) as DisplayObjectContainer
      ).getChildAt(0) as DisplayObjectContainer
     ).getChildAt(0) as DisplayObjectContainer
    ).getChildAt(0) as DisplayObjectContainer
   ).name);
   // MC[0][0][0][0]
   
   
   
   // 用 DisplayObjectProxy 取出不存在的 Child 物件
   trace(mainProxy[0][0][0][2]);
   // null
   
   
   // 將 DisplayObjectProxy 脫殼
   trace(describeType(mainProxy[0][0][0][0].valueOf()).@name);
   // flash.display::MovieClip
   
   
   // 對 DisplayObjectProxy 加入 DisplayObjectProxy
   var mc:MovieClip = new MovieClip();
   mc.name = "mc";
   mainProxy[0] = new DisplayObjectProxy(mc);
   trace(mainProxy[0].name);
   // mc
   
   
  }
 }
 
}

相關連結:
自製 DisplayObjectProxy Class - 快速遊走於 DisplayObject Tree

Read more...

AS3 測試物件是否含有特定屬性技巧   [+/-]

Ticore's Blog

ActionScript 3.0 增加了許多內建物件型別、語法
像是 Dictionary、XML、XMLList、Namespace、QName、...
假如臨時遇到想要檢查這些新增物件內是否含有特定屬型時
文件上又沒有特別交代情況下
往往會回歸到最原始的方式,全部取出來,一個一個 Loop
或者是完全找不到解答...

一般情況下,可以用 AS3 一般性語法檢查物件是否含有特定屬性

trace("prop" in Object);

以下就幾種特殊物件屬性進行測試

測試 Object 內有無特定屬性

var obj:Object = {prop1: "prop1"};
trace(obj.hasOwnProperty("prop1")); // true
trace(obj.hasOwnProperty("prop2")); // false
trace("prop1" in obj); // true
trace("prop2" in obj); // false
trace(new QName("prop1") in obj); // true
trace(new QName("prop2") in obj); // false

測試 Array 內有無特定屬性

var obj:Array = ["a", "b"];
trace(obj.hasOwnProperty("0")); // true
trace(obj.hasOwnProperty("2")); // false
trace("0" in obj); // true
trace("2" in obj); // false
trace(new QName("0") in obj); // true
trace(new QName("2") in obj); // false

測試 Dictionary 內有無特定屬性

var obj:Dictionary = new Dictionary();
var key1:Object = {};
var key2:Object = {};
obj[key1] = "Key 1";
// 無法用 hasOwnProperty 來判定
trace(obj.hasOwnProperty(key1)); // false
trace(obj.hasOwnProperty(key2)); // false
trace(key1 in obj); // true
trace(key2 in obj); // false
// 無法用 QName in Object 來判定
trace(new QName(key1) in obj); // false
trace(new QName(key2) in obj); // false

測試 XML Node 有無特定 Attribute

var xml:XML = <xml attr1="Attribute 1" ns:attr2="Attribute 2"
   xmlns:ns="http://ticore.blogspot.com/" />;
var ns:Namespace = new Namespace("ns", "http://ticore.blogspot.com/");

// 檢查 XML 物件內是否含有特定 Attribute
trace("@attr1" in xml); // true
trace("@attr2" in xml); // false

// 無法直接以 QName in XML 檢查 Namespace Attribute
trace(new QName("@attr1") in xml); // true
trace(new QName("@attr2") in xml); // false

trace(new QName("http://ticore.blogspot.com/", "@attr2") in xml); // false
trace(xml[new QName("http://ticore.blogspot.com/", "@attr2")]); // Attribute 2

trace(xml.ns::["@attr2"]); // Attribute 2

// 利用 QName 檢查 XML 物件內是否含有特定 Namespace Attribute
trace(xml.ns::["@attr1"].length()); // 0
trace(xml.ns::["@attr1"] == <></>); // true

trace(xml.ns::["@attr2"].length()); // 1
trace(xml.ns::["@attr2"] == <></>); // false

trace(xml[new QName("http://ticore.blogspot.com/", "@attr1")].length()); // 0
trace(xml[new QName("http://ticore.blogspot.com/", "@attr1")] == <></>); // true

trace(xml[new QName("http://ticore.blogspot.com/", "@attr2")].length()); // 1
trace(xml[new QName("http://ticore.blogspot.com/", "@attr2")] == <></>); // false

試誤法測試自訂類別物件內有無特定 Namesapce Property

MyClass.as

public class MyClass {
 namespace ns = "http://ticore.blogspot.com/";
 ns var prop:String = "prop";
 ns function fun():void{}
}
var obj:MyClass = new MyClass();
try {
 trace(obj[new QName("http://ticore.blogspot.com/", "fun")]);
 trace(obj[new QName("http://ticore.blogspot.com/", "fun2")]);
} catch (e:Error) {
 trace(e);
 // ReferenceError: Error #1069: .MyClass 上找不到屬性
 // http://ticore.blogspot.com/::fun2,而且沒有預設值。
}
Read more...

2007年11月5日 星期一

Flex Embed 外部資源技巧   [+/-]

Ticore's Blog

在 Flex 內要使用外部資源檔案,通常使用 Embed 將外部檔案嵌入
也可以指定一個 Class 名稱
如文件上所示:

[Embed(source="logo.gif")]
[Bindable]
public var imgCls:Class;

這樣做法只是將外部資源轉成 Class
無法繼承或是改變它的行為
當然也可以用複合的方式來達到類似的功能

後來發現
其實 Embed 是可以 Link 到一個自訂的 Class
就像在 Flash 內,一個 Symbol Link 到一個 Class 一樣
做法很簡單,直接把 Embed 加在自訂 Class 前面即可

package {
 import flash.display.MovieClip;

 [Embed(source="assets/assets.swf", symbol="FlashSymbol1")]
 public class SymbolClass1 extends MovieClip {
  public function SymbolClass1():void{
   roll();
  }
  public function roll():void{
   this.x = Math.random() * 300;
   this.y = Math.random() * 300;
   this.alpha = Math.random();
   this.rotation = Math.random() * 360;
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

這樣就可以直接繼承並增加 function

需要注意的是以上做法 Document Class 無效
因為 Document Class 本身就已經有 Link 到一個 Symbol 了

同理,Sub Class Link Symbol 也會取代 Super Class Link Symbol

相關連結:
利用 static 區塊建立額外 Document Class 實體
AS3 Document Class 實體化怪異現象
Flex Embed 點陣圖檔小技巧
兩種使用 Flash 開發 Flex Skin 方式比較

Read more...

2007年11月4日 星期日

AS3 - 使用 prototype 與 final class 造成 Flash Player Crash Bug   [+/-]

Ticore's Blog

問題描述:
使用一個 final class instance 作為 constructor function 的 prototype 時
用 constructor function 建立的實體之後
對該實體呼叫 final class 才有的屬性會造成 Flash Player 當掉

Bug 示範程式:

var fun:Function = function ():void{};
fun.prototype = new XML();
var o:* = new fun();
trace(o.name);

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

以下是實際測試過會發生問題的版本
Flash Player 9.0.15.0
Flash Player 9.0.16.0
Flash Player 9.0.28.0
Flash Player 9.0.45.0
Flash Player 9.0.47.0

Flash Player 9.0.60.120 之後的版本似乎已經修正此 Bug

雖然較新的版本已經不會遇到此 Bug
但是 Flash CS3 內建的 Flash Player 9.0.45.0
與 Adobe 網站上正式可下載安裝的版本 Flash Player 9.0.47.0
都還是會有問題
所以我覺得有必要將問題寫出來

Read more...

2007年11月1日 星期四

一行 AS3 程式讓 Flash Player 9 死機 Part 3   [+/-]

Ticore's Blog

這次的 Bug 並非新發現,而是由之前的
用 @* 指定 Attributes 造成 Flash Player 9 Crash』簡化而來

AS3 一行死機程式:

<x><c/></x>.*.(trace(parent().@* = 1), "" + parent());

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

最近再度測試該 Bug 時,發現光是對 XML 物件指定 @*,並不會觸發
仔細測試才知道,原來 Bug 觸發條件,主要分為三個步驟:

  1. 宣告含有子節點 XML 物件
  2. 繼續對該 XML 物件的 @* 進行指定操作
  3. 最後呼叫 XML 物件的 toString() or toXMLString() 觸發 Bug

var e:XML = <x><c/></x>;
e.@* = 1;
trace(e + '');

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

實際測試過會掛掉的版本:
Flash Player 9.0.45.0
Flash Player 9.0.47.0
Flash Player 9.0.60.120
Flash Player 9.0.60.184
Flash Player 9.0.60.235
Flash Player 9.0.64.0
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.2.54
Flash Player 10.0.12.10
Flash Player 10.0.12.29
Flash Player 10.0.12.36
Flash Player 10.0.15.3 LNX
Flash Player 10.0.22.87

相關連結:
一行 AS3 程式讓 Flash Player 10 死機 Part 5
一行 AS3 程式讓 Flash Player 9 死機 Part 4
一行 AS3 程式讓 Flash Player 9 死機 Part 2
一行 AS3 程式讓 Flash Player 9 死機
用 @* 指定 Attributes 造成 Flash Player 9 Crash

Read more...