Created
October 6, 2015 11:01
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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