1<HTML><HEAD><TITLE>Using python to create Macintosh applications, part one</TITLE></HEAD> 2<BODY> 3 4<H1>Using python to create Macintosh applications, part one</H1> 5<HR> 6 7This document will show you how to create a simple mac-style 8application using Python. We will glance at how to use dialogs and 9resources. <p> 10 11The example application we look at will be a simple program with a 12dialog that allows you to perform domain name lookups on IP addresses 13and hostnames. 14The <A HREF="example1/dnslookup-1.py">source code</A> and 15<A HREF="example1/dnslookup-1.rsrc">resource file</A> 16for this application are available in the <A 17HREF="example1">example1</A> folder (which you will have to download 18if you are reading this document over the net and if you want to look 19at the resources). <p> 20 21We will use the builtin module "socket" that allows a 22Python program to perform all sorts of networking functions, and we 23will create the user interface around that. You should be able to run 24the sample code with the standard Python distribution.<p> 25 26<CITE> 27If you are interested in building your own extensions to python you 28should check out the companion document <A 29HREF="plugins.html">Creating Macintosh Python C extensions</A>, 30which tells you how to build your own C extension. 31<p> 32</CITE> 33 34<H2><A NAME="dialog-resources">Creating dialog resources</A></H2> 35 36Let us start with the creative bit: building the dialogs and creating 37an icon for our program. For this you need ResEdit, and a reasonable 38working knowledge of how to use it. "Inside Mac" or various books on 39macintosh programming will help here. <p> 40 41There is one fine point that deserves to be mentioned here: <A 42NAME="resource-numbering">resource numbering</A>. Because often your 43resources will be combined with those that the Python interpreter and 44various standard modules need you should give your DLOG and DITL 45resources numbers above 512. 128 and below are reserved for Apple, 46128-228 are for extensions like Tk, 47228-255 for the Python interpreter and 256-511 for standard 48modules. If you are writing a module that you will be distributing for 49inclusion in other people's programs you may want to register a number 50in the 256-511 range, contact Guido or myself or whoever you think is 51"in charge" of Python for the Macintosh at the moment. Even though the 52application we are writing at the moment will keep its resources in a 53separate resource file it is still a good idea to make sure that no 54conflicts arise: once you have opened your resource file any attempt 55by the interpreter to open a dialog will also search your resource 56file. <p> 57 58Okay, let's have a look at dnslookup-1.rsrc, our resource file. 59The DLOG and accompanying DITL resource both have number 512. Since 60ResEdit creates both with default ID=128 you should take care to 61change the number on both. The dialog itself is pretty basic: two 62buttons (Lookup and Quit), two labels and 63two text entry areas, one of which is used for output only. Here's what 64the dialog will look like at run time<p> 65<div align=center> 66<img width=324 height=189 src="example1/dnslookup-1.gif" alt="dialog image"> 67</div> 68<p> 69 70<H2><A NAME="modal-dialog">An application with a modal dialog</A></H2> 71 72Next, we will have to write the actual application. For this example, 73we will use a modal dialog. This means that we will put up the dialog 74and go into a loop asking the dialog manager for events (buttons 75pushed). We handle the actions requested by the user until the Quit 76button is pressed, upon which we exit our loop (and the program). This 77way of structuring your program is actually rather antisocial, since 78you force the user to do whatever you, the application writer, happen 79to want. A modal dialog leaves no way of escape whatsoever (except 80command-option-escape), and is usually not a good way to structure 81anything but the most simple questions. Even then: how often have you 82been confronted with a dialog asking a question that you could not 83answer because the data you needed was obscured by the dialog itself? 84In the next example we will look at an application that does pretty 85much the same as this one but in a more user-friendly way. <p> 86 87The code itself is contained in the file <A 88HREF="example1/dnslookup-1.py"> dnslookup-1.py</A>. Have 89a copy handy before you read on. The file starts off with a 90textstring giving a short description. Not many tools do anything with 91this as yet, but at some point in the future we <EM>will</EM> have all 92sorts of nifty class browser that will display this string, so just 93include it. Just put a short description at the start of each module, 94class, method and function. After the initial description and some 95comments, we import the modules we need. <p> 96 97<A NAME="easydialogs"><CODE>EasyDialogs</CODE></A> is a handy standard 98module that provides you with routines that put up common text-only 99modal dialogs: 100<UL> 101<LI> <CODE>Message(str)</CODE> 102displays the message "str" and an OK button, 103<LI> <CODE>AskString(prompt, default)</CODE> 104asks for a string, displays OK and Cancel buttons, 105<LI> <CODE>AskYesNoCancel(question, default)</CODE> 106displays a question and Yes, No and Cancel buttons. 107</UL> 108 109<A NAME="res"><CODE>Res</CODE></A> is a pretty complete interface to 110the MacOS Resource Manager, described fully in Inside Mac. There is 111currently no documentation of it, but the Apple documentation (or 112Think Ref) will help you on your way if you remember two points: 113<UL> 114<LI> Resources are implemented as Python objects, and each routine 115with a resource first argument is implemented as a python method. 116<LI> When in doubt about the arguments examine the routines docstring, 117as in <CODE>print Res.OpenResFile.__doc__</CODE> 118</UL> 119 120Similarly, <A NAME="dlg"><CODE>Dlg</CODE></A> is an interface to the 121Dialog manager (with Dialogs being implemented as python objects and 122routines with Dialog arguments being methods). The sys module you 123know, I hope. The string module is an often used module that enables 124you to perform many string related operations. In this case however, we 125are only using the "digits" constant from the string module. We could 126have simply defined "digits" as "0123456789". The socket module enables 127us to perform the domain name lookups. We 128use two calls from it: 129<UL> 130<LI> <CODE>gethostbyaddr()</CODE> 131returns the hostname associated with an IP address 132<LI> <CODE>gethostbyname()</CODE> 133returns the IP address associated with a hostname 134</UL> 135 136Next in the source file we get definitions for our dialog resource 137number and for the item numbers in our dialog. These should match the 138situation in our resource file dnslookup-1.rsrc, 139obviously.<p> 140 141On to the main program. We start off with opening our resource file, 142which should live in the same folder as the python source. If we 143cannot open it we use <CODE>EasyDialogs</CODE> to print a message and 144exit. You can try it: just move the resource file somewhere else for a 145moment. Then we call do_dialog() to do the real work. <p> 146 147<CODE>Do_dialog()</CODE> uses <CODE>Dlg.GetNewDialog()</CODE> to open 148a dialog window initialized from 'DLOG' resource ID_MAIN and putting 149it on screen in the frontmost position. Next, we go into a loop, 150calling <CODE>Dlg.ModalDialog()</CODE> to wait for the next user 151action. <CODE>ModalDialog()</CODE> will return us the item number that 152the user has clicked on (or otherwise activated). It will handle a few 153slightly more complicated things also, like the user typing into 154simple textfields, but it will <EM>not</EM> do things like updating 155the physical appearance of radio buttons, etc. See Inside Mac or 156another programming guide for how to handle this 157yourself. Fortunately, our simple application doesn't have to bother with this, 158since buttons and textfields are the only active elements we have. So, we do a 159simple switch on item number and call the appropriate routine to implement the 160action requested. Upon the user pressing "Quit" we simply leave the loop and, 161hence, <CODE>do_dialog()</CODE>. This will cause the python dialog object 162<CODE>my_dlg</CODE> to be deleted and the on-screen dialog to disappear. <p> 163 164<A NAME="dialog-warning">Time for a warning</A>: be very careful what 165you do as long as a dialog is on-screen. Printing something, for 166instance, may suddenly cause the standard output window to appear over 167the dialog, and since we took no measures to redraw the dialog it will 168become very difficult to get out of the dialog. Also, command-period 169may or may not work in this situation. I have also seen crashes in 170such a situation, probably due to the multiple event loops involved or 171some oversight in the interpreter. You have been warned. <p> 172 173The implementation of the "Lookup" command can use a bit more 174explaining: we get the necessary information with <CODE>dnslookup()</CODE> 175but now we have to update the on-screen dialog to present this 176information to the user. The <CODE>GetDialogItem()</CODE> method of 177the dialog returns three bits of information about the given item: its 178type, its data handle and its rect (the on-screen <CODE>x,y,w,h</CODE> 179coordinates). We are only interested in the data handle here, on which 180we call <CODE>SetDialogItemText()</CODE> to set our new text. Note 181here that python programmers need not bother with the C-string versus 182pascal-string controversy: the python glue module knows what is needed 183and converts the python string to the correct type. <p> 184 185And that concludes our first example of the use of resources and 186dialogs. Next, you could have a look at the source of EasyDialogs for 187some examples of using input fields and filterprocs. Or, go on with 188reading the <A HREF="example2.html">second part</A> of this document 189to see how to implement a better version of this application.<p> 190 191</BODY> 192</HTML> 193 194