Search This Blog

Loading...

Sep 23, 2009

經濟部水利署發表以 Adobe Flex Builder 建立的新系統


[水文水資源資料管理供應系統]

以下是其公關稿節錄:

讓水文水資源資料管理供應系統更加專業便捷

【2009 年 9 月 22 日,台北訊】全球軟體大廠奧多比今日宣布再添一 Adobe® Flash® 平台技術應用佳績!以提供技術服務、軟體工程、應用服務為主的地理資訊系統整合商銳俤科技,成功協助經濟部水利署「水文水資源資料管理供應系統」(http://gweb.wra.gov.tw/wrweb/) 的開發與升級,使其更具互動便利性。銳俤科技以 Adobe Flex® Builder™ 3 將現有複雜的水資源統計資料與空間數據轉化為可隨點即查的豐富型媒體系統,建立人性親和的系統介面。 ~ more...

裡面使用 Flex 製作的是「地理資訊」選項,用 Safari 4.0.3 + OSX 10.5.8 看的時候會有 Button 被遮蔽的問題等於是無法使用,這個 bug 是比較神奇一些...也蠻有可能是一開始的 UserProxy Error Response 導致...FireFox debug flash player 有捕捉到錯誤‧

最近 Erin 的主力都是在做 Flex 相關開發,當然樂見在台灣有越來越多的使用案例上市!!Flex 加油! =)

Sep 2, 2009

[Flex] flexstore 的 find 功能補完

關於 Adobe flexstore 這個範例應該對學習過 Flex 的人是無人不知無人不曉,剛好有人問我如何將範例中的 Products / Find 功能補上,以下就是一個簡單改法:
1. 修改 samples.flexstore.ProductFilter.as
先加入一個公開屬性 searchText:String

public var searchText:String;


補上 find function

public function find(product:Product):Boolean
{
var str:RegExp=new RegExp(searchText, "i");
return (searchText == "") ? true :
(str.test(String(product.name))) ||
(str.test(String(product.price))) ||
(str.test(String(product.series))) ||
(str.test(product.description)) ||
(str.test(product.highlight1)) ||
(str.test(product.highlight2)) ||
(str.test( "Tri-band" )) ||
(str.test("Camera")) ||
(str.test("Video"));
}


2. 修改 ProductFilterPanel.mxml
加入 callFind event function

private function callFind(event:Event):void{
var filter:ProductFilter = new ProductFilter();
filter.searchText = searchText.text;
var e:ProductFilterEvent =
new ProductFilterEvent( filter, false);
dispatchEvent(e);
currentState = "showingThumbnails";
}

在 Go 的按鈕加上 click = "callFind(evenr)",並對 search input field 命名

<mx:HBox width="100%">
<mx:TextInput styleName="glass" width="100%" id="searchText"/>
<mx:Button styleName="glass" label="Go" click="callFind(event)"/>
</mx:HBox>
<code>


3. 修改 ProductCatalogPanel.mxml
在 filter function 內加上 find 的判定,其他直接照貼...

if (productFilter.searchText)
{
if (productFilter.find(product))
{
accepted[product]=true;
thumb.alpha=1;
count++;
}else
{
accepted[product]=false;
if (thumb.alpha == 1) //only fade if we hadn't started
{
targets.push(thumb);
}
}
}


完整的 filter function:

public function filter(productFilter:ProductFilter, live:Boolean):void
{
currentState="browse";
thumbnailState="browse";
var count:int=0;
var n:int=thumbnails.length;
var fadeOut:Fade=new Fade();
fadeOut.alphaFrom=1;
fadeOut.alphaTo=.1;
var targets:Array=[];
for (var i:int=0; i < n; i++)
{
var thumb:ProductCatalogThumbnail=thumbnails[i];
var product:Product=thumb.product;
//if FIND ------
if (productFilter.searchText)
{
if (productFilter.find(product))
{
accepted[product]=true;
thumb.alpha=1;
count++;
}else
{
accepted[product]=false;
if (thumb.alpha == 1) //only fade if we hadn't started
{
targets.push(thumb);
}
}
} //---------
else
{
if (productFilter.accept(product))
{
accepted[product]=true;
thumb.alpha=1;
count++;
}
else
{
accepted[product]=false;
if (live)
{
thumb.alpha=.1;
}
else if (thumb.alpha == 1) //only fade if we hadn't started
{
targets.push(thumb);
}
}
}
}
productFilter.count=count;
filterCount=count;

if (targets.length > 0)
{
fadeOut.targets=targets;
fadeOut.play();
fadeOut.addEventListener(EffectEvent.EFFECT_END, function(event:EffectEvent):void
{
layoutCatalog();
});
}
else if (!live)
{
layoutCatalog();
}
}


flexstore 的 source 在 live demo 頁面上點選滑鼠右鍵 "view source" 即可下載喔!

Aug 25, 2009

[AS3] pureMVC Utility - WidgetsConsole 1.0.0


Project Name: pureMVC Utility - WidgetsConsole
Version: 1.0.0
Project Owner: Erin Lin
Description: An utility is under pureMVC Multicore that has Flex only and AS3 two versions.
Demo: WidgetsConsole Live Demo with source code
Download: WidgetsConsole Open Source Project Home
pureMVC website: http://puremvc.org/



沒想到我第一個 google code open source project 就獻給 pureMVC 了...

套用 pureMVC 到 Flex 專案第一個遇到的問題就是 view components 的控制,Flex 專案的 view 總類太多:有 Modules, UIComponent, external swf and pop-up view...etc. 整個專案作下來光 view 就可能換上幾十個頁面,先前分享了運用 StateMachine 來處理 view 的轉換,中大型專案作下來 code 的複雜度也是非常可觀。我在今年二月分享了 [Flex] pureMVC MultiCore with Modules 就開始著手將其概念包裝成 pureMVC 的工具包,使用到目前為止整個架構還是挺完善,所以在這邊與大家分享。

WdigetConsole 顧名思義是「 相同目的 views 組合 = Widget 」 的中央控制中心,將程式內加入 WidgetsConsole 的 widget 統一控管,最終只需要 sendNotification 就可以達到 view 的新增跟刪除(因為我是懶人工具的愛好者,懶人工具的定義就是以最低的限度達到所需要的效果,所以這個工具包的自由度很高!)

以下是簡單講解 WidgetsConsole 是什麼:

Widget 的定義: View component(s) + WidgetMediator + WidgetCommand
實作的 WidgetCommand:SimpleCommand 會掌控相關 views, proxies, commands 的註冊與移除。你可以發現上次在 pureMVC + StateMachine 文章中,Erin 建議將一個 view 的相關 Mediators, Proxies , Commands 都用一個 Command 來控制建立與刪除,其重點就是"只"讓一個 Command 掌握一個 views 組合的所有細節。

Interfaces: 想要自動化,介面是不可缺少的

  1. IWidgetShell:所有放置 Widget 的 DisplayObjectContainder 都需要實作。
  2. IWidget:view component or modules 只要需要被中央控管的 views 都要實作 IWidget
  3. IWidgetInfo:定義傳遞的 Value Object 介面


IWidgetShell 的實作
可以 extends 任何的 DisplayObjectContainder Class 來實作 IWidgetShell 介面,當然也可以參考 Live Demo 內的 AssignShell 寫法製作。如果你很在意巢狀容器的話,請避免使用 DisplayObjectContainder Class 來實作 IWidgetShell 介面。

WidgetCommand:SimpleCommand
寫法跟一般寫 Command 沒兩樣,差別在 execute 中只處理 WidgetsConsole.CREATE_WIDGET and WidgetsConsole.DESTROY_WIDGET。
  1. WidgetsConsole.CREATE_WIDGET:處理所有相關 View, mediator, proxies 的註冊,統一在此處理 view component 的 WidgetsConsole.ADD_WIDGET_TO_SHELL

    sendNotification(
    WidgetsConsole.ADD_WIDGET_TO_SHELL,
    widget:IWidget,
    ShellName:String
    );

  2. WidgetsConsole.DESTROY_WIDGET:處理所有相關 View, mediator, proxies 的刪除
    需要在此處理 view component 的 WidgetsConsole.REMOVE_WIDGET_FROM_SHELL

    sendNotification(
    WidgetsConsole.REMOVE_WIDGET_FROM_SHELL,
    widget:IWidget,
    ShellName:String
    );



How to Inject WidgetsConsole?
inject 函式的命名寫法參考自 pureMVC Utility - StateMachine

var wc:WidgetsConsole = new WidgetsConsole();
wc.inject( this.multitonKey );
wc.registerWidget( widgetName:String, command:Class );
//在這邊將做好的 WidgetCommand 註冊
wc.registerShell(name:String, shell:IWidgetShell);
//註冊 shell,由於 shell 是一個 IWidgetShell 實體,所以在實體被移除前一定要執行 removeShell


Widget 的呼叫:

sendNotification(
WidgetsConsole.CREATE_WIDGET,
new WidgetInfo( widgetName:String , mediatorName:String , targetShellName:String , moduleURL:String = null, attachment:Object = null )
);

mediatorName 由外部指定才能讓同一個 Widget 有不同的 Instances, 也可以將之 push 到不同的 shell 內。請參考 Live Demo

這邊的 moduleURL:String 欄位請自由運用,在 WidgetCommand 內可以藉由 IWidgetInfo.getURL() 取得,由於一開始 Erin 就是針對 Flex 開發出這個工具包,所以 IWidgetInfo 並沒有分版本;AS3 版本只是將 Module 相關拿掉而已。
*Edit:10.26,2009 筆誤... moduleURL:String 寫成 targetShellName:String...

LazyWidget 的呼叫:懶人 widget,WidgetMediator and WidgetCommand 已由 WidgetsConsole 提供
只有 ViewUI 的 Widget,單純展示畫面,多為測試用。 inject WidgetsConsole 的時候 registerLazyWidget(),才可以使用。

sendNotification(
WidgetsConsole.CREATE_WIDGET,
new WidgetInfo( WidgetsConsole.LAZY_WIDGET , mediatorName:String , targetShellName:String , moduleURL:String =null, viewUIInstance:IWidget )
);
//*Edit:10.26,2009 筆誤... moduleURL:String 寫成 targetShellName:String...
//attachment 欄位直接帶入 IWidget


Widget 的刪除

//刪除全部 Widgets
sendNotification(WidgetsConsole.DESTROY_ALL_WIDGETS);

//刪除指定 shell 內所有的 Widgets
sendNotification(WidgetsConsole.DESTROY_WIDGETS_BY_SHELL, shellName:String );

sendNotification(WidgetsConsole.DESTROY_WIDGET, mediatorName:String );
//刪除特定 Widget


Module 專區 - Flex only version

ModuleWidget 的呼叫:外部 ModuleWidget 共用,WidgetMediator and WidgetCommand 已由 WidgetsConsole 提供
需要在 inject WidgetsConsole 的時候順便 registerModuleWidget(),才可以使用。

sendNotification(
WidgetsConsole.CREATE_WIDGET,
new WidgetInfo( WidgetsConsole.MODULE_WIDGET , mediatorName:String , targetShellName:String , moduleURL:String , attachment:Object = null )
);
//WidgetsConsole 會將 attachment:Object 送到 Module.data,所以需要直接寄到 Module 的參數可以利用 attachment 傳送。



Module 專用的 broadcast to Global Notification:WidgetsConsole.MODULE_SENDER
發出通知後會自動轉變成 「WidgetsConsole.BROADCASTING 」到 System facade ,也會順便轉發出 「WidgetsConsole.MODULE_RECEIVER」 送進"其他"的 ModuleWidget(自己發送的 Notification 就不會接收),所以 WidgetsConsole.BROADCASTING 請謹慎使用...

sendNotification( WidgetsConsole.MODULE_SENDER , body:Object , type:String );
//body is an Object...可以放任何你想要傳出去的物件~~萬物皆物件啊!


Module 外部資料接收器:WidgetsConsole.MODULE_RECEIVER

override public function listNotificationInterests():Array
{
return [
WidgetsConsole.MODULE_RECEIVER
];
}
override public function handleNotification(notification:INotification):void
{
//就是處理你要的東西
}


Module remove Notification:WidgetsConsole.MODULE_REMOVE
不管是由 Module 發出 WidgetsConsole.MODULE_REMOVE,又或者從 System facade 發出 WidgetsConsole.DESTROY_WIDGET 都會送出 WidgetsConsole.MODULE_REMOVE 讓 Module facade 收聽,所以請記得在 Module's ApplicationFacade 內註冊 WidgetsConsole.MODULE_REMOVE Command,並將此 Module 在移除時需要清除的東西寫在此 Command 內。

sendNotification( WidgetsConsole.MODULE_REMOVE );
// remove self



其實目前 mx.modules.ModuleManager 有要命的 memory leak bug...建議現階段還是少用 Module 比較安全。這也是我使用 RSL(Runtime Shared Library) 來處理專案的主要原因,Module 只用來實作非主要的 view componet。

想要取得你所載入的 Module's ModuleInfo 去執行 unload() 的話,請利用 ModuleManager.getModule(url):IModuleInfo 來取得,關於這點我沒有在 WidgetsConsole 內處理的原因是:不管 ModuleInfo 有沒有執行 unload,其 ModuleInfo 還是會剩下一個實體不被回收,可能的原因是 ModuleManager 內的 inner class ModuleManagerImpl 有個 moduleList 在 ModuleInfo.unload 的時候並沒有順便清掉其 reference,當然也可能還有其他的因素。既然有沒有 unload 都沒差別那就不需要特別處理它了...=)

Aug 21, 2009

[pureMVC] Flex app 開發的心得分享

使用 pureMVC 開發到現在,也遇到不少網友詢問相關問題,以下是 Erin 整理的幾個使用 pureMVC framework 開發 Flex app 的心得分享:

  1. 雖然 pureMVC Standard 版本就很夠用了,但是你的 app 有未知擴充需求的話還是建議使用 Mulitcore 版本以達最大的開發彈性。

  2. 先問問自己能不能理解架構內 Notification and Command 是什麼作用?如果答案是『NO』,請先熟悉 pureMVC 的架構再行考量是不是要實作...因為有太多問題都可以利用它們解決。

  3. 先搞清楚你將要開發的 app 流程,花點時間研究官網上的 pureMVC Utilities,一定有工具包可以解決你的需求。

  4. 除了 Application 外 view component 不應該持有任何跟 pureMVC 有關的 Class instance reference,請善用 Flex & Flash Event 機制與外部溝通。

  5. 別把 view component 直接對 view component 溝通的開發邏輯帶到架構內,如果你還是打算這樣作就根本不需要使用任何 framework 來幫助開發!
    View componet 溝通邏輯應該是 A-view component -> Event -> A-Mediator -> Notification -> Proxy, Command or B-Mediator -> B-view component。Event 機制在這邊有很大的作用,Mediator "儘量"不持有 view componet 子物件只接收其 Event ,不僅可以讓你跳脫如何用 A view 控制 B view 的思維...因為 A view 根本不需要去知道它發了 Event 後誰會被控制; 對 view component 新增修改也比較容易,ex. view component 由 Flex 3 改 Flex 4 版本(尤其 Flex 4 的架構改很大...你就會發現用 Event 的重要性...)

  6. Mediator 要 override onRegister and onRemove function,做人要有始有終,請記得 EventListener 在移除前都清乾淨。

  7. 跨 view components 的資料最好都使用 proxy or command 處理,別直接 mediator 互傳。

  8. 整合 Flex 綁定資料機制:Value Object and Proxy 內使用 [Bindable] 來同步資料,可以省下處理後 update 資料的 Notification。如:


  9. public class SomeProxy extends Proxy implements IProxy
    {
    [Bindable]
    public var itemlist:ArrayCollection;
    .........
    所有的 itemlist 處理都是由 SomeProxy 執行,
    只需要在 view component 初始化的時候由其 Mediator
    將 itemlist 指定進去,view component 不作任何的
    ArrayCollection 操作,只將"操作的動作"發送 Event
    由 SomeProxy 同步,這樣同一個資料就可以讓不同
    的 view component 持有但是又不會互相干擾!

  10. 善用 runtime shared library。利用 Flex Library project 打包所需要的 asset files。再來想想你還需不需要 Module?目前 Erin 手上開發的專案使用 RSL,專案主程式僅 260kb, Flex runtime framework 564kb(不會重複載入), project assets swf 217kb....這樣還需要用 Module 嗎?所以 Module 在 Erin 的定義是久久出現一次的 view component 才會用它實作。



先寫到這邊,其他等想到再補充~~

Aug 4, 2009

[AS3] 簡單講客製 Event (2)

一般的使用只需要繼承自 flash.events.Event,
並且覆寫 clone 這個 function

package events
{
import flash.events.Event;

public class CustomEvent extends Event
{
public var data:Object; // 喜歡什麼都可以自己加~~當然也可以用 getter & setter 宣告
public function CustomEvent( type:String , data:Object )
{
super(type);
this.data = data;
}
override public function clone():Event {
return new CustomEvent( type , data );
}
}
}

如果你的 Event 需要 bubbles 請修改:
super( type , true )

方便 debug 版本,就是多一個覆寫 toString function
package events
{
import flash.events.Event;

public class Custom2Event extends Event
{
public var output:String;
public static const UPDATE_OUTPUT:String = "update_output";
public function Custom2Event( type:String , output:String)
{
super(type);
this.output = output;
}
override public function clone():Event {
return new Custom2Event( type , output );
}
override public function toString():String {
//印出你想要看的資訊
return formatToString("Custom2Event", "type" , "output" );
}
}
}


簡單的測試一下....TestEvent.as
package
{
import events.Custom2Event;
import fl.controls.Button;
import flash.display.Sprite;
import flash.events.MouseEvent;

/**
* TestEvent
* @author Erin
*/
public class TestEvent extends Sprite
{
public function TestEvent()
{
var btn:Button = new Button;
addChild( btn );
btn.addEventListener(MouseEvent.CLICK, onClick);
addEventListener( Custom2Event.UPDATE_OUTPUT, onCustomEvent );
}
private function onClick(e:MouseEvent):void {
dispatchEvent(new Custom2Event( Custom2Event.UPDATE_OUTPUT , "lalala"));
}
private function onCustomEvent(e:Custom2Event):void {
trace(e);
}
}
}


output : [Custom2Event type="update_output" output="lalala"]

Jul 24, 2009

[Flex] pureMVC and Utility-StateMachine (2)

Reference: PureMVC AS3 Utility - StateMachine

補充講解一下 StateMachine 是怎樣運作的。

public class StateMachine extends Mediator
打開它的原始碼就可以清楚看到它是一個 Mediator,其實整個機制就是像轉接器,收到 StateMachine.ACTION 通知後,就自動轉到對應的 State 然後利用 sendNotification(); 將新的通知轉發出去,所以它統一的 Notification 寫法就是:
sendNotification( StateMachine.ACTION , data , "Your_State_Action_String" );
然後它就會轉發
sendNotification( "Your_State_Exiting/Entering/Changed_String" , data );

在 InjectFSMCommand.as 內使用 XML 來宣告 State
<state name="Your_State" exiting="Exiting_Notification_Name" entering="Entering_Notification_Name" changed="Changed_Notification_Name"></state>
用法跟一般 Command or Mediator 處理 Notifications 一樣,將 exiting , entering , changed 狀態分別註冊到 Command 又或者直接在 Mediator 內處理通知。