Home  >  

Flex 101: Flexing Mouse Cursors

Author photo
January 20, 2010 | | Comments (7)
AddThis Social Bookmark Button

You probably already knew that you have the ability to customize mouse cursors in Flex. Did you also know that you can make them animated and interactive, completely with ActionScript? In this post, we will have some fun exploring techniques and playing around with mouse cursors.

First, let's take a look at a few examples. Click on a button below to switch mouse cursors. The first button just restores the mouse cursor to the system default... nothing exciting there. The second button sets the mouse cursor to a static png image. Again, nothing special here.

The following buttons, however get a bit more interesting. Did you know that you can set the mouse cursor as ANY ActionScript class? You will need to extend from flash.display.Sprite in order for it to be visible, but inside that class, you can pretty much do anything that you want. The next button will show a a fairly simple cursor that is created programmatically in ActionScript. This is followed by a button that will add an animated mouse cursor, and finally a button that will add an interactive mouse cursor. In this case, the mouse cursor will hold on to the coordinates at mouseDown, and whenever the mouse moves, it will draw a line to the last mouse down coordinate. These are not necessarily *pretty* or *usable* cursors, they are simply techniques used to demonstrate the concepts. Go ahead and click around below to check it out...

The main CursorExplorer.mxml file is below. As you can see, it is an application that contains a few buttons. Each button just calls the setCursor function and passes in a class declaration for the appropriate mouse cursor.

CursorExplorer.mxml (main)

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
  xmlns:mx="http://www.adobe.com/2006/mxml" 
  layout="vertical"
  backgroundColor="#FFFFFF"
  backgroundGradientColors="[#FFFFFF]" 
  viewSourceURL="srcview/index.html">
  
  <mx:Script>
    <![CDATA[
      import cursors.InteractiveCursor;
      import cursors.AnimatedCursor;
      import cursors.SimpleCursor;
      import mx.managers.CursorManager;
      
            [Embed(source="assets/cursor.png")]
            public var staticCursor:Class;
            
            public function setCursor( cursorClass : Class ) : void
            {
               CursorManager.removeAllCursors();
               CursorManager.setCursor( cursorClass );
             }
            
    ]]>
  </mx:Script>
  
  <mx:Button label="Default Cursor"
         click="CursorManager.removeAllCursors();"/>
  <mx:Button label="Image Based Cursor"
         click="setCursor( staticCursor )"/>
  <mx:Button label="Simple Programmatic Cursor"
         click="setCursor( SimpleCursor );"/>
  <mx:Button label="Animated Programmatic Cursor"
         click="setCursor( AnimatedCursor );"/>
  <mx:Button label="Interactive Cursor"
         click="setCursor( InteractiveCursor );"/>
  
</mx:Application>

The first two buttons are straightforward and don't warrant any more explanation, so let's move on to the third button. In this case, the mouse cursor isn't necessarily interesting, however one thing to note is that it is completely rendered via ActionScript. The SimpleCursor class is below.

SimpleCursor.as

package cursors
{
   import flash.display.Sprite;
 
   public class SimpleCursor extends Sprite
   {
      public function SimpleCursor()
      {
         super();
         with (this.graphics)
         {
            lineStyle(1, 0, 1);
            beginFill( 0xFF0000, .5 );
            moveTo( 0,0 );
            lineTo( 20, 7 );
            lineTo( 10, 10 );
            lineTo( 7, 20 );
            lineTo( 0, 0 );
            endFill();
          }
       }
    }
}

The next example gets a little more interesting (if you are as easily entertained as I am). It is very similar to the previous example, except the cursor triangle is drawn within a child Sprite instance, and an enterFrame event listener is added. On each enterFrame event, the rotation property of the graphicsTarget sprite is incremented, thus rotating the mouse cursor around the tip.

AnimatedCursor.as

package cursors
{
   import flash.display.Sprite;
   import flash.events.Event;
 
   public class AnimatedCursor extends Sprite
   {
      private var graphicsTarget : Sprite;
      public function AnimatedCursor()
      {
         super();
         
         graphicsTarget = new Sprite();
         addChild( graphicsTarget );
         
         with (graphicsTarget.graphics)
         {
            lineStyle(1, 0, 1);
            beginFill( 0x0000FF, .5 );
            moveTo( 0,0 );
            lineTo( 20, 7 );
            lineTo( 10, 10 );
            lineTo( 7, 20 );
            lineTo( 0, 0 );
            endFill();
          }
         
         addEventListener( Event.ENTER_FRAME, onEnterFrame, false, 0, true );
       }
      
      private function onEnterFrame( event : Event ) : void
      {
         graphicsTarget.rotation += 2;
       }
      
    }
}

The next example takes things a little further, and adds an element of interactivity to the cursor. In this case, it adds event listeners to the stage, and the cursor itself responds to mouse events. In the example below, I had to use setTimeout to set a delay before the event listeners are added. Otherwise, you get a null object error when trying to reference the stage object.

InteractiveCursor.as

package cursors
{
   import flash.display.Sprite;
   import flash.events.MouseEvent;
   import flash.geom.Point;
   import flash.utils.setTimeout;
 
   public class InteractiveCursor extends Sprite
   {
      private var mouseDownPoint : Point = new Point(); 
      
      public function InteractiveCursor()
      {
         super();
         setTimeout( init, 1 );
         render();
       }
      
      private function init() : void
      {
         stage.addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown, false, 0, true );
         stage.addEventListener( MouseEvent.MOUSE_MOVE, onMouseMove, false, 0, true );  
         mouseDownPoint = new Point( stage.mouseX, stage.mouseY );
       }
      
      private function onMouseDown( event : MouseEvent ) : void
      {
         if ( stage )
           mouseDownPoint = new Point( stage.mouseX, stage.mouseY );
         render();
       }
      
      private function onMouseMove( event : MouseEvent ) : void
      {
         if ( mouseDownPoint )
           render();
       }
      
      private function render() : void
      {
         with (graphics)
         {
            clear();
          
            lineStyle(1, 0, 1);
            beginFill( 0x00FF00, .5 );
            moveTo( 0,0 );
            lineTo( 20, 7 );
            lineTo( 10, 10 );
            lineTo( 7, 20 );
            lineTo( 0, 0 );
            endFill();
            
            if ( mouseDownPoint )
            {
               moveTo( 0,0 );
               var local : Point = globalToLocal( mouseDownPoint );
               lineTo( local.x, local.y );
             }
          }  
       }
    }
}

As with all other techniques, these should be used tastefully, sparingly, and only in cases where they actually add benefit to the user experience and interactions. These examples are only intended to show (and exaggerate) techniques.

You can download the full source code online at:

http://tricedesigns.com/portfolio/cursorexplorer/srcview/index.html

Read more from Andrew Trice. Andrew Trice's Atom feed

Comments

7 Comments

David Stockton said:

Great example. One thing you might note with this example is that when using a custom cursor you loose the cursors completely when in the right-click menu.

Andrew Trice said:

Good point David. I hadn't even noticed that.

Arpit said:

You can listen to the event for context menu and make the default mouse appear. Once it closes, you can hide the default mouse

Victor said:

Very useful info.
I am also working with special mouse pointer events flex applications.
Do you know how to manage several mouse pointers?

Thanx.

nick said:

One small thing missing in this tutorial. Centering of custom cursor.

If you have let's say a crosshair cursor, you need to set the offset properly by two additional parameters like this:

CursorManager.setCursor( cursorClass,2,centerX,centerY );

Number 2 is default priority for the cursor manager. Hope it will help someone, this tut comes pretty high on google search.

sydd said:

Nice example, but it would be more useful if one could change the default cursors ( for example use a custom hand cursor on all links in your app ). As far as i know its not possible, and with this method you need to write cursor managing code for every component.

Minimum said:

You should not use timer to guess when stage is ready, but use the following:

this.addEventListener( Event.ADDED_TO_STAGE , stageReadyEvent );


Leave a comment


Type the characters you see in the picture above.


Tag Cloud

Technical Speakers

Who is the best technical speaker you have seen?

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.