#wxPythonとthreadingを使ったら...
これはWindowsに限った話です。
Python無知がwxPythonとthreadingを使ったらおかしなことになりました。
このコードをご覧ください。↓
import wx
import time
import threading
class MyFrame(wx.Frame):
def TimeSleep(self,value=0):
time.sleep(value)
self.OnStart()
def __init__(self):
wx.Frame.__init__(self,None,-1,"title")
self.panel = wx.Panel(self,-1)
self.panel.SetBackgroundColour("black")
self.Refresh()
t1=threading.Thread(target=self.TimeSleep,args=(2,))
t1.start()
def OnStart(self):
self.panel.SetBackgroundColour("white")
lbl = wx.StaticText(self.panel,-1,"Finish")
self.Refresh()
app = wx.App(False)
f = MyFrame()
f.Show(True)
app.MainLoop()
これで実行した結果、なんと[Finish]が表示されないというバグに至ってしまいました...
どいうことかというと、threadingを使った後、新しいウィジェットが表示されなくなったということです。
また、threadingと同時にwx.Timerも使えないということです。
色々と試した結果原因と解決方法が見つかったので説明したいと思います。
#原因
無知なのでこういう図もどう作ればいいかわからなくて...
っでまあこのように外にいってその外からメインのGUIを操作できないということでした。
それで新しいウィジェットをつくれない!ということでした。プログラミングって難しい...
それで直接wxPython, threadingで調べてみてもこのことがかかれていなかったのでめちゃめちゃ苦労しました。それでたまたま見つかった関数があってそれが「wx.CallAfter」です。
#解決方法
さきほどいった通り、wx.CallAfterを使用して、外からメインのGUIに戻るということです。
それで以下のようなコードになりました。
import wx
import time
import threading
class MyFrame(wx.Frame):
def TimeSleep(self,value=0):
time.sleep(value)
wx.CallAfter(self.OnStart) ##ここ!
def __init__(self):
wx.Frame.__init__(self,None,-1,"title")
self.panel = wx.Panel(self,-1)
self.panel.SetBackgroundColour("black")
self.Refresh()
t1=threading.Thread(target=self.TimeSleep,args=(2,))
t1.start()
def OnStart(self):
self.panel.SetBackgroundColour("white")
lbl = wx.StaticText(self.panel,-1,"Finish")
self.Refresh()
app = wx.App(False)
f = MyFrame()
f.Show(True)
app.MainLoop()
#おわりに
これ解決するのに何カ月もかかりました 笑
これ環境によってはこの方法をつかわなくてもできたということもありますし、もしくはバージョンによっても変わるということがあるのでその場合は使わなくてもいいです(でも外からGUIをいじるのは安全ではないので使うことを推奨します。)
ブログ開設しときました。まだ全然記事あげてませんが、これから色々とあげる予定です。是非見に来てください。→ programming-self-study.blogspot.com/
###環境
Python 3.9.1
Windows10
64bit
誤字あったら教えてね!