Moin!
Ich habe eine Funktion in einer Klasse, die Berechnungen durchführt und am Ende das Ergebnis über return an eine GUI Klasse zurückgibt.
Als Erweiterung würde ich gerne schon Zwischenergebnisse ausgeben und vielleicht auch den Fortschritt der Berechnung anzeigen.
Dazu lasse ich die Berechnung in einem eigenen Thread laufen.
Muss ich mit wx.CallAfter() arbeiten, um mir schon während der Laufzeit Zwischenergebnisse liefern zu lassen?
Danke
Threads - Zwischenergebnisse an GUI übergeben
Könnte mir vielleicht jemand erklären, wie ich wx.CallAfter() kann?
Bisher rufe ich eine Funktion ganz normal auf und lasse mir die Ergebnisse zurückgeben:
Wie würde ich sowas mit einem Thread umsetzen?
Bisher rufe ich eine Funktion ganz normal auf und lasse mir die Ergebnisse zurückgeben:
Code: Alles auswählen
ergebnis = test.run()
Eine bessere lösung wäre es, einfach die GUI upzudaten, wärend deiner Berechnung. Dann musst du dich nicht mit Thread-Synchronisation herumschlagen.tomate hat geschrieben:Dazu lasse ich die Berechnung in einem eigenen Thread laufen.
http://www.wxwidgets.org/manuals/2.6/wx ... ppdispatch
Es ist nett, freundlich zu sein.
Auch nett: [url=http://www.progchild.de]Homepage[/url]
Auch nett: [url=http://www.progchild.de]Homepage[/url]
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo tomate!tomate hat geschrieben:Muss ich mit wx.CallAfter() arbeiten, um mir schon während der Laufzeit Zwischenergebnisse liefern zu lassen?
Ja! Aber dazu brauchst du etwas, was du von deiner arbeitenden Funktion aus an die GUI zurück geben kannst.
Suche hier im Forum nach "wx.CallAfter" und gehe die Suchergebnisse von unten nach oben durch. Nimm dir die Zeit. Dort findest du Anleitungen, Hintergründe und Beispiele.
Wenn du in deiner arbeitenden Funktion eine Schleife durchläufst, so dass du immer wieder zwischendurch die GUI am Laufen halten kannst (mit wx.YieldIfNeeded), dann musst du nicht unbedingt auf einen zusätzlichen Thread ausweichen. Aber ein Thread ist nicht schlecht, dann bleibt die GUI auf jeden Fall flüssig und bedienbar.
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.
Danke für Eure Hilfe.
Ich denke, ich werde es mit Threads versuchen, damit die GUI bedienbar bleibt.
Normalerweise sollte man ja möglichst GUI und Logik trennen oder?
Ich habe im Moment mein Programm auf zwei Dateien aufgeteilt. Eine für die Logik, eine für die GUI.
Sehe ich es richtig, dass ich wenn ich mit wx.CallAfter arbeite, automatisch auch GUI-Elemente in meiner Logik-Datei einbauen muss?
Mein Problem ist, dass ich in meiner GUI-Datei Klassen aus der Logik-Datei importiere. Aber wenn ich Threads nutzen will, müsste ich aus der Logik-Datei eigentlich auch Zugriff auf die GUI haben oder? Wie mache ich das?
Um mal auf ein Beispielvon dir zurückzukommen:
Könnte ich auch in jedem Schleifendurchlauf etwas an die GUI zurückgeben? Also z.b. "SchleifeX"
Ich denke, ich werde es mit Threads versuchen, damit die GUI bedienbar bleibt.
Normalerweise sollte man ja möglichst GUI und Logik trennen oder?
Ich habe im Moment mein Programm auf zwei Dateien aufgeteilt. Eine für die Logik, eine für die GUI.
Sehe ich es richtig, dass ich wenn ich mit wx.CallAfter arbeite, automatisch auch GUI-Elemente in meiner Logik-Datei einbauen muss?
Mein Problem ist, dass ich in meiner GUI-Datei Klassen aus der Logik-Datei importiere. Aber wenn ich Threads nutzen will, müsste ich aus der Logik-Datei eigentlich auch Zugriff auf die GUI haben oder? Wie mache ich das?
Um mal auf ein Beispielvon dir zurückzukommen:
Code: Alles auswählen
class MyWorker(threading.Thread):
def __init__(self, finished_function = None):
threading.Thread.__init__(self)
self.canceled = threading.Event()
self.finished_function = finished_function
def run(self):
for i in xrange(10):
if self.canceled.isSet():
print "Gestoppt..."
break
print "Ich arbeite..."
time.sleep(1)
if self.finished_function:
self.finished_function()
def stop(self):
self.canceled.set()
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo tomate!
Ich habe jetzt keinen Bock auf erklären:
example_lib.py:
example_gui.py:
mfg
Gerold
Ich habe jetzt keinen Bock auf erklären:
example_lib.py:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
import time
def my_worker(start = 0, stop = 10, step = 1, status_func = None, finished_func = None):
"""
Arbeitende Funktion.
:param start: Gibt die Zahl an, ab der gezählt werden soll.
:param stop: Gibt die Zahl an, bis zu der gezählt werden soll.
:param step: Schrittwert
:param status_func: Wenn angegeben, dann wird eine Funktion erwartet, an die
man als Parameter den Zwischenstand übergeben kann.
Z.B. so: ``status_func("Neuer Zwischenstand")``
:param finished_func: Wird ausgeführt, wenn der Worker mit seiner Arbeit fertig ist.
Es wird eine ausführbare Funktion oder None erwartet.
"""
if not callable(status_func):
status_func = None
for i in range(start, stop, step):
if status_func:
status_func("Zwischenstand: %i" % i)
time.sleep(0.6)
if status_func:
status_func("Fertig")
if callable(finished_func):
finished_func()
def main():
# Testen
def status_func(message):
print message
def finished_func():
print "END"
my_worker(2, 8, status_func = status_func, finished_func = finished_func)
if __name__ == "__main__":
main()
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
import wx
from thread import start_new_thread
import example_lib
wx.SetDefaultPyEncoding("iso-8859-15")
class MyFrame(wx.Frame):
def __init__(
self, parent = None, title = "Example", size = wx.Size(550, 420)
):
wx.Frame.__init__(self, parent, -1, title, size = size)
panel = wx.Panel(self)
vbox_main = wx.BoxSizer(wx.VERTICAL)
panel.SetSizer(vbox_main)
vbox = wx.BoxSizer(wx.VERTICAL)
vbox_main.Add(vbox, 1, wx.EXPAND | wx.ALL, 5)
txt_status = wx.TextCtrl(
panel, style = wx.TE_MULTILINE | wx.TE_AUTO_SCROLL | wx.TE_READONLY
)
vbox.Add(txt_status, 1, wx.EXPAND | wx.ALL)
self.txt_status = txt_status
btn_start = wx.Button(panel, label = "Start")
vbox.Add(btn_start, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
btn_start.Bind(wx.EVT_BUTTON, self.start_worker)
self.btn_start = btn_start
def show_status(self, message):
"""
Zeigt den neuen Status in der Textbox an.
:param message: Dieser Text wird in der Textbox angehängt.
"""
message = message.rstrip() + "\n"
# Hier findet eine Trennung zwischen den Threads statt
wx.CallAfter(self.txt_status.AppendText, message)
def worker_finished(self):
"""
Wird ausgeführt, wenn der Worker fertig ist. Damit könnte man den
Start-Button wieder aktivieren, falls man diesen vorher deaktiviert
hat.
"""
# Hier findet eine Trennung zwischen den Threads statt
wx.CallAfter(self.btn_start.Enable)
def start_worker(self, event):
"""
Startet den Worker aus dem Modul "example_lib".
"""
# self.btn_start.Disable()
self.txt_status.SetValue("")
start_new_thread(
example_lib.my_worker, (),
dict(
start = 10, stop = 29, step = 2, status_func = self.show_status,
finished_func = self.worker_finished
)
)
def main():
"""Testing"""
app = wx.PySimpleApp()
f = MyFrame()
f.Center()
f.Show()
app.MainLoop()
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.
Code: Alles auswählen
start_new_thread(
example_lib.my_worker, (),
dict(
start = 10, stop = 29, step = 2, status_func = self.show_status,
finished_func = self.worker_finished
)
)
Angenommen my_worker befindet sich in der Klasse "MeineKlasse".
Könnte ich dann eine Instanz dieser Klasse erzeugen, dieser die Parameter (start =10...) übergeben und dann erst start_new_thread aufrufen?
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo tomate!tomate hat geschrieben:Angenommen my_worker befindet sich in der Klasse "MeineKlasse".
Könnte ich dann eine Instanz dieser Klasse erzeugen, dieser die Parameter (start =10...) übergeben und dann erst start_new_thread aufrufen?
Ja das funktioniert so. Aber das hättest du selber auch ausprobieren können. Und die Hilfe zu start_new_thread findest du hier: http://docs.python.org/lib/module-thread.html
In etwa so:
Code: Alles auswählen
class MeineKlasse(object):
def __init__(self,...):
...
def my_worker(self):
...
meine_klasseninstanz = MeineKlasse(start = 1, ...)
start_new_thread(meine_klasseninstanz.my_worker, ())
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.