Hallo Pythoner!
In meiner Applikation kann ich einen Dialog rufen, in dessen Init eine MySQL-Abfrage übers Internet gestartet wird. Und hier liegt mein Problem. Die Abfrage dauert etwa 2 bis 4 Sekunden. Dementsprechend poppt der Dialog auch erst nach einer kurzen Warte zeit auf.
Ich würde währenddessen gerne eine asynchrone Meldung wie "Daten werden geladen..." bringen.
Was muss ich um meinen Funktionsaufruf, welcher mir die abgefragten Daten zurückgibt herumbauen, damit das klappt?
Nach dem Motto:
Öffne Wartemeldung
Rufe Funktion die Daten ruft
Schließe Wartemeldung
Geht das mit wx.Thread() ?
Viele Grüße
JR
Wartemeldung - Thread
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi JR!JR hat geschrieben:Öffne Wartemeldung
Rufe Funktion die Daten ruft
Schließe Wartemeldung
So könnte es ohne Threads funktionieren:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import wx
import time
wx.SetDefaultPyEncoding("iso-8859-1")
class MyDialog(wx.Dialog):
def __init__(self, parent = None, id = -1, title = "Hallo"):
wx.Dialog.__init__(self, parent, id, title)
statuslabel = wx.StaticText(self, -1)
self.statuslabel = statuslabel
wx.CallAfter(self.ich_tu_was)
def ich_tu_was(self):
statuslabel = self.statuslabel
for i in range(1, 11):
statuslabel.SetLabel(str(i))
wx.YieldIfNeeded()
time.sleep(0.5)
def main():
app = wx.PySimpleApp()
diag = MyDialog()
diag.ShowModal()
if __name__ == "__main__":
main()
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import wx
import time
from thread import start_new_thread
wx.SetDefaultPyEncoding("iso-8859-1")
class MyDialog(wx.Dialog):
def __init__(self, parent = None, id = -1, title = "Hallo"):
wx.Dialog.__init__(self, parent, id, title)
statuslabel = wx.StaticText(self, -1)
self.statuslabel = statuslabel
start_new_thread(self.ich_tu_was, ())
def ich_tu_was(self):
statuslabel = self.statuslabel
for i in range(1, 11):
wx.CallAfter(statuslabel.SetLabel, str(i))
wx.YieldIfNeeded()
time.sleep(0.5)
def main():
app = wx.PySimpleApp()
diag = MyDialog()
diag.ShowModal()
if __name__ == "__main__":
main()
lg
Gerold

Edit: Code verbessert.
Zuletzt geändert von gerold am Freitag 5. Januar 2007, 19:03, insgesamt 1-mal geändert.
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 Gerold!
Zunächst einmal vielen Dank für die Codebeispiele.
Habe sie mir eben durchgelesen und weiß nicht, ob das so klappen kann.
Im Prinzip habe ich in der Funktion ich_tu_was einfach nur einen MySQL-Abfragestring den ich über die MySQL-Schnittstelle absende.
Diese Abfrage dauert lange.
Das heißt, die MySQL-Abfrage und die Funktion ich_tu_was müssten gleichzeitig laufen und wenn die Abfrage zu Ende ist, müsste die Schleife abgebrochen werden.
Ich versuchs mal
Grüße
Jamil
Zunächst einmal vielen Dank für die Codebeispiele.
Habe sie mir eben durchgelesen und weiß nicht, ob das so klappen kann.
Im Prinzip habe ich in der Funktion ich_tu_was einfach nur einen MySQL-Abfragestring den ich über die MySQL-Schnittstelle absende.
Diese Abfrage dauert lange.
Das heißt, die MySQL-Abfrage und die Funktion ich_tu_was müssten gleichzeitig laufen und wenn die Abfrage zu Ende ist, müsste die Schleife abgebrochen werden.
Ich versuchs mal
Grüße
Jamil
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi JR!JR hat geschrieben:und wenn die Abfrage zu Ende ist, müsste die Schleife abgebrochen werden
Hier ist noch ein Beispiel. Allerdings spiele ich mich darin mit Threads und das ist für den Anfang nicht immer einfach.
Das Wichtigste ist, dass du nichts was die grafische Oberfläche ändert oder ändern kann, in einem Thread machst. Wenn sich etwas an der GUI ändern soll, dann übergebe den Auftrag an den Hauptthread, in dem das Programm selber läuft.
Das geht am Einfachsten mit ``wx.CallAfter()``.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import wx
import time
from thread import start_new_thread
wx.SetDefaultPyEncoding("iso-8859-1")
class MyDialog(wx.Dialog):
def __init__(self, parent = None, id = -1, title = "Hallo"):
# Dialogfenster initialisieren
wx.Dialog.__init__(self, parent, id, title)
# Abbruchvariable vorbereiten
self.cancel = False
# Einfaches Label für Statusanzeige
statuslabel = wx.StaticText(self, -1, "Gleich tut er etwas...")
self.statuslabel = statuslabel
# Neuen Thread starten. In diesem Thread wird gearbeitet und alles
# was irgendwie an den Hauptthread übergeben wird, wird über ``wx.CallAfter``
# geleitet.
# Alles was irdengetwas mit der GUI zu tun hat, hat im Hauptthread zu bleiben.
# Deshalb wird alles, was die Anzeige verändert, per ``wx.CallAfter`` an
# den Hauptthread weitergeleitet und nicht diret in einem anderen Thread
# geändert.
start_new_thread(self.ich_tu_was, ())
def show_progressdiag(self):
# ProgressDialog anzeigen
diag = wx.ProgressDialog(
"Arbeitsmeldung", "Jetzt tu ich etwas...", 100, self
)
# In einer Schleife die Progressbar bewegen.
while True:
time.sleep(0.1)
diag.UpdatePulse()
# Wenn die Abbruchvariable gesetzt wurde --> Fertig
if self.cancel:
diag.Destroy()
return
def ich_tu_was(self):
statuslabel = self.statuslabel
# Label setzen (über Threadgrenzen hinweg -- deshalb mit CallAfter)
wx.CallAfter(statuslabel.SetLabel , "Jetzt tu ich etwas...")
wx.CallAfter(wx.YieldIfNeeded)
# Abbruchvariable auf False setzen
self.cancel = False
# Den Progressdialog im Hauptthread starten.
# (über Threadgrenzen hinweg -- deshalb mit CallAfter)
wx.CallAfter(self.show_progressdiag)
# Hier wird gearbeitet
time.sleep(5) # Hier könntest du die SQL-Abfrage durchführen
# Abbruchvariable setzen, damit der PrograssDialog endet
self.cancel = True
# Label setzen (über Threadgrenzen hinweg -- deshalb mit CallAfter)
wx.CallAfter(statuslabel.SetLabel , "Fertig!")
wx.CallAfter(wx.YieldIfNeeded)
def main():
app = wx.PySimpleApp()
diag = MyDialog()
diag.ShowModal()
if __name__ == "__main__":
main()
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 Gerold!
Deine Mühen sind wirklich toll.
Also ich habe wohl genau den klassischen Fehler gemacht und im Thread meinen "Bitte warten..." Dialog gestartet. Ging auch halbwegs schief
Baue jetzt deine letzte Variante ein und melde mich dann bestimmt glücklich zurück...
"Bitte warten..."
Gruß
Jamil
Deine Mühen sind wirklich toll.
Also ich habe wohl genau den klassischen Fehler gemacht und im Thread meinen "Bitte warten..." Dialog gestartet. Ging auch halbwegs schief

Baue jetzt deine letzte Variante ein und melde mich dann bestimmt glücklich zurück...
"Bitte warten..."
Gruß
Jamil
Hi Gerold,
also es ist doch etwas komplizierter.
Erst einmal habe ich gemerkt, wieviel Performance es schluckt, wenn man mehrere MySQL-Abfragen durch eine Schleife hat.
Konnte eine Schleife mit vielen Abfragen durch eine sinnvollere Abfrage ersetzen und benötige an dieser Stelle keine "Bitte warten..." Meldung mehr.
Dennoch gibt es andere Stellen, wo die Abarbeitung solch eine Meldung parallel bringen sollte, damit meine Anwender nicht denken, dass das Programm abgeschmiert ist.
Ich muss mich mit dem Threading mehr auseinandersetzen. Mein Problem ist, dass ich versucht habe, über den Thread ganze Methoden (inkl. Rückgabewert und GUI-Steuerung) auszulösen. Das ging aber alles nicht so, wie ich es wollte. Entweder kam nur ein weißer Dialog oder meine Stelle, wo ich das Abbruchkriterium für die Progressschleife setze, wurde nicht durchlaufen etc.
Also ich werde es einfach mal die Tage versuchen, hinzubekommen.
Vielen Dank jedenfalls nochmals für deine rasche Reaktion.
Viele Grüße
Jamil
also es ist doch etwas komplizierter.
Erst einmal habe ich gemerkt, wieviel Performance es schluckt, wenn man mehrere MySQL-Abfragen durch eine Schleife hat.
Konnte eine Schleife mit vielen Abfragen durch eine sinnvollere Abfrage ersetzen und benötige an dieser Stelle keine "Bitte warten..." Meldung mehr.
Dennoch gibt es andere Stellen, wo die Abarbeitung solch eine Meldung parallel bringen sollte, damit meine Anwender nicht denken, dass das Programm abgeschmiert ist.
Ich muss mich mit dem Threading mehr auseinandersetzen. Mein Problem ist, dass ich versucht habe, über den Thread ganze Methoden (inkl. Rückgabewert und GUI-Steuerung) auszulösen. Das ging aber alles nicht so, wie ich es wollte. Entweder kam nur ein weißer Dialog oder meine Stelle, wo ich das Abbruchkriterium für die Progressschleife setze, wurde nicht durchlaufen etc.
Also ich werde es einfach mal die Tage versuchen, hinzubekommen.
Vielen Dank jedenfalls nochmals für deine rasche Reaktion.
Viele Grüße
Jamil
Hallo!
Keine Frage, sondern jetzt im Folgenden der Code dessen, was ich gesucht habe.
Ist im Prinzip komplett die obige Lösung von Gerold, wobei in den Zeilen 82-85
irgendetwas passiert, was halt länger dauern kann.
Viele Grüße
Jamil
Keine Frage, sondern jetzt im Folgenden der Code dessen, was ich gesucht habe.
Ist im Prinzip komplett die obige Lösung von Gerold, wobei in den Zeilen 82-85
irgendetwas passiert, was halt länger dauern kann.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import wx
import time
from thread import start_new_thread
wx.SetDefaultPyEncoding("iso-8859-1")
class MyDialog(wx.Dialog):
def __init__(self, parent = None, id = -1, title = "Hallo"):
# Dialogfenster initialisieren
wx.Dialog.__init__(self, parent, id, title)
# Abbruchvariable vorbereiten
self.cancel = False
# Einfaches Label für Statusanzeige
statuslabel = wx.StaticText(self, -1, "Gleich tut er etwas...")
self.statuslabel = statuslabel
# Neuen Thread starten. In diesem Thread wird gearbeitet und alles
# was irgendwie an den Hauptthread übergeben wird, wird über ``wx.CallAfter``
# geleitet.
# Alles was irdengetwas mit der GUI zu tun hat, hat im Hauptthread zu bleiben.
# Deshalb wird alles, was die Anzeige verändert, per ``wx.CallAfter`` an
# den Hauptthread weitergeleitet und nicht diret in einem anderen Thread
# geändert.
start_new_thread(self.ich_tu_was, ())
def show_progressdiag(self):
# ProgressDialog anzeigen
diag = wx.ProgressDialog(title="Arbeitsmeldung",
message="Jetzt tu ich etwas...",
maximum=100, parent=self,
style=wx.PD_APP_MODAL|
wx.PD_CAN_ABORT|
wx.PD_SMOOTH^
wx.PD_AUTO_HIDE)
self.diag = diag
# In einer Schleife die Progressbar bewegen.
i = 0
while True:
time.sleep(0.5)
if i * 10 >= 100:
i=0
try:
self.diag.Update(i * 10)
except:
pass
i += 1
# Wenn die Abbruchvariable gesetzt wurde --> Fertig
if self.cancel:
diag.Destroy()
return
def ich_tu_was(self):
statuslabel = self.statuslabel
# Label setzen (über Threadgrenzen hinweg -- deshalb mit CallAfter)
wx.CallAfter(statuslabel.SetLabel , "Jetzt tu ich etwas...")
wx.CallAfter(wx.YieldIfNeeded)
# Abbruchvariable auf False setzen
self.cancel = False
# Den Progressdialog im Hauptthread starten.
# (über Threadgrenzen hinweg -- deshalb mit CallAfter)
wx.CallAfter(self.show_progressdiag)
# Hier wird gearbeitet
for i in range(10):
time.sleep(1) # Hier könntest du die SQL-Abfrage durchführen
print i
# Abbruchvariable setzen, damit der PrograssDialog endet
self.cancel = True
# Label setzen (über Threadgrenzen hinweg -- deshalb mit CallAfter)
wx.CallAfter(statuslabel.SetLabel , "Fertig!")
wx.CallAfter(wx.YieldIfNeeded)
def main():
app = wx.PySimpleApp()
diag = MyDialog()
diag.ShowModal()
if __name__ == "__main__":
main()
Jamil