177 lines
9.6 KiB
HTML
177 lines
9.6 KiB
HTML
<HTML><HEAD><TITLE>Using python to create Macintosh applications, part two</TITLE></HEAD>
|
|
<BODY>
|
|
<H1>Using python to create Macintosh applications, part two</H1>
|
|
<HR>
|
|
|
|
In this document we rewrite the application of the <A
|
|
HREF="example1.html">previous example</A> to use modeless dialogs. We
|
|
will use an application framework, and we will have a look at creating
|
|
applets, standalone applications written in Python. <A
|
|
HREF="example2/InterslipControl-2.py">Source</A> and resource file (in
|
|
binary and <A HREF="example2/InterslipControl-2.rsrc.hqx">BinHex</A>
|
|
form for downloading) are available in the folder <A
|
|
HREF="example2">example2</A>. <p>
|
|
|
|
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 <A NAME="bundle">BNDL resource</A> and related stuff that
|
|
an application cannot be without. (Actually, a python applet can be
|
|
without, <A HREF="#no-bundle">see below</A>). "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. <p>
|
|
|
|
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 "BuildApplet", 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. <p>
|
|
|
|
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. <p>
|
|
|
|
<H2>A modeless dialog application using FrameWork</H2>
|
|
|
|
On to the source code in <A
|
|
HREF="example2/InterslipControl-2.py">InterslipControl-2.py</A>. The
|
|
start is similar to our previous example program <A
|
|
HREF="example1/InterslipControl-1.py">InterSlipControl-1.py</A>, with
|
|
one extra module being imported. To make life more simple we will use
|
|
the <CODE>FrameWork</CODE> 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. <p>
|
|
|
|
<BLOCKQUOTE>
|
|
If you have not used <code>FrameWork</code> before you may want to
|
|
first take a look at the <A HREF="textedit.html">Pathetic EDitor</A>
|
|
example, which builds a minimal text editor using FrameWork and TextEdit.
|
|
On the other hand: we don't use many features of FrameWork, so you could
|
|
also continue with this document.
|
|
</BLOCKQUOTE>
|
|
|
|
After the imports we get the definitions of resource-IDs in our
|
|
resource file, slightly changed from the previous version of our
|
|
program, and the state to string mapping. The main program is also
|
|
similar to our previous version, with one important exception: we
|
|
first check to see whether our resource is available before opening
|
|
the resource file. Why is this? Because later, when we will have
|
|
converted the script to an applet, our resources will be available in
|
|
the applet file and we don't need the separate resource file
|
|
anymore. <p>
|
|
|
|
Next comes the definition of our main class,
|
|
<CODE>InterslipControl</CODE>, which inherits
|
|
<CODE>FrameWork.Application</CODE>. The Application class handles the
|
|
menu bar and the main event loop and event dispatching. In the
|
|
<CODE>__init__</CODE> 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 we call <CODE>self._quit</CODE>,
|
|
which we will do when the user selects "quit". When we create
|
|
the instance of <CODE>MyDialog</CODE> (which inherits
|
|
<CODE>DialogWindow</CODE>, which inherits <CODE>Window</CODE>) 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. <p>
|
|
|
|
The <CODE>makeusermenus()</CODE> method (which is called sometime
|
|
during the Application <CODE>__init__</CODE> routine) creates a File
|
|
menu with a Quit command (shortcut command-Q), which will callback to
|
|
our quit() method. <CODE>Quit()</CODE>, in turn, calls <CODE>_quit</CODE> which
|
|
causes the mainloop to terminate at a convenient time. <p>
|
|
|
|
Application provides a standard about box, but we override this by
|
|
providing our own <CODE>do_about()</CODE> 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. <p>
|
|
|
|
Our main object finally overrides <CODE>idle()</CODE>, 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. <p>
|
|
|
|
The <CODE>MyDialog</CODE> class is the container for our main
|
|
window. Initialization is again done by first calling the base class
|
|
<CODE>__init__</CODE> function and finally setting two local variables
|
|
that are used by <CODE>updatestatus()</CODE> later. <p>
|
|
|
|
<CODE>Do_itemhit()</CODE> 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. <CODE>Connect()</CODE> and <CODE>disconnect()</CODE>
|
|
are again quite similar to our previous example. <p>
|
|
|
|
<CODE>Updatestatus()</CODE> 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,
|
|
<CODE>interslip.status()</CODE> 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. <p>
|
|
|
|
<H2><IMG SRC="html.icons/mkapplet.gif"><A NAME="applets">Creating applets</A></H2>
|
|
|
|
Now let us try to turn the python script into an applet, a standalone
|
|
application. This will <em>not</em> work if you have the "classic 68k"
|
|
Python distribution, only if you have the cfm68k or PPC distribution.
|
|
Actually, "standalone" is probably not the correct term here, since an
|
|
applet does still depend on a lot of the python environment: the
|
|
PythonCore shared library, the Python Preferences file, the python Lib
|
|
folder and any other modules that the main module depends on. It is
|
|
possible to get rid of all these dependencies except for the dependency
|
|
on PythonCore, but at the moment that is still quite difficult so we
|
|
will ignore that possibility for now. By standalone we mean here that
|
|
the script has the look-and-feel of an application, including the
|
|
ability to have its own document types, be droppable, etc. <p>
|
|
|
|
The easiest way to create an applet is to take your source file and
|
|
drop it onto "BuildApplet", 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 'Pyt0'. The latter
|
|
also happens if you do have a resource file but without the BNDL
|
|
combo. <A NAME="no-bundle">Actually</A>, 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. <p>
|
|
|
|
If you need slightly more control over the BuildApplet process you can
|
|
double-click it, 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. <p>
|
|
|
|
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. <p>
|
|
|
|
That's all for this example, you may now return to the <A HREF="index.html">
|
|
table of contents</A> to pick another topic. <p>
|