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()

