mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	
		
			
	
	
		
			212 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
		
		
			
		
	
	
			212 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| 
								 | 
							
								<HTML><HEAD><TITLE>Using python to create Macintosh applications, part one</TITLE></HEAD>
							 | 
						||
| 
								 | 
							
								<BODY>
							 | 
						||
| 
								 | 
							
								<H1>Using python to create Macintosh applications, part one</H1>
							 | 
						||
| 
								 | 
							
								<HR>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This document will show you how to create a simple mac-style
							 | 
						||
| 
								 | 
							
								application using Python. We will glance at how to use dialogs and
							 | 
						||
| 
								 | 
							
								resources. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The example application we look at will be a simple program with a
							 | 
						||
| 
								 | 
							
								dialog that allows you to control and monitor InterSLIP, a device
							 | 
						||
| 
								 | 
							
								driver that connects your mac to the Internet via a modem connection.
							 | 
						||
| 
								 | 
							
								<A HREF="example1/InterslipControl-1.py">Source</A> and resource file
							 | 
						||
| 
								 | 
							
								(in binary and <A
							 | 
						||
| 
								 | 
							
								HREF="example1/InterslipControl-1.rsrc.hqx">BinHex</A> form for
							 | 
						||
| 
								 | 
							
								downloading) for this application are available in the <A
							 | 
						||
| 
								 | 
							
								HREF="example1">example1</A> folder (which you will have to download
							 | 
						||
| 
								 | 
							
								if you are reading this document over the net and if you want to look
							 | 
						||
| 
								 | 
							
								at the resources). <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								We will use a C extension module module "interslip" that allows a
							 | 
						||
| 
								 | 
							
								Python program to control and monitor the behaviour of the low-level
							 | 
						||
| 
								 | 
							
								driver, and we will create the user interface around that. If you want
							 | 
						||
| 
								 | 
							
								to actually run the code, you will obvously need InterSLIP and the
							 | 
						||
| 
								 | 
							
								interslip module. The latter is available as a dynamically loadable
							 | 
						||
| 
								 | 
							
								extension for PowerPC macs, and may be compiled in your Python
							 | 
						||
| 
								 | 
							
								interpreter for 68K macs. As of this writing there is still a slight
							 | 
						||
| 
								 | 
							
								problem with the Python interslip module causing it to say "file not
							 | 
						||
| 
								 | 
							
								found" if the driver is not loaded yet. The workaround is to load the
							 | 
						||
| 
								 | 
							
								driver by starting InterSLIP Control and quitting it. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<CITE>
							 | 
						||
| 
								 | 
							
								If you are interested in building your own extensions to python you
							 | 
						||
| 
								 | 
							
								should check out the companion document <A
							 | 
						||
| 
								 | 
							
								HREF="plugins.html">Creating Macintosh Python C extensions</A>,
							 | 
						||
| 
								 | 
							
								which tells you how to build your own C extension. Not completely
							 | 
						||
| 
								 | 
							
								coincidental this document uses the interslip module that we will use
							 | 
						||
| 
								 | 
							
								here as an example. <p>
							 | 
						||
| 
								 | 
							
								</CITE>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<H2><A NAME="dialog-resources">Creating dialog resources</A></H2>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Let us start with the creative bit: building the dialogs and creating
							 | 
						||
| 
								 | 
							
								an icon for our program. For this you need ResEdit, and a reasonable
							 | 
						||
| 
								 | 
							
								working knowledge of how to use it. "Inside Mac" or various books on
							 | 
						||
| 
								 | 
							
								macintosh programming will help here. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								There is one fine point that deserves to be mentioned here: <A
							 | 
						||
| 
								 | 
							
								NAME="resource-numbering">resource numbering</A>.  Because often your
							 | 
						||
| 
								 | 
							
								resources will be combined with those that the Python interpreter and
							 | 
						||
| 
								 | 
							
								various standard modules need you should give your DLOG and DITL
							 | 
						||
| 
								 | 
							
								resources numbers above 512. 128 and below are reserved for Apple,
							 | 
						||
| 
								 | 
							
								128-255 for the Python interpreter and 256-511 for standard
							 | 
						||
| 
								 | 
							
								modules. If you are writing a module that you will be distributing for
							 | 
						||
| 
								 | 
							
								inclusion in other people's programs you may want to register a number
							 | 
						||
| 
								 | 
							
								in the 256-511 range, contact Guido or myself or whoever you think is
							 | 
						||
| 
								 | 
							
								"in charge" of Python for the Macintosh at the moment. Even though the
							 | 
						||
| 
								 | 
							
								application we are writing at the moment will keep its resources in a
							 | 
						||
| 
								 | 
							
								separate resource file it is still a good idea to make sure that no
							 | 
						||
| 
								 | 
							
								conflicts arise: once you have opened your resource file any attempt
							 | 
						||
| 
								 | 
							
								by the interpreter to open a dialog will also search your resource
							 | 
						||
| 
								 | 
							
								file. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Okay, let's have a look at InterslipControl-1.rsrc, our resource file.
							 | 
						||
| 
								 | 
							
								The DLOG and accompanying DITL resource both have number 512. Since
							 | 
						||
| 
								 | 
							
								ResEdit creates both with default ID=128 you should take care to
							 | 
						||
| 
								 | 
							
								change the number on both. The dialog itself is pretty basic: four
							 | 
						||
| 
								 | 
							
								buttons (connect, disconnect, update status and quit), two labels and
							 | 
						||
| 
								 | 
							
								two status fields. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<H2><A NAME="modal-dialog">An application with a modal dialog</A></H2>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Next, we will have to write the actual application. For this example,
							 | 
						||
| 
								 | 
							
								we will use a modal dialog. This means that we will put up the dialog
							 | 
						||
| 
								 | 
							
								and go into a loop asking the dialog manager for events (buttons
							 | 
						||
| 
								 | 
							
								pushed). We handle the actions requested by the user until the quit
							 | 
						||
| 
								 | 
							
								button is pressed, upon which we exit our loop (and the program). This
							 | 
						||
| 
								 | 
							
								way of structuring your program is actually rather antisocial, since
							 | 
						||
| 
								 | 
							
								you force the user to do whatever you, the application writer, happen
							 | 
						||
| 
								 | 
							
								to want. A modal dialog leaves no way of escape whatsoever (except
							 | 
						||
| 
								 | 
							
								command-option-escape), and is usually not a good way to structure
							 | 
						||
| 
								 | 
							
								anything but the most simple questions.  Even then: how often have you
							 | 
						||
| 
								 | 
							
								been confronted with a dialog asking a question that you could not
							 | 
						||
| 
								 | 
							
								answer because the data you needed was obscured by the dialog itself?
							 | 
						||
| 
								 | 
							
								In the next example we will look at an application that does pretty
							 | 
						||
| 
								 | 
							
								much the same as this one but in a more user-friendly way. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								On to the code itself, in file <A
							 | 
						||
| 
								 | 
							
								HREF="example1/InterslipControl-1.py"> InterslipControl-1.py</A>. Have
							 | 
						||
| 
								 | 
							
								a copy handy before you read on.  The file starts off with a
							 | 
						||
| 
								 | 
							
								textstring giving a short description. Not many tools do anything with
							 | 
						||
| 
								 | 
							
								this as yet, but at some point in the future we <EM>will</EM> have all
							 | 
						||
| 
								 | 
							
								sorts of nifty class browser that will display this string, so just
							 | 
						||
| 
								 | 
							
								include it. Just put a short description at the start of each module,
							 | 
						||
| 
								 | 
							
								class, method and function.  After the initial description and some
							 | 
						||
| 
								 | 
							
								comments, we import the modules we need. <p>
							 | 
						||
| 
								 | 
							
								 
							 | 
						||
| 
								 | 
							
								<A NAME="easydialogs"><CODE>EasyDialogs</CODE></A> is a handy standard
							 | 
						||
| 
								 | 
							
								module that provides you with routines that put up common text-only
							 | 
						||
| 
								 | 
							
								modal dialogs:
							 | 
						||
| 
								 | 
							
								<UL>
							 | 
						||
| 
								 | 
							
								<LI> <CODE>Message(str)</CODE>
							 | 
						||
| 
								 | 
							
								displays the message "str" and an OK button,
							 | 
						||
| 
								 | 
							
								<LI> <CODE>AskString(prompt, default)</CODE>
							 | 
						||
| 
								 | 
							
								asks for a string, displays OK and Cancel buttons,
							 | 
						||
| 
								 | 
							
								<LI> <CODE>AskYesNoCancel(question, default)</CODE>
							 | 
						||
| 
								 | 
							
								displays a question and Yes, No and Cancel buttons.
							 | 
						||
| 
								 | 
							
								</UL>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<A NAME="res"><CODE>Res</CODE></A> is a pretty complete interface to
							 | 
						||
| 
								 | 
							
								the MacOS Resource Manager, described fully in Inside Mac. There is
							 | 
						||
| 
								 | 
							
								currently no documentation of it, but the Apple documentation (or
							 | 
						||
| 
								 | 
							
								Think Ref) will help you on your way if you remember two points:
							 | 
						||
| 
								 | 
							
								<UL>
							 | 
						||
| 
								 | 
							
								<LI> Resources are implemented as Python objects, and each routine
							 | 
						||
| 
								 | 
							
								with a resource first argument is implemented as a python method.
							 | 
						||
| 
								 | 
							
								<LI> When in doubt about the arguments examine the routines docstring,
							 | 
						||
| 
								 | 
							
								as in <CODE>print Res.OpenResFile.__doc__</CODE>
							 | 
						||
| 
								 | 
							
								</UL>
							 | 
						||
| 
								 | 
							
								  	
							 | 
						||
| 
								 | 
							
								Similarly, <A NAME="dlg"><CODE>Dlg</CODE></A> is an interface to the
							 | 
						||
| 
								 | 
							
								Dialog manager (with Dialogs being implemented as python objects and
							 | 
						||
| 
								 | 
							
								routines with Dialog arguments being methods). The sys module you
							 | 
						||
| 
								 | 
							
								know, I hope.  <A NAME="interslip"><CODE>Interslip</CODE></A>,
							 | 
						||
| 
								 | 
							
								finally, is the module with the interface to the InterSLIP driver. We
							 | 
						||
| 
								 | 
							
								use four calls from it:
							 | 
						||
| 
								 | 
							
								<UL>
							 | 
						||
| 
								 | 
							
								<LI> <CODE>open()</CODE>
							 | 
						||
| 
								 | 
							
								opens the driver
							 | 
						||
| 
								 | 
							
								<LI> <CODE>connect()</CODE>
							 | 
						||
| 
								 | 
							
								asks it to initiate a connection procedure (without waiting)
							 | 
						||
| 
								 | 
							
								<LI> <CODE>disconnect()</CODE>
							 | 
						||
| 
								 | 
							
								asks it to initiate a disconnection procedure (without waiting)
							 | 
						||
| 
								 | 
							
								<LI> <CODE>status()</CODE>
							 | 
						||
| 
								 | 
							
								returns the current connection status in the form of an integer state,
							 | 
						||
| 
								 | 
							
								an integer "message sequence number" and a message string.
							 | 
						||
| 
								 | 
							
								</UL>
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								Next in the source file we get definitions for our dialog resource
							 | 
						||
| 
								 | 
							
								number and for the item numbers in our dialog. These should match the
							 | 
						||
| 
								 | 
							
								situation in our resource file InterslipControl-1.rsrc,
							 | 
						||
| 
								 | 
							
								obviously. Then we get an array converting numeric state codes
							 | 
						||
| 
								 | 
							
								returned by <CODE>interslip.status()</CODE> to textual messages. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								On to the main program. We start off with opening our resource file,
							 | 
						||
| 
								 | 
							
								which should live in the same folder as the python source. If we
							 | 
						||
| 
								 | 
							
								cannot open it we use <CODE>EasyDialogs</CODE> to print a message and
							 | 
						||
| 
								 | 
							
								exit. You can try it: just move the resource file somewhere else for a
							 | 
						||
| 
								 | 
							
								moment. Then, we try to open the interslip driver, again catching an
							 | 
						||
| 
								 | 
							
								error. All modules that raise <A NAME="macos-errors">MacOS error
							 | 
						||
| 
								 | 
							
								exceptions</A> will pass a 2-tuple to the exception handler with the
							 | 
						||
| 
								 | 
							
								first item being the numeric <CODE>OSErr</CODE> code and the second
							 | 
						||
| 
								 | 
							
								one being an informative message. If no informative message is
							 | 
						||
| 
								 | 
							
								available it will be the rather uninformative <CODE>"MacOS Error
							 | 
						||
| 
								 | 
							
								-12345"</CODE>, but at least the second item will always be a
							 | 
						||
| 
								 | 
							
								printable string. Finally we call do_dialog() to do the real work. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<CODE>Do_dialog()</CODE> uses <CODE>Dlg.GetNewDialog()</CODE> to open
							 | 
						||
| 
								 | 
							
								a dialog window initialized from 'DLOG' resource ID_MAIN and putting
							 | 
						||
| 
								 | 
							
								it on screen in the frontmost position.  Next, we go into a loop,
							 | 
						||
| 
								 | 
							
								calling <CODE>Dlg.ModalDialog()</CODE> to wait for the next user
							 | 
						||
| 
								 | 
							
								action. <CODE>ModalDialog()</CODE> will return us the item number that
							 | 
						||
| 
								 | 
							
								the user has clicked on (or otherwise activated). It will handle a few
							 | 
						||
| 
								 | 
							
								slightly more complicated things also, like the user typing into
							 | 
						||
| 
								 | 
							
								simple textfields, but it will <EM>not</EM> do things like updating
							 | 
						||
| 
								 | 
							
								the physical appearance of radio buttons, etc. See Inside Mac or
							 | 
						||
| 
								 | 
							
								another programming guide for how to handle this
							 | 
						||
| 
								 | 
							
								yourself. Fortunately, our simple application doesn't have to bother
							 | 
						||
| 
								 | 
							
								with this, since buttons are the only active elements we have. So, we
							 | 
						||
| 
								 | 
							
								do a simple switch on item number and call the appropriate routine to
							 | 
						||
| 
								 | 
							
								implement the action requested. Upon the user pressing "quit" we
							 | 
						||
| 
								 | 
							
								simply leave the loop and, hence, <CODE>do_dialog()</CODE>. This will
							 | 
						||
| 
								 | 
							
								cause the python dialog object <CODE>my_dlg</CODE> to be deleted and
							 | 
						||
| 
								 | 
							
								the on-screen dialog to disappear. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<A NAME="dialog-warning">Time for a warning</A>: be very careful what
							 | 
						||
| 
								 | 
							
								you do as long as a dialog is on-screen.  Printing something, for
							 | 
						||
| 
								 | 
							
								instance, may suddenly cause the standard output window to appear over
							 | 
						||
| 
								 | 
							
								the dialog, and since we took no measures to redraw the dialog it will
							 | 
						||
| 
								 | 
							
								become very difficult to get out of the dialog. Also, command-period
							 | 
						||
| 
								 | 
							
								may or may not work in this situation. I have also seen crashes in
							 | 
						||
| 
								 | 
							
								such a situation, probably due to the multiple event loops involved or
							 | 
						||
| 
								 | 
							
								some oversight in the interpreter. You have been warned. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The implementation of the "update status" command can use a bit more
							 | 
						||
| 
								 | 
							
								explaining: we get the new information with <CODE>do_status()</CODE>
							 | 
						||
| 
								 | 
							
								but now we have to update the on-screen dialog to present this
							 | 
						||
| 
								 | 
							
								information to the user. The <CODE>GetDialogItem()</CODE> method of
							 | 
						||
| 
								 | 
							
								the dialog returns three bits of information about the given item: its
							 | 
						||
| 
								 | 
							
								type, its data handle and its rect (the on-screen <CODE>x,y,w,h</CODE>
							 | 
						||
| 
								 | 
							
								coordinates). We are only interested in the data handle here, on which
							 | 
						||
| 
								 | 
							
								we call <CODE>SetDialogItemText()</CODE> to set our new text.  Note
							 | 
						||
| 
								 | 
							
								here that python programmers need not bother with the C-string versus
							 | 
						||
| 
								 | 
							
								pascal-string controversy: the python glue module knows what is needed
							 | 
						||
| 
								 | 
							
								and converts the python string to the correct type. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Finally, the three implementation routines <CODE>do_connect()</CODE>,
							 | 
						||
| 
								 | 
							
								<CODE>do_disconnect()</CODE> and <CODE>do_status()</CODE> are simply
							 | 
						||
| 
								 | 
							
								boring wrappers around the corresponding interslip methods that will
							 | 
						||
| 
								 | 
							
								put up a dialog in case of an error. <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								And that concludes our first example of the use of resources and
							 | 
						||
| 
								 | 
							
								dialogs. Next, you could have a look at the source of EasyDialogs for
							 | 
						||
| 
								 | 
							
								some examples of using input fields and filterprocs. Or, go on with
							 | 
						||
| 
								 | 
							
								reading the <A HREF="example2.html">second part</A> of this document
							 | 
						||
| 
								 | 
							
								to see how to implement a better version of this application. Not only
							 | 
						||
| 
								 | 
							
								will it allow the user to go back to the finder (or other apps) when
							 | 
						||
| 
								 | 
							
								your application is running, it will also free her of the RSI-inducing
							 | 
						||
| 
								 | 
							
								chore of pressing "update status" continuously... <p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 |