Oops -- Lib/Test should be Lib/test, of course!
[python/dscho.git] / Mac / Demo / example1.html
blobada669b29df325dcd1731e36bf37c898b4cb922f
1 <HTML><HEAD><TITLE>Using python to create Macintosh applications, part one</TITLE></HEAD>
2 <BODY>
3 <H1>Using python to create Macintosh applications, part one</H1>
4 <HR>
6 This document will show you how to create a simple mac-style
7 application using Python. We will glance at how to use dialogs and
8 resources. <p>
10 The example application we look at will be a simple program with a
11 dialog that allows you to control and monitor InterSLIP, a device
12 driver that connects your mac to the Internet via a modem connection.
13 <A HREF="example1/InterslipControl-1.py">Source</A> and resource file
14 (in binary and <A
15 HREF="example1/InterslipControl-1.rsrc.hqx">BinHex</A> form for
16 downloading) for this application are available in the <A
17 HREF="example1">example1</A> folder (which you will have to download
18 if you are reading this document over the net and if you want to look
19 at the resources). <p>
21 We will use a C extension module module "interslip" that allows a
22 Python program to control and monitor the behaviour of the low-level
23 driver, and we will create the user interface around that. If you want
24 to actually run the code, you will obvously need InterSLIP and the
25 interslip module. The latter is available as a dynamically loadable
26 extension for PowerPC/cfm68k Pythons, and may be compiled in your static 68K
27 Python. As of this writing there is still a slight
28 problem with the Python interslip module causing it to say "file not
29 found" if the driver is not loaded yet. The workaround is to load the
30 driver by starting InterSLIP Control and quitting it. <p>
32 <CITE>
33 If you are interested in building your own extensions to python you
34 should check out the companion document <A
35 HREF="plugins.html">Creating Macintosh Python C extensions</A>,
36 which tells you how to build your own C extension. Not completely
37 coincidental this document uses the interslip module that we will use
38 here as an example. <p>
39 </CITE>
41 <H2><A NAME="dialog-resources">Creating dialog resources</A></H2>
43 Let us start with the creative bit: building the dialogs and creating
44 an icon for our program. For this you need ResEdit, and a reasonable
45 working knowledge of how to use it. "Inside Mac" or various books on
46 macintosh programming will help here. <p>
48 There is one fine point that deserves to be mentioned here: <A
49 NAME="resource-numbering">resource numbering</A>. Because often your
50 resources will be combined with those that the Python interpreter and
51 various standard modules need you should give your DLOG and DITL
52 resources numbers above 512. 128 and below are reserved for Apple,
53 128-228 are for extensions like Tk,
54 228-255 for the Python interpreter and 256-511 for standard
55 modules. If you are writing a module that you will be distributing for
56 inclusion in other people's programs you may want to register a number
57 in the 256-511 range, contact Guido or myself or whoever you think is
58 "in charge" of Python for the Macintosh at the moment. Even though the
59 application we are writing at the moment will keep its resources in a
60 separate resource file it is still a good idea to make sure that no
61 conflicts arise: once you have opened your resource file any attempt
62 by the interpreter to open a dialog will also search your resource
63 file. <p>
65 Okay, let's have a look at InterslipControl-1.rsrc, our resource file.
66 The DLOG and accompanying DITL resource both have number 512. Since
67 ResEdit creates both with default ID=128 you should take care to
68 change the number on both. The dialog itself is pretty basic: four
69 buttons (connect, disconnect, update status and quit), two labels and
70 two status fields. <p>
72 <H2><A NAME="modal-dialog">An application with a modal dialog</A></H2>
74 Next, we will have to write the actual application. For this example,
75 we will use a modal dialog. This means that we will put up the dialog
76 and go into a loop asking the dialog manager for events (buttons
77 pushed). We handle the actions requested by the user until the quit
78 button is pressed, upon which we exit our loop (and the program). This
79 way of structuring your program is actually rather antisocial, since
80 you force the user to do whatever you, the application writer, happen
81 to want. A modal dialog leaves no way of escape whatsoever (except
82 command-option-escape), and is usually not a good way to structure
83 anything but the most simple questions. Even then: how often have you
84 been confronted with a dialog asking a question that you could not
85 answer because the data you needed was obscured by the dialog itself?
86 In the next example we will look at an application that does pretty
87 much the same as this one but in a more user-friendly way. <p>
89 On to the code itself, in file <A
90 HREF="example1/InterslipControl-1.py"> InterslipControl-1.py</A>. Have
91 a copy handy before you read on. The file starts off with a
92 textstring giving a short description. Not many tools do anything with
93 this as yet, but at some point in the future we <EM>will</EM> have all
94 sorts of nifty class browser that will display this string, so just
95 include it. Just put a short description at the start of each module,
96 class, method and function. After the initial description and some
97 comments, we import the modules we need. <p>
99 <A NAME="easydialogs"><CODE>EasyDialogs</CODE></A> is a handy standard
100 module that provides you with routines that put up common text-only
101 modal dialogs:
102 <UL>
103 <LI> <CODE>Message(str)</CODE>
104 displays the message "str" and an OK button,
105 <LI> <CODE>AskString(prompt, default)</CODE>
106 asks for a string, displays OK and Cancel buttons,
107 <LI> <CODE>AskYesNoCancel(question, default)</CODE>
108 displays a question and Yes, No and Cancel buttons.
109 </UL>
111 <A NAME="res"><CODE>Res</CODE></A> is a pretty complete interface to
112 the MacOS Resource Manager, described fully in Inside Mac. There is
113 currently no documentation of it, but the Apple documentation (or
114 Think Ref) will help you on your way if you remember two points:
115 <UL>
116 <LI> Resources are implemented as Python objects, and each routine
117 with a resource first argument is implemented as a python method.
118 <LI> When in doubt about the arguments examine the routines docstring,
119 as in <CODE>print Res.OpenResFile.__doc__</CODE>
120 </UL>
122 Similarly, <A NAME="dlg"><CODE>Dlg</CODE></A> is an interface to the
123 Dialog manager (with Dialogs being implemented as python objects and
124 routines with Dialog arguments being methods). The sys module you
125 know, I hope. <A NAME="interslip"><CODE>Interslip</CODE></A>,
126 finally, is the module with the interface to the InterSLIP driver. We
127 use four calls from it:
128 <UL>
129 <LI> <CODE>open()</CODE>
130 opens the driver
131 <LI> <CODE>connect()</CODE>
132 asks it to initiate a connection procedure (without waiting)
133 <LI> <CODE>disconnect()</CODE>
134 asks it to initiate a disconnection procedure (without waiting)
135 <LI> <CODE>status()</CODE>
136 returns the current connection status in the form of an integer state,
137 an integer "message sequence number" and a message string.
138 </UL>
140 Next in the source file we get definitions for our dialog resource
141 number and for the item numbers in our dialog. These should match the
142 situation in our resource file InterslipControl-1.rsrc,
143 obviously. Then we get an array converting numeric state codes
144 returned by <CODE>interslip.status()</CODE> to textual messages. <p>
146 On to the main program. We start off with opening our resource file,
147 which should live in the same folder as the python source. If we
148 cannot open it we use <CODE>EasyDialogs</CODE> to print a message and
149 exit. You can try it: just move the resource file somewhere else for a
150 moment. Then, we try to open the interslip driver, again catching an
151 error. All modules that raise <A NAME="macos-errors">MacOS error
152 exceptions</A> will pass a 2-tuple to the exception handler with the
153 first item being the numeric <CODE>OSErr</CODE> code and the second
154 one being an informative message. If no informative message is
155 available it will be the rather uninformative <CODE>"MacOS Error
156 -12345"</CODE>, but at least the second item will always be a
157 printable string. Finally we call do_dialog() to do the real work. <p>
159 <CODE>Do_dialog()</CODE> uses <CODE>Dlg.GetNewDialog()</CODE> to open
160 a dialog window initialized from 'DLOG' resource ID_MAIN and putting
161 it on screen in the frontmost position. Next, we go into a loop,
162 calling <CODE>Dlg.ModalDialog()</CODE> to wait for the next user
163 action. <CODE>ModalDialog()</CODE> will return us the item number that
164 the user has clicked on (or otherwise activated). It will handle a few
165 slightly more complicated things also, like the user typing into
166 simple textfields, but it will <EM>not</EM> do things like updating
167 the physical appearance of radio buttons, etc. See Inside Mac or
168 another programming guide for how to handle this
169 yourself. Fortunately, our simple application doesn't have to bother
170 with this, since buttons are the only active elements we have. So, we
171 do a simple switch on item number and call the appropriate routine to
172 implement the action requested. Upon the user pressing "quit" we
173 simply leave the loop and, hence, <CODE>do_dialog()</CODE>. This will
174 cause the python dialog object <CODE>my_dlg</CODE> to be deleted and
175 the on-screen dialog to disappear. <p>
177 <A NAME="dialog-warning">Time for a warning</A>: be very careful what
178 you do as long as a dialog is on-screen. Printing something, for
179 instance, may suddenly cause the standard output window to appear over
180 the dialog, and since we took no measures to redraw the dialog it will
181 become very difficult to get out of the dialog. Also, command-period
182 may or may not work in this situation. I have also seen crashes in
183 such a situation, probably due to the multiple event loops involved or
184 some oversight in the interpreter. You have been warned. <p>
186 The implementation of the "update status" command can use a bit more
187 explaining: we get the new information with <CODE>do_status()</CODE>
188 but now we have to update the on-screen dialog to present this
189 information to the user. The <CODE>GetDialogItem()</CODE> method of
190 the dialog returns three bits of information about the given item: its
191 type, its data handle and its rect (the on-screen <CODE>x,y,w,h</CODE>
192 coordinates). We are only interested in the data handle here, on which
193 we call <CODE>SetDialogItemText()</CODE> to set our new text. Note
194 here that python programmers need not bother with the C-string versus
195 pascal-string controversy: the python glue module knows what is needed
196 and converts the python string to the correct type. <p>
198 Finally, the three implementation routines <CODE>do_connect()</CODE>,
199 <CODE>do_disconnect()</CODE> and <CODE>do_status()</CODE> are simply
200 boring wrappers around the corresponding interslip methods that will
201 put up a dialog in case of an error. <p>
203 And that concludes our first example of the use of resources and
204 dialogs. Next, you could have a look at the source of EasyDialogs for
205 some examples of using input fields and filterprocs. Or, go on with
206 reading the <A HREF="example2.html">second part</A> of this document
207 to see how to implement a better version of this application. Not only
208 will it allow the user to go back to the finder (or other apps) when
209 your application is running, it will also free her of the RSI-inducing
210 chore of pressing "update status" continuously... <p>