| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | <HTML><HEAD><TITLE>Using python to create Macintosh applications, part two</TITLE></HEAD> | 
					
						
							|  |  |  | <BODY> | 
					
						
							|  |  |  | <H1>Using python to create Macintosh applications, part two</H1> | 
					
						
							|  |  |  | <HR> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In this document we rewrite the application of the <A | 
					
						
							|  |  |  | HREF="example1.html">previous example</A> to use modeless dialogs. We | 
					
						
							|  |  |  | will use an application framework, and we will have a look at creating | 
					
						
							|  |  |  | applets, standalone applications written in Python.  <A | 
					
						
							|  |  |  | HREF="example2/InterslipControl-2.py">Source</A> and resource file (in | 
					
						
							|  |  |  | binary and <A HREF="example2/InterslipControl-2.rsrc.hqx">BinHex</A> | 
					
						
							|  |  |  | form for downloading) are available in the folder <A | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | HREF="example2">example2</A>. <p> | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Again, we start with ResEdit to create our dialogs. Not only do we | 
					
						
							|  |  |  | want a main dialog this time but also an "About" dialog, and we | 
					
						
							|  |  |  | provide the <A NAME="bundle">BNDL resource</A> and related stuff that | 
					
						
							|  |  |  | an application cannot be without. (Actually, a python applet can be | 
					
						
							|  |  |  | without, <A HREF="#no-bundle">see below</A>). "Inside Mac" or various | 
					
						
							|  |  |  | books on macintosh programming will help here. Also, you can refer to | 
					
						
							|  |  |  | the resource files provided in the Python source distribution for some | 
					
						
							|  |  |  | of the python-specific points of BNDL programming: the | 
					
						
							|  |  |  | "appletbundle.rsrc" file is what is used for creating applets if you | 
					
						
							|  |  |  | don't provide your own resource file. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Let's have a look at InterslipControl-2.rsrc, our resource file. First | 
					
						
							|  |  |  | off, there's the standard BNDL combo. I've picked 'PYTi' as signature | 
					
						
							|  |  |  | for the application. I tend to pick PYT plus one lower-case letter for | 
					
						
							|  |  |  | my signatures.  The finder gets confused if you have two applications | 
					
						
							|  |  |  | with the same signature. This may be due to some incorrectness on the | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | side of "BuildApplet", I am not sure.  There is one case when you | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | definitely need a unique signature: when you create an applet that has | 
					
						
							|  |  |  | its own data files and you want the user to be able to start your | 
					
						
							|  |  |  | applet by double-clicking one of the datafiles. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | There's little to tell about the BNDL stuff: I basically copied the | 
					
						
							|  |  |  | generic Python applet icons and pasted in the symbol for | 
					
						
							|  |  |  | InterSLIP. The two dialogs are equally unexciting: dialog 512 is our | 
					
						
							|  |  |  | main window which has four static text fields (two of which we will be | 
					
						
							|  |  |  | modifying during runtime, to show the status of the connection) and | 
					
						
							|  |  |  | two buttons "connect" and "disconnect". The "quit" and "update status" | 
					
						
							|  |  |  | buttons have disappeared, because they are handled by a menu choice | 
					
						
							|  |  |  | and automatically, respectively. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <H2>A modeless dialog application using FrameWork</H2> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | On to the source code in <A | 
					
						
							|  |  |  | HREF="example2/InterslipControl-2.py">InterslipControl-2.py</A>.  The | 
					
						
							|  |  |  | start is similar to our previous example program <A | 
					
						
							|  |  |  | HREF="example1/InterslipControl-1.py">InterSlipControl-1.py</A>, with | 
					
						
							|  |  |  | one extra module being imported. To make life more simple we will use | 
					
						
							|  |  |  | the <CODE>FrameWork</CODE> module, a nifty piece of code that handles | 
					
						
							|  |  |  | all the gory mac details of event loop programming, menubar | 
					
						
							|  |  |  | installation and all the other code that is the same for every mac | 
					
						
							|  |  |  | program in the world.  Like most standard modules, FrameWork will run | 
					
						
							|  |  |  | some sample test code when you invoke it as a main program, so try it | 
					
						
							|  |  |  | now. It will create a menu bar with an Apple menu with the about box | 
					
						
							|  |  |  | and a "File" menu with some pythonesque choices (which do nothing | 
					
						
							|  |  |  | interesting, by the way) and a "Quit" command that works. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-04-19 15:56:08 +00:00
										 |  |  | <BLOCKQUOTE> | 
					
						
							|  |  |  | If you have not used <code>FrameWork</code> before you may want to | 
					
						
							|  |  |  | first take a look at the <A HREF="textedit.html">Pathetic EDitor</A> | 
					
						
							|  |  |  | example, which builds a minimal text editor using FrameWork and TextEdit. | 
					
						
							|  |  |  | On the other hand: we don't use many features of FrameWork, so you could | 
					
						
							|  |  |  | also continue with this document.  | 
					
						
							|  |  |  | </BLOCKQUOTE> | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | After the imports we get the definitions of resource-IDs in our | 
					
						
							|  |  |  | resource file, slightly changed from the previous version of our | 
					
						
							|  |  |  | program, and the state to string mapping. The main program is also | 
					
						
							|  |  |  | similar to our previous version, with one important exception: we | 
					
						
							|  |  |  | first check to see whether our resource is available before opening | 
					
						
							|  |  |  | the resource file. Why is this? Because later, when we will have | 
					
						
							|  |  |  | converted the script to an applet, our resources will be available in | 
					
						
							|  |  |  | the applet file and we don't need the separate resource file | 
					
						
							|  |  |  | anymore. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Next comes the definition of our main class, | 
					
						
							|  |  |  | <CODE>InterslipControl</CODE>, which inherits | 
					
						
							|  |  |  | <CODE>FrameWork.Application</CODE>. The Application class handles the | 
					
						
							|  |  |  | menu bar and the main event loop and event dispatching. In the | 
					
						
							|  |  |  | <CODE>__init__</CODE> routine we first let the base class initialize | 
					
						
							|  |  |  | itself, then we create our modeless dialog and finally we jump into | 
					
						
							| 
									
										
										
										
											1996-09-17 12:39:12 +00:00
										 |  |  | the main loop. The main loop continues until we call <CODE>self._quit</CODE>, | 
					
						
							|  |  |  | which we will do when the user selects "quit". When we create | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | the instance of <CODE>MyDialog</CODE> (which inherits | 
					
						
							|  |  |  | <CODE>DialogWindow</CODE>, which inherits <CODE>Window</CODE>) we pass | 
					
						
							|  |  |  | a reference to the application object, this reference is used to tell | 
					
						
							|  |  |  | Application about our new window.  This enables the event loop to keep | 
					
						
							|  |  |  | track of all windows and dispatch things like update events and mouse | 
					
						
							|  |  |  | clicks. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The <CODE>makeusermenus()</CODE> method (which is called sometime | 
					
						
							|  |  |  | during the Application <CODE>__init__</CODE> routine) creates a File | 
					
						
							|  |  |  | menu with a Quit command (shortcut command-Q), which will callback to | 
					
						
							| 
									
										
										
										
											1996-09-17 12:39:12 +00:00
										 |  |  | our quit() method. <CODE>Quit()</CODE>, in turn, calls <CODE>_quit</CODE> which | 
					
						
							|  |  |  | causes the mainloop to terminate at a convenient time. <p> | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Application provides a standard about box, but we override this by | 
					
						
							|  |  |  | providing our own <CODE>do_about()</CODE> method which shows an about | 
					
						
							|  |  |  | box from a resource as a modal dialog. This piece of code should look | 
					
						
							|  |  |  | familiar to you from the previous example program. That do_about is | 
					
						
							|  |  |  | called when the user selects About from the Apple menu is, again, | 
					
						
							|  |  |  | taken care of by the __init__ routine of Application. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Our main object finally overrides <CODE>idle()</CODE>, the method | 
					
						
							|  |  |  | called when no event is available. It passes the call on to our dialog | 
					
						
							|  |  |  | object to give it a chance to update the status fields, if needed. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The <CODE>MyDialog</CODE> class is the container for our main | 
					
						
							|  |  |  | window. Initialization is again done by first calling the base class | 
					
						
							|  |  |  | <CODE>__init__</CODE> function and finally setting two local variables | 
					
						
							|  |  |  | that are used by <CODE>updatestatus()</CODE> later. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <CODE>Do_itemhit()</CODE> is called when an item is selected in this | 
					
						
							|  |  |  | dialog by the user. We are passed the item number (and the original | 
					
						
							|  |  |  | event structure, which we normally ignore). The code is similar to the | 
					
						
							|  |  |  | main loop of our previous example program: a switch depending on the | 
					
						
							|  |  |  | item selected.  <CODE>Connect()</CODE> and <CODE>disconnect()</CODE> | 
					
						
							|  |  |  | are again quite similar to our previous example. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <CODE>Updatestatus()</CODE> is different, however. It is now | 
					
						
							|  |  |  | potentially called many times per second instead of only when the | 
					
						
							|  |  |  | user presses a button we don't want to update the display every time | 
					
						
							|  |  |  | since that would cause some quite horrible flashing. Luckily, | 
					
						
							|  |  |  | <CODE>interslip.status()</CODE> not only provides us with a state and | 
					
						
							|  |  |  | a message but also with a message sequence number. If neither state | 
					
						
							|  |  |  | nor message sequence number has changed since the last call there is | 
					
						
							|  |  |  | no need to update the display, so we just return. For the rest, | 
					
						
							|  |  |  | nothing has changed. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <H2><IMG SRC="html.icons/mkapplet.gif"><A NAME="applets">Creating applets</A></H2> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | Now let us try to turn the python script into an applet, a standalone | 
					
						
							|  |  |  | application. This will <em>not</em> work if you have the "classic 68k" | 
					
						
							| 
									
										
										
										
											1998-02-25 15:40:35 +00:00
										 |  |  | Python distribution, only if you have the cfm68k or PPC distribution. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <blockquote> | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | Actually, "standalone" is probably not the correct term here, since an | 
					
						
							|  |  |  | applet does still depend on a lot of the python environment: the | 
					
						
							|  |  |  | PythonCore shared library, the Python Preferences file, the python Lib | 
					
						
							|  |  |  | folder and any other modules that the main module depends on. It is | 
					
						
							| 
									
										
										
										
											1998-02-25 15:40:35 +00:00
										 |  |  | possible to get rid of all these dependencies and create true standalone | 
					
						
							|  |  |  | applications in Python, but this is a bit difficult. See <a href="standalone.html"> | 
					
						
							|  |  |  | Standalone Applications in Python</a> for details. For this | 
					
						
							|  |  |  | document, by standalone we mean here that | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | the script has the look-and-feel of an application, including the | 
					
						
							| 
									
										
										
										
											1998-02-25 15:40:35 +00:00
										 |  |  | ability to have its own document types, be droppable, etc. | 
					
						
							|  |  |  | </blockquote> | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The easiest way to create an applet is to take your source file and | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | drop it onto "BuildApplet", located in the Python home | 
					
						
							|  |  |  | folder. This will create an applet with the same name as your python | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | source with the ".py" stripped. Also, if a resource file with the same | 
					
						
							|  |  |  | name as your source but with ".rsrc" extension is available the | 
					
						
							|  |  |  | resources from that file will be copied to your applet too. If there | 
					
						
							|  |  |  | is no resource file for your script a set of default resources will be | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | used, and the applet will have the default creator 'Pyt0'. The latter | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | also happens if you do have a resource file but without the BNDL | 
					
						
							|  |  |  | combo. <A NAME="no-bundle">Actually</A>, for our example that would | 
					
						
							|  |  |  | have been the most logical solution, since our applet does not have | 
					
						
							|  |  |  | its own data files.  It would have saved us hunting for an unused | 
					
						
							|  |  |  | creator code. The only reason for using the BNDL in this case is | 
					
						
							|  |  |  | having the custom icon, but that could have been done by pasting an | 
					
						
							|  |  |  | icon on the finder Info window, or by providing an custon icon in your | 
					
						
							|  |  |  | resource file and setting the "custom icon" finder bit. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | If you need slightly more control over the BuildApplet process you can | 
					
						
							|  |  |  | double-click it, and you will get dialogs for source and | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | destination of the applet. The rest of the process, including locating | 
					
						
							|  |  |  | the resource file, remains the same. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Note that though our example application completely bypasses the | 
					
						
							|  |  |  | normal python user interface this is by no means necessary. Any python | 
					
						
							|  |  |  | script can be turned into an applet, and all the usual features of the | 
					
						
							|  |  |  | interpreter still work. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | That's all for this example, you may now return to the <A HREF="index.html"> | 
					
						
							|  |  |  | table of contents</A> to pick another topic. <p> |