2009年5月31日星期日

Flex Bottom Bleeding DataGrid 2   [+/-]

Ticore's Blog

之前在開發 Flex Bottom Bleeding DataGrid
連帶發現 Flex DataGrid 有好幾項 Bug
經過一段時間的測試修改
終於將大部份的問題修好
特別將這些 Fix 與之前的 Bottom Bleeding DataGrid 整合在一起

本次主要修復的問題:

BleedingDataGrid 2 Class:

package {
 import flash.display.*;
 import flash.events.*;
 import flash.utils.*;
 
 import mx.controls.DataGrid;
 import mx.controls.dataGridClasses.*;
 import mx.controls.listClasses.*;
 import mx.core.*;
 import mx.events.*;

 use namespace mx_internal;

 public class BleedingDataGrid extends DataGrid {

  protected var _bottomBleed_:int = 0;
  
  [Bindable]
  public function get bottomBleed():int{
   return _bottomBleed_;
  }
  public function set bottomBleed(value:int):void{
   _bottomBleed_ = value;
   offscreenExtraRowsOrColumns = Math.ceil(Math.abs(value) / rowHeight);
   // trace(value, rowHeight, offscreenExtraRowsOrColumns);
  }

  public function BleedingDataGrid() {
   super();
  }

  // Force item renderer text to be masked.
  override protected function createChildren():void {
   super.createChildren();
   listContent.blendMode = "layer";
   this.addEventListener(ScrollEvent.SCROLL, adjustColumnBackground);
  }
  
  override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
   // trace("BleedingDataGrid.updateDisplayList();");
   var h:int = unscaledHeight - viewMetrics.top - viewMetrics.bottom;
   if (bottomBleed < 0) {
    // Reduced ScrollBar Mode
    super.updateDisplayList(unscaledWidth, unscaledHeight + ((h + bottomBleed <= minHeight)
     ? 0 : bottomBleed));
    maskShape.height = h;
   } else {
    // Bleeding Content Mode
    super.updateDisplayList(unscaledWidth, unscaledHeight);
    maskShape.height = (h <= minHeight) ? h : h + bottomBleed;
   }
   fixSortScrollPosition();
   adjustColumnBackground();
  }
  
  // From makeRowsAndColumnsWithExtraRows, fix sorting issue
  public function fixSortScrollPosition():void {
   var index:int = scrollPositionToIndex(horizontalScrollPosition, verticalScrollPosition - offscreenExtraRowsTop);
   seekPositionSafely(index);
  }

  // Force column background do not overlap on header.
  protected function adjustColumnBackground(evtObj:ScrollEvent = null):void {
   var colBGs:FlexSprite = listContent.getChildByName("colBGs") as FlexSprite;
   if (colBGs) {
    if (showHeaders) {
     colBGs.y = headerHeight - listContent.y + borderMetrics.top + 2;
    } else {
     colBGs.y = -listContent.y + borderMetrics.top;
    }
   }
  }

  // Force hide overlapping HighlightIndicator when keyboard scroll down.
  override protected function drawHighlightIndicator(indicator:Sprite, x:Number, y:Number,
       width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void{
   super.drawHighlightIndicator(indicator, x, y, width, height, color, itemRenderer);
   
   var topOffset:int = listContent.topOffset;
   
   if ((y + topOffset) < 0 && (y + height + topOffset) > -headerHeight) {
    indicator.visible = false;
   } else {
    indicator.visible = true;
   }
  }

  override protected function adjustListContent(unscaledWidth:Number = -1, unscaledHeight:Number = -1):void {
   // trace("adjustListContent();");
   super.adjustListContent(unscaledWidth, unscaledHeight);
   var itemClass:Class = itemRenderer["generator"];
   var topOffset:int = listContent.topOffset;
   var child:DisplayObject, i:int;
   
   // Force top offscreen selectionLayer invisible
   for (i = 0; i < selectionLayer.numChildren; ++i) {
    child = selectionLayer.getChildAt(i);
    // child.visible = (child.y < Math.abs(topOffset) && topOffset < 0) ? false : true;
    // trace(child.name, child.y, topOffset, listContent.y);
    if ((child.y + topOffset) < 0 && (child.y + child.height + topOffset) > -headerHeight) {
     child.visible = false;
    } else {
     child.visible = true;
    }
   }

   // Force top offscreen ItemRenderer invisible
   for (i = 0; i < listContent.numChildren; ++i) {
    child = listContent.getChildAt(i);
    if (child is itemClass) {
     // trace(child.y, listContent.y, headerHeight, topOffset);
     // Warning, use visible property will cause item position disorder!
     child.alpha = (child.y < Math.abs(topOffset) && topOffset < 0) ? 0 : 1;
     // Another way to make it invisible
     // child.scrollRect = (child.y < Math.abs(topOffset) && topOffset < 0) ? new Rectangle() : null;
    }
   }
  }

  // Force column background bottom bleeding.
  override protected function drawColumnBackground(s:Sprite, columnIndex:int, color:uint
   , column:DataGridColumn):void {
   // trace("drawColumnBackground();");
   // super.drawColumnBackground(s, columnIndex, color, column);
   // adjustColumnBackground();
   var background:Shape;
   background = Shape(s.getChildByName(columnIndex.toString()));
   if (!background) {
    background = new FlexShape();
    s.addChild(background);
    background.name = columnIndex.toString();
   }

   var g:Graphics = background.graphics;
   g.clear();
   g.beginFill(color, 1);
   var lastRow:Object = rowInfo[listItems.length - 1];
   
   var columnHeader:DataGridHeader = (s.parent == lockedColumnContent) ?
     DataGridHeader(lockedColumnHeader) : DataGridHeader(header);

   // trace(columns[columnIndex].width);
   var xx:Number = 0;
   if (showHeaders) {
    xx = columnHeader.rendererArray[columnIndex].x;
   } else {
    for (var i:Number = 0 ; i < columnIndex ; ++i) {
     xx += columns[columnIndex].width;
    }
   }
   var yy:Number = rowInfo[0].y;

   // Height is usually as tall is the items in the row, but not if
   // it would extend below the bottom of listContent
   // var height:Number = Math.min(lastRow.y + lastRow.height, listContent.height - yy);
   
   var height:Number = 0;
   height = Math.max(lastRow.y + lastRow.height, listContent.height) + (bottomBleed > 0 ? bottomBleed : 0);

   // trace(xx, yy);
   // yy += headerHeight - s.parent.y + borderMetrics.top + 2;
   
   if (showHeaders) {
    g.drawRect(xx, yy, visibleColumns[columnIndex].width, height + headerHeight);
   } else {
    g.drawRect(xx, yy, visibleColumns[columnIndex].width, height);
   }
   g.endFill();
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com

Flex MXML 範例程式與之前差不多,就不貼上來了

底部出血 DataGrid 線上範例:

捲軸內縮 DataGrid 線上範例:

相關連結:
Flex DataGrid Header and Column Bgs Bug
DataGrid offscreenExtraRowsOrColumns Bug
Flex Bottom Bleeding DataGrid
Flex - 不規則底部形狀的 DataGrid

Read more...

2009年5月27日星期三

Multiple Frames Flex Application   [+/-]

Ticore's Blog

什麼,Flex 也有影格,不是只有一格嗎?
當然不只,一般 Flex Application 至少會有分兩格
Frame 1: SystemManager (document class)、Preloader
Frame 2: Main Application
否則怎樣能做到 Preloader 呢?

假如想要再更多的影格怎麼辦?
以前有介紹過 Frame Metadata Tag
但是那使用起來有點彆手彆腳的
以下介紹另一種方式
可以更自由的管理 Flex App 影格與內容

利用 mxmlc compiler command 可以在 Flex App 既有兩個影格上
額外再追加其它影格,並且可以指定影格標籤與額外放置 Class 定義內容
compiler frames 語法如下:

-frames.frame=[Frame Label],[Class Name 1],[Class Name 2],....

每多加一個 frame,就要將以上參數整個重複一次
很累贅吧!
沒關係,還可以寫在 flex-config.xml 裡面
先在 project folder 下建立以下的 flex-config.xml

<?xml version="1.0"?>
<flex-config>
 <frames>
  <frame>
   <label>ExtraFrame01</label>
   <classname>FrameClass01</classname>
  </frame>
  <frame>
   <label>ExtraFrame02</label>
   <classname>FrameClass02</classname>
  </frame>
  <frame>
   <label>ExtraFrame03</label>
   <classname>FrameClass03</classname>
  </frame>
  <frame>
   <label>ExtraFrame04</label>
   <classname>AssetsHolder</classname>
  </frame>
 </frames>
</flex-config>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

compiler arguments 改用 -load-config+=../flex-config.xml
就能夠使用 flex-config.xml 作為額外的編譯參數設定

至於 FrameClass01 Class:

package {
 public class FrameClass01 {
  public static function frame(o:*):void{
   trace("FrameClass01.frame(" + o + ");");
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

其它以此類推....

每個額外附加的 frame 標籤可以隨意命名
並且可以包入一個以上的 Class
需要注意的是每個額外 frame 內第一個指定包入的 class
必須要提供 public static function frame(o:*):void; 讓 SystemManager 呼叫

只要運用以上的技巧,就能夠自由加入額外影格
並且在影格內指定包入的內容,自由安排下載順序
達到最佳化的效果

相關連結:
Flex Metadata Tag - Frame FactoryClass

Read more...

2009年5月24日星期日

Flex DataGrid Header and Column Bgs Bug   [+/-]

Ticore's Blog

Flex 3 DataGrid 有支援隱藏 Header 與指定 Column Background Color 的功能
但是假如同時使用這兩個屬性,就會出現 Error 了!

Bug 重覆步驟很簡單,建立一個含有 DataGrid 的 Flex App
指定 Column BackgroundColor 並且將 showHeaders 設為 false

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" backgroundColor="#FFFFFF">
 <mx:Panel title="DataGrid showHeaders bug" height="100%" width="100%">
  <mx:DataGrid id="dg" width="100%" height="100%" showHeaders="false">
   <mx:columns>
    <mx:DataGridColumn dataField="name" headerText="Name" backgroundColor="#FFB0B0" />
    <mx:DataGridColumn dataField="phone" headerText="Phone"/>
    <mx:DataGridColumn dataField="email" headerText="Email" backgroundColor="#B0B0FF" />
   </mx:columns>
  </mx:DataGrid>
  <mx:ControlBar paddingTop="5" paddingBottom="5" horizontalAlign="right">
   <mx:Text><mx:htmlText>
    <![CDATA[ <u><a href="http://ticore.blogspot.com"> ]]>
    <![CDATA[ Ticore's Blog - http://ticore.blogspot.com/</a></u> ]]>
   </mx:htmlText></mx:Text>
  </mx:ControlBar>
 </mx:Panel>
</mx:Application>

編譯並執行,就會得到 Error了

TypeError: Error #1010: 詞彙未定義且沒有屬性。
 at mx.controls::DataGrid/drawColumnBackground()[C:\autobuild\3.3.0\frameworks\projects\framework\src\mx\controls\DataGrid.as:3012]
 at mx.controls::DataGrid/drawLinesAndColumnGraphics()[C:\autobuild\3.3.0\frameworks\projects\framework\src\mx\controls\DataGrid.as:3311]
 at mx.controls::DataGrid/drawLinesAndColumnBackgrounds()[C:\autobuild\3.3.0\frameworks\projects\framework\src\mx\controls\DataGrid.as:3207]
 at mx.controls::DataGrid/updateDisplayList()[C:\autobuild\3.3.0\frameworks\projects\framework\src\mx\controls\DataGrid.as:1506]
 at mx.controls.listClasses::ListBase/validateDisplayList()[C:\autobuild\3.3.0\frameworks\projects\framework\src\mx\controls\listClasses\ListBase.as:3280]
 at mx.managers::LayoutManager/validateDisplayList()[C:\autobuild\3.3.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:622]
 at mx.managers::LayoutManager/doPhasedInstantiation()[C:\autobuild\3.3.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:677]
 at Function/http://adobe.com/AS3/2006/builtin::apply()
 at mx.core::UIComponent/callLaterDispatcher2()[C:\autobuild\3.3.0\frameworks\projects\framework\src\mx\core\UIComponent.as:8633]
 at mx.core::UIComponent/callLaterDispatcher()[C:\autobuild\3.3.0\frameworks\projects\framework\src\mx\core\UIComponent.as:8573]

修正的方式如下,自行繼承 DataGrid 並覆寫 drawColumnBackground 成員函式:

package {
 import flash.display.*;

 import mx.controls.DataGrid;
 import mx.controls.dataGridClasses.*;
 import mx.core.*;

 use namespace mx_internal;

 public class MyDataGrid extends DataGrid {

  override protected function drawColumnBackground(
       s:Sprite, columnIndex:int, color:uint, column:DataGridColumn):void {
   // Fix drawColumnBackground bug when showHeaders=false.
   var background:Shape;
   background = Shape(s.getChildByName(columnIndex.toString()));
   if (!background) {
    background = new FlexShape();
    s.addChild(background);
    background.name = columnIndex.toString();
   }

   var g:Graphics = background.graphics;
   g.clear();
   g.beginFill(color, 1);

   var lastRow:Object = rowInfo[listItems.length - 1];

   var columnHeader:DataGridHeader = (s.parent == lockedColumnContent) ?
      DataGridHeader(lockedColumnHeader) : DataGridHeader(header);

   var xx:Number = 0;
   if (showHeaders) {
    xx = columnHeader.rendererArray[columnIndex].x;
   } else {
    for (var i:Number = 0; i < columnIndex; ++i) {
     xx += columns[columnIndex].width;
    }
   }

   var yy:Number = rowInfo[0].y;
   var height:Number = Math.min(lastRow.y + lastRow.height, listContent.height - yy);

   if (showHeaders) {
    g.drawRect(xx, yy, visibleColumns[columnIndex].width, height + headerHeight);
   } else {
    g.drawRect(xx, yy, visibleColumns[columnIndex].width, height);
   }
   g.endFill();
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com

測試環境:Flex SDK 3.1, 3.2, 3.3

相關連結:
Flex Bottom Bleeding DataGrid 2
DataGrid offscreenExtraRowsOrColumns Bug
Flex Bottom Bleeding DataGrid

Read more...

2009年5月23日星期六

DataGrid offscreenExtraRowsOrColumns Bug   [+/-]

Ticore's Blog

之前有介紹過 Bottom Bleeding DataGrid
是藉由 offscreenExtraRowsOrColumns 來達到的
可是這屬性有一個 Bug

將 offscreenExtraRowsOrColumns 設為 3 或更多
點選 row 1,點擊 column header 排序兩次
拖曳 ScrollBar 的 Thumb 上下捲動
就會發現 DataGrid 內的資料錯亂了

這個 Bug 真的很麻煩,也很難改
已經困擾我很久了
最近又開始在 Flex 原始碼內來回反覆修改測試
終於找到最關鍵的兩行 Code
坦白說,完全是用試誤法找出來的,不知道原理
以下便是修補程式~

MyDataGrid Class:

package {
 import mx.controls.DataGrid;
 
 public class MyDataGrid extends DataGrid {
  public function MyDataGrid() {
   offscreenExtraRowsOrColumns = 3;
  }
  override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
   super.updateDisplayList(unscaledWidth, unscaledHeight);
   var index:int = scrollPositionToIndex(horizontalScrollPosition, verticalScrollPosition - offscreenExtraRowsTop);
   seekPositionSafely(index);
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

MXML 測試程式:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" fontSize="12" backgroundColor="#FFFFFF">
 <mx:Panel title="DataGrid.offscreenExtraRowsOrColumns Bug" height="100%" width="100%">
  <local:MyDataGrid xmlns:local="*" id="dg" width="100%" height="100%"
    dataProvider="{employees}" borderStyle="none" top="0">
   <local:columns>
    <mx:DataGridColumn dataField="name" headerText="Name" />
    <mx:DataGridColumn dataField="phone" headerText="Phone"/>
    <mx:DataGridColumn dataField="email" headerText="Email" />
   </local:columns>
  </local:MyDataGrid>
  <mx:ControlBar paddingTop="5" paddingBottom="5" horizontalAlign="right">
   <mx:Text><mx:htmlText>
    <![CDATA[ <u><a href="http://ticore.blogspot.com">Ticore's Blog - http://ticore.blogspot.com/</a></u> ]]>
   </mx:htmlText></mx:Text>
  </mx:ControlBar>
 </mx:Panel>
 
 <mx:XMLList id="employees">
  <employee>
   <name>Christina Coenraets</name>
   <phone>000-000-0000</phone>
   <email>ccoenraets@fictitious.com</email>
  </employee>
  <employee>
   <name>Christina Coenraets</name>
   <phone>000-111-0000</phone>
   <email>ccoenraets@fictitious.com</email>
  </employee>
  <employee>
   <name>Joanne Wall</name>
   <phone>000-222-0000</phone>
   <email>jwall@fictitious.com</email>
  </employee>
  <employee>
   <name>Maurice Smith</name>
   <phone>000-333-0000</phone>
   <email>maurice@fictitious.com</email>
  </employee>
  <employee>
   <name>Mary Jones</name>
   <phone>000-444-0000</phone>
   <email>mjones@fictitious.com</email>
  </employee>
  <employee>
   <name>Christina Coenraets</name>
   <phone>000-555-0000</phone>
   <email>ccoenraets@fictitious.com</email>
  </employee>
  <employee>
   <name>Joanne Wall</name>
   <phone>000-666-0000</phone>
   <email>jwall@fictitious.com</email>
  </employee>
  <employee>
   <name>Maurice Smith</name>
   <phone>000-777-0000</phone>
   <email>maurice@fictitious.com</email>
  </employee>
  <employee>
   <name>Mary Jones</name>
   <phone>000-888-0000</phone>
   <email>mjones@fictitious.com</email>
  </employee>
  <employee>
   <name>Christina Coenraets</name>
   <phone>000-999-0000</phone>
   <email>ccoenraets@fictitious.com</email>
  </employee>
  <employee>
   <name>Joanne Wall</name>
   <phone>111-000-0000</phone>
   <email>jwall@fictitious.com</email>
  </employee>
  <employee>
   <name>Maurice Smith</name>
   <phone>111-111-0000</phone>
   <email>maurice@fictitious.com</email>
  </employee>
  <employee>
   <name>Mary Jones</name>
   <phone>111-222-0000</phone>
   <email>mjones@fictitious.com</email>
  </employee>
 </mx:XMLList>
</mx:Application>

測試環境:Flex SDK 3.3, 3.2, 3.1

相關連結:
Flex Bottom Bleeding DataGrid 2
Flex DataGrid Header and Column Bgs Bug
Flex Bottom Bleeding DataGrid

Read more...

2009年5月19日星期二

jQuery 語法速查表   [+/-]

Ticore's Blog

jQuery 語法速查表,需要的請自便吧

A Coding Fool - jQuery 1.3 Cheat Sheet
ToolBox - jQuery Cheat Sheet
gscottolson - jQuery 1.2 Cheat Sheet
Nettuts+ - jQuery 1.2 Cheat Sheet
Nilesh Patel - jQuery Cheat Sheets v 1.1.1

Read more...

2009年5月17日星期日

AS2 與 AS3 的差異   [+/-]

Ticore's Blog

ActionScript 2.0 與 ActionScript 3.0 到底有什麼差別?
很多人都被問過,或是問過別人吧
執行期型別檢查、事件流、物件導向、E4X...
解釋一堆,沒有實際用過的人,可能還是如鴨子聽雷一般霧茫茫
這裡有一個淺顯易懂的解釋
The Differences between ActionScript 2 and ActionScript 3

(以下只是照原文翻譯而已)
AS1.0 是給經驗不足的人、設計師與非技術人員使用的
AS2.0 是給女孩用的
AS3.0 是給真正男人用的

AS3.0 像是日本廚師刀,精巧的工藝,但是使用時須要謹慎與足夠的技巧
AS2.0 像是大砍刀,適合砍東西,不適合作精巧的控制
AS1.0 像是塑膠湯匙

經常被問到這問題的人,不妨參考看看~~

這個解釋雖然有點輕視貶低女性與設計師的意味
但是反過來仔細想想看 Silverlight 為什麼會失敗
或許就是因為它缺少了類似 AS1.0 這段簡易的開發過程
另一方面,Flash Player 在進步到 AS3 的過程中
因為進入門檻太高而且 AS2 與 AS3 很難共存
其實已經開始失去不少初級開發者與設計師的支持

個人的淺見,Adobe 除了繼續增加 Flash Player AS3 功能以外
可能需要考慮到 AS1 的支援程度
假如能夠支援把 AS1 語法編譯為 AS3 Class、Bytecode 應該會不錯
或是類似 Dreamweaver、Director 的 Behavior 的功能
但是最終可以輸出 AS3 的 SWF
這樣設計師還是能夠撰寫簡單的語法與互動功能
而且也不會有 AS2, AS3 相容的問題

相關連結:
Silverlight 唱衰文

Read more...

2009年5月16日星期六

Flex Builder 將改名為 Flash Builder   [+/-]

Ticore's Blog

剛剛看到 About the rebranding of Flex Builder into Flash Builder
好消息是 Flash Catalyst 與 Flash Builder 4 即將在 2009 夏天釋出公開測試版
耶? 不是 Flex Builder 嗎?
不是打錯字,Flex Builder 將會改名為 Flash Builder

主要原因是開發人員定位的曖昧不明
很多人用 Flex SDK 而不用 Flex Builder 開發 Flex、AIR Application
還有很多人用 Flex Builder 但是沒用到 Flex Framework...

正確的定位應該是,只要用到 Flex SDK 就是 Flex Developer
而 Flex Builder 一定會產生 SWF 在 Flash Player 上跑
所以改名為 Flash Builder 比較合適

相關連結:
Say goodbye to Flex Builder
Flex 2 != AS3
Next version of Flex Builder will be named Flash Builder 4!

Read more...

Silverlight 唱衰文   [+/-]

Ticore's Blog

Silverlight 出到現在也好幾年了
網路上已經出現不少負面的評論

CNET News - Demand for Microsoft Silverlight remains sluggish
CNET News - Why baseball benched Microsoft Silverlight Digital Media
ZDNet - Silverlight strikes out with MLB
ZDNet Taiwan - 大聯盟為何讓Silverlight坐冷板凳?
ComputerWorld - Little demand yet for Silverlight programmers
Smashing Magazine - Flash vs. Silverlight What Suits Your Needs Best
Brown's Blog - Silverlight.NET vs FlashFlex (or not) and My Silverlight Wishlist
FAIL: Silverlight Advertising
Some Random Dude - Why Silverlight Should Fail
Tim Anderson's ITWriting - Silverlight developer win, designer fail
Chuck Freedman - Learning Silverlight in the dark
Tim Anderson's ITWriting - Morgan Stanley why we didn't use Silverlight for Matrix

還有人從兩年前就分析覺得 Silverlight 會失敗
一年前更新過分析,一樣失敗
最近又更新,還是失敗
真的挺慘的!
至少我自己在兩年前,還是持保留觀望態度

Chad Udell - Why Microsoft Silverlight Will Fail
Chad Udell - Update Why Microsoft Silverlight Will Fail - 1 Year Later
Chad Udell - 2 Years Later… An Update on Why Microsoft Silverlight Will Fail

Silverlight 需要多多加油啊
活著當 Flash 的競爭對手
這樣 Flash 才會進步

相關連結:
用 Google 預測某項產品的死亡?

Read more...

2009年5月15日星期五

PV3D 2.0 互動選單測試   [+/-]

Ticore's Blog

之前很少在用 Flash 3D Engine
不知不覺 PV3D 都出到 2.0 了
實際來測試看看
API 似乎比之前好用多了

Read more...

2009年5月14日星期四

Flash CS4 更新檔下載   [+/-]

Ticore's Blog

Adobe Flash CS4 Professional (10.0.2) 更新檔出了喔
主要解決 Flash CS4 效能的問題以及一堆 Bug
詳細的更新內容可以參考
Galvan on Flash: Flash CS4 update now available

剛剛裝起來了,Library 內物件拖動的效能的確好多了
可是這個 Bug 還是存在 Flash CS4 Drawing Tools Bug
難道都沒有人發現?

相關連結:
Flash CS4 Drawing Tools Bug

Read more...

2009年5月9日星期六

Flex 4 Gumbo Language Reference   [+/-]

Ticore's Blog

Adobe 雖然有提供 Flex 4 Gumbo Language Reference
但其實那已經過期了~

還殘留很多 Fx 開頭的 Class,很多 Spark package 下的 Class 都沒列出來

假如下載最新的 Flex SDK nightly build 來測試
就會面臨沒有 Language Reference 可用的窘境

不過可以自行呼叫 Flex SDK 內附的 asdoc 來產生最新的文件

set sourcePath=%sourcePath% ..\frameworks\projects\flex4\src
set sourcePath=%sourcePath% ..\frameworks\projects\framework\src
set sourcePath=%sourcePath% ..\frameworks\projects\framework_textLayout\src
set sourcePath=%sourcePath% ..\frameworks\projects\sparkskins\src
set sourcePath=%sourcePath% ..\frameworks\projects\wireframe\src
set sourcePath=%sourcePath% ..\frameworks\projects\haloclassic\src
set sourcePath=%sourcePath% ..\frameworks\projects\halo\src
set sourcePath=%sourcePath% ..\frameworks\projects\rpc\src
set sourcePath=%sourcePath% ..\frameworks\projects\airframework\src
set sourcePath=%sourcePath% ..\frameworks\projects\utilities\src

set docClasses=%docClasses% Flex4Classes
set docClasses=%docClasses% FrameworkClasses
set docClasses=%docClasses% FrameworkTextLayoutClasses
set docClasses=%docClasses% SparkSkinsClasses
set docClasses=%docClasses% WireframeClasses
set docClasses=%docClasses% HaloClassicClasses
set docClasses=%docClasses% HaloClasses
set docClasses=%docClasses% RPCClasses
set docClasses=%docClasses% AIRFrameworkClasses
set docClasses=%docClasses% UtilitiesClasses

asdoc.exe +configname=air -strict=false -main-title "Flex 4 Gumbo Language Reference" -source-path %sourcePath% -doc-classes %docClasses%
pause

用以上內容建立批次檔,放在 flex sdk 的 bin folder 下面執行就可以了

Read more...

2009年5月6日星期三

Flash Player 10 unloadAndStop 測試   [+/-]

Ticore's Blog

Flash Player 10 新增的 Loader.unloadAndStop 函式很好用
可以自動幫你停掉外部 SWF 內的聲音、事件、Timer、....
但是它並非萬靈丹,以下便是一個例子

這三個 Document Class 編譯出來
Main03.swf 會載入 Main02.swf
Main02.swf 會載入 Main01.swf
過了三秒之後 Main03.swf 會呼叫 unloadAndStop 卸載 Main02.swf

Main03 Class:

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

 public class Main3 extends Sprite {
  
  private var ldr:Loader = new Loader();
  
  public function Main3() {
   trace("Main3();");
   ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
   var ldrCxt:LoaderContext = new LoaderContext(false, new ApplicationDomain());
   ldr.load(new URLRequest("Main2.swf"), ldrCxt);
  }
  
  public function onLoadComplete(evtObj:Event):void{
   setTimeout(unloadLdr, 3000);
  }
  
  public function unloadLdr():void{
   ldr.unloadAndStop(true);
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

Main02 Class:

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

 public class Main2 extends Sprite {
  
  private var ldr:Loader = new Loader();
  
  public function Main2() {
   trace("Main2();");
   setInterval(onTimer, 1000);
   this.loaderInfo.addEventListener(Event.UNLOAD, onSelfUnload);
   
   var ldrCxt:LoaderContext = new LoaderContext(false, new ApplicationDomain());
   ldr.load(new URLRequest("Main1.swf"), ldrCxt);
  }
  
  public function onSelfUnload(evtObj:Event):void{
   trace("Main2.onSelfUnload();", getTimer());
   // ldr.unloadAndStop(true);
  }
  
  public function onTimer():void{
   trace("Main2.onTimer();", getTimer());
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

Main01 Class:

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

 public class Main1 extends Sprite {
  
  public function Main1() {
   trace("Main1();");
   setInterval(onTimer, 1000);
   this.loaderInfo.addEventListener(Event.UNLOAD, onSelfUnload);
  }
  
  public function onSelfUnload(evtObj:Event):void{
   trace("Main1.onSelfUnload();", getTimer());
  }
  
  public function onTimer():void{
   trace("Main1.onTimer();", getTimer());
  }
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

實際測試輸出結果

Main3();
Main2();
Main1();
Main2.onTimer(); 1102
Main1.onTimer(); 1029
Main2.onTimer(); 2134
Main1.onTimer(); 2060
Main2.onSelfUnload(); 3100
Main1.onTimer(); 3095
Main1.onTimer(); 4126
Main1.onTimer(); 5128
...
..

會發現 Main02.swf 內的 Timer 可以成功被停止
但是 Main01.swf 的卻跑不停~

解決的方式很簡單,只要把註解的那行打開就好了
Loader.unloadAndStop 帶來很多便利
但是這並不意味著,開發時候可以盲目的亂用
每個 SWF 還是必須要肩負卸載自己產生 Loader 的責任

測試版本 Flash Player 10.0.22.87 win

相關連結:
Adobe Flash Player 10 beta 2 出了

Read more...

2009年5月1日星期五

用 Google 預測某項產品的死亡?   [+/-]

Ticore's Blog

有人提出利用搜尋 xxx is dead 的方式來觀察一些趨勢
<enter product name here> is dead
挺有意思的,不過都已經可以用 Google 預測流感疾病了
預測某項東西的死亡似乎也沒什麼特別的

你也來預測看看吧~

"java is dead" - 20,400 項結果
"flash is dead" - 14,200 項結果
"html is dead" - 24,000 項結果
"php is dead" - 4,730 項結果
"javascript is dead" - 1,840 項結果
"actionscript is dead" - 7 項結果

"flex is dead" - 357 項結果
"silverlight is dead" - 1,510 項結果
"javafx is dead" - 1,880 項結果

"MS is dead" - 10,500 項結果
"Adobe is dead" - 916 項結果
"Nokia is dead" - 2,620 項結果
"Google is dead" - 20,200 項結果

結果還真出人意料,這幾年新出的玩意兒 JavaFx, Silverlight
居然也有不少搜尋結果出來
更奇怪的是 Google 本身怎麼會跑出那麼多結果~
就這幾項搜尋結果而言,死最大的似乎是 HTML !?

2009/5/5 補充
搜尋結果是會一直變動的~
其中 Silverlight 變動的幅度實在很誇張
2009/5/3 剩下 169 項結果
2009/5/5 只剩下 10 項結果了
為什麼會這樣,自己猜猜看吧

相關連結:
Flash or HTML/Ajax ?

相關連結:
Silverlight 唱衰文

Read more...

AS3 除錯技巧 - 用 Error 取得呼叫堆疊   [+/-]

Ticore's Blog

在開發 Flash or Flex AS3 程式的時候
除非用除錯模式執行,配合開發工具
否則很難知道某個 function 是被誰呼叫的
網路上看到一個很不錯的除錯技巧
Actionscript debug tips: who called my actionscript method?
只要自己丟出一個 Error
然後馬上捕捉,就能夠立即獲得目前執行點的呼叫堆疊資訊
真的很方便~

譬如以下的 Flash AS3 測試程式:

function showStackTrace() {
 try {
  throw new Error();
 } catch (e:Error) {
  trace(e.getStackTrace());
 }
}

function fun():void{
 setTimeout(showStackTrace, 10);
}

setTimeout(fun, 10);

可以拿到這樣的呼叫堆疊資料

Error
 at Untitled_fla::MainTimeline/showStackTrace()
 at Function/http://adobe.com/AS3/2006/builtin::apply()
 at ()
 at SetIntervalTimer/onTimer()
 at flash.utils::Timer/_timerDispatch()
 at flash.utils::Timer/tick()

再用 Flex Application 測試看看

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:creationComplete>
  <![CDATA[
   try {
    throw new Error();
   } catch (e:Error) {
    trace(e.getStackTrace());
   }
  ]]>
 </mx:creationComplete>
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

這輸出就比較複雜了

Error
 at main/___main_Application1_creationComplete()
 at flash.events::EventDispatcher/dispatchEventFunction()
 at flash.events::EventDispatcher/dispatchEvent()
 at mx.core::UIComponent/dispatchEvent()
 at mx.core::UIComponent/set initialized()
 at mx.managers::LayoutManager/doPhasedInstantiation()
 at Function/http://adobe.com/AS3/2006/builtin::apply()
 at mx.core::UIComponent/callLaterDispatcher2()
 at mx.core::UIComponent/callLaterDispatcher()

但是這樣的資訊對於除錯還是很有用的
其實還可以再簡化如下

trace(new Error().getStackTrace());

需要注意的是,需要 Flash Player Debug 版才有用

Read more...