2010-08-17 3 views
7

Von dem, was ich über verdreht verstehe, sollte nichts im Reaktor Thread blockieren. Alle blockierenden Aktivitäten sollten an andere Threads delegiert werden, um Callbacks in den Reaktor-Thread zurück zu schreiben, wenn sie fertig sind.twisted + gtk: sollte ich GUI-Dinge in Threads oder im Reaktor Thread laufen lassen?

Also gilt das auch für GTK-Dinge? Ich möchte zum Beispiel eine Meldung "Verbindung fehlgeschlagen" anzeigen, wenn die Verbindung fehlgeschlagen ist. Muss ich tun:

def connectionFailed(self, reason): 
    dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, 
         buttons=gtk.BUTTONS_CLOSE, 
         message_format="Could not connect to server:\n%s" % (
          reason.getErrorMessage())) 
    dlg.run() 

oder:

def connectionFailed(self, reason): 
    dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, 
         buttons=gtk.BUTTONS_CLOSE, 
         message_format="Could not connect to server:\n%s" % (
          reason.getErrorMessage())) 
    reactor.callInThread(dlg.run) 

oder:

def connectionFailed(self, reason): 
    def bloogedy(): 
     dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, 
          buttons=gtk.BUTTONS_CLOSE, 
          message_format="Could not connect to server:\n%s" % (
           reason.getErrorMessage())) 
     dlg.run() 
    reactor.callInThread(bloogedy) 

?

EDIT: Ooh ok, die letzten beiden wirklich durcheinander. also denke ich, die Antwort ist die erste. Dann ist meine Frage: warum? Es scheint, als würde dies den Reaktorfaden blockieren.

Antwort

10

Ihr Problem hat eigentlich nichts mit Threads und GUIs zu tun. Sie sollten Twisted und GTK immer aus demselben Thread verwenden: Sie müssen nicht anders vorgehen.

Ihr Problem ist, dass Sie gtk.Dialog.run() verwenden. Dies ist eine API, die Sie nie verwenden sollten, Twisted oder nicht. Es wird eine wiederkehrende Hauptschleife ausgeführt, die den aktuellen Ereignishandler blockiert, aber anderen Ereignishandlern erlaubt, eine Ebene im Stapel auszuführen. GTK hat eine hervorragende Unterstützung für Hauptschleifen, aber Twisted nicht (und das ist in Ordnung, denn wie ich sagte, sollten Sie sie nicht verwenden).

MessageDialog.run funktioniert sowieso nicht in einem Thread, so dass Sie diese Option eigentlich nicht haben. Dies führt zu unvorhersehbarem Verhalten, das dazu führen kann, dass sich Ihre Anwendung merkwürdig verhält oder abstürzt. GTK hat feine Unterstützung für Threads, aber es gibt Dinge, die Sie nie mit einem Thread tun sollten, weil es keinen Sinn ergibt, und das ist einer von ihnen.

Wenn Sie mit Code arbeiten, der keine Verarbeitung durchführt, sondern nur auf etwas warten möchte (z. B. warten, bis ein Benutzer eine Schaltfläche in einem Dialogfeld drückt), sollten Sie Funktionen verwenden, die Deferred s zurückgeben keine Fäden. Wie es passiert, gtk.Dialog s wird ein Signal an dem Punkt, an dem sie beantwortet werden: "response". Sie können dies verwenden, um eine sehr einfache Funktion zu verkabeln, die Ihre Nachricht mit einem Dialog anzeigt und nach Abschluss einen Deferred zurückgibt. Hier ein Beispiel:

def showMessage(text): 
    mdlg = gtk.MessageDialog(type=gtk.MESSAGE_INFO, 
          buttons=gtk.BUTTONS_CLOSE, 
          message_format=text) 
    result = Deferred() 
    def response(dialog, response_id): 
     mdlg.destroy() 
     result.callback(response_id) 
     return False 
    mdlg.connect("response", response) 
    mdlg.show_all() 
    return result 
+0

ah beginnt, die mehr Sinn macht. Ich ahnte, dass es etwas mit 'run()' zu tun hatte. Defereds sind definitiv der richtige Weg. – Claudiu

0

Aus meiner Erfahrung mit Gtk + ist die beste Option, GUI in einem separaten Thread auszuführen. Sie können mit dem GUI-Thread arbeiten, indem Sie Funktionen in der Gtk + -Main-Schleife ausführen (mittels der Funktion idle_add). Ich weiß nichts über Reaktor, aber von Ihren Beispielen scheint es, dass die gleiche Art der Kommunikation von GUI möglich ist.

Eg, so (sorry, ich habe den Code nicht getestet):

def connectionFailed(self, reason): 
    def frob(): 
     dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, 
          buttons=gtk.BUTTONS_CLOSE, 
          message_format="Could not connect to server:\n%s" % (
           reason.getErrorMessage())) 
     dlg.run() 
    gobject.idle_add(frob) 

(neben diesem Code Gtk.main wird auf einem eigenen Thread hat zu laufen)

Diese wird die Frob-Funktion in Gtk + -Faden ausführen und den Reaktorfaden nicht blockieren.

Dies startet Gtk + in separaten Thread:

import threading 
import pygtk 
pygtk.require('2.0') 
import gtk 
import gobject 
def gtk_thread(): 
    gtk.main() 
threading.Thread(target=gtk_thread) 

Wenn Sie einige komplexe GUI-Interaktionen benötigen, werden Sie continuation-passing style

Programm bearbeiten müssen mit: added Beispiel für Lauf Gtk + in separaten thread

+0

Wie führe ich die GUI in einem anderen Thread? Ich habe 'gtk2reactor.install()' gemacht und diesen Reaktor benutzt. Ich hatte große Probleme, als ich versuchte, twisted + gtk ohne zu verwenden. – Claudiu

+0

Ich habe die Nachricht bearbeitet, um Code enthalten, der Gtk + in separaten Thread –

0

Obwohl es nicht und nicht unterstützt empfohlen, mit Twisted-10.x scheint es, dass der folgende Code wird es möglich, über die Verwendung Gtk.main zu halten()/dialog.run()

gobject.idle_add(lambda *x: reactor.runUntilCurrent()) 
    reactor.startRunning()  
    dialog.run() 
Verwandte Themen