Version 18 of custom cursors

Updated 2005-06-15 13:31:17 by lwv

TR The -cursor option of many Tk widgets not only allows you to choose from the builtin cursors but also to use your own creations.

Widgets can be configured with any of the following cursor definitions:

name ?fgColor? ?bgColor?

Name is the name of a cursor in the standard X cursor cursor, i.e., any of the names defined in cursorcursor.h, without the XC_. Some example values are X_cursor, hand2, or left_ptr. Appendix B of "The X Window System" by Scheifler & Gettys has illustrations showing what each of these cursors looks like. If fgColor and bgColor are both specified, they give the foreground and background colors to use for the cursor (any of the forms acceptable to Tk_GetColor may be used). If only fgColor is specified, then there will be no background color: the background will be transparent. If no colors are specified, then the cursor will use black for its foreground color and white for its background color.

The Macintosh version of Tk supports all of the X cursors and will also accept any of the standard Mac cursors including ibeam, crosshair, watch, plus, and arrow. In addition, Tk will load Macintosh cursor resources of the types crsr (color) and CURS (black and white) by the name of the of the resource. The application and all its open dynamic library's resource files will be searched for the named cursor. If there are conflicts color cursors will always be loaded in preference to black and white cursors.

@sourceName maskName fgColor bgColor

In this form, sourceName and maskName are the names of files describing cursors for the cursor's source bits and mask. Each file must be in standard X11 or X10 cursor format. FgColor and bgColor indicate the colors to use for the cursor, in any of the forms acceptable to Tk_GetColor. This form of the command will not work on Macintosh or Windows computers.

@sourceName fgColor

This form is similar to the one above, except that the source is used as mask also. This means that the cursor's background is transparent. This form of the command will not work on Macintosh or Windows computers.

@sourceName

This form only works on Windows, and will load a Windows system cursor (.ani or .cur) from the file specified in sourceName.


LV Anyone have pointers to a tcl/tk program that would create the .ani or .cur files?


Windows uses a .cur files and unix uses .xbm files.

 set dir /path/to/cursor/files

 switch -- $tcl_platform(platform) {
   unix {
     set file [file join $dir cursorfile.xbm]
     set cursor [list @$file black]
   }
   windows {
     set file [file join $dir cursorfile.cur]
     set cursor [list @$file]
   }
 }
 $widget configure -cursor $cursor

To accomplish this, you must specify the file, where the cursor lives:

 # windows:
 $widget configure -cursor "@path/to/cursorfile.cur"
 # unix:
 $widget configure -cursor "@path/to/cursorfile.xbm black"

the cursor will be displayed in the size it was defined.


Here is a 16x16 pixel cursor named hand.xbm:

 #define hand_width 16
 #define hand_height 16
 #define hand_x_hot 6
 #define hand_y_hot 0
 static unsigned char panPointer_bits[] = {
    0x00, 0x00, 0x80, 0x01, 0x58, 0x0e, 0x64, 0x12, 0x64, 0x52, 0x48, 0xb2,
    0x48, 0x92, 0x16, 0x90, 0x19, 0x80, 0x11, 0x40, 0x02, 0x40, 0x04, 0x40,
    0x04, 0x20, 0x08, 0x20, 0x10, 0x10, 0x20, 0x10 };

This file has two extra lines compared to "normal" xbm files that define where the so-called "hot spot" is. This is the point in the bitmap where a click event appears to come from. The coordinates count from left to right (x) and from top to bottom (y), just like the canvas coordinate system.


On Windows, there is a nice cursor named "no", which is unfortunately unavailable on Unix. Therefore here is a little xbm file which can be used as such:

 #define no_width 17
 #define no_height 17
 #define no_x_hot 8
 #define no_y_hot 8
 static unsigned char no_bits[] = {
   0x80, 0x03, 0x00, 0xf0, 0x1f, 0x00, 0xf8, 0x3e, 0x00, 0x3c, 0x70, 0x00,
   0x7e, 0xe0, 0x00, 0xfe, 0xc0, 0x00, 0xf6, 0xc1, 0x01, 0xe7, 0xc3, 0x01,
   0xc3, 0x87, 0x01, 0x87, 0xcf, 0x00, 0x06, 0xdf, 0x00, 0x06, 0xfe, 0x00,
   0x0e, 0xfc, 0x00, 0x1c, 0x78, 0x00, 0xf8, 0x3c, 0x00, 0xf0, 0x1f, 0x00,
   0x00, 0x05, 0x00 };

Save this text in a file named "no.xbm" and use

 .mywidget configure -cursor @path/to/no.xbm

to set the cursor. I wasn't able to figure out how to define a cursor "no", so that the setting of the cursor could be identical to using the "no" cursor on Windows.


On Windows you should always create your cursor files with a size of 32x32 pixels even if you do not need so much space. If you created a 16x16 pixel cursor (as with unix above) it would get enlarged by a factor of two when displayed. A windows cursor file can easily be created from a bmp or gif file by the free Windows program IconShop [L1 ] (yes, it can also create windows icons). The only problem is, you cannot specify your own hotspot. But since the cur file format is known, we can do that with Tcl. Thus:

 set cur [open myCursorFile.cur r+]
 fconfigure $cur -encoding binary -translation binary
 # this is the file position of the x coord of the hot spot:
 seek $cur 10
 # set x=6
 puts -nonewline $cur [binary format c 6]
 # dto. for the y coord of the hot spot:
 seek $cur 12
 # set y=0
 puts -nonewline $cur [binary format c 0]
 close $cur

Now you have a nice cursor for your Unix and Windows programs.


Who can tell what to do on MacOS?


Beware of an issue relating to many Windows OS's that have spaces in the path name of default installation locations. If a software package happens to be installed in such a place, the following will fail:

 set filename "C:/Program Files/MyApp/linkcursor.cur"
 . configure -cursor @$filename

As Jeff Hobbs pointed out in c.l.t. on 25-Jan-2004, the canonical mouse cursor specification is a proper Tcl list. Therefore, the following invocation must be used to succesfully load a mouse cursor from such places:

 set filename "C:/Program Files/MyApp/linkcursor.cur"
 . configure -cursor [list @$filename]

What would be the proper way to set filename in the previous example, making use of file join ?

LV I don't use Windows, but would think that something like:

 set filename [file join "C:/Program Files" MyApp linkcursor.cur]

would be close. I have been unsuccessful, to date, in finding a way to join the drive designator and first level directory without hard coding a slash.


Tk syntax help

Category GUI