Making a Cooler Cursor in Flex

Skip Intro

Preface

Creating custom cursors in Flex is pretty straightforward.  You call the CursorManager’s setCursor method, passing in your cursor as the first parameter, and you’re good to go.  It can be an image, a SWF, or a custom class; as long as it’s a DisplayObject, it’ll work.  However, some cursors are more dynamic than just animating to indicate a state, or showing some text to let the user know what’s happening.  Some can show some minor status of what is going on.  I say the word “minor” here to indicate that you can still operate the app, and the cursor should still imply you can click around the app, or indicate the type of interaction you can do.

For example, drawing tools applications will give you an eraser icon when you click it on a tool palette, indicating you can now erase, and when you click, you are erasing.  Some applications will show an hourglass to let you know the application is busy.  Others will show an hourglass + an arrow indicating that while the application is busy, you can still do other things.  This may seem a trivial difference, but sometimes things happening in the app ARE trivial enough, that devoting a section of the application real-estate for them isn’t worth it.

Such was the case in one of my projects.  We have a playback mode that plays back a series of images.  Each image has to download first before the timer starts, and a new image is shown.  Some images can take longer than others depending on their file size, time of day, and even potentially loading more than 1 image.  The whole time, we’re in a playback mode.  The interface itself is being driven by a timer, but the user can interact with it if they so choose.

The problem I ran into was that Flex CursorManager treats a cursor as a read-only object, in effect just an image.  If you wish to represent a variety of minor states, you need a variety of many different cursors.  This made the code nasty because I had to keep track of all those cursor ID’s (numbers you utilize to remove cursors later).  What I really needed was one cursor that could dynamically update it’s state.  Those types of things in Flex and Flash are called components… so why couldn’t I create a cursor component?  Like a lot of the fun things in Flex, the actual cursor class reference is private.

Monkey Patching Flex

But what if it wasn’t?  My past article on creating a cooler preloader utilized existing Flex functionality.  As you create more design heavy applications in Flex 3 or 2, you’ll find that the Flex SDK code sometimes has to be modified for you to complete your tasks vs. extended.  These are sometimes called “Monkey Patches“.  The code is open source, so you’re legally allowed to do this.  Additionally, some of your patches and/or bug fixes could be contributed back into the main Flex SDK trunk, thus helping the community.

This isn’t one of those things that would make it past QA, but if you have a need of a dynamic cursor, you have to hack it since the variable you need is private.  Hacking Flex classes is pretty easy.  Many people have done it to fix bugs, or to add useful debugging functionality on top of the existing framework.  Flash, JavaScript, and Ruby developers have been doing this for years to extend their language and frameworks.  This is especially true in more dynamic languages where, by their very nature being dynamic, and potentially used in a short deadline environment encourages hacking to get something to work… or just working they way you think it should work.

It’s really easy to do this in Flex. You just copy the class(es) you wish to modify into your source path including their dependencies (for example Version.as) and modify them.  That’s it!  Both the Flex and Flash compiler (in case you’re hacking Flash CS3/CS4 components and have deleted your SWC’s) will use local class paths over the  main built-in ones.

Hacking CursorManager

Why not just create a cursor the old fashion Flash way?  Just make a MovieClip, attach to root, hide the mouse, and have the MovieClip follow the mouse via the stage’s MouseEvent.MOVE?  By doing so, you’re excluding a lot of functionality that the CursorManager gives you.  If you choose to go the old fashioned route, ensure you realize what you are giving up, and what you are getting yourself into (ability to set multiple cursors with different priority levels, built-in busy cursor responding automatically to web services, already built-in depth management that works with existing depths of tooltips and pop-ups, etc.).

So if we create a custom cursor class, what do we have to modify in Flex to allow us to have fun?  4 modifications in 2 classes and an interface.

  • mx.managers.CursorManager
  • mx.managers.CursorManagerImpl
  • mx.managers.ICursorManager

First, you need to add the currentCursor variable in the CursorManager class since he provides no access to the internal implementations’ copy.

public static function get currentCursor():DisplayObject { return _impl.currentCursor; }

Second, in CursorManagerImpl you need to do a find and replace (wrap search + case sensitive + whole word) on the currentCursor variable, changing it to _currentCursor.  We’re going to make a public getter for it, and the underscore follows the Flex coding conventions.  Even hackers have guidelines.  So this:

private var currentCursor:DisplayObject;

Becomes this:

private var _currentCursor:DisplayObject;

Third, you need to add a public getter function:

public function get currentCursor():DisplayObject { return _currentCursor; }

Fourth, add a function signature to the ICursorManager:

function get currentCursor():DisplayObject;

Voila!  You can now immediately get access to your cursor after setting it.  Keep in mind if you are using many different cursors with many different priority levels, the currentCursor may not be who you think he is… but then, why are you hacking CursorManager for the sole purpose of using 1 dynamic cursor only to then use multiples?  Besides, even if you are because your project is large, you can still test the currentCursor’s type, or even extend the CursorManager more to allow access to cursors as they come available, perhaps by dispatching custom events.

Simple Cross-hair Cursor in Action

Here’s a simple cross-hair cursor I built in Flash.  It’s a cross with 2 TextFields inside a MovieClip.  Inside Flex, I then update the TextField’s text value with the x and y coordinates of your mouse when you move it.

You just create your cursor in Flash as a MovieClip, create a wrapper class (or perhaps just a variable), and set that class / variable to the CursorManager.setCursor’s first parameter.

Creating the cursor in Flash is pretty straightforward; make sure to give your dynamic TextFields on stage instance names:

Custom Cursor 01

It doesn’t matter what you give it for a class name; all you’re doing is exporting the MovieClip/Sprite symbol and it’s contents.  You’ll write the actual code for it elsewhere.  The only thing you’re class will do is expose the TextField’s as public variables so you can actually access them in Flex.  Also, keep in mind the registration point is where your cursor will be.  In the CursorCrosshair.fla, you can see how I moved the cursor to -10 by -10 pixels to ensure the cross is exactly where the mouse cursor would usually be.  You can change it in Flex programmatically with offsets, but I find offsets confusing; just do it right in your graphics and you’re good to go, no thinking involved.

package
{
        import flash.display.Sprite;
        import flash.text.TextField;

        [Embed(source="CursorCrosshair.swf", symbol="CrosshairCursor")]
        public class CrosshairCursor extends Sprite
        {
                public var xValue:TextField;
                public var yValue:TextField;

                public function CrosshairCursor()
                {
                        super();
                }

        }
}

To instantiate it in Flex, you pass the class itself to the CursorManager like so:

CursorManager.setCursor(CrosshairCursor, CursorManagerPriority.HIGH);

You can then immediately snag a reference to it:

private var cursor:CrosshairCursor;
cursor = CursorManager.currentCursor as CrosshairCursor;

Finally, you can then update your TextField values.  I listen for a mouse move, and set their values to the stage’s mouse x and y:

this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);

private function onAddedToStage(event:Event):void
{
        stage.addEventListener(MouseEvent.MOUSE_MOVE, onILikeToMoveItMoveItILikeTooooooooMOVEIT);
}

private function onILikeToMoveItMoveItILikeTooooooooMOVEIT(event:MouseEvent):void
{
        cursor.xValue.text = stage.mouseX.toString();
        cursor.yValue.text = stage.mouseY.toString();
        event.updateAfterEvent();
}

Cursor’s as UIComponents

You’ll notice the cursor above extends Sprite.  What if, however, you’re cursor is more dynamic, and you decide you want to extend UIComponent instead to ensure you get invalidation routines?  There is one problem with this, and that is that CursorManager utilizes FlexSprite as the master holder for cursors.  While UIComponents extend FlexSprite, and he in turn extends Sprite, FlexSprite is missing all understanding of how UIComponents work.  Case in point, if you add your UIComponent to a Flex sprite, none of his initial setup will get run (createChildren, commitProperites, etc.).  The easy fix to this is one more hack.  You change cursorHolder in CursorManagerImpl to a UIComponent instead of a FlexSprite:

private var cursorHolder:UIComponent;

That way, if you create cursors that extend UIComponent… they’ll actually work.  Here’s an example of one.  It utilizes 2 classes instead of 1.

I won’t go into the details of why, as I’ve covered this twice in the past, but suffice it to say that Flash will sometimes export your Symbol class as a Sprite instead of MovieClip.  If it only see’s one frame in your component, it’ll optimize it, and extend Sprite instead.  The problem with Sprite is he is not a dynamic class like MovieClip, and thus you can’t “magically” access components that you drag onto stage.  So, the best practices is to embed your symbol to a class with a “Symbol” suffix on its name, define the variables (similar to un-checking “automatically delcare stage instances”), and then embed that class via composition that does not have the “Symbol” suffix on its name.

In this case, I have a makeshift progress bar with an instance name of “preloadBar”:

Custom Cursor 02

I want to be able to access that MovieClip via code, so I define him in the PlaybackCursorSymbol class, as well as immediately call stop() on him in the constructor (no frame code FTW).

package
{
        import flash.display.MovieClip;
        import flash.display.Sprite;

        [Embed(source="CursorPlayback.swf", symbol="PlaybackCursor")]
        public class PlaybackCursorSymbol extends Sprite
        {

                public var preloadBar:MovieClip;

                public function PlaybackCursorSymbol()
                {
                        super();
                        preloadBar.stop();
                }

        }
}

The wrapper class, PlaybackCursor, can then dynamically update the current frame this MovieClip is on:

var percent:uint = Math.round((value / 100) * 100);
if(percent == 0) percent = 1;
cursor.preloadBar.gotoAndStop(percent);

Conclusions

Hopefully you can see how you can easily create your own custom cursors by doing some extremely minor changes to CursorManager.  While you don’t need to utilize Flash, for laying the small graphical, yet dynamic elements that can make up cursors, it just makes it easier. The FLA’s in the source files are saved using Flash CS3.

Crosshair CursorSee It | Source | Download

Playback CursorSee It | Source | Download

11 Replies to “Making a Cooler Cursor in Flex”

  1. Nice, although I thought there must be a way to do it without monkeypatching CursorManagerImpl. Now we just need to figure out the voodoo Adobe uses to embed the system cursor in cursor symbols :) The .fla file for the framework contains what looks like the OSX cursor, but under Windows their drag cursors look like normal (plus the little drag status icon) AFAIK.

  2. Wow, that’s pretty damn cool. I love the idea with the progress bar actually being on the cursor.

    I wonder how well this all transfers to AIR applications…

  3. Nice post!
    I wonder when we can define custom cursors for different components through css like in html…

  4. I’m doing a whiteboard in Flex, and I need to have some cursors on my stage. It would be possible to show 2 or 3 or more cursors using this method?. If wouldn’t, what can I do?

  5. very nice, I can not do the “monkey patch” but a singleton object/class extending FlexSprite works just fine.
    Dynamic cursor, nice.

  6. Nice work. Since u seem to be a cursor expert I have a question in case u want to help ;) How can I add an event listener on my main app for detecting when cursor changes to busy?
    Thanks in advance

Comments are closed.