Over the development of a few applications with pys60 I have standardized on an app skeleton that simplifies and speeds-up the initial process of getting something going. The basic idea is to have an application shell up and running on various environments without needing a lot of configuration changes as quickly as possible. By default the app will run fine in the following environments without any changes: emulator, phone (script shell), phone (stand-alone).
The core idea behind the skeleton is that of a simple launcher and a directory holding the application. The launcher is responsible for setting the import paths based on the environment and bootstraping the application with generic exception handling. The actual application code is in a separate module. The application and data views are also based on individual classes. This allows for simple navigation between views / screens even in situations where the hierarchy is quite complex.
The sample skeleton project zip file has the following contents:
app_myapp.py
AppFolder
logger.py
debug.py
myapp.pyHere is how you can get started with your own app in seconds in a emulator (the steps below are based on N97 emulator installed in default location and the paths will have to change to reflect any other emulator editions) :
At this point you can either launch the app from the Python Script Shell
Hopefully the launcher code is self explanatory and will illustrate whats happening behind the scenes when you launch the app:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | print "MyApp Name" import appuifw import sys import os import os.path import e32 try: global DATA_PATH print "Loading, please wait..." e32.ao_sleep(.1) e32.ao_yield() if e32.in_emulator(): if e32.pys60_version_info[0] == 1 and e32.pys60_version_info[1] < 5: DATA_PATH = 'c:\\python\\myapp_folder\\' else: DATA_PATH = 'c:\\data\\python\\myapp_folder\\' else: #create app dir if neccessery drive = 'e' if os.path.exists('e:'): drive = 'e' DATA_PATH = 'e:\\data\\myapp_folder' elif os.path.exists('c:'): drive = 'c' DATA_PATH = 'c:\\data\\myapp_folder' try: os.makedirs('%s:\\data\\myapp_folder' % drive) except: pass #also add current script path (if we are running from a sis file) sys.path.insert(0,os.getcwd()) #not 100% sure this is needed if os.path.exists(DATA_PATH) == False: appuifw.note(u'Unable to set data directory. Exiting Application.') e32.ao_sleep(3) appuifw.app.set_exit() sys.exit() sys.path = sys.path + [DATA_PATH] import myapp old_title = appuifw.app.title exit_handler = appuifw.app.exit_key_handler appuifw.app.screen = 'normal' menu = appuifw.app.menu myApp = myapp.App() myApp.run() myApp.close() if e32.in_emulator(): appuifw.app.title = old_title appuifw.app.exit_key_handler = exit_handler appuifw.app.menu = menu else: appuifw.app.title = old_title appuifw.menu = None except: import sys import traceback import e32 import appuifw if e32.in_emulator(): if e32.pys60_version_info[0] == 1 and e32.pys60_version_info[1] < 5: DATA_PATH = 'c:\\python\\myapp_folder' else: DATA_PATH = 'c:\\data\\python\\myapp_folder' else: DATA_PATH = 'e:\\data\\myapp_folder' sys.path = sys.path + [DATA_PATH] from logger import Logger errlog = Logger("%s\\myapp_error_log.txt" % DATA_PATH) errlog.start_trace() appuifw.app.screen = "normal" # Restore screen to normal size. appuifw.app.focus = None # Disable focus callback. body = appuifw.Text() appuifw.app.body = body # Create and use a text control. exitlock = e32.Ao_lock() def exithandler(): exitlock.signal() appuifw.app.exit_key_handler = exithandler # Override softkey handler. appuifw.app.menu = [(u"Exit", exithandler)] # Override application menu. errlog.writeline("\n".join(traceback.format_exception(*sys.exc_info()))) body.set(unicode("\n".join(traceback.format_exception(*sys.exc_info())))) exitlock.wait() # Wait for exit key press. appuifw.app.set_exit() |
The launcher will create a ‘myapp’ application object and call the run method. From then on, the run method is responsible for creating the first view and for creating a signal lock until the view is closed or an app exit is requested by the user.