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