Startet wx.App einen eigenen Thread ?
Also ist die Mainloop dann ein eigener Thread ?
Wenn ja, dann wuesste ich endlich warum ein paar Sachen mit GUI-Aktualisierungen nicht funktionieren.
Weil die GUI Elemente sind ja nicht Threadsafe, und wenn die GUI Elemente nicht in der App verwaltet werden, wuerde dass ja bedeuten, dass ein Thread parallel zu App versucht, Gui komponenten zu aktualisieren, was natuerlich zu problemen fuehrt.
Wenn nicht, habe ich immer noch ein grosses Verstaendnisproblem, aber das kann ich ja dann immer noch darstellen
edit: also laut meinen Tests ist das die einzige erklaerung
beispiel ist mein anderer Thread mit dem Progressdialog
Mach ich ne Klasse, die von App oder PySimpleApp abgeleitet ist und lasse diese Klasse das MainFrame erzeugen und dieses mainframe wiederum den Progressdialog, so laeuft alles einwandfrei
laeuft App quasi parallel dazu (also mainframe wird im hauptprogramm erzeugt und der progressdialog damit auch), so haengt es sich beim ProgressDialog.Destroy() auf
Verständnisfrage:
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Nein. Wenn du den Python-Interpreter startest, dann hast du automatisch einen Prozess mit einem Thread. Wenn du in diesem die Mainloop startest, dann läuft die Schleife in diesem einem Thread und die Ausführung hängt in der Schleife.maxip hat geschrieben:Startet wx.App einen eigenen Thread ?
Also ist die Mainloop dann ein eigener Thread ?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo maxip!maxip hat geschrieben:Startet wx.App einen eigenen Thread ?
Also ist die Mainloop dann ein eigener Thread ?
Startest du ein Python-Programm (egal welches), dann läuft dieses in einem Thread. Ich nenne ihn jetzt mal Hauptthread.
wxPyhon-Programme sind da nicht anders gestrickt. Dort wo du die App-erstellst (initialisierst), dort, in diesem Thread läuft die wxPython-GUI. Und das ist normalerweise (ich kenne nur sehr wenige Ausnahmen) der Hauptthread.
Code: Alles auswählen
import wx
app = wx.PySimpleApp()
f = wxFrame(None)
f.Show()
app.MainLoop()
Kommt das Python-Programm nie zur ``app.MainLoop()``-Zeile, dann funktioniert auch das Eventsystem von wxPython nicht. Es ist also wichtig, dass man beim Starten des Programms das Programm auch wirklich bis zu dieser Zeile kommen lässt.
Will man jetzt trotzdem, während das Programm in der wxPython-MainLoop läuft, "Arbeit" durchführen, die den Aufbau der GUI bzw. die MainLoop unterbricht, dann muss diese Arbeit in einen zusätzlichen Thread ausgelagert werden.
Es gibt manchmal eine Alternative. Man kann, kurz dauernde Arbeiten periodisch über einen Timer aufrufen. Die vom Timer aufgerufene Funktion läuft in einem neuen Thread.
In allen Fällen muss man die Threads trennen und darf nicht von einem Thread aus auf wxPython-Objekte zugreifen und diese verändern. --> ``wx.CallAfter()``
Mehr fällt mir jetzt nicht ein.
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Stimm das wirklich? Ich dachte immer, man könnte aus einem Timer-Event ganz normal auf die GUI zugreifen.gerold hat geschrieben:Es gibt manchmal eine Alternative. Man kann, kurz dauernde Arbeiten periodisch über einen Timer aufrufen. Die vom Timer aufgerufene Funktion läuft in einem neuen Thread.
In allen Fällen muss man die Threads trennen und darf nicht von einem Thread aus auf wxPython-Objekte zugreifen und diese verändern. --> ``wx.CallAfter()``
MfG
HWK
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo HWK!HWK hat geschrieben:Stimm das wirklich? Ich dachte immer, man könnte aus einem Timer-Event ganz normal auf die GUI zugreifen.
Ich bin mit der Aussage
ein wenig über das Ziel herausgeschossen. Diese Aussage von mir stimmt nicht.gerold hat geschrieben:Die vom Timer aufgerufene Funktion läuft in einem neuen Thread.
Richtig ist: Ein Timer löst ein Event aus und das Event wird abgearbeitet, wie alle anderen Events auch. Der Event-Handler (die aufgerufene Funktion) läuft also nicht in einem eigenen Thread. Und somit ist der Event-Handler des Timers für lange laufende Arbeiten, welche den Aufbau der GUI verhindern können, ungeeignet.
Wenn man aber in der mit dem Timer aufgerufenen Funktion, der MainLoop immer wieder Zeit zum Arbeiten lasst (z.B. mit ``wx.YieldIfNeeded()``), dann kann sich die MainLoop erholen, die GUI neu aufbauen und auch auf Tastendrücke reagieren.
Wie komfortabel das GUI-Verhalten ist, hängt dann direkt davon ab, wie oft man ``wx.YieldIfNeeded()`` ausführen kann und wie sehr die Arbeit den Computer auslastet.
Diese Probleme gibt es nicht, wenn man die Arbeit in einen Thread auslagert. Man muss dann zwar mit ``wx.CallAfter`` arbeiten, aber die MainLoop wird nie unterbrochen und das Programm reagiert wie gewohnt auf Eingaben und baut sich automatisch neu auf.
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Hi,
kannst du mir dann nochmal erklaeren, warum deine Version fuktioniert und meine sich aufhaengt ?
http://www.python-forum.de/topic-14581.html
Der einzige Unterschied ist doch, dass du von wx.App ableitest und das Frame sozusagen in der App verankerst und ich das nicht tue.
Ansonsten ist doch alles vom Prinzip her gleich ?
kannst du mir dann nochmal erklaeren, warum deine Version fuktioniert und meine sich aufhaengt ?
http://www.python-forum.de/topic-14581.html
Der einzige Unterschied ist doch, dass du von wx.App ableitest und das Frame sozusagen in der App verankerst und ich das nicht tue.
Ansonsten ist doch alles vom Prinzip her gleich ?
Du darfst nicht direkt aus einem anderen Thread auf die GUI zugreifen. Das funktioniert bei keinem mir bekannten GUI-Toolkit.
Deine ``runWork``-Funktion wird einem eigenen Thread ausgeführt. Also darfst du dort ``_pd.Update(i)`` und ``_pd.Destroy()`` nicht machen, und musst sie stattdessen indirekt durch ``wx.CallAfter``(``gobject.idle_add`` bei gtk) aufrufen. Wenn wx dann wieder die Event-Schleife abarbeitet, wird die übergebene Funktion *im Mainloop-Thread* aufgerufen. Und das ist bei gerolds Beispiel der Fall. `progressdialog_update` wird im MainLoop-Thread ausgeführt und nicht im Worker-Thread.
Deine ``runWork``-Funktion wird einem eigenen Thread ausgeführt. Also darfst du dort ``_pd.Update(i)`` und ``_pd.Destroy()`` nicht machen, und musst sie stattdessen indirekt durch ``wx.CallAfter``(``gobject.idle_add`` bei gtk) aufrufen. Wenn wx dann wieder die Event-Schleife abarbeitet, wird die übergebene Funktion *im Mainloop-Thread* aufgerufen. Und das ist bei gerolds Beispiel der Fall. `progressdialog_update` wird im MainLoop-Thread ausgeführt und nicht im Worker-Thread.