Contents

Swinging Duke
Feedback Button
Left ArrowRight Arrow

 

Custom Cursors

In Swing, a custom cursor is a mouse cursor that uses an image supplied by an application. This specification explains how custom cursors are implemented in Swing. It does not contain material about any other kinds of cursors, such as text position cursors (also known as carets).


How Swing Implements Custom Cursors

In Swing, you can define a custom cursor by specifying two things: its source image and a hot spot. The source image is a java.awt.Image instance. Every cursor has a hot spot, which is used to define the single pixel a cursor is pointing to when the mouse is clicked. Specifically, a cursor's hot spot is expressed as an x, y offset from the top left corner of its source image. For example, if a cursor is displayed on the screen at coordinates 100, 200, and has a hot spot at source-image coordinates 2, 4, the mouse position is considered to be 102, 204.


Creating a Custom Cursor

The AWT supports custom cursors by creating them using the following new Toolkit method:

    /**
     * Creates a new custom cursor object.
     * @param image the image to display when the cursor is active.
     * @param hotSpot the X and Y of the large cursor's hot spot.  The
     * hotSpot values must be less than the Dimension returned by 
     * getBestCursorSize().
     * @param name a description of the cursor, for Java Accessibility use.
     * @exception IndexOutOfBoundsException if the hotSpot values are outside
     * the bounds of the cursor.
     */
    public Cursor createCustomCursor(Image cursor, Point hotSpot, String name)
        throws IndexOutOfBoundsException;

Swing's Cursor class currently supports only predefined system cursors, which are referenced by class constants such as DEFAULT_CURSOR and WAIT_CURSOR. These constants define the cursor's "type," and are returned by the getType() method. Cursors are created by specifying the desired cursor type. A new CUSTOM_CURSOR type will be added to Cursor (with a value of -1 to avoid conflicting with predefined cursor types), and all custom cursors will return the same type ID.

A Toolkit implementation doesn't have to support custom cursors, because it isn't practical to do so on some systems (handheld devices, for example). If it doesn't support custom cursors, that Toolkit's createCustomCursor() method should return an instance of DEFAULT_CURSOR. A program can verify whether a custom cursor was actually created by checking that the returned cursor's type is CUSTOM_CURSOR.


Cursor Size

Different systems support different sizes of cursors, either explicitly ( as the Macintosh) does or depending on the capabilities of the system's display driver (as in Win32 and X11). To determine what sizes are supported, Swing adds the following Toolkit method:

     Dimension getBestCursorSize(int desiredWidth, int desiredHeight);

Although many different cursor sizes are theoretically possible, most systems in use today support just two cursor sizes: either 32 pixels by 32 pixels or 16 by 16. An application that uses custom cursors should define them for (at least) both of these dimensions, and then use the appropriate one based on the dimension returned by getBestCursorSize(). Any width and height can be requested; this method returns the closest match. On many systems, that is the one supported size, but applications should not assume any specific cursor size.

If the image's size doesn't match a supported cursor size, the underlying system code attempts to scale the image to fit. Since this may result in a less-than-optimum representation of the original image (low-resolution scaling often distorts the image), it is strongly recommended that applications at least have 32-by-32 and 16-by-16 images of their cursor and use the one which is nearest to the values returned from getBestCursorSize().

The following code fragment shows how an application can pick the best cursor when three image sizes (64 by 64, 32 by 32, and 16 by 16) are available. (This example assumes that square cursors are being used). In this particular example, the largest cursor size is requested because it is the highest-resolution image. But an application can choose any size as a preferred size:

   Dimension cursorSize = 
        Toolkit.getDefaultToolkit().getBestCursorSize(64, 64);
    if (cursorSize.width > 32)
        myCursorImage = papaCursor;
    else if (cursorSize.width > 16)
        myCursorImage = mamaCursor;
    else
        myCursorImage = babyCursor;


Color Support

This section explains how Swing supports color in cursors.

Color Cursors

In the black-and-white era of the computer industry, cursor coloring was simple: There was black, white, transparent, and (sometime)s inverse. Today, different systems can have very different levels of support for color cursors. Many systems now support 256-color cursors, while some only support cursors that have only two visible colors and a transparent color. To support these various systems in a device-independent way, a method being added to the Toolkit returns the number of supported colors:

    int getMaximumCursorColors();

If an image that is to be used for a cursor has more colors than the system supports, the system attempts to map it to a smaller palette. Because that mapping might not result in the best possible image, it is strongly recommended that applications use getMaximumCursorColors() to pick an appropriate cursor.

One strategy is to have both color and black-and-white images available, and to fall back to black-and-white if too few colors are supported. In the following example, an application has a 256-color cursor and a black-and-white version. The developer here chooses to gamble that a 256-to-16 color flattening will still look reasonable, and so makes the following test:

   if (Toolkit.getDefaultToolkit().getMaximumCursorColors() >= 16)
        myCursorImage = colorCursor;
    else
        myCursorImage = bwCursor;

Transparent 'Color'

Although most cursors images are square, a mask is usually used to indicate which bits of that square are transparent. Java images support transparency. So, rather than requiring a separate mask image, AWT custom cursors will now use the transparent information from the image. Thus, the easiest way to create an image suitable for a custom cursor is to create a GIF file with a transparent color; of course, any other method of creating an AWT image with transparency can be used as well.

Inverse 'Color'

Inverse "color" was originally developed for character-based displays and was used to ensure that a cursor would be visible even if the background was the same color as the cursor. Today, not all platforms support inverse color (X11, for example). Therefore, AWT custom cursors do not offer any support for "inverse" bits in an image. This makes sense because today, the usual way to ensure that a cursor is always visible is to surround a cursor with a one-bit border of a contrasting color; for example, a white border around a black cursor.


Implementation

Each Toolkit implementation will now be required to implement the three Toolkit methods described in this specification, but are free to do so in whatever manner is most appropriate for the platform being used. Sun's implementations support custom cursors using new subclasses of java.awt.Cursor; for example, sun.awt.windows.WCursor on the Win32 platform. These new classes have methods for creating custom cursors, including methods for scaling images to supported cursor sizes and creating the transparency mask from the supplied image. They also store the native handle for the new cursor, and have a finalize() method to ensure the handle is released when the cursor is destroyed.

Arrows


Version 0.5. Last modified 09/04/97.
Copyright © 1995-97 Sun Microsystems, Inc. All Rights Reserved.

Sun's Home Page