Skip to content

Instantly share code, notes, and snippets.

@rsnape
Created October 6, 2015 11:01
Show Gist options
  • Save rsnape/e7299e56eafec0e92334 to your computer and use it in GitHub Desktop.
Save rsnape/e7299e56eafec0e92334 to your computer and use it in GitHub Desktop.
Little threading application in wxPython for Morgan - http://stackoverflow.com/questions/32467060/wxpython-threads-blocking
import wx
#from wx.lib.pubsub.core import Publisher #If you want to manage your own publisher use this
from wx.lib.pubsub import pub
import threading
class ParcelData(object):
def __init__(self,count,current,message):
self.parcel_count = count
self.current_parcel = current
self.message = message
def __repr__(self):
return str(self.parcel_count)+':'+str(self.current_parcel)+':'+str(self.message)
class PrepareThread(threading.Thread):
def __init__(self, notify_window):
threading.Thread.__init__(self)
self._notify_window = notify_window
self._want_abort = False
#self.pub = Publisher() #If you want to manage your own publisher use this, then refer to this publisher
def run(self):
"""
You want some error checking in here - so you can post
a `prepare.failure' or similar event to ungrey the button
if it doesn't work
"""
while not self._want_abort:
for status in self.my_long_database_preparation():
self.post_event('prepare.running', status)
self.post_event('prepare.complete', None)
return None
def my_long_database_preparation(self):
"""
This is a placeholder - just stubbing out your
prepare_collection basically
"""
import time
for transaction in range(10):
#print('Just doing some more work')
time.sleep(1)
yield ParcelData(10,transaction,'Getting the work done on collection '+str(transaction))
self.abort()
def abort(self):
self._want_abort = True
def post_event(self,message, payload):
wx.CallAfter(lambda *a: pub.sendMessage(message, data=payload))
class MainForm(wx.Frame):
PREPARE_ID = 1
DO_STUFF_ID = 2
REAL_STUFF_ID = 3
def __init__(self, title):
wx.Frame.__init__(self, None, title=title, pos=(150,150), size=(350,350))
self.Bind(wx.EVT_CLOSE, self.on_close)
self.prepare_thread = PrepareThread(self)
self.panel = wx.Panel(self) #Have to keep reference to the panel for the on_status_result method
box = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
self.panel.status_label = wx.StaticText(self.panel,label='You need to click prepare')
self.panel.progress_bar = wx.Gauge(self.panel, range=10, size=(250,25))
hbox1.Add(self.panel.progress_bar, 0, wx.ALIGN_CENTRE)
self.start_button = wx.Button(self.panel, self.PREPARE_ID, "Prepare thyself")
self.start_button.Bind(wx.EVT_BUTTON, self.start_prepare)
hbox2.Add(self.start_button, 0, wx.ALL, 10)
self.still_responsive = wx.Button(self.panel, self.DO_STUFF_ID, "Click me repeatedly")
self.still_responsive.Bind(wx.EVT_BUTTON, self.do_stuff)
hbox2.Add(self.still_responsive, 0, wx.ALL, 10)
self.real_action = wx.Button(self.panel, self.REAL_STUFF_ID, "Really get going")
self.real_action.Disable() #Disabled until prepare has finished
self.real_action.Bind(wx.EVT_BUTTON, self.do_real_stuff)
box.Add(hbox1, 0, wx.ALL, 10)
box.Add(self.panel.status_label,0,wx.ALL,10)
box.Add(hbox2, 0, wx.ALL, 10)
box.Add(self.real_action, 0, wx.ALL, 10)
self.panel.SetSizer(box)
self.panel.Layout()
pub.subscribe(self.on_status_result, 'prepare.running')
pub.subscribe(self.on_status_finished, 'prepare.complete')
def start_prepare(self, event):
self.start_button.Disable()
self.prepare_thread.start()
def do_stuff(self, event):
''' Currently just here to demonstrate UI responsiveness
However - could be doing your other work, or starting
other threads etc...
'''
print('I can still do stuff, see')
def do_real_stuff(self, event):
''' Currently just here to demonstrate something you could
do once your prepare thread has notified completion...
'''
print('Now we\'re cooking - you can start some more threads here')
def on_status_result(self,data):
if not self.panel.progress_bar.GetRange():
self.panel.progress_bar.SetRange(data.parcel_count)
self.panel.progress_bar.SetValue(data.current_parcel)
self.panel.status_label.SetLabel(data.message)
def on_status_finished(self,data):
print('And now to ungrey my action buttons and unleash my powers!!')
# Make it look like it's finished
self.panel.progress_bar.SetValue(self.panel.progress_bar.GetRange())
self.real_action.Enable()
def on_close(self, message):
print('Adieu, sweet world')
self.Destroy()
app = wx.App()
top = MainForm('Threaded bar')
top.Show()
app.MainLoop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment