FAQ Index - Search - Recent Changes - Everything - Add entry

<< Previous Entry | FAQ Entry 5.6 | Next Entry >>

5.6. How do I change the cursor for a certain widget?

Changing the cursor is remarkably easy in pygtk:

To change it for a button,

 def realize_cb(widget):
   b.window.set_cursor(watch)

 b = gtk.Button()
 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 b.connect("realize", realize_cb)
And to change it back to normal:

 b.window.set_cursor(None)
To make an invisible cursor (aka hide the cursor), you can use this code:

 pix_data = """/* XPM */
 static char * invisible_xpm[] = {
 "1 1 1 1",
 "       c None",
 " "};"""
 color = gtk.gdk.Color()
 pix = gtk.gdk.pixmap_create_from_data(None, pix_data, 1, 1, 1, color, color)
 invisible = gtk.gdk.Cursor(pix, pix, color, color, 0, 0)

 b.window.set_cursor(invisible)
To change it for a label, which lacks its own gdk.Window, for instance:

 boat = gtk.gdk.Cursor(gtk.gdk.BOAT)

 b = gtk.EventBox()
 l = gtk.Label()
 b.add(l)
 b.window.set_cursor(boat)
Note that the widget may already define a cursor: for instance, GtkEntry defines an I-bar for the cursor. X allows you to set a cursor on each gdk.Window, and if a window doesn't have a cursor associated with it, it gets the parent window's cursor.

To change the cursor for all the widgets, you'd need to recurse into all child widgets and set_cursor() on their gdk.Windows.

However, there is an other way, that can be implemented using some gdk.Window functions. For details, read: [www.daa.com.au]

It is also worth noticing that some widgets are composed of multiple X windows. gtk.Entry is an example -- see FAQ 14.3 (you can use the gdk.Window's children() method to get its child windows). Another example is TextView, described in FAQ 14.15.

The constants for icons defined in gtk.gdk are:

 X_CURSOR            ARROW                BASED_ARROW_DOWN
 BASED_ARROW_UP      BOAT                 BOGOSITY
 BOTTOM_LEFT_CORNER  BOTTOM_RIGHT_CORNER  BOTTOM_SIDE
 BOTTOM_TEE          BOX_SPIRAL           CENTER_PTR
 CIRCLE              CLOCK                COFFEE_MUG
 CROSS               CROSS_REVERSE        CROSSHAIR
 DIAMOND_CROSS       DOT                  DOTBOX
 DOUBLE_ARROW        DRAFT_LARGE          DRAFT_SMALL
 DRAPED_BOX          EXCHANGE             FLEUR
 GOBBLER             GUMBY                HAND1
 HAND2               HEART                ICON
 IRON_CROSS          LEFT_PTR             LEFT_SIDE
 LEFT_TEE            LEFTBUTTON           LL_ANGLE
 LR_ANGLE            MAN                  MIDDLEBUTTON
 MOUSE               PENCIL               PIRATE
 PLUS                QUESTION_ARROW       RIGHT_PTR
 RIGHT_SIDE          RIGHT_TEE            RIGHTBUTTON
 RTL_LOGO            SAILBOAT             SB_DOWN_ARROW
 SB_H_DOUBLE_ARROW   SB_LEFT_ARROW        SB_RIGHT_ARROW
 SB_UP_ARROW         SB_V_DOUBLE_ARROW    SHUTTLE
 SIZING              SPIDER               SPRAYCAN
 STAR                TARGET               TCROSS
 TOP_LEFT_ARROW      TOP_LEFT_CORNER      TOP_RIGHT_CORNER
 TOP_SIDE            TOP_TEE              TREK
 UL_ANGLE            UMBRELLA             UR_ANGLE
 WATCH               XTERM                CURSOR_IS_PIXMAP
Also if you plan to do anything time consuming and want to use the watch cursor you have to be careful that you don't starve the gui thread before it can change the cursor, e.g.

 ## This Will Not Work ##
 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 gtk_window.set_cursor(watch)
 time.sleep(10)             # your time consuming operation here
 gtk_window.set_cursor(None)
instead call the time consuming in an idle callback (or in a different thread if you absolutely have to)...

 def idle_cb(gtk_window):
    time.sleep(10)             # your time consuming operation here
    gtk_window.set_cursor(None)

 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 gtk_window.set_cursor(watch)
 gobject.idle_add(idle_cb, gtk_window)

PyGTK FAQ Wizard | PyGTK Homepage | Feedback to faq at pygtk.org