Beim Erstellen des Worker-Threads wird eine Funktion übergeben, die vom Thread laufend aufgerufen wird. Diese Funktion ruft über wx.CallAfter eine andere Funktion auf, die sich darum kümmert, dass der ProgressDialog einen neuen Wert bekommt. Außerdem wird auch abgefragt, ob der Benutzer den "Abbruch"-Button gedrückt hat. Wenn Ja, dann wird der Thread abgebrochen.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# wx.ProgressDialog mit Threading.
# Die Trennung zwischen Worker-Thread und GUI findet hier über eine Funktion statt
import wx
import threading
import time
wx.SetDefaultPyEncoding("iso-8859-15")
class MyWorkerThread(threading.Thread):
"""
Dieser Thread ruft in Intervallen die übergebene Funktion "statusfunction" auf.
Damit kann ein Status an die GUI übergeben werden.
"""
def __init__(self, statusfunction = None):
threading.Thread.__init__(self)
self.canceled = threading.Event()
self.statusfunction = statusfunction
def run(self):
"""
Hier wird gearbeitet
"""
for i in xrange(1, 101):
# Abbruch, wenn notwendig
if self.canceled.isSet():
print "Der Thread wurde abgebrochen"
break
print i
# Statusfunktion aufrufen
if self.statusfunction:
self.statusfunction(i)
# Ein wenig Arbeit simulieren
time.sleep(0.1)
def cancel(self):
"""
Abbruchbedingung setzen
"""
self.canceled.set()
class MyFrame(wx.Frame):
def __init__(
self, parent = None, title = "Example", size = wx.Size(250, 150)
):
wx.Frame.__init__(self, parent, -1, title, size = size)
panel = wx.Panel(self)
vbox_main = wx.BoxSizer(wx.VERTICAL)
panel.SetSizer(vbox_main)
vbox_main.AddStretchSpacer()
btn_start = wx.Button(panel, label = u"Start")
vbox_main.Add(btn_start, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
btn_start.Bind(wx.EVT_BUTTON, self.start_thread)
vbox_main.AddStretchSpacer()
def start_thread(self, event = None):
"""
Startet den neuen Thread
"""
self.progressdialog = wx.ProgressDialog(
title = u"Demo", message = u"Huiiiiii... Jetzt geht's loooos...", parent = self,
style = wx.PD_AUTO_HIDE | wx.PD_APP_MODAL | wx.PD_CAN_ABORT
)
self.progressdialog.Show()
# Beim erstellen des neuen Threads wird gleich die Funktion mitgegeben,
# die bei Statusänderungen aufgerufen werden soll.
self.worker = MyWorkerThread(self.worker_statusfunc)
self.worker.start()
def worker_statusfunc(self, value):
"""
Diese Funktion wird vom Worker-Thread aus aufgerufen
Es wird ``wx.CallAfter`` verwendet um einen Trennung zwischen Thread und
GUI zu verwirklichen.
"""
wx.CallAfter(self.progressdialog_update, value)
def progressdialog_update(self, value):
(thread_continue, thread_skip) = self.progressdialog.Update(value)
# Wenn die Rückgabe (thread_continue) nicht mehr True ist, dann
# Thread abbrechen
if not thread_continue:
# Thread abbrechen
self.worker.cancel()
# Kurz warten um dem Thread noch ein wenig Zeit zum Beenden zu lassen.
time.sleep(0.3)
# ProgressDialog zerstören
self.progressdialog.Destroy()
def main():
"""Testing"""
app = wx.PySimpleApp()
f = MyFrame()
f.Center()
f.Show()
app.MainLoop()
if __name__ == "__main__":
main()
Gerold