blob: 3bd2791b9f3b5941b144b2f2bae8201ebfb7c13c [file] [log] [blame]
Jack Jansena6308131996-03-18 13:38:52 +00001<HTML><HEAD><TITLE>Using python to create Macintosh applications, part two</TITLE></HEAD>
2<BODY>
3<H1>Using python to create Macintosh applications, part two</H1>
4<HR>
5
6In this document we rewrite the application of the <A
7HREF="example1.html">previous example</A> to use modeless dialogs. We
8will use an application framework, and we will have a look at creating
9applets, standalone applications written in Python. <A
10HREF="example2/InterslipControl-2.py">Source</A> and resource file (in
11binary and <A HREF="example2/InterslipControl-2.rsrc.hqx">BinHex</A>
12form for downloading) are available in the folder <A
13HREF="example2">example2</A>. If you want to run the program on your
14machine you will also need a new copy of <A
15HREF="update-to-1.3/FrameWork.py">FrameWork.py</A>, which has been
16updated since the 1.3 release. <p>
17
18Again, we start with ResEdit to create our dialogs. Not only do we
19want a main dialog this time but also an "About" dialog, and we
20provide the <A NAME="bundle">BNDL resource</A> and related stuff that
21an application cannot be without. (Actually, a python applet can be
22without, <A HREF="#no-bundle">see below</A>). "Inside Mac" or various
23books on macintosh programming will help here. Also, you can refer to
24the resource files provided in the Python source distribution for some
25of the python-specific points of BNDL programming: the
26"appletbundle.rsrc" file is what is used for creating applets if you
27don't provide your own resource file. <p>
28
29Let's have a look at InterslipControl-2.rsrc, our resource file. First
30off, there's the standard BNDL combo. I've picked 'PYTi' as signature
31for the application. I tend to pick PYT plus one lower-case letter for
32my signatures. The finder gets confused if you have two applications
33with the same signature. This may be due to some incorrectness on the
34side of "mkapplet", I am not sure. There is one case when you
35definitely need a unique signature: when you create an applet that has
36its own data files and you want the user to be able to start your
37applet by double-clicking one of the datafiles. <p>
38
39There's little to tell about the BNDL stuff: I basically copied the
40generic Python applet icons and pasted in the symbol for
41InterSLIP. The two dialogs are equally unexciting: dialog 512 is our
42main window which has four static text fields (two of which we will be
43modifying during runtime, to show the status of the connection) and
44two buttons "connect" and "disconnect". The "quit" and "update status"
45buttons have disappeared, because they are handled by a menu choice
46and automatically, respectively. <p>
47
48<H2>A modeless dialog application using FrameWork</H2>
49
50On to the source code in <A
51HREF="example2/InterslipControl-2.py">InterslipControl-2.py</A>. The
52start is similar to our previous example program <A
53HREF="example1/InterslipControl-1.py">InterSlipControl-1.py</A>, with
54one extra module being imported. To make life more simple we will use
55the <CODE>FrameWork</CODE> module, a nifty piece of code that handles
56all the gory mac details of event loop programming, menubar
57installation and all the other code that is the same for every mac
58program in the world. Like most standard modules, FrameWork will run
59some sample test code when you invoke it as a main program, so try it
60now. It will create a menu bar with an Apple menu with the about box
61and a "File" menu with some pythonesque choices (which do nothing
62interesting, by the way) and a "Quit" command that works. <p>
63
64<CITE>
65A more complete description of <A NAME="framework">FrameWork</A> is
66sorely needed, and will (at some point) be incorporated in the
67programmers manual or in place of this paragraph. For now you'll have
68to make do with the knowledge that you use FrameWork by building your
69classes upon the classes provided by it and selectively overriding
70methods to extend its functionality (or override the default
71behaviour). And you should read the Source, of Course:-) <p>
72</CITE>
73
74After the imports we get the definitions of resource-IDs in our
75resource file, slightly changed from the previous version of our
76program, and the state to string mapping. The main program is also
77similar to our previous version, with one important exception: we
78first check to see whether our resource is available before opening
79the resource file. Why is this? Because later, when we will have
80converted the script to an applet, our resources will be available in
81the applet file and we don't need the separate resource file
82anymore. <p>
83
84Next comes the definition of our main class,
85<CODE>InterslipControl</CODE>, which inherits
86<CODE>FrameWork.Application</CODE>. The Application class handles the
87menu bar and the main event loop and event dispatching. In the
88<CODE>__init__</CODE> routine we first let the base class initialize
89itself, then we create our modeless dialog and finally we jump into
90the main loop. The main loop continues until <CODE>self</CODE> is
91raised, which we will do when the user selects "quit". When we create
92the instance of <CODE>MyDialog</CODE> (which inherits
93<CODE>DialogWindow</CODE>, which inherits <CODE>Window</CODE>) we pass
94a reference to the application object, this reference is used to tell
95Application about our new window. This enables the event loop to keep
96track of all windows and dispatch things like update events and mouse
97clicks. <p>
98
99The <CODE>makeusermenus()</CODE> method (which is called sometime
100during the Application <CODE>__init__</CODE> routine) creates a File
101menu with a Quit command (shortcut command-Q), which will callback to
102our quit() method. <CODE>Quit()</CODE>, in turn, raises 'self' which
103causes the mainloop to terminate. <p>
104
105Application provides a standard about box, but we override this by
106providing our own <CODE>do_about()</CODE> method which shows an about
107box from a resource as a modal dialog. This piece of code should look
108familiar to you from the previous example program. That do_about is
109called when the user selects About from the Apple menu is, again,
110taken care of by the __init__ routine of Application. <p>
111
112Our main object finally overrides <CODE>idle()</CODE>, the method
113called when no event is available. It passes the call on to our dialog
114object to give it a chance to update the status fields, if needed. <p>
115
116The <CODE>MyDialog</CODE> class is the container for our main
117window. Initialization is again done by first calling the base class
118<CODE>__init__</CODE> function and finally setting two local variables
119that are used by <CODE>updatestatus()</CODE> later. <p>
120
121<CODE>Do_itemhit()</CODE> is called when an item is selected in this
122dialog by the user. We are passed the item number (and the original
123event structure, which we normally ignore). The code is similar to the
124main loop of our previous example program: a switch depending on the
125item selected. <CODE>Connect()</CODE> and <CODE>disconnect()</CODE>
126are again quite similar to our previous example. <p>
127
128<CODE>Updatestatus()</CODE> is different, however. It is now
129potentially called many times per second instead of only when the
130user presses a button we don't want to update the display every time
131since that would cause some quite horrible flashing. Luckily,
132<CODE>interslip.status()</CODE> not only provides us with a state and
133a message but also with a message sequence number. If neither state
134nor message sequence number has changed since the last call there is
135no need to update the display, so we just return. For the rest,
136nothing has changed. <p>
137
138<H2><IMG SRC="html.icons/mkapplet.gif"><A NAME="applets">Creating applets</A></H2>
139
140Now, if you have a PowerPC Macintosh, let us try to turn the python
141script into an applet, a standalone application. Actually,
142"standalone" is probably not the correct term here, since an applet
143does still depend on a lot of the python environment: the PythonCore
144shared library, the Python Preferences file, the python Lib folder and
145any other modules that the main module depends on. It is possible to
146get rid of all these dependencies except for the dependency on
147PythonCore, but at the moment that is still quite difficult so we will
148ignore that possibility for now. By standalone we mean here that the
149script has the look-and-feel of an application, including the ability
150to have its own document types, be droppable, etc. <p>
151
152The easiest way to create an applet is to take your source file and
153drop it onto "mkapplet" (normally located in the Python home
154folder). This will create an applet with the same name as your python
155source with the ".py" stripped. Also, if a resource file with the same
156name as your source but with ".rsrc" extension is available the
157resources from that file will be copied to your applet too. If there
158is no resource file for your script a set of default resources will be
159used, and the applet will have the default creator 'PYTa'. The latter
160also happens if you do have a resource file but without the BNDL
161combo. <A NAME="no-bundle">Actually</A>, for our example that would
162have been the most logical solution, since our applet does not have
163its own data files. It would have saved us hunting for an unused
164creator code. The only reason for using the BNDL in this case is
165having the custom icon, but that could have been done by pasting an
166icon on the finder Info window, or by providing an custon icon in your
167resource file and setting the "custom icon" finder bit. <p>
168
169If you need slightly more control over the mkapplet process you can
170double-click mkapplet, and you will get dialogs for source and
171destination of the applet. The rest of the process, including locating
172the resource file, remains the same. <p>
173
174Note that though our example application completely bypasses the
175normal python user interface this is by no means necessary. Any python
176script can be turned into an applet, and all the usual features of the
177interpreter still work. <p>
178
179That's all for this example, you may now return to the <A HREF="index.html">
180table of contents</A> to pick another topic. <p>