Hallo Toni83!
Ich habe jetzt leider keine Zeit mehr für viele Erklärungen. Nur eines ist zu sagen: Unter wxPython ist es sehr wichtig, Threads nicht direkt miteinander kommunizieren zu lassen. Es muss immer über ein "Thread-sicheres" Objekt (z.B. threading.Event) kommuniziert werden. Irgendwo zwischen den Threads muss immer so ein threadsicheres Objekt stehen.
Grob gesagt: Der Thread ist alles was in der "run"-Methode drinnen ist. Du darfst also nichts direkt von außen anfassen, was vom Thread verwendet wird. Und umgekehrt. Deshalb auch "wx.CallAfter()".
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
import wx
import threading
from itertools import count
import time
wx.SetDefaultPyEncoding("iso-8859-15")
class StepMotor(threading.Thread):
def __init__(self, statusfunction = None):
threading.Thread.__init__(self)
self._statusfunction = statusfunction
self._exit_event = threading.Event()
self._run_event = threading.Event()
def run(self):
print "thread started"
for step in count():
self._run_event.wait()
if self._exit_event.isSet():
break
if self._statusfunction and callable(self._statusfunction):
wx.CallAfter(self._statusfunction, "Step %i" % step)
print step
time.sleep(0.5)
print "thread stoped"
def motor_run(self):
print "motor_run"
self._run_event.set()
def motor_halt(self):
print "motor_halt"
self._run_event.clear()
def exit_thread(self):
print "exit_thread"
self._exit_event.set()
self._run_event.set()
class MyFrame(wx.Frame):
def __init__(
self, parent = None, id = -1, title = "Schrittmotorsteuerung",
style = wx.DEFAULT_FRAME_STYLE ^ (
wx.RESIZE_BORDER | wx.RESIZE_BOX | wx.MAXIMIZE_BOX | wx.MINIMIZE_BOX
)
):
wx.Frame.__init__(self, parent, id, title, style = style)
panel = wx.Panel(self)
self.panel = panel
vbox = wx.BoxSizer(wx.VERTICAL)
panel.SetSizer(vbox)
self.motor = StepMotor(self.update_status)
self.motor.start() # Thread starten
lab_status = wx.StaticText(
panel, label = "<>", size = (250, -1), style = wx.TE_CENTER
)
vbox.Add(lab_status, 0, wx.ALL | wx.EXPAND, 5)
self.lab_status = lab_status
btn_run = wx.Button(panel, -1, "Run")
vbox.Add(btn_run, 0, wx.ALL | wx.EXPAND, 5)
btn_run.Bind(wx.EVT_BUTTON, lambda event: self.motor.motor_run())
btn_halt = wx.Button(panel, -1, "Halt")
vbox.Add(btn_halt, 0, wx.ALL | wx.EXPAND, 5)
btn_halt.Bind(wx.EVT_BUTTON, lambda event: self.motor.motor_halt())
btn_exit = wx.Button(panel, -1, "Exit")
vbox.Add(btn_exit, 0, wx.ALL | wx.EXPAND, 5)
btn_exit.Bind(wx.EVT_BUTTON, lambda event: self.Close())
self.Bind(wx.EVT_CLOSE, self.on_frame_close)
panel.Fit()
self.Fit()
def on_frame_close(self, event):
event.Skip()
self.motor.exit_thread()
self.motor.join()
def update_status(self, message):
self.panel.Freeze()
self.lab_status.SetLabel(message)
self.panel.Layout()
self.panel.Thaw()
def main():
app = wx.PySimpleApp()
f = MyFrame()
f.Center()
f.Show()
app.MainLoop()
if __name__ == "__main__":
main()
mfg
Gerold
