web-dev-qa-db-fra.com

Comment changer le curseur en sablier dans une application python gtk3

J'ai une fonction qui prend beaucoup de temps à exécuter et j'essaie de changer le curseur en un sablier pendant l'exécution de la fonction. Mais cela ne fonctionne que la toute première fois que la fonction est appelée. Je fais ceci (c'est dans un gestionnaire d'événement on_click d'un bouton):

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 est une fenêtre construite avec Glade/GtkBuilder et nommée ... window. Je reçois une poignée dessus dans la __init__() de la classe window comme ceci:

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

Comme je l'ai dit, le sablier n'apparaît que la première fois que je clique sur le bouton. La deuxième fois, ça ne marche plus. Alors je le fais mal. Mais qu'est-ce que je fais mal?

4
Michel Leunen

Voici un exemple de travail de ce que vous voulez.

Vous devez comprendre le concept de la boucle principale GTK pour comprendre pourquoi il est important de séparer le code de manipulation d'interface graphique du code de blocage long. Espérons que les commentaires et les instructions de débogage de mon exemple vous aideront à comprendre. Cette entrée PyGTK FAQ est utile, et le concept s’applique également à Python avec l’introspection de GTK3 et de GObject.

Exemple de code:

Ce code crée une fenêtre avec un simple bouton intitulé "Cliquez-moi". Une fois que vous cliquez dessus, il passera à "Working", le curseur deviendra un sablier et l'interface graphique restera sensible. Une fois que dix secondes se sont écoulées, le libellé du bouton deviendra "Terminé" et le curseur reviendra à la normale.

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 __== "__main__":
    main()
3
Flimm