I am trying to update a textctrl in wxpython while a long running thread is finding some sort of information. It works well until the user changes focus to another window, and then upon returning to the wxpython script, the GUI is unresponsive until the thread is finished.
Is there a way to return to this script and still see the textctrl updating with the animated cursor?
Here’s the code:
#!/usr/bin/env python
import wx
import thread
import Queue
from time import sleep
class MyFrame1 ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer2 = wx.BoxSizer( wx.VERTICAL )
self.m_button1 = wx.Button( self.m_panel1, wx.ID_ANY, u"MyButton", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer2.Add( self.m_button1, 0, wx.ALL, 5 )
self.m_panel1.SetSizer( bSizer2 )
self.m_panel1.Layout()
bSizer2.Fit( self.m_panel1 )
bSizer1.Add( self.m_panel1, 1, wx.EXPAND |wx.ALL, 5 )
self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer3 = wx.BoxSizer( wx.VERTICAL )
self.m_textCtrl1 = wx.TextCtrl( self.m_panel2, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE )
bSizer3.Add( self.m_textCtrl1, 1, wx.ALL|wx.EXPAND, 5 )
self.m_panel2.SetSizer( bSizer3 )
self.m_panel2.Layout()
bSizer3.Fit( self.m_panel2 )
bSizer1.Add( self.m_panel2, 1, wx.EXPAND |wx.ALL, 5 )
self.SetSizer( bSizer1 )
self.Layout()
self.Centre( wx.BOTH )
# Connect Events
self.m_button1.Bind( wx.EVT_BUTTON, self.do_something )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def do_something( self, event ):
event.Skip()
class MyFrame( MyFrame1 ):
def __init__( self, parent ):
MyFrame1.__init__( self, parent )
def do_something(self, event):
self.Result = Queue.Queue()
thread.start_new_thread(self.do_loop, ())
self.m_textCtrl1.AppendText("searching for something... ")
self.found= 0
for character in self.cursor():
self.m_textCtrl1.AppendText(character)
self.Update()
sleep(0.1)
self.m_textCtrl1.Undo()
if (self.found == 1):
self.m_textCtrl1.AppendText('\n')
break
num = self.Result.get()
print num
def cursor(self):
characters='.oOo'
i = 0
while 1:
yield characters[i]
i = (i + 1) % len(characters)
def do_loop(self):
x = 0
while (x < 20007):
print x
x = x + 1
if x == 20000:
self.Result.put(x)
self.found = 1
break
class threadtest(wx.App):
def OnInit(self):
self.m_frame = MyFrame(None)
self.m_frame.Show()
self.SetTopWindow(self.m_frame)
return True
app = threadtest(0)
app.MainLoop()
Here is a solution based on Anonymous Coward’s comment. I moved everything from the button event into a thread. Let me know if there is a better way to do this.