Aqui está um exemplo prático do que você quer.
Você precisa compreender o conceito do que o loop principal do GTK faz para entender por que é importante separar o código de manipulação da GUI do código de bloqueio longo. Espero que os comentários e as instruções de depuração no meu exemplo ajudem você a entender. Esta entrada de FAQ do PyGTK é útil, e o conceito se aplica ao Python com GTK3 e GObject introspecção também.
Exemplo de código:
Este código cria uma janela com um simples botão chamado "Clique-me". Depois que você clicar nele, ele será alterado para "Trabalhando", o cursor se tornará uma ampulheta e a GUI permanecerá responsiva. Decorridos dez segundos, o rótulo do botão mudará para "Concluído" e o cursor retornará ao 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()