blob: 95e2d0a1e8a714d7458b34b9c67cc278d25ad59c [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
Jack Jansen3412c5d1997-08-27 14:08:22 +000013HREF="example2">example2</A>. <p>
Jack Jansena6308131996-03-18 13:38:52 +000014
15Again, we start with ResEdit to create our dialogs. Not only do we
16want a main dialog this time but also an "About" dialog, and we
17provide the <A NAME="bundle">BNDL resource</A> and related stuff that
18an application cannot be without. (Actually, a python applet can be
19without, <A HREF="#no-bundle">see below</A>). "Inside Mac" or various
20books on macintosh programming will help here. Also, you can refer to
21the resource files provided in the Python source distribution for some
22of the python-specific points of BNDL programming: the
23"appletbundle.rsrc" file is what is used for creating applets if you
24don't provide your own resource file. <p>
25
26Let's have a look at InterslipControl-2.rsrc, our resource file. First
27off, there's the standard BNDL combo. I've picked 'PYTi' as signature
28for the application. I tend to pick PYT plus one lower-case letter for
29my signatures. The finder gets confused if you have two applications
30with the same signature. This may be due to some incorrectness on the
Jack Jansen3412c5d1997-08-27 14:08:22 +000031side of "BuildApplet", I am not sure. There is one case when you
Jack Jansena6308131996-03-18 13:38:52 +000032definitely need a unique signature: when you create an applet that has
33its own data files and you want the user to be able to start your
34applet by double-clicking one of the datafiles. <p>
35
36There's little to tell about the BNDL stuff: I basically copied the
37generic Python applet icons and pasted in the symbol for
38InterSLIP. The two dialogs are equally unexciting: dialog 512 is our
39main window which has four static text fields (two of which we will be
40modifying during runtime, to show the status of the connection) and
41two buttons "connect" and "disconnect". The "quit" and "update status"
42buttons have disappeared, because they are handled by a menu choice
43and automatically, respectively. <p>
44
45<H2>A modeless dialog application using FrameWork</H2>
46
47On to the source code in <A
48HREF="example2/InterslipControl-2.py">InterslipControl-2.py</A>. The
49start is similar to our previous example program <A
50HREF="example1/InterslipControl-1.py">InterSlipControl-1.py</A>, with
51one extra module being imported. To make life more simple we will use
52the <CODE>FrameWork</CODE> module, a nifty piece of code that handles
53all the gory mac details of event loop programming, menubar
54installation and all the other code that is the same for every mac
55program in the world. Like most standard modules, FrameWork will run
56some sample test code when you invoke it as a main program, so try it
57now. It will create a menu bar with an Apple menu with the about box
58and a "File" menu with some pythonesque choices (which do nothing
59interesting, by the way) and a "Quit" command that works. <p>
60
Jack Jansen08365421996-04-19 15:56:08 +000061<BLOCKQUOTE>
62If you have not used <code>FrameWork</code> before you may want to
63first take a look at the <A HREF="textedit.html">Pathetic EDitor</A>
64example, which builds a minimal text editor using FrameWork and TextEdit.
65On the other hand: we don't use many features of FrameWork, so you could
66also continue with this document.
67</BLOCKQUOTE>
Jack Jansena6308131996-03-18 13:38:52 +000068
69After the imports we get the definitions of resource-IDs in our
70resource file, slightly changed from the previous version of our
71program, and the state to string mapping. The main program is also
72similar to our previous version, with one important exception: we
73first check to see whether our resource is available before opening
74the resource file. Why is this? Because later, when we will have
75converted the script to an applet, our resources will be available in
76the applet file and we don't need the separate resource file
77anymore. <p>
78
79Next comes the definition of our main class,
80<CODE>InterslipControl</CODE>, which inherits
81<CODE>FrameWork.Application</CODE>. The Application class handles the
82menu bar and the main event loop and event dispatching. In the
83<CODE>__init__</CODE> routine we first let the base class initialize
84itself, then we create our modeless dialog and finally we jump into
Jack Jansenef5cd051996-09-17 12:39:12 +000085the main loop. The main loop continues until we call <CODE>self._quit</CODE>,
86which we will do when the user selects "quit". When we create
Jack Jansena6308131996-03-18 13:38:52 +000087the instance of <CODE>MyDialog</CODE> (which inherits
88<CODE>DialogWindow</CODE>, which inherits <CODE>Window</CODE>) we pass
89a reference to the application object, this reference is used to tell
90Application about our new window. This enables the event loop to keep
91track of all windows and dispatch things like update events and mouse
92clicks. <p>
93
94The <CODE>makeusermenus()</CODE> method (which is called sometime
95during the Application <CODE>__init__</CODE> routine) creates a File
96menu with a Quit command (shortcut command-Q), which will callback to
Jack Jansenef5cd051996-09-17 12:39:12 +000097our quit() method. <CODE>Quit()</CODE>, in turn, calls <CODE>_quit</CODE> which
98causes the mainloop to terminate at a convenient time. <p>
Jack Jansena6308131996-03-18 13:38:52 +000099
100Application provides a standard about box, but we override this by
101providing our own <CODE>do_about()</CODE> method which shows an about
102box from a resource as a modal dialog. This piece of code should look
103familiar to you from the previous example program. That do_about is
104called when the user selects About from the Apple menu is, again,
105taken care of by the __init__ routine of Application. <p>
106
107Our main object finally overrides <CODE>idle()</CODE>, the method
108called when no event is available. It passes the call on to our dialog
109object to give it a chance to update the status fields, if needed. <p>
110
111The <CODE>MyDialog</CODE> class is the container for our main
112window. Initialization is again done by first calling the base class
113<CODE>__init__</CODE> function and finally setting two local variables
114that are used by <CODE>updatestatus()</CODE> later. <p>
115
116<CODE>Do_itemhit()</CODE> is called when an item is selected in this
117dialog by the user. We are passed the item number (and the original
118event structure, which we normally ignore). The code is similar to the
119main loop of our previous example program: a switch depending on the
120item selected. <CODE>Connect()</CODE> and <CODE>disconnect()</CODE>
121are again quite similar to our previous example. <p>
122
123<CODE>Updatestatus()</CODE> is different, however. It is now
124potentially called many times per second instead of only when the
125user presses a button we don't want to update the display every time
126since that would cause some quite horrible flashing. Luckily,
127<CODE>interslip.status()</CODE> not only provides us with a state and
128a message but also with a message sequence number. If neither state
129nor message sequence number has changed since the last call there is
130no need to update the display, so we just return. For the rest,
131nothing has changed. <p>
132
133<H2><IMG SRC="html.icons/mkapplet.gif"><A NAME="applets">Creating applets</A></H2>
134
Jack Jansen3412c5d1997-08-27 14:08:22 +0000135Now let us try to turn the python script into an applet, a standalone
136application. This will <em>not</em> work if you have the "classic 68k"
Jack Jansena2139fe1998-02-25 15:40:35 +0000137Python distribution, only if you have the cfm68k or PPC distribution.
138
139<blockquote>
Jack Jansen3412c5d1997-08-27 14:08:22 +0000140Actually, "standalone" is probably not the correct term here, since an
141applet does still depend on a lot of the python environment: the
142PythonCore shared library, the Python Preferences file, the python Lib
143folder and any other modules that the main module depends on. It is
Jack Jansena2139fe1998-02-25 15:40:35 +0000144possible to get rid of all these dependencies and create true standalone
145applications in Python, but this is a bit difficult. See <a href="standalone.html">
146Standalone Applications in Python</a> for details. For this
147document, by standalone we mean here that
Jack Jansen3412c5d1997-08-27 14:08:22 +0000148the script has the look-and-feel of an application, including the
Jack Jansena2139fe1998-02-25 15:40:35 +0000149ability to have its own document types, be droppable, etc.
150</blockquote>
Jack Jansena6308131996-03-18 13:38:52 +0000151
152The easiest way to create an applet is to take your source file and
Jack Jansen3412c5d1997-08-27 14:08:22 +0000153drop it onto "BuildApplet", located in the Python home
154folder. This will create an applet with the same name as your python
Jack Jansena6308131996-03-18 13:38:52 +0000155source 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
Jack Jansen3412c5d1997-08-27 14:08:22 +0000159used, and the applet will have the default creator 'Pyt0'. The latter
Jack Jansena6308131996-03-18 13:38:52 +0000160also 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
Jack Jansen3412c5d1997-08-27 14:08:22 +0000169If you need slightly more control over the BuildApplet process you can
170double-click it, and you will get dialogs for source and
Jack Jansena6308131996-03-18 13:38:52 +0000171destination 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>