Again, we start with ResEdit to create our dialogs. Not only do we want a main dialog this time but also an "About" dialog, and we provide the BNDL resource and related stuff that an application cannot be without. (Actually, a python applet can be without, see below). "Inside Mac" or various books on macintosh programming will help here. Also, you can refer to the resource files provided in the Python source distribution for some of the python-specific points of BNDL programming: the "appletbundle.rsrc" file is what is used for creating applets if you don't provide your own resource file.
Let's have a look at InterslipControl-2.rsrc, our resource file. First off, there's the standard BNDL combo. I've picked 'PYTi' as signature for the application. I tend to pick PYT plus one lower-case letter for my signatures. The finder gets confused if you have two applications with the same signature. This may be due to some incorrectness on the side of "mkapplet", I am not sure. There is one case when you definitely need a unique signature: when you create an applet that has its own data files and you want the user to be able to start your applet by double-clicking one of the datafiles.
There's little to tell about the BNDL stuff: I basically copied the generic Python applet icons and pasted in the symbol for InterSLIP. The two dialogs are equally unexciting: dialog 512 is our main window which has four static text fields (two of which we will be modifying during runtime, to show the status of the connection) and two buttons "connect" and "disconnect". The "quit" and "update status" buttons have disappeared, because they are handled by a menu choice and automatically, respectively.
FrameWork
module, a nifty piece of code that handles
all the gory mac details of event loop programming, menubar
installation and all the other code that is the same for every mac
program in the world. Like most standard modules, FrameWork will run
some sample test code when you invoke it as a main program, so try it
now. It will create a menu bar with an Apple menu with the about box
and a "File" menu with some pythonesque choices (which do nothing
interesting, by the way) and a "Quit" command that works.
A more complete description of FrameWork is
sorely needed, and will (at some point) be incorporated in the
programmers manual or in place of this paragraph. For now you'll have
to make do with the knowledge that you use FrameWork by building your
classes upon the classes provided by it and selectively overriding
methods to extend its functionality (or override the default
behaviour). And you should read the Source, of Course:-)
Next comes the definition of our main class,
InterslipControl
, which inherits
FrameWork.Application
. The Application class handles the
menu bar and the main event loop and event dispatching. In the
__init__
routine we first let the base class initialize
itself, then we create our modeless dialog and finally we jump into
the main loop. The main loop continues until self
is
raised, which we will do when the user selects "quit". When we create
the instance of MyDialog
(which inherits
DialogWindow
, which inherits Window
) we pass
a reference to the application object, this reference is used to tell
Application about our new window. This enables the event loop to keep
track of all windows and dispatch things like update events and mouse
clicks.
The makeusermenus()
method (which is called sometime
during the Application __init__
routine) creates a File
menu with a Quit command (shortcut command-Q), which will callback to
our quit() method. Quit()
, in turn, raises 'self' which
causes the mainloop to terminate.
Application provides a standard about box, but we override this by
providing our own do_about()
method which shows an about
box from a resource as a modal dialog. This piece of code should look
familiar to you from the previous example program. That do_about is
called when the user selects About from the Apple menu is, again,
taken care of by the __init__ routine of Application.
Our main object finally overrides idle()
, the method
called when no event is available. It passes the call on to our dialog
object to give it a chance to update the status fields, if needed.
The MyDialog
class is the container for our main
window. Initialization is again done by first calling the base class
__init__
function and finally setting two local variables
that are used by updatestatus()
later.
Do_itemhit()
is called when an item is selected in this
dialog by the user. We are passed the item number (and the original
event structure, which we normally ignore). The code is similar to the
main loop of our previous example program: a switch depending on the
item selected. Connect()
and disconnect()
are again quite similar to our previous example.
Updatestatus()
is different, however. It is now
potentially called many times per second instead of only when the
user presses a button we don't want to update the display every time
since that would cause some quite horrible flashing. Luckily,
interslip.status()
not only provides us with a state and
a message but also with a message sequence number. If neither state
nor message sequence number has changed since the last call there is
no need to update the display, so we just return. For the rest,
nothing has changed.
The easiest way to create an applet is to take your source file and drop it onto "mkapplet" (normally located in the Python home folder). This will create an applet with the same name as your python source with the ".py" stripped. Also, if a resource file with the same name as your source but with ".rsrc" extension is available the resources from that file will be copied to your applet too. If there is no resource file for your script a set of default resources will be used, and the applet will have the default creator 'PYTa'. The latter also happens if you do have a resource file but without the BNDL combo. Actually, for our example that would have been the most logical solution, since our applet does not have its own data files. It would have saved us hunting for an unused creator code. The only reason for using the BNDL in this case is having the custom icon, but that could have been done by pasting an icon on the finder Info window, or by providing an custon icon in your resource file and setting the "custom icon" finder bit.
If you need slightly more control over the mkapplet process you can double-click mkapplet, and you will get dialogs for source and destination of the applet. The rest of the process, including locating the resource file, remains the same.
Note that though our example application completely bypasses the normal python user interface this is by no means necessary. Any python script can be turned into an applet, and all the usual features of the interpreter still work.
That's all for this example, you may now return to the table of contents to pick another topic.