1
2
3<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
6
7<html xmlns="http://www.w3.org/1999/xhtml">
8  <head>
9    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
10    
11    <title>Creating your first PyObjC application. &mdash; PyObjC-Core 2.5.0b1 documentation</title>
12    
13    <link rel="stylesheet" href="/_static/default.css" type="text/css" />
14    <link rel="stylesheet" href="/_static/pygments.css" type="text/css" />
15    
16    <script type="text/javascript">
17      var DOCUMENTATION_OPTIONS = {
18        URL_ROOT:    '../',
19        VERSION:     '2.5.0b1',
20        COLLAPSE_INDEX: false,
21        FILE_SUFFIX: '.html',
22        HAS_SOURCE:  true
23      };
24    </script>
25    <script type="text/javascript" src="/_static/jquery.js"></script>
26    <script type="text/javascript" src="/_static/underscore.js"></script>
27    <script type="text/javascript" src="/_static/doctools.js"></script>
28    <link rel="top" title="PyObjC-Core 2.5.0b1 documentation" href="/index.html" />
29    <link rel="up" title="PyObjC Tutorials" href="index.html" />
30    <link rel="next" title="Tutorial - Adding Python code to an existing ObjC application" href="embedded.html" />
31    <link rel="prev" title="Understanding existing PyObjC examples" href="intro.html" /> 
32  </head>
33  <body>
34    <div class="related">
35      <h3>Navigation</h3>
36      <ul>
37        <li class="right" style="margin-right: 10px">
38          <a href="/genindex.html" title="General Index"
39             accesskey="I">index</a></li>
40        <li class="right" >
41          <a href="/py-modindex.html" title="Python Module Index"
42             >modules</a> |</li>
43        <li class="right" >
44          <a href="embedded.html" title="Tutorial - Adding Python code to an existing ObjC application"
45             accesskey="N">next</a> |</li>
46        <li class="right" >
47          <a href="intro.html" title="Understanding existing PyObjC examples"
48             accesskey="P">previous</a> |</li>
49        <li><a href="/index.html">PyObjC-Core 2.5.0b1 documentation</a> &raquo;</li>
50          <li><a href="index.html" accesskey="U">PyObjC Tutorials</a> &raquo;</li> 
51      </ul>
52    </div>  
53
54    <div class="document">
55      <div class="documentwrapper">
56        <div class="bodywrapper">
57          <div class="body">
58            
59  <div class="section" id="creating-your-first-pyobjc-application">
60<h1>Creating your first PyObjC application.<a class="headerlink" href="#creating-your-first-pyobjc-application" title="Permalink to this headline">¶</a></h1>
61<p>WARNING: This tutorial assumes you&#8217;re using Xcode 2.5 and is therefore not
62entirely valid with Xcode 3 (that is MacOS 10.5).</p>
63<p>In this tutorial you will learn how to create your first Python Cocoa
64application: a simple dialog that allows you to convert amounts of money from
65one currency to another.  Definitely easier to do with a calculator, but in the
66process of following the tutorial you will learn which bits of Apple&#8217;s Cocoa
67documentation apply to PyObjC and which bits are different, and how to adapt
68the different bits to PyObjC from Objective-C.</p>
69<p>To follow the tutorial you need:</p>
70<blockquote>
71<div><ul class="simple">
72<li>PyObjC 1.3.1</li>
73<li>py2app 0.2 or later (included in the binary installer for PyObjC)</li>
74<li>Python 2.3 or later (note: PyObjC is NOT compatible with MacPython-OS9)</li>
75<li>Mac OS X 10.2 or later</li>
76<li>Xcode Tools (was Developer Tools for Mac OS X 10.2)</li>
77</ul>
78</div></blockquote>
79<p>If you do not have a <tt class="docutils literal"><span class="pre">/Developer</span></tt> folder, then you do not have Xcode Tools
80installed.  See <a class="reference external" href="http://developer.apple.com/tools/download/">Getting the Xcode Tools</a>.</p>
81<div class="section" id="getting-started">
82<h2>Getting Started<a class="headerlink" href="#getting-started" title="Permalink to this headline">¶</a></h2>
83<div class="admonition note">
84<p class="first admonition-title">Note</p>
85<p class="last">Before you start, download the <a class="reference download internal" href="/_downloads/firstapp_src.zip"><tt class="xref download docutils literal"><span class="pre">reference</span> <span class="pre">source</span> <span class="pre">package</span></tt></a> for this tutorial.</p>
86</div>
87<ol class="arabic simple">
88<li>Create a work directory <tt class="docutils literal"><span class="pre">src</span></tt>.  Check which Python you have installed
89PyObjC for, by running <tt class="docutils literal"><span class="pre">python</span></tt> and checking that <tt class="docutils literal"><span class="pre">import</span> <span class="pre">Foundation</span></tt>
90works.  If it does not work it could be that you have installed PyObjC for
91<tt class="docutils literal"><span class="pre">/usr/local/bin/python</span></tt> but Apple&#8217;s <tt class="docutils literal"><span class="pre">/usr/bin/python</span></tt> comes first in
92your <tt class="docutils literal"><span class="pre">$PATH</span></tt>.  Make sure you use the right python wherever it says
93<tt class="docutils literal"><span class="pre">python</span></tt> in this tutorial.</li>
94<li>Start Interface Builder, select <em>Cocoa Application</em>
95in the new file dialog, save this file as <tt class="docutils literal"><span class="pre">src/MainMenu.nib</span></tt>.</li>
96<li>Proceed with the instructions as lined out in Apple&#8217;s
97<a class="reference external" href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCTutorial/index.html">Developing Cocoa Objective-C Applications: a Tutorial</a>, <a class="reference external" href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCTutorial/index.html?http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCTutorial/chapter03/chapter_3_section_1.html">chapter 3</a>,
98just after the section &#8220;<em>Creating the Currency Converter Interface</em>&#8221;.
99Work through &#8220;Defining the Classes of Currency Converter&#8221;, &#8220;Connecting
100ConverterController to the Interface&#8221;, and stop at
101&#8220;<em>Implementing the Classes of Currency Converter</em>&#8221;, as we are going to do
102this in Python, not Objective-C.  Your nib file should now be the same as
103<em>step3-MainMenu.nib</em>.</li>
104</ol>
105<ol class="arabic" start="4">
106<li><p class="first">Create the skeleton Python script by running the <tt class="docutils literal"><span class="pre">nibclassbuilder</span></tt> script.
107<tt class="docutils literal"><span class="pre">nibclassbuilder</span></tt> will parse the NIB file and create a skeleton module for
108you.  Invoke it as follows (from the <tt class="docutils literal"><span class="pre">src</span></tt> directory):</p>
109<div class="highlight-sh"><div class="highlight"><pre><span class="nv">$ </span>python -c <span class="s2">&quot;import PyObjCScripts.nibclassbuilder&quot;</span> MainMenu.nib &gt; CurrencyConverter.py
110</pre></div>
111</div>
112<p>Depending on your installation, the <tt class="docutils literal"><span class="pre">nibclassbuilder</span></tt> script may be on your <tt class="docutils literal"><span class="pre">$PATH</span></tt>.
113If so, it can be invoked as such:</p>
114<div class="highlight-sh"><div class="highlight"><pre><span class="nv">$ </span>nibclassbuilder MainMenu.nib &gt; CurrencyConverter.py
115</pre></div>
116</div>
117<p>The result of this can be seen in <em>step4-CurrencyConverter.py</em>.</p>
118</li>
119</ol>
120</div>
121<div class="section" id="testing-the-user-interface">
122<h2>Testing the user interface<a class="headerlink" href="#testing-the-user-interface" title="Permalink to this headline">¶</a></h2>
123<ol class="arabic" start="5">
124<li><p class="first">Now we need to create an build script for CurrencyConverter.  To do this,
125create a file named <tt class="docutils literal"><span class="pre">setup.py</span></tt> with the following contents:</p>
126<div class="highlight-python"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
1272
1283
1294
1305
1316
1327</pre></div></td><td class="code"><div class="highlight"><pre>  <span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span>
133  <span class="kn">import</span> <span class="nn">py2app</span>
134
135  <span class="n">setup</span><span class="p">(</span>
136      <span class="n">app</span><span class="o">=</span><span class="p">[</span><span class="s">&#39;CurrencyConverter.py&#39;</span><span class="p">],</span>
137      <span class="n">data_files</span><span class="o">=</span><span class="p">[</span><span class="s">&#39;MainMenu.nib&#39;</span><span class="p">],</span>
138  <span class="p">)</span>
139</pre></div>
140</td></tr></table></div>
141<p>The result of this can be seen in <em>step5-setup.py</em>.</p>
142</li>
143<li><p class="first">Run the setup script to create a temporary application bundle for
144development:</p>
145<div class="highlight-sh"><div class="highlight"><pre><span class="nv">$ </span>python setup.py py2app -A
146</pre></div>
147</div>
148<p>Note that we use the <tt class="docutils literal"><span class="pre">-A</span></tt> argument to create an alias bundle at
149<tt class="docutils literal"><span class="pre">dist/CurrencyConverter.app</span></tt>.  Alias bundles contain an alias to the
150main script (<tt class="docutils literal"><span class="pre">CurrencyConverter.py</span></tt>) and symlinks to the data files
151(<tt class="docutils literal"><span class="pre">MainMenu.nib</span></tt>), rather than including them and their dependencies
152into a standalone application bundle.  This allows us to keep working on
153the source files without having to rebuild the application.  This alias
154bundle is similar to a ZeroLink executable for Xcode - it is for
155DEVELOPMENT ONLY, and will not work on other machines.</p>
156</li>
157<li><p class="first">Run the program.  This can be done in three ways:</p>
158<ul>
159<li><p class="first">double-click <tt class="docutils literal"><span class="pre">dist/CurrencyConverter</span></tt> from the Finder
160(you won&#8217;t see the .app extension)</p>
161</li>
162<li><p class="first">open it from the terminal with:</p>
163<div class="highlight-sh"><div class="highlight"><pre><span class="nv">$ </span>open dist/CurrencyConverter.app
164</pre></div>
165</div>
166</li>
167<li><p class="first">run it directly from the Terminal, as:</p>
168<div class="highlight-sh"><div class="highlight"><pre><span class="nv">$ </span>/dist/CurrencyConverter.app/Contents/MacOS/CurrencyConverter
169</pre></div>
170</div>
171</li>
172</ul>
173<p>The last method is typically the best to use for development: it leaves
174stdout and stderr connected to your terminal session so you can see what
175is going on if there are errors, and it allows you to interact with <tt class="docutils literal"><span class="pre">pdb</span></tt>
176if you are using it to debug your application.  Note that your application
177will likely appear in the background, so you will have to cmd-tab or click
178on its dock icon to see its user interface.</p>
179<p>The other methods cause stdout and stderr to go to the Console log, which
180can be viewed with <tt class="docutils literal"><span class="pre">/Applications/Utilities/Console.app</span></tt>.</p>
181<p>When you run your script as it is now it should behave identically as when
182you tested your interface in Interface Builder in step 3, only now the
183skeleton is in Python, not Objective-C.</p>
184</li>
185</ol>
186</div>
187<div class="section" id="writing-the-code">
188<h2>Writing the code<a class="headerlink" href="#writing-the-code" title="Permalink to this headline">¶</a></h2>
189<ol class="arabic" start="8">
190<li><p class="first">Time to actually write some code.  Open <tt class="docutils literal"><span class="pre">CurrencyConverter.py</span></tt> in your
191favorite text editor.  Follow Apple&#8217;s documentation again, chapter 3,
192section &#8220;Implementing Currency Converter&#8217;s Classes&#8221;.  To translate this
193Objective C code to Python syntax, we will need to do some name mangling of
194the selectors.  See <em>An introduction to PyObjC</em> for the details, but the
195short is that:</p>
196<div class="highlight-objective-c"><div class="highlight"><pre><span class="p">[</span><span class="n">anObject</span> <span class="nl">modifyArg:</span> <span class="n">arg1</span> <span class="nl">andAnother:</span> <span class="n">arg2</span><span class="p">]</span>
197</pre></div>
198</div>
199</li>
200</ol>
201<blockquote>
202<div><p>translates into the following Python code, by replacing the colons in the
203selector with underscores, and passing the arguments as you would with a
204normal Python method call:</p>
205<div class="highlight-python"><div class="highlight"><pre><span class="n">anObject</span><span class="o">.</span><span class="n">modifyArg_andAnother_</span><span class="p">(</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">)</span>
206</pre></div>
207</div>
208<p>Note that we don&#8217;t do this mangling for <tt class="docutils literal"><span class="pre">Converter.convertAmount()</span></tt>: this
209method is only called by other Python code, so there is no need to go
210through the name mangling.  Also, if we would want to make this method
211callable from ObjC code we may have to tell the PyObjC runtime system about
212the types of the arguments, so it could do the conversion.  This is beyond
213the scope of this first tutorial, <em>An introduction to PyObjC</em> has a little
214more detail on this.</p>
215<p>The application should now be fully functional, try it.  The results of what
216we have up to now can be seen in <em>step8-CurrencyConverter.py</em>.</p>
217</div></blockquote>
218</div>
219<div class="section" id="extending-the-functionality">
220<h2>Extending the functionality<a class="headerlink" href="#extending-the-functionality" title="Permalink to this headline">¶</a></h2>
221<ol class="arabic" start="9">
222<li><p class="first">We are going to add one more goodie, just to show how you edit an existing
223application.  The main problem, which may be obvious, is that we cannot run
224<tt class="docutils literal"><span class="pre">nibclassbuilder</span></tt> again because we would destroy all the code we wrote in
225steps 5 and 8, so we do this by hand.  What we are going to do is add an
226&#8220;invert rate&#8221; command, because I always get this wrong: instead of typing
227in the exchange rate from dollars to euros I type in the rate to convert
228from euros to dollars.</p>
229<p>Open <tt class="docutils literal"><span class="pre">MainMenu.nib</span></tt> in Interface Builder.  Select the <em>Classes</em> view and
230then select the <tt class="docutils literal"><span class="pre">ConverterController</span></tt> class.  In the info panel select
231the <em>Attributes</em> from the popup.  Select the <em>Actions</em> tab, and add an
232action <tt class="docutils literal"><span class="pre">invertRate:</span></tt>.  You have now told Interface Builder that instances
233of the <tt class="docutils literal"><span class="pre">ConverterController</span></tt> class have grown a new method
234<tt class="docutils literal"><span class="pre">invertRate_()</span></tt>.</p>
235<p>In the <tt class="docutils literal"><span class="pre">MainMenu.nib</span> <span class="pre">main</span></tt> window open the <em>MainMenu</em> menubar.  Select
236the <tt class="docutils literal"><span class="pre">Edit</span></tt> menu.  Make sure the <em>Menus</em> palette is open and selected,
237drag a separator to the <tt class="docutils literal"><span class="pre">Edit</span></tt> menu and then drag an <tt class="docutils literal"><span class="pre">Item</span></tt> there.
238Double-click the item and set the text to <tt class="docutils literal"><span class="pre">Invert</span> <span class="pre">Exchange</span> <span class="pre">Rate</span></tt>.</p>
239<p>Make the connection by control-dragging from the new
240<tt class="docutils literal"><span class="pre">Invert</span> <span class="pre">Exchange</span> <span class="pre">Rate</span></tt> menu item to the <tt class="docutils literal"><span class="pre">ConverterController</span></tt> instance
241in the Instances tab in the <tt class="docutils literal"><span class="pre">MainMenu.nib</span></tt> main window.</p>
242<p><em>NOTE:</em> you drag to the <em>instance</em> of <tt class="docutils literal"><span class="pre">ConverterController</span></tt>, not to the
243class.</p>
244<p>In the <em>Info</em> panel, <em>Connections</em> section, select <tt class="docutils literal"><span class="pre">invertRate:</span></tt> and
245press <em>Connect</em>.</p>
246</li>
247<li><p class="first">We know our program can&#8217;t invert rates yet, because we haven&#8217;t actually
248written the code to do it, but we are going to try it anyway, just to see
249what sort of spectacular crash we get.  Alas, nothing spectacular about it:
250when the NIB is loaded the Cocoa runtime system tries to make the
251connection, notices that we have no <tt class="docutils literal"><span class="pre">invertRate_()</span></tt> method in our
252<tt class="docutils literal"><span class="pre">ConverterController</span></tt> class and it gives an error message:</p>
253<div class="highlight-sh"><div class="highlight"><pre><span class="nv">$ </span>/dist/CurrencyConverter.app/Contents/MacOS/CurrencyConverter
2542004-12-09 03:29:09.957 CurrencyConverter<span class="o">[</span>4454<span class="o">]</span> Could not connect the action
255invertRate: to target of class ConverterController
256</pre></div>
257</div>
258<p>Moreover, it has disabled the <tt class="docutils literal"><span class="pre">Invert</span> <span class="pre">Exchange</span> <span class="pre">Rate</span></tt> menu command and
259continues, so the program works as it did before, only with one more
260(disabled) menu item.</p>
261</li>
262</ol>
263</div>
264<div class="section" id="debugging">
265<h2>Debugging<a class="headerlink" href="#debugging" title="Permalink to this headline">¶</a></h2>
266<ol class="arabic" start="11">
267<li><p class="first">Writing the code is easy: add a method <tt class="docutils literal"><span class="pre">invertRate_(self,</span> <span class="pre">sender)</span></tt> that
268gets the float value of <tt class="docutils literal"><span class="pre">rateField</span></tt>, inverts it and puts it back.  We
269deliberately forget to test for divide by zero.  We run the program again,
270and now the menu entry is enabled.  After trying it with a couple of
271non-zero exchange rates we try it with an exchange rate of zero (or empty,
272which is the same).  We get a dialog box giving the Python exception, and
273offering the choice of continuing or quitting.</p>
274<p>To debug this application with pdb, start the application with the
275following command line:</p>
276<div class="highlight-sh"><div class="highlight"><pre><span class="nv">$ </span>env <span class="nv">USE_PDB</span><span class="o">=</span>1 /dist/CurrencyConverter.app/Contents/MacOS/CurrencyConverter
277</pre></div>
278</div>
279<p>When running in this mode, we will get a <tt class="docutils literal"><span class="pre">pdb.post_mortem(...)</span></tt> console
280in the terminal instead of the alert panel.  You can see this in action if
281you try and invert an exchange rate of <tt class="docutils literal"><span class="pre">0</span></tt>.</p>
282</li>
283<li><p class="first">Fix the final bug by testing for <tt class="docutils literal"><span class="pre">rate</span> <span class="pre">==</span> <span class="pre">0.0</span></tt> in <tt class="docutils literal"><span class="pre">invertRate_()</span></tt>.
284The result is in the <em>step12-src</em> directory.</p>
285</li>
286</ol>
287</div>
288<div class="section" id="creating-a-redistributable-application">
289<h2>Creating a redistributable application<a class="headerlink" href="#creating-a-redistributable-application" title="Permalink to this headline">¶</a></h2>
290<p>Your application is finished, and you want to run it on other computers, or
291simply just move it to the <tt class="docutils literal"><span class="pre">Applications</span></tt> folder (or anywhere else) and
292insulate it from the original source code.</p>
293<p>This can be done with the following steps from the <tt class="docutils literal"><span class="pre">src</span></tt> directory:</p>
294<blockquote>
295<div></div></blockquote>
296<p>Now the application bundle located at <tt class="docutils literal"><span class="pre">dist/CurrencyConverter.app</span></tt> is a fully
297standalone application that should run on any computer running the same major
298version of Mac OS X or later.  This means that applications built on
299Mac OS X 10.2 are compatible with Mac OS X 10.3, but NOT vice versa.  If you
300are not using an Apple-supplied version of Python, a subset of your Python
301installation will be included in this application.</p>
302<p>For more complicated examples of py2app usage to do things such as change the
303application&#8217;s icon, see the Examples or the py2app documentation.</p>
304</div>
305</div>
306
307
308          </div>
309        </div>
310      </div>
311      <div class="sphinxsidebar">
312        <div class="sphinxsidebarwrapper">
313  <h3><a href="/index.html">Table Of Contents</a></h3>
314  <ul>
315<li><a class="reference internal" href="#">Creating your first PyObjC application.</a><ul>
316<li><a class="reference internal" href="#getting-started">Getting Started</a></li>
317<li><a class="reference internal" href="#testing-the-user-interface">Testing the user interface</a></li>
318<li><a class="reference internal" href="#writing-the-code">Writing the code</a></li>
319<li><a class="reference internal" href="#extending-the-functionality">Extending the functionality</a></li>
320<li><a class="reference internal" href="#debugging">Debugging</a></li>
321<li><a class="reference internal" href="#creating-a-redistributable-application">Creating a redistributable application</a></li>
322</ul>
323</li>
324</ul>
325
326  <h4>Previous topic</h4>
327  <p class="topless"><a href="intro.html"
328                        title="previous chapter">Understanding existing PyObjC examples</a></p>
329  <h4>Next topic</h4>
330  <p class="topless"><a href="embedded.html"
331                        title="next chapter">Tutorial - Adding Python code to an existing ObjC application</a></p>
332  <h3>This Page</h3>
333  <ul class="this-page-menu">
334    <li><a href="/_sources/tutorials/firstapp.txt"
335           rel="nofollow">Show Source</a></li>
336  </ul>
337<div id="searchbox" style="display: none">
338  <h3>Quick search</h3>
339    <form class="search" action="/search.html" method="get">
340      <input type="text" name="q" />
341      <input type="submit" value="Go" />
342      <input type="hidden" name="check_keywords" value="yes" />
343      <input type="hidden" name="area" value="default" />
344    </form>
345    <p class="searchtip" style="font-size: 90%">
346    Enter search terms or a module, class or function name.
347    </p>
348</div>
349<script type="text/javascript">$('#searchbox').show(0);</script>
350        </div>
351      </div>
352      <div class="clearer"></div>
353    </div>
354    <div class="related">
355      <h3>Navigation</h3>
356      <ul>
357        <li class="right" style="margin-right: 10px">
358          <a href="/genindex.html" title="General Index"
359             >index</a></li>
360        <li class="right" >
361          <a href="/py-modindex.html" title="Python Module Index"
362             >modules</a> |</li>
363        <li class="right" >
364          <a href="embedded.html" title="Tutorial - Adding Python code to an existing ObjC application"
365             >next</a> |</li>
366        <li class="right" >
367          <a href="intro.html" title="Understanding existing PyObjC examples"
368             >previous</a> |</li>
369        <li><a href="/index.html">PyObjC-Core 2.5.0b1 documentation</a> &raquo;</li>
370          <li><a href="index.html" >PyObjC Tutorials</a> &raquo;</li> 
371      </ul>
372    </div>
373    <div class="footer">
374        &copy; Copyright 2009-2012, Ronald Oussoren.
375      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
376    </div>
377  </body>
378</html>