遇到一個問題是,想要自訂 Flex App 的 Cursor 可是又要能存取 Cursor 實體
以便做其他的動態控制
可是 Flex CursorManager 基本上是不允許這樣做的
只能以 Class 方式設定 Cursor,也無法存取到目前 Cursor 實體
網路上有人提過解決方式 Jesse Warden – Making a Cooler Cursor in Flex
可是他是藉由 Hack CursorManager 方式做到
實際用 Flex 4.5 測試,發現只要將編譯模式從 Merged into code 改為 RSL
這個方法就失效了,只好自行另外想辦法

觀察 StyleManager 實作,發現 Cursor 實體是放在 systemManager.cursorChildren > cursorHolder 內
於是想到可以自行指定空的 Sprite 作為 Cursor,然後自行取出 Cursor 實體
另外再加以控制

CustomCursorPanel1.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx"
  width="400" height="300" title="Custom Cursor Panel 1"
  rollOver="onRollOverHandler(event);"
  rollOut="onRollOutHandler(event);">
 <fx:Declarations>
  <flash:TextField id="cursorTxt" xmlns:flash="flash.text.*" border="true" autoSize="left" />
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import mx.core.IChildList;
 
   protected var cursorID:int;
 
   public function onRollOverHandler(e:MouseEvent):void{
    cursorID = cursorManager.setCursor(Sprite);
 
    var cursorChildren:IChildList = systemManager.cursorChildren;
    if (!cursorChildren) return;
    var cursorHolder:Sprite = cursorChildren.getChildByName("cursorHolder") as Sprite;
    if (!cursorHolder || !cursorHolder.numChildren) return;
    var cursor:Sprite = cursorHolder.getChildAt(0) as Sprite;
    if (!cursor) return;
    cursor.addChildAt(cursorTxt, 0);
 
    addEventListener(MouseEvent.MOUSE_MOVE, onMouseEventHandler);
    addEventListener(MouseEvent.MOUSE_DOWN, onMouseEventHandler);
    addEventListener(MouseEvent.MOUSE_UP, onMouseEventHandler);
   }
 
   public function onRollOutHandler(e:MouseEvent):void{
    cursorManager.removeCursor(cursorID);
    removeEventListener(MouseEvent.MOUSE_MOVE, onMouseEventHandler);
    removeEventListener(MouseEvent.MOUSE_DOWN, onMouseEventHandler);
    removeEventListener(MouseEvent.MOUSE_UP, onMouseEventHandler);
   }
 
   public function onMouseEventHandler(e:MouseEvent):void{
    cursorTxt.text = e.type + " ("+ e.localX + " : " + e.localY + ")";
   }
  ]]>
 </fx:Script>
</s:Panel>

CustomCursorPanel1 實際範例

This movie requires Flash Player 9

不過缺點是萬一 CursorManager 實作方式大改可能就會失效了
所以又想了另一個方式
實做一個 CursorProxy 類別

package com.ticore.utils  {
 import flash.display.DisplayObject;
 import flash.display.Sprite;
 
 /**
  * 提供一個 proxy 類別,給 Flex CursorManager 設定 cursor
  * CursorProxy 另外宣告一靜態的 getter/setter 供存取 cursor 實體
  * 每次 CursorProxy 實體被創建時,都會將靜態 cursor 實體加入自己 display list 下
  * 
  * @author Ticore Shih
  */
 public class CursorProxy extends Sprite {
 
  static protected var _cursor_:DisplayObject;
 
  static public function get cursor():DisplayObject{
   return _cursor_;
  }
 
  static public function set cursor(value:DisplayObject):void{
   _cursor_ = value;
   if (!_cursorProxy_) return;
   while (_cursorProxy_.numChildren) {
    _cursorProxy_.removeChildAt(0);
   }
   _cursorProxy_.addChild(_cursor_);
  }
 
 
  static protected var _cursorProxy_:CursorProxy;
 
  public function CursorProxy() {
   _cursorProxy_ = this;
   if (_cursor_) _cursorProxy_.addChild(_cursor_);
  }
 }
}

使用範例如下 CustomCursorPanel2.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx"
  width="400" height="300" title="Custom Cursor Panel 1"
  rollOver="onRollOverHandler(event);"
  rollOut="onRollOutHandler(event);">
 <fx:Declarations>
  <flash:TextField id="cursorTxt" xmlns:flash="flash.text.*" border="true" autoSize="left" />
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import com.ticore.utils.CursorProxy;
   import mx.core.IChildList;
 
   protected var cursorID:int;
 
   public function onRollOverHandler(e:MouseEvent):void{
 
    cursorID = cursorManager.setCursor(CursorProxy);
    CursorProxy.cursor = cursorTxt;
    addEventListener(MouseEvent.MOUSE_MOVE, onMouseEventHandler);
    addEventListener(MouseEvent.MOUSE_DOWN, onMouseEventHandler);
    addEventListener(MouseEvent.MOUSE_UP, onMouseEventHandler);
   }
 
   public function onRollOutHandler(e:MouseEvent):void{
    cursorManager.removeCursor(cursorID);
    removeEventListener(MouseEvent.MOUSE_MOVE, onMouseEventHandler);
    removeEventListener(MouseEvent.MOUSE_DOWN, onMouseEventHandler);
    removeEventListener(MouseEvent.MOUSE_UP, onMouseEventHandler);
   }
 
   public function onMouseEventHandler(e:MouseEvent):void{
    cursorTxt.text = e.type + " ("+ e.localX + " : " + e.localY + ")";
   }
  ]]>
 </fx:Script>
</s:Panel>

CustomCursorPanel2 實際範例

This movie requires Flash Player 9

原始檔案下載