| 1 | <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 |  | 
|---|
| 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.  The <A | 
|---|
| 10 | HREF="example2/dnslookup-2.py">source code</A> and | 
|---|
| 11 | <A HREF="example2/dnslookup-2.rsrc">resource file</A> are available in the folder | 
|---|
| 12 | <A HREF="example2">example2</A>. <p> | 
|---|
| 13 |  | 
|---|
| 14 | Again, we start with ResEdit to create our dialogs. Not only do we | 
|---|
| 15 | want a main dialog this time but also an "About" dialog.  This example is less | 
|---|
| 16 | than complete since we do not provide a <A NAME="bundle">BNDL resource</A> | 
|---|
| 17 | and related stuff that an application cannot be without. We are able to do this | 
|---|
| 18 | when building a python applet since BuildApplet will substitute default resources | 
|---|
| 19 | for BNDL, etc. when none are supplied (<A HREF="#no-bundle">See below</A>.) | 
|---|
| 20 | "Inside Mac" or various | 
|---|
| 21 | books on Macintosh programming will help here. Also, you can refer to | 
|---|
| 22 | the resource files provided in the Python source distribution for some | 
|---|
| 23 | of the python-specific points of BNDL programming: the | 
|---|
| 24 | "appletbundle.rsrc" file is what is used for creating applets if you | 
|---|
| 25 | don't provide your own resource file. <p> | 
|---|
| 26 |  | 
|---|
| 27 | When creating your own BNDL resouorces, keep in mind that the Finder gets | 
|---|
| 28 | confused if you have more than one application with the same signature. This may be due | 
|---|
| 29 | to some incorrectness on the side of "BuildApplet", I am not sure.  There is one | 
|---|
| 30 | case when you definitely need a unique signature: when you create an applet that | 
|---|
| 31 | has its own data files and you want the user to be able to start your | 
|---|
| 32 | applet by double-clicking one of the datafiles. <p> | 
|---|
| 33 |  | 
|---|
| 34 | Let's have a look at dnslookup-2.rsrc, our resource file. Dialog 512 is the | 
|---|
| 35 | main window which has one button (Lookup), two labels and | 
|---|
| 36 | two text entry areas, one of which is used for output only. The "Quit" | 
|---|
| 37 | button has disappeared, because its function is handled by a menu choice.  Here's | 
|---|
| 38 | what it will look like at run time:<p> | 
|---|
| 39 | <div align=center> | 
|---|
| 40 | <img width=324 height=205 src="example2/dnslookup-2.gif" alt="dialog image"> | 
|---|
| 41 | </div> | 
|---|
| 42 | <p> | 
|---|
| 43 |  | 
|---|
| 44 | <H2>A modeless dialog application using FrameWork</H2> | 
|---|
| 45 |  | 
|---|
| 46 | On to the source code in <A | 
|---|
| 47 | HREF="example2/dnslookup-2.py">dnslookup-2.py</A>.  The | 
|---|
| 48 | start is similar to our previous example program <A | 
|---|
| 49 | HREF="example1/dnslookup-1.py">dnslookup-1.py</A>, with | 
|---|
| 50 | one extra module being imported. To make life more simple we will use | 
|---|
| 51 | the <CODE>FrameWork</CODE> module, a nifty piece of code that handles | 
|---|
| 52 | all the gory Mac details of event loop programming, menubar | 
|---|
| 53 | installation and all the other code that is the same for every Mac | 
|---|
| 54 | program in the world.  Like most standard modules, FrameWork will run | 
|---|
| 55 | some sample test code when you invoke it as a main program, so try it | 
|---|
| 56 | now. It will create a menu bar with an Apple menu with the about box | 
|---|
| 57 | and a "File" menu with some pythonesque choices (which do nothing | 
|---|
| 58 | interesting, by the way) and a "Quit" command that works. <p> | 
|---|
| 59 |  | 
|---|
| 60 | <BLOCKQUOTE> | 
|---|
| 61 | If you have not used <code>FrameWork</code> before you may want to | 
|---|
| 62 | first take a look at the <A HREF="textedit.html">Pathetic EDitor</A> | 
|---|
| 63 | example, which builds a minimal text editor using FrameWork and TextEdit. | 
|---|
| 64 | On the other hand: we don't use many features of FrameWork, so you could | 
|---|
| 65 | also continue with this document. | 
|---|
| 66 | </BLOCKQUOTE> | 
|---|
| 67 |  | 
|---|
| 68 | After the imports we get the definitions of resource-IDs in our | 
|---|
| 69 | resource file, slightly changed from the previous version of our | 
|---|
| 70 | program. The main program is also | 
|---|
| 71 | similar to our previous version, with one important exception: we | 
|---|
| 72 | first check to see whether our resource is available before opening | 
|---|
| 73 | the resource file. Why is this? Because later, when we will have | 
|---|
| 74 | converted the script to an applet, our resources will be available in | 
|---|
| 75 | the applet file and we don't need the separate resource file | 
|---|
| 76 | anymore. <p> | 
|---|
| 77 |  | 
|---|
| 78 | Next comes the definition of our main class, | 
|---|
| 79 | <CODE>DNSLookup</CODE>, which inherits | 
|---|
| 80 | <CODE>FrameWork.Application</CODE>. The Application class handles the | 
|---|
| 81 | menu bar and the main event loop and event dispatching. In the | 
|---|
| 82 | <CODE>__init__</CODE> routine we first let the base class initialize | 
|---|
| 83 | itself, then we create our modeless dialog and finally we jump into | 
|---|
| 84 | the main loop. The main loop continues until we call <CODE>self._quit</CODE>, | 
|---|
| 85 | which we will do when the user selects "Quit". When we create | 
|---|
| 86 | the instance of <CODE>MyDialog</CODE> (which inherits | 
|---|
| 87 | <CODE>DialogWindow</CODE>, which inherits <CODE>Window</CODE>) we pass | 
|---|
| 88 | a reference to the application object, this reference is used to tell | 
|---|
| 89 | Application about our new window.  This enables the event loop to keep | 
|---|
| 90 | track of all windows and dispatch things like update events and mouse | 
|---|
| 91 | clicks. <p> | 
|---|
| 92 |  | 
|---|
| 93 | The <CODE>makeusermenus()</CODE> method (which is called sometime | 
|---|
| 94 | during the Application <CODE>__init__</CODE> routine) creates a File | 
|---|
| 95 | menu with a Quit command (shortcut command-Q), which will callback to | 
|---|
| 96 | our quit() method. <CODE>Quit()</CODE>, in turn, calls <CODE>_quit</CODE> which | 
|---|
| 97 | causes the mainloop to terminate at a convenient time. <p> | 
|---|
| 98 |  | 
|---|
| 99 | Application provides a standard about box, but we override this by | 
|---|
| 100 | providing our own <CODE>do_about()</CODE> method which shows an about | 
|---|
| 101 | box from a resource as a modal dialog. This piece of code should look | 
|---|
| 102 | familiar to you from the previous example program. That do_about is | 
|---|
| 103 | called when the user selects About from the Apple menu is, again, | 
|---|
| 104 | taken care of by the __init__ routine of Application. <p> | 
|---|
| 105 |  | 
|---|
| 106 | The <CODE>MyDialog</CODE> class is the container for our main | 
|---|
| 107 | window. Initialization is again done by first calling the base class | 
|---|
| 108 | <CODE>__init__</CODE> function and finally setting the local variable | 
|---|
| 109 | "parent." <p> | 
|---|
| 110 |  | 
|---|
| 111 | <CODE>Do_itemhit()</CODE> is called when an item is selected in this | 
|---|
| 112 | dialog by the user. We are passed the item number (and the original | 
|---|
| 113 | event structure, which we normally ignore). The code is similar to the | 
|---|
| 114 | main loop of our previous example program: a switch depending on the | 
|---|
| 115 | item selected.  <CODE>Dnslookup()</CODE> is quite similar to our previous | 
|---|
| 116 | example. <p> | 
|---|
| 117 |  | 
|---|
| 118 | <H2><IMG SRC="html.icons/mkapplet.gif"><A NAME="applets">Creating applets</A></H2> | 
|---|
| 119 |  | 
|---|
| 120 | Now let us try to turn the python script into an applet, a standalone | 
|---|
| 121 | application. This will <em>not</em> work if you have the "classic 68k" | 
|---|
| 122 | Python distribution, only if you have the cfm68k or PPC distribution. | 
|---|
| 123 |  | 
|---|
| 124 | <blockquote> | 
|---|
| 125 | Actually, "standalone" is probably not the correct term here, since an | 
|---|
| 126 | applet does still depend on a lot of the python environment: the | 
|---|
| 127 | PythonCore shared library, the Python Preferences file, the python Lib | 
|---|
| 128 | folder and any other modules that the main module depends on. It is | 
|---|
| 129 | possible to get rid of all these dependencies and create true standalone | 
|---|
| 130 | applications in Python, but this is a bit difficult. See <a href="freezing.html"> | 
|---|
| 131 | Standalone Applications in Python</a> for details. For this | 
|---|
| 132 | document, by standalone we mean here that | 
|---|
| 133 | the script has the look-and-feel of an application, including the | 
|---|
| 134 | ability to have its own document types, be droppable, etc. | 
|---|
| 135 | </blockquote> | 
|---|
| 136 |  | 
|---|
| 137 | The easiest way to create an applet is to take your source file and | 
|---|
| 138 | drop it onto "BuildApplet", located in the Python home | 
|---|
| 139 | folder. This will create an applet with the same name as your python | 
|---|
| 140 | source with the ".py" stripped. Also, if a resource file with the same | 
|---|
| 141 | name as your source but with ".rsrc" extension is available the | 
|---|
| 142 | resources from that file will be copied to your applet too. If there | 
|---|
| 143 | is no resource file for your script a set of default resources will be | 
|---|
| 144 | used, and the applet will have the default creator 'Pyt0'. The latter | 
|---|
| 145 | also happens if you do have a resource file but without the BNDL | 
|---|
| 146 | combo. <A NAME="no-bundle">Actually</A>, as in the present example. | 
|---|
| 147 | <p> | 
|---|
| 148 |  | 
|---|
| 149 | If you need slightly more control over the BuildApplet process you can | 
|---|
| 150 | double-click it, and you will get dialogs for source and | 
|---|
| 151 | destination of the applet. The rest of the process, including locating | 
|---|
| 152 | the resource file, remains the same. <p> | 
|---|
| 153 |  | 
|---|
| 154 | Note that though our example application completely bypasses the | 
|---|
| 155 | normal python user interface this is by no means necessary. Any python | 
|---|
| 156 | script can be turned into an applet, and all the usual features of the | 
|---|
| 157 | interpreter still work. <p> | 
|---|
| 158 |  | 
|---|
| 159 | That's all for this example, you may now return to the <A HREF="index.html"> | 
|---|
| 160 | table of contents</A> to pick another topic. <p> | 
|---|
| 161 | </BODY> | 
|---|
| 162 | </HTML> | 
|---|