From: <kc1...@ya...> - 2006-07-24 23:30:54
|
Somebody asked me for a sample program on how to multithread a Pythoncard application. Multithreading in Python is pretty easy to code. All you have to do is to declare a class that's subclassing from the threading.thread class and then kick start it with a start method. Like: import threading class Worker(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): ....actual code... myWorker=Worker().start() The actual work, of course, is synchronization. The Thread class provides counters, locks, and so forth to help that. I've put together a very simple mind multi-thread example to show how to do things in Pythoncard. The code doesn't quite work yet (I did it real quick over lunch time) in that the thread doesn't release the CPU like I expect it to and so one thread would hog the CPU and doesn't switch between threads). But for those that are not familiar with multi-threading PythonCard, this can serve as a sample. If you get the code to work properly, it should allow the user to click the Start menu option twice, and it would run 2 processing threads, and when the user click on Stop, both threads would stop. #!/usr/bin/python """ __version__ = "$Revision: 1.1 $" __date__ = "$Date: 2004/10/24 19:21:46 $" """ import wx import threading import thread import time from PythonCard import model class MyBackground(model.Background): def on_initialize(self, event): # if you have any initialization # including sizer setup, do it here self.running(False) self.textAreas=(self.components.TextArea1,) pass def on_menuFileStart_select(self, event): on_menuFileStart_exe(self.textAreas[0]) return def on_menuFileStart_exe(self, textArea): textArea.visible=True self.running(True) for i in range(10000000): textArea.text = "Got up to %d" % i ## print i for j in range(i): k = 0 time.sleep(0) if not self.running(): break try: wx.SafeYield(self) except: pass if not self.running(): break textArea.text = "Finished at %d" % i return def on_menuFileStop_select(self, event): self.running(False) def on_Stop_mouseClick(self, event): self.on_menuFileStop_select(event) pass def running(self, flag=None): if flag!=None: self.runningFlag=flag return self.runningFlag class MyBackgroundThreaded(MyBackground): def on_initialize(self, event): # if you have any initialization # including sizer setup, do it here self.myLock=thread.allocate_lock() self.myThreadCount = 0 self.running(False) self.textAreas=[self.components.TextArea1,] self.textAreas.append(self.components.TextArea2) pass def on_menuFileStart_select(self, event): self.myThread=MyBackgroundWorker(self).run() def on_menuFileStop_select(self, event): self.running(False) self.menuBar.setEnabled("menuFileStart", True) def on_Stop_mouseClick(self, event): self.on_menuFileStop_select(event) def running(self, flag=None): self.myLock.acquire() if flag!=None: self.runningFlag=flag flag=self.runningFlag self.myLock.release() return flag class MyBackgroundWorker(threading.Thread): def __init__(self, parent): threading.Thread.__init__(self) self.parent=parent self.parent.myLock.acquire() threadCount=self.parent.myThreadCount self.parent.myLock.release() self.textArea=self.parent.textAreas[threadCount] def run(self): self.parent.myLock.acquire() self.parent.myThreadCount += 1 if self.parent.myThreadCount==2: self.parent.menuBar.setEnabled("menuFileStart", False) self.parent.myLock.release() self.parent.on_menuFileStart_exe(self.textArea) self.parent.myLock.acquire() self.parent.myThreadCount -= 1 if self.parent.myThreadCount==0: self.parent.menuBar.setEnabled("menuFileStart", True) self.parent.myLock.release() return if __name__ == '__main__': app = model.Application(MyBackgroundThreaded) app.MainLoop() Here's the resource file: {'application':{'type':'Application', 'name':'Template', 'backgrounds': [ {'type':'Background', 'name':'bgTemplate', 'title':'Standard Template with File->Exit menu', 'size':(400, 300), 'style':['resizeable'], 'menubar': {'type':'MenuBar', 'menus': [ {'type':'Menu', 'name':'menuFile', 'label':'&File', 'items': [ {'type':'MenuItem', 'name':'menuFileStart', 'label':u'&Start', }, {'type':'MenuItem', 'name':'menuFileStop', 'label':u'Sto&p', }, {'type':'MenuItem', 'name':'menuFile--', 'label':u'--', }, {'type':'MenuItem', 'name':'menuFileExit', 'label':'E&xit', 'command':'exit', }, ] }, ] }, 'components': [ {'type':'StaticText', 'name':'TextArea1', 'position':(10, 100), 'text':u'This is a test', 'visible':False, }, {'type':'StaticText', 'name':'TextArea2', 'position':(10, 200), 'text':u'This is a test', 'visible':False, }, ] # end components } # end background ] # end backgrounds } } -- John Henry |