wxPythonでスレッドを使ってみる
wxPythonでスレッドを使う例がwxPythonのサンプルコードにある。これを参考にして試してみたのでメモしておく。
wxPythonに特別なスレッドクラスが存在するわけではなく、thread.start_new_thread
でスレッドを作成し、スレッドからイベントを投げることで、メッセージをウィンドウに渡してあげる。
試したスクリプトでは、スレッドは1秒ごとの時間をイベントのメッセージとして、メインウインドウに投げる。メインウィンドウはイベントを受信すると、メッセージとして受け取った時間をTextCtrlの表示域に表示する。
また、メインウィンドウを閉じるときはウィンドウ右上の×をクリックする。wx.EVT_CLOSE イベントを受け取ると、スレッドを停止処理し、完全に停止するを確認してからメインウィンドウを閉じる。
実験環境
- Windows XP
- Python 2.7
- wxPython 2.8
試したスクリプト wxthr.py
#!/usr/bin/env python # -*- coding:utf-8 -*- import time import thread import wx import wx.lib.newevent # 新しいイベントクラスとイベントを定義する (MyThreadEvent, EVT_MY_THREAD) = wx.lib.newevent.NewEvent() class MyThread: def __init__(self, win): self.win = win def Start(self): self.keepGoing = True self.running = True thread.start_new_thread(self.Run, ()) def Stop(self): self.keepGoing = False def IsRunning(self): return self.running def Run(self): while self.keepGoing: ts = time.strftime('%Y/%d/%m %H:%M:%S', time.localtime()) #メッセージを格納したイベントを作る evt = MyThreadEvent(msg = ts) #イベントを投げる wx.PostEvent(self.win, evt) time.sleep(1) self.running = False class MainWindow(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(380, 200)) panel = wx.Panel(self) self.text_disp = wx.TextCtrl(panel, style=wx.TE_MULTILINE) sizer = wx.BoxSizer() sizer.Add(self.text_disp, 1, wx.EXPAND) panel.SetSizer(sizer) #新しく定義したイベントに対応する処理関数をバインドする self.Bind(EVT_MY_THREAD, self.OnUpdate) self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) #スレッドのインスタンスを作り、起動する self.my_thread = MyThread(self) self.my_thread.Start() self.Centre() self.Show(True) def OnCloseWindow(self, evt): #スレッドが停止するまで待ってから、ウィンドウを閉じる self.my_thread.Stop() while self.my_thread.IsRunning(): time.sleep(0.1) self.Destroy() def OnUpdate(self, evt): #スレッドからイベントを受信したときの処理 self.text_disp.AppendText(evt.msg+'\n') app = wx.App() #デバッグするときはwx.PySimpleApp()を使う #app = wx.PySimpleApp() MainWindow(None, wx.ID_ANY, 'wxthr.py') app.MainLoop()