Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I've a function taking quite a long time to perform and I'm trying to change the cursor to an hour glass during the time the function is executed. But it only works the very first time the function is called. I'm doing this (it's in an on_click event handler of a button):

from gi.repository import Gtk, Gdk, GObject
import time

def on_grabbtn_clicked(self, button):
    # Change the cursor to hour Glass
    cursor = Gdk.Cursor.new(Gdk.CursorType.WATCH)
    self.window.get_root_window().set_cursor(cursor)

    # lenghty process here
    time.sleep(10)

     # Set the cursor to normal Arrow
    cursor = Gdk.Cursor.new(Gdk.CursorType.ARROW)
    self.window.get_root_window().set_cursor(cursor)

window is a window build with Glade/GtkBuilder and named...window. I get a handle on it in the __init__() of the window class like this:

self.window = self.builder.get_object('window')

As I said, the hour glass appears only the first time I click on the button. The second time it doesn't work anymore. So I'm doing it wrong. But what Am I doing wrong ?

share|improve this question
1  
welcome to askubuntu. In the case of programming questions it would be extremely useful if you can provide a minimal program that shows the behaviour in question. SO: can you provide code that when run shows the cursor problem (pastebin.com)? –  xubuntix May 20 '12 at 6:47
    
Maybe a video of it running, and a step by step to replicate your progress will help others to figure it out, I would be willing to test if I could follow what you are doing better. –  Mateo May 20 '12 at 20:22
    
did some digging, looks like people have been having problems with time.sleep taking over or something. velocityreviews.com/forums/… this might be relevant stackoverflow.com/questions/5136266/… –  Mateo May 21 '12 at 14:34
    
get_root_window returns the window of the desktop in the background, you probably want get_window here. –  Flimm Nov 16 '12 at 17:31
add comment

1 Answer 1

Here's a working example of what you want.

You need to grasp the concept of what the GTK main loop does to understand why it is important to separate GUI manipulation code from long blocking code. Hopefully, the comments and the debugging statements in my example will help you understand. This PyGTK FAQ entry is useful, and the concept applies to Python with GTK3 and GObject introspection as well.

Example code:

This code creates a window with a simple button labelled "Click me". Once you click it, it will change to "Working", the cursor will become an hourglass, and the GUI will remain responsive. Once ten seconds have elapsed, the button label will change to "Done" and the cursor will return to normal.

import time
import threading

from gi.repository import Gtk, Gdk, GObject

window = None

def main():
    GObject.threads_init()
    Gdk.threads_init()

    # Build GUI:
    global window
    window = Gtk.Window()
    button = Gtk.Button(label="Click me")
    window.add(button)
    window.set_default_size(200, 200)
    window.show_all()

    # Connect signals:
    window.connect("delete-event", Gtk.main_quit)
    button.connect("clicked", on_button_click)

    Gtk.main()

def on_button_click(button):
    print "Debug on_button_click: current_thread name:", threading.current_thread().name

    # This is a callback called by the main loop, so it's safe to
    # manipulate GTK objects:
    watch_cursor = Gdk.Cursor(Gdk.CursorType.WATCH)
    window.get_window().set_cursor(watch_cursor)
    button.set_label("Working...")
    button.set_sensitive(False)

    def lengthy_process():
        print "Debug lengthy_process: current_thread name:", threading.current_thread().name
        # We're in a new thread, so we can run lengthy processes without
        # freezing the GUI, but we can't manipulate GTK objects except
        # through GObject.idle_add
        time.sleep(10)
        def done():
            print "Debug done: current_thread name:", threading.current_thread().name
            window.get_window().set_cursor(None)
            button.set_label("Done!")
            return False
        GObject.idle_add(done)

    thread = threading.Thread(target=lengthy_process)
    thread.start()

if __name__ == "__main__":
    main()
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.