<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>learning python &#187; tutorial</title>
	<atom:link href="http://www.learningpython.com/category/python/tutorial/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.learningpython.com</link>
	<description>one man's journey into python...</description>
	<lastBuildDate>Mon, 26 Apr 2010 01:21:51 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Elegant XML parsing using the ElementTree Module</title>
		<link>http://www.learningpython.com/2008/05/07/elegant-xml-parsing-using-the-elementtree-module/</link>
		<comments>http://www.learningpython.com/2008/05/07/elegant-xml-parsing-using-the-elementtree-module/#comments</comments>
		<pubDate>Wed, 07 May 2008 16:21:48 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[ElementTree]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=74</guid>
		<description><![CDATA[
			
				
			
		
Mark Mruss
Note: This article was first published the October 2007 issue of Python Magazine
XML is everywhere.  It seems you can&#8217;t do much these days unless you utilize XML in one way or another. Fortunately, Python developers have a new tool in our standard arsenal: the ElementTree module. This article aims to introduce you to [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2008%2F05%2F07%2Felegant-xml-parsing-using-the-elementtree-module%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2008%2F05%2F07%2Felegant-xml-parsing-using-the-elementtree-module%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<p><strong>Mark Mruss</strong></p>
<p><strong>Note:</strong> This article was first published the October 2007 issue of <a href="http://www.pythonmagazine.com">Python Magazine</a></p>
<p>XML is everywhere.  It seems you can&#8217;t do much these days unless you utilize XML in one way or another. Fortunately, Python developers have a new tool in our standard arsenal: the ElementTree module. This article aims to introduce you to reading, writing, saving, and loading XML using the ElementTree module.</p>
<ol>
<li><a href="#Introduction">Introduction</a></li>
<li><a href="#ReadingXMLdata">Reading XML data</a></li>
<li><a href="#Listing1">Listing 1</a></li>
<li><a href="#Listing2">Listing 2</a></li>
<li><a href="#ReadingXMLAttributes">Reading XML Attributes</a></li>
<li><a href="#WritingXML">Writing XML</a></li>
<li><a href="#Listing3">Listing 3</a></li>
<li><a href="#WritingXMLAttributes">Writing XML Attributes</a></li>
<li><a href="#ReadingXMLFiles">Reading XML Files</a></li>
<li><a href="#WritingXMLDatatoaFile">Writing XML Data to a File</a></li>
<li><a href="#ReadingfromtheWeb">Reading from the Web</a></li>
<li><a href="#Conclusion">Conclusion</a></li>
</ol>
<p><span id="more-74"></span><!--more--></p>
<h2><a href="#Introduction">Introduction</a></h2>
<p>It seems like everyone needs to parse XML these days.  They&#8217;re either saving their own information in XML or loading in someone else&#8217;s data.  This is why I was glad to learn that as of Python 2.5, the <em>ElementTree</em> XML package has been added to the standard library in the XML module.</p>
<p>What I like about the <em>ElementTree</em> module is that it just seems to make sense.  This might seem like a strange thing to say about an XML module, but I&#8217;ve had to parse enough XML in my time to know that if an XML module makes sense the first time you use it, it&#8217;s probably a keeper. The <em>ElementTree</em> module allows me to work with XML data in a way that is similar to how I <em>think</em> about XML data.</p>
<p>A subset of the full <em>ElementTree</em> module is available in the Python 2.5 standard library as <code>xml.etree</code>, but you don&#8217;t have to use Python 2.5 in order to use the <em>ElementTree</em> module. If you are still using an older version of Python (1.5.2 or later) you can simply download the module from its website and manually install it on your system.  The website also has very easy to follow installation instructions, which you should consult to avoid issues while installing <em>ElementTree</em>.</p>
<p>In general, the <em>ElementTree</em> module treats XML data as a list of lists.  All XML has a root element that will have zero or more subelements (or child elements). Each of those subelements may in turn have subelements of their own.  The best way to think about this is with a brief example.</p>
<p>First let&#8217;s take a look at some sample XML data:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-default">&lt;</span><span class="hl-identifier">root</span><span class="hl-default">&gt;
&lt;</span><span class="hl-identifier">child</span><span class="hl-default">&gt;</span><span class="hl-identifier">One</span><span class="hl-default">&lt;/</span><span class="hl-identifier">child</span><span class="hl-default">&gt;
&lt;</span><span class="hl-identifier">child</span><span class="hl-default">&gt;</span><span class="hl-identifier">Two</span><span class="hl-default">&lt;/</span><span class="hl-identifier">child</span><span class="hl-default">&gt;
&lt;/</span><span class="hl-identifier">root</span><span class="hl-default">&gt;</span></pre></div></div>
<p>Here we have a root element with two child elements. Each child element has some text associated with it seen here as &#8220;one&#8221; and &#8220;two&#8221;. If we examine the XML as a hierarchical list of lists we see that we have one element &#8220;root&#8221; in our root list.  Within the &#8220;root&#8221; element we have a list containing two subelements &#8220;child&#8221; and &#8220;child&#8221;. The two &#8220;child&#8221; elements would then contain empty lists representing their lack of subelements. Not too complicated so far, is it?</p>
<h2><a href="#ReadingXMLdata">Reading XML data</a></h2>
<p>Now let&#8217;s use the <em>ElementTree</em> package to parse this XML and print the text data associated with each child element.  To start, we&#8217;ll create a Python file with the contents shown in Listing 1.</p>
<p><strong><a href="#Listing1">Listing 1</a></strong></p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">def </span><span class="hl-identifier">main</span><span class="hl-brackets">()</span><span class="hl-default">:
	</span><span class="hl-reserved">pass

if </span><span class="hl-identifier">__name__</span><span class="hl-default"> == </span><span class="hl-quotes">&quot;</span><span class="hl-string">__main__</span><span class="hl-quotes">&quot;</span><span class="hl-default">:
	</span><span class="hl-identifier">main</span><span class="hl-brackets">()</span></pre></div></div>
<p>This is basically a template that I use for many of my simple &#8220;*.py&#8221; files.  It doesn&#8217;t actually do anything except set up the script so that when the file is run, the <code>main</code> method will be executed. Some people like to use the Python interactive interpreter for simple hacking like this. Personally, I prefer having my code stored in a handy file so I can make simple changes and re-run the entire script when I am just playing around.</p>
<p>The first thing that we need to do in our Python code is import the <em>ElementTree</em> module:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-reserved">from </span><span class="hl-identifier">xml</span><span class="hl-default">.</span><span class="hl-identifier">etree </span><span class="hl-reserved">import </span><span class="hl-identifier">ElementTree as ET</span></pre></div></div>
<p><strong>Note</strong>: If you are not using Python 2.5 and have installed the <em>ElementTree</em> module on your own, you should import the <em>ElementTree</em> module as follows:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-reserved">from </span><span class="hl-identifier">elementtree </span><span class="hl-reserved">import </span><span class="hl-identifier">ElementTree as ET</span></pre></div></div>
<p>This will import the ElementTree section of the module into your program aliased as ET.  However, you don&#8217;t have to import <em>ElementTree</em> using an alias; you can simply import it and access it as <code>ElementTree</code>. Using ET is demonstrated in the Python 2.5 &#8220;What&#8217;s new&#8221; documentation[1] and I think it&#8217;s a great way to eliminate some key strokes.</p>
<p>Now we&#8217;ll begin writing code in the <code>main</code> method.  The first step is to load the XML data described above.  Normally you will be working with a file or URL; for now we want to keep this simple and load the XML data directly from the text:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">element</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(
       </span><span class="hl-quotes">&quot;</span><span class="hl-string">&lt;root&gt;&lt;child&gt;One&lt;/child&gt;&lt;child&gt;Two&lt;/child&gt;&lt;/root&gt;</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span></pre></div></div>
<p>The <code>XML</code> function is described in the <em>ElementTree</em> documentation as follows: &#8220;Parses an XML document from a string constant. This function can be used to embed &#8220;XML literals&#8221; in Python code&#8221;[2].</p>
<p>Be careful here! The <code>XML</code> function returns an Element object, and not an ElementTree object as one might expect. Element objects are used to represent XML elements, whereas the ElementTree object is used to represent the entire XML document. Element objects <em>may</em> represent the entire XML document if they are the root element but will not if they are a subelement. ElementTree objects also add &#8220;some extra support for serialization to and from standard XML.&#8221;[3] The Element object that is returned represents the <code><root></root></code> element in our XML data.</p>
<p>Thankfully, the Element object is an iterator object so we can use a <code>for</code> loop to loop through all of its child elements:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-reserved">for </span><span class="hl-identifier">subelement </span><span class="hl-reserved">in </span><span class="hl-identifier">element</span><span class="hl-default">:</span></pre></div></div>
<p>This will give us all the child elements in the root element.  As mentioned earlier, each element in the XML tree is represented as an Element object, so as we iterate through the root element&#8217;s child elements we are getting Element objects with which to work. Meaning that each loop though the for loop will give us the next child element in the form of an Element object until there are no more children left. In order to print out the text associated with an Element object we simply have to access the Element object&#8217;s <code>text</code> attribute:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">for </span><span class="hl-identifier">subelement </span><span class="hl-reserved">in </span><span class="hl-identifier">element</span><span class="hl-default">:
       </span><span class="hl-reserved">print </span><span class="hl-identifier">subelement</span><span class="hl-default">.</span><span class="hl-identifier">text</span></pre></div></div>
<p>To recap, have a look at the code in Listing 2.</p>
<p><strong><a href="#Listing2">Listing 2</a></strong></p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">from </span><span class="hl-identifier">xml</span><span class="hl-default">.</span><span class="hl-identifier">etree </span><span class="hl-reserved">import </span><span class="hl-identifier">ElementTree as ET

</span><span class="hl-reserved">def </span><span class="hl-identifier">main</span><span class="hl-brackets">()</span><span class="hl-default">:
	</span><span class="hl-identifier">element</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">&lt;root&gt;&lt;child&gt;One&lt;/child&gt;&lt;child&gt;Two&lt;/child&gt;&lt;/root&gt;</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-reserved">for </span><span class="hl-identifier">subelement </span><span class="hl-reserved">in </span><span class="hl-identifier">element</span><span class="hl-default">:
		</span><span class="hl-reserved">print </span><span class="hl-identifier">subelement</span><span class="hl-default">.</span><span class="hl-identifier">text

</span><span class="hl-reserved">if </span><span class="hl-identifier">__name__</span><span class="hl-default"> == </span><span class="hl-quotes">&quot;</span><span class="hl-string">__main__</span><span class="hl-quotes">&quot;</span><span class="hl-default">:
	</span><span class="hl-comment"># Someone is launching this directly
	</span><span class="hl-identifier">main</span><span class="hl-brackets">()</span></pre></div></div>
<p>Once you run the code you should get the following output:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">One
Two</span></pre></div></div>
<p>If an XML element does not have any text associated with it, like our root element, the Element object&#8217;s <code>text</code> attribute will be set to <code>None</code>. If you want to check if an element had any text associated with it, you can do the following:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">if </span><span class="hl-identifier">element</span><span class="hl-default">.</span><span class="hl-identifier">text </span><span class="hl-reserved">is not None</span><span class="hl-default">:
       </span><span class="hl-reserved">print </span><span class="hl-identifier">element</span><span class="hl-default">.</span><span class="hl-identifier">text</span></pre></div></div>
<h2><a href="#ReadingXMLAttributes">Reading XML Attributes</a></h2>
<p>Let&#8217;s alter the XML that we are working with to add attributes to the elements and look at how we would parse that information.</p>
<p>If the XML uses attributes in addition to, or instead of, inner text they can be accessed using the Element object&#8217;s <code>attrib</code> attribute.  The <code>attrib</code> attribute is a Python dictionary and is relatively easy to use:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">main</span><span class="hl-brackets">()</span><span class="hl-default">:
       </span><span class="hl-identifier">element</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(
               </span><span class="hl-quotes">'</span><span class="hl-string">&lt;root&gt;&lt;child val=&quot;One&quot;/&gt;&lt;child val=&quot;Two&quot;/&gt;&lt;/root&gt;</span><span class="hl-quotes">'</span><span class="hl-brackets">)
       </span><span class="hl-reserved">for </span><span class="hl-identifier">subelement </span><span class="hl-reserved">in </span><span class="hl-identifier">element</span><span class="hl-default">:
               </span><span class="hl-reserved">print </span><span class="hl-identifier">subelement</span><span class="hl-default">.</span><span class="hl-identifier">attrib</span></pre></div></div>
<p>When you run the code you get the following output:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-default">{</span><span class="hl-quotes">'</span><span class="hl-string">val</span><span class="hl-quotes">'</span><span class="hl-default">: </span><span class="hl-quotes">'</span><span class="hl-string">One</span><span class="hl-quotes">'</span><span class="hl-default">}
{</span><span class="hl-quotes">'</span><span class="hl-string">val</span><span class="hl-quotes">'</span><span class="hl-default">: </span><span class="hl-quotes">'</span><span class="hl-string">Two</span><span class="hl-quotes">'</span><span class="hl-default">}</span></pre></div></div>
<p>These are the attributes for each child element stored in a dictionary. Being able to work with an XML element&#8217;s attributes as a Python dictionary is a great feature and fits well with the dynamic nature of XML attributes.</p>
<h2><a href="#WritingXML">Writing XML</a></h2>
<p>Now that we&#8217;ve tried our hand at reading XML, let&#8217;s try creating some. If you understand the reading process, you should have no trouble understanding the creation process because it works in much the same manner. What we are going to do in this example is recreate the XML data that we were working with above.</p>
<p>The first step is to create our <code><root></root></code> element:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#create the root &lt;root&gt;
</span><span class="hl-identifier">root_element</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">Element</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">root</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span></pre></div></div>
<p>After this code is executed, the variable <code>root_element</code> is an Element object, just like the Element objects that we used earlier to parse the XML.</p>
<p>The next step is to create the two child elements. There are two ways to do this.</p>
<p>In the first method, if you know exactly what you are creating, it&#8217;s easiest to use the <code>SubElement</code> method, which creates an Element object that is a subelement (or child) of another Element object:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#create the first child &lt;child&gt;One&lt;/child&gt;
</span><span class="hl-identifier">child</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">SubElement</span><span class="hl-brackets">(</span><span class="hl-identifier">root_element</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">child</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span></pre></div></div>
<p>This will create a <code><child></child></code> Element that is a child of <code>root_element</code>.  We then need to set the text associated with that element.  To do this we use the same text attribute that we used in the first parsing example. However, instead of simply reading the text attribute we set its value:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">child</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">One</span><span class="hl-quotes">&quot;</span></pre></div></div>
<p>The second approach to creating a child element is to create an Element object separately (rather than a sub element) and append it to a parent Element object.  The results are exactly the same &#8211; this is simply a different approach that may come in handy when creating your XML,or working with two sets of XML data.</p>
<p>First we create an Element object in the same way that we created the root element:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#create the second child &lt;child&gt;Two&lt;/child&gt;
</span><span class="hl-identifier">child</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">Element</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">child</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">child</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Two</span><span class="hl-quotes">&quot;</span></pre></div></div>
<p>This creates the <code>child</code> Element object and sets its text to &#8220;Two&#8221;.  We then append it to the root element: </p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#now append
</span><span class="hl-identifier">root_element</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">child</span><span class="hl-brackets">)</span></pre></div></div>
<p>Pretty simple!  Now, if we want to look at the contents of our <code>root_element</code> (or any other Element object for that matter) we can use the handy <code>tostring</code> function. It does exactly what it says that it does: it converts an Element object into a human readable string.</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Let's see the results
</span><span class="hl-reserved">print </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">tostring</span><span class="hl-brackets">(</span><span class="hl-identifier">root_element</span><span class="hl-brackets">)</span></pre></div></div>
<p><strong><a href="#Listing3">Listing 3</a></strong></p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">from </span><span class="hl-identifier">xml</span><span class="hl-default">.</span><span class="hl-identifier">etree </span><span class="hl-reserved">import </span><span class="hl-identifier">ElementTree as ET

</span><span class="hl-reserved">def </span><span class="hl-identifier">main</span><span class="hl-brackets">()</span><span class="hl-default">:
	</span><span class="hl-comment">#create the root &lt;/root&gt;&lt;root&gt;
	</span><span class="hl-identifier">root_element</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">Element</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">root</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#create the first child &lt;child&gt;One&lt;/child&gt;
	</span><span class="hl-identifier">child</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">SubElement</span><span class="hl-brackets">(</span><span class="hl-identifier">root_element</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">child</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">child</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">One</span><span class="hl-quotes">&quot;
	</span><span class="hl-comment">#create the second child &lt;child&gt;Two&lt;/child&gt;
	</span><span class="hl-identifier">child</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">Element</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">child</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">child</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Two</span><span class="hl-quotes">&quot;
	</span><span class="hl-comment">#now append
	</span><span class="hl-identifier">root_element</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">child</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Let's see the results
	</span><span class="hl-reserved">print </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">tostring</span><span class="hl-brackets">(</span><span class="hl-identifier">root_element</span><span class="hl-brackets">)

</span><span class="hl-reserved">if </span><span class="hl-identifier">__name__</span><span class="hl-default"> == </span><span class="hl-quotes">&quot;</span><span class="hl-string">__main__</span><span class="hl-quotes">&quot;</span><span class="hl-default">:
	</span><span class="hl-comment"># Someone is launching this directly
	</span><span class="hl-identifier">main</span><span class="hl-brackets">()</span></pre></div></div>
<p>To recap, have a look at the code in Listing 3. When you run this code you will get the following output:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-default">&lt;/</span><span class="hl-identifier">root</span><span class="hl-default">&gt;&lt;</span><span class="hl-identifier">root</span><span class="hl-default">&gt;&lt;</span><span class="hl-identifier">child</span><span class="hl-default">&gt;</span><span class="hl-identifier">One</span><span class="hl-default">&lt;/</span><span class="hl-identifier">child</span><span class="hl-default">&gt;&lt;</span><span class="hl-identifier">child</span><span class="hl-default">&gt;</span><span class="hl-identifier">Two</span><span class="hl-default">&lt;/</span><span class="hl-identifier">child</span><span class="hl-default">&gt;&lt;/</span><span class="hl-identifier">root</span><span class="hl-default">&gt;</span></pre></div></div>
<h2><a href="#WritingXMLAttributes">Writing XML Attributes</a></h2>
<p>If you want to create the XML with attributes (as illustrated in the second reading example), you can use the Element object&#8217;s <code>set</code> method.  To add the <code>val</code> attribute to the first element, use the following:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">child</span><span class="hl-default">.</span><span class="hl-identifier">set</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">val</span><span class="hl-quotes">&quot;</span><span class="hl-code">,</span><span class="hl-quotes">&quot;</span><span class="hl-string">One</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span></pre></div></div>
<p>You may also set attributes when you create Element objects:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">child</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">Element</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">child</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-identifier">val</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">One</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span></pre></div></div>
<h2><a href="#ReadingXMLFiles">Reading XML Files</a></h2>
<p>Most of the time you won&#8217;t be working with XML data that you explicitly create in your code, instead you will usually read the XML data in from a data source, work with it, and then save it back out when you are done. Fortunately, configuring <em>ElementTree</em> to work with different data sources is very easy.  For example, let&#8217;s take the XML data that we first used and save it into a file named <code>our.xml</code> in the same location as our Python file.</p>
<p>There are a few methods that we can use to load XML data from a file. We are going to use the <code>parse</code> function. This function is nice because it will accept, as a parameter, the path to a file OR a &#8220;file-like&#8221; object.  The term &#8220;file-like&#8221; is used on purpose because the object does not have to be a file object per se &#8211; it simply has to be an object that behaves in a file-like manner. A &#8220;file-like&#8221; object is an object that implements a &#8220;file-like&#8221; interface, meaning that it shares many (if not all) methods with the file object. If an object is &#8220;file-like&#8221; this fact will usually be prominently mentioned in its documentation.</p>
<p>The first thing that we need in order to load the XML data is determine the full path to the <code>our.xml</code> file. In order to calculate this, we determine the full path of our Python source file, strip the filename from it, and then append <code>our.xml</code> to the path. This is rather simple given that the <code>__file__</code> attribute (available in Python 2.2 and later) is the relative path and filename of our Python source file. Although the <code>__file__</code> attribute will be a relative path, we can use it to calculate the absolute path using the standard <em>os</em> module:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-reserved">import </span><span class="hl-identifier">os</span></pre></div></div>
<p>We then call the <code>abspath</code> function to get the absolute path:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">xml_file</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">abspath</span><span class="hl-brackets">(</span><span class="hl-identifier">__file__</span><span class="hl-brackets">)</span></pre></div></div>
<p>However, since we only want the directory name (not the full path and filename of our Python source file) we have to strip off the filename:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">xml_file</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">dirname</span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-brackets">)</span></pre></div></div>
<p>Now that we have the directory in which the <code>our.xml</code> file resides, all we have to do is append the <code>our.xml</code> filename to the <code>xml_file</code> variable.  However, instead of just doing something like:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">xml_file</span><span class="hl-default"> += </span><span class="hl-quotes">&quot;</span><span class="hl-string">/our.xml</span><span class="hl-quotes">&quot;</span></pre></div></div>
<p>we will use the <em>os</em> module to join the two paths so that the resulting path is always correct regardless of what operating system our code is executed on:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">xml_file</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">join</span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">our.xml</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span></pre></div></div>
<p><strong>Note</strong>: If you have any trouble understanding what any of the code used to determine the path of <code>our.xml</code> is doing, try printing out <code>xml_file</code> after each of the above lines and it should become clear.</p>
<p>We now have the full path to the <code>our.xml</code> file.  In order to load its XML data we simply pass the path to the <code>parse</code> function:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">tree</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">parse</span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-brackets">)</span></pre></div></div>
<p>We now have an ElementTree object instance that represents our XML file.</p>
<p>Since we are working with files, we should watch out for incorrect paths, I/O errors, or the parse function failing for any other reason.  If you wish to be extra careful, you can wrap the parse function in a try/except block in order to catch any exceptions that may be thrown:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">try</span><span class="hl-default">:
       </span><span class="hl-identifier">tree</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">parse</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">sar</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-reserved">except Exception</span><span class="hl-default">, </span><span class="hl-identifier">inst</span><span class="hl-default">:
       </span><span class="hl-reserved">print </span><span class="hl-quotes">&quot;</span><span class="hl-string">Unexpected error opening %s: %s</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-code">, </span><span class="hl-identifier">inst</span><span class="hl-brackets">)
       </span><span class="hl-reserved">return</span></pre></div></div>
<p>In the except block, I catch the Exception base class so that I catch any and all exceptions that may be thrown (in the case of a missing file it will most likely be an <code>IOError</code> exception).</p>
<h2><a href="#WritingXMLDatatoaFile">Writing XML Data to a File</a></h2>
<p>Now that we know how to read in XML data, we should look at how one writes XML data out to a file.  Let&#8217;s assume that after reading in the <code>out.xml</code> fiie we want to add another item to the XML file that we just read in:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">child</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">SubElement</span><span class="hl-brackets">(</span><span class="hl-identifier">tree</span><span class="hl-code">.</span><span class="hl-identifier">getroot</span><span class="hl-brackets">()</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">child</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">child</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Three</span><span class="hl-quotes">&quot;</span></pre></div></div>
<p>Notice that in order to add a child to the root element we used the ElementTree object&#8217;s <code>getroot</code> function. The <code>getroot</code> function simply returns the root Element object of the XML data.</p>
<p>Now that we have a third child element, let&#8217;s write the XML data back out to <code>our.xml</code>. Thanks to <em>ElementTree</em> this is a painless experience:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">tree</span><span class="hl-default">.</span><span class="hl-identifier">write</span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-brackets">)</span></pre></div></div>
<p>That&#8217;s it!</p>
<p>If we want to be really careful when writing the XML data out to a file, we&#8217;ll watch out for exceptions. However most of the time the <code>write</code> method will succeed without throwing an exception; it is more important to be sure that the path used is correct.  Often times, instead of getting the exception that you want, you end up with an XML file stored in some far off and strange location on your hard drive because your path was incorrect or you did not specify the full path.  But, as is often the case when programming, better safe than sorry:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">try</span><span class="hl-default">:
       </span><span class="hl-identifier">tree</span><span class="hl-default">.</span><span class="hl-identifier">write</span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-brackets">)
</span><span class="hl-reserved">except Exception</span><span class="hl-default">, </span><span class="hl-identifier">inst</span><span class="hl-default">:
       </span><span class="hl-reserved">print </span><span class="hl-quotes">&quot;</span><span class="hl-string">Unexpected error writing to file %s: %s</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-code">, </span><span class="hl-identifier">inst</span><span class="hl-brackets">)
       </span><span class="hl-reserved">return</span></pre></div></div>
<p>To recap you can find all of the code from this section in Listing 4.</p>
<p><strong><a href="#Listing4">Listing 4</a></strong></p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">from </span><span class="hl-identifier">xml</span><span class="hl-default">.</span><span class="hl-identifier">etree </span><span class="hl-reserved">import </span><span class="hl-identifier">ElementTree as ET
</span><span class="hl-reserved">import </span><span class="hl-identifier">os

</span><span class="hl-reserved">def </span><span class="hl-identifier">main</span><span class="hl-brackets">()</span><span class="hl-default">:

	</span><span class="hl-identifier">xml_file</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">abspath</span><span class="hl-brackets">(</span><span class="hl-identifier">__file__</span><span class="hl-brackets">)
	</span><span class="hl-identifier">xml_file</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">dirname</span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-brackets">)
	</span><span class="hl-identifier">xml_file</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">join</span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">our.xml</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)

	</span><span class="hl-reserved">try</span><span class="hl-default">:
		</span><span class="hl-identifier">tree</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">parse</span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-brackets">)
	</span><span class="hl-reserved">except Exception</span><span class="hl-default">, </span><span class="hl-identifier">inst</span><span class="hl-default">:
		</span><span class="hl-reserved">print </span><span class="hl-quotes">&quot;</span><span class="hl-string">Unexpected error opening %s: %s</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-code">, </span><span class="hl-identifier">inst</span><span class="hl-brackets">)
		</span><span class="hl-reserved">return

	</span><span class="hl-identifier">child</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">SubElement</span><span class="hl-brackets">(</span><span class="hl-identifier">tree</span><span class="hl-code">.</span><span class="hl-identifier">getroot</span><span class="hl-brackets">()</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">child</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">child</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Three</span><span class="hl-quotes">&quot;

	</span><span class="hl-reserved">try</span><span class="hl-default">:
		</span><span class="hl-identifier">tree</span><span class="hl-default">.</span><span class="hl-identifier">write</span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-brackets">)
	</span><span class="hl-reserved">except Exception</span><span class="hl-default">, </span><span class="hl-identifier">inst</span><span class="hl-default">:
		</span><span class="hl-reserved">print </span><span class="hl-quotes">&quot;</span><span class="hl-string">Unexpected error writing to file %s: %s</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">xml_file</span><span class="hl-code">, </span><span class="hl-identifier">inst</span><span class="hl-brackets">)
		</span><span class="hl-reserved">return

if </span><span class="hl-identifier">__name__</span><span class="hl-default"> == </span><span class="hl-quotes">&quot;</span><span class="hl-string">__main__</span><span class="hl-quotes">&quot;</span><span class="hl-default">:
	</span><span class="hl-comment"># Someone is launching this directly
	</span><span class="hl-identifier">main</span><span class="hl-brackets">()</span></pre></div></div>
<p>When you run the code and take a look at the <code>our.xml</code> file you should see that the the third child element has been added:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-default">&lt;</span><span class="hl-identifier">root</span><span class="hl-default">&gt;
&lt;</span><span class="hl-identifier">child</span><span class="hl-default">&gt;</span><span class="hl-identifier">One</span><span class="hl-default">&lt;/</span><span class="hl-identifier">child</span><span class="hl-default">&gt;
&lt;</span><span class="hl-identifier">child</span><span class="hl-default">&gt;</span><span class="hl-identifier">Two</span><span class="hl-default">&lt;/</span><span class="hl-identifier">child</span><span class="hl-default">&gt;
&lt;</span><span class="hl-identifier">child</span><span class="hl-default">&gt;</span><span class="hl-identifier">Three</span><span class="hl-default">&lt;/</span><span class="hl-identifier">child</span><span class="hl-default">&gt;
&lt;/</span><span class="hl-identifier">root</span><span class="hl-default">&gt;</span></pre></div></div>
<h2><a href="#ReadingfromtheWeb">Reading from the Web</a></h2>
<p>Working with a local file is very useful, but you might also be in a situation where you will have to work with an XML file that is located on the Internet, perhaps an RSS feed.  Fortunately, since the <code>parse</code> function explained above works with file-like elements, loading a URL is very easy.</p>
<p>First off, you need to import the <em>urllib</em> module; a standard module that allows you to open URLs in a method similar to opening local files:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-reserved">import </span><span class="hl-identifier">urllib</span></pre></div></div>
<p>In order to open a URL we use:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">feed</span><span class="hl-default"> = </span><span class="hl-identifier">urllib</span><span class="hl-default">.</span><span class="hl-identifier">urlopen</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">http://pythonmagazine.com/c/news/atom</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">tree</span><span class="hl-default"> = </span><span class="hl-identifier">ET</span><span class="hl-default">.</span><span class="hl-identifier">parse</span><span class="hl-brackets">(</span><span class="hl-identifier">feed</span><span class="hl-brackets">)</span></pre></div></div>
<h2><a href="#Conclusion">Conclusion</a></h2>
<p>And that&#8217;s that!  This concludes our brief introduction to XML parsing using the <em>ElementTree</em> module. Hopefully throughout this article you have seen how easy it is to create and manipulate XML using <em>ElementTree</em> &#8230;and I&#8217;ve only scratched the surface.  For more information take a look at the official Python documentation and some of the great examples on the effbot website. I&#8217;m sure you&#8217;ll be an XML wizard in no time.</p>
<p>[1] <a href="http://docs.python.org/whatsnew/modules.html#SECTION0001420000000000000000">http://docs.python.org/whatsnew/modules.html#SECTION0001420000000000000000</a><br />
[2] <a href="http://effbot.org/zone/pythondoc-elementtree-ElementTree.htm#elementtree.ElementTree.XML-function">http://effbot.org/zone/pythondoc-elementtree-ElementTree.htm#elementtree.ElementTree.XML-function</a><br />
[3] <a href="http://effbot.org/zone/pythondoc-elementtree-ElementTree.htm#elementtree.ElementTree.ElementTree-class">http://effbot.org/zone/pythondoc-elementtree-ElementTree.htm#elementtree.ElementTree.ElementTree-class</a></p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2008/05/07/elegant-xml-parsing-using-the-elementtree-module/&title=Elegant XML parsing using the ElementTree Module&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2008/05/07/elegant-xml-parsing-using-the-elementtree-module/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>PyLan a GTD todo application written in python and PyGTK &#8211; part four context menus!</title>
		<link>http://www.learningpython.com/2007/09/23/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus/</link>
		<comments>http://www.learningpython.com/2007/09/23/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus/#comments</comments>
		<pubDate>Sun, 23 Sep 2007 18:18:35 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[PyGTK]]></category>
		<category><![CDATA[PyLan]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=65</guid>
		<description><![CDATA[
			
				
			
		
PyLan Four
Hello welcome to the fourth installment of the PyLan tutorial. This will be a quick tutorial to introduce one feature: context (or popup) menus. I&#8217;ve had many questions regarding this so I thought I would take a quick stab at it.
If you want to follow along with the code in detail, and have not [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F09%2F23%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F09%2F23%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<h2>PyLan Four</h2>
<p>Hello welcome to the fourth installment of the PyLan tutorial. This will be a quick tutorial to introduce one feature: context (or popup) menus. I&#8217;ve had many questions regarding this so I thought I would take a quick stab at it.</p>
<p>If you want to follow along with the code in detail, and have not done so already, you should read <a href="http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/">part one</a>, <a href="http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/">part two</a> and <a href="http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/">part three</a> of this series. </p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_04.tar.gz">here</a>.</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_04/pylan_04_02.png" alt="Python GTD pyGTK" border="0"/></p>
<p><span id="more-65"></span></p>
<p>This tutorial is organized into the following sections:</p>
<ol>
<li><a href="#Glade">Adding the menu in Glade</a></li>
<li><a href="#Python">Showing the menu in Python</a></li>
</ol>
<h2><a href="#Glade">Adding the menu in Glade</a></h2>
<p>So let&#8217;s startup glade and create a new popup menu item. Add the following four items to the menu:</p>
<ol>
<li>New Category. Name &#8211; &#8220;new_category_menu&#8221; Handler &#8211; &#8220;on_add_category&#8221;</li>
<li>New Task. Name &#8211; &#8220;new_task_menu&#8221; Handler &#8211; &#8220;on_add_task&#8221;</li>
<li>_Edit. Name &#8211; &#8220;edit_context_menu&#8221; Handler &#8211; &#8220;on_edit_object&#8221;</li>
<li>_Remove. Name &#8211; &#8220;remove_context_menu&#8221; Handler &#8211; &#8220;on_remove_item&#8221;</li>
</ol>
<p>Call the menu itself: contextMenu</p>
<p>That&#8217;s it for glade.</p>
<h2><a href="#Python">Showing the menu in Python</a></h2>
<p>The first thing that we need to do is get the menu widget in our initialize_widgets() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#load the menu from the glade file
</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">contextMenu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-comment">#connect the menu with the signals
</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
</span><span class="hl-comment">#Get the menu dialog widget
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">context_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">contextMenu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span></pre></div></div>
<p>Now that we have the widget we need to actually show it when people right-click on our TreeView. We didn&#8217;t have to add a button press handler to our TreeView because we added one in the last tutorial, but we will have to edit it.</p>
<p>Here is the original function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_todoTree_button_press_event</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">There has been a button press on the TodoTree
	for now we use this as a quick hack to remove
	the selection.  Perhaps there is a better way?
	@param widget - gtk.TreeView - The Tree View
	@param event - gtk.gdk.event - Event information
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the path at the specific mouse position
	</span><span class="hl-identifier">path</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_path_at_pos</span><span class="hl-brackets">(</span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-brackets">))
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">path</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">If we didn't get apath then we don't want anything
		to be selected.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
		</span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">unselect_all</span><span class="hl-brackets">()</span></pre></div></div>
<p>We will have to change this function to show our menu widget, which is a pretty simple addition to the end of the function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">button</span><span class="hl-code"> == </span><span class="hl-number">3</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-comment">#This is a right-click
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">context_menu</span><span class="hl-default">.</span><span class="hl-identifier">popup</span><span class="hl-brackets">( </span><span class="hl-reserved">None</span><span class="hl-code">, </span><span class="hl-reserved">None</span><span class="hl-code">, </span><span class="hl-reserved">None</span><span class="hl-code">
		, </span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">button</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">time</span><span class="hl-brackets">)</span></pre></div></div>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_04/pylan_04_01.png" alt="Python GTD pyGTK" border="0"/></p>
<p>So far so good, you&#8217;ll notice that since the menu handlers are the same as our toolbar handlers everything already works!  The only problem is that the sensitive state of the menu items does not match the sensitive state of the toolbar buttons.</p>
<p>Thankfully since we added this feature to the buttons in the last tutorial doing this is pretty easy.</p>
<p>The first thing that we need to do is get the menu items and disable them in the same way that we do the buttons in the initialize_widgets() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Get the menu widgets
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">new_category_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">new_category_menu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">new_task_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">new_task_menu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_context_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">edit_context_menu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">remove_context_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">remove_context_menu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)

</span><span class="hl-comment">#disable them like the buttons
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">new_task_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_context_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">remove_context_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)</span></pre></div></div>
<p>Then in the on_tree_selection_changed() function we need to update the menu items sensitive state:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">new_task_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_context_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">remove_context_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))</span></pre></div></div>
<p>Now we have nice context menus!</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_04/pylan_04_02.png" alt="Python GTD pyGTK" border="0"/></p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_04.tar.gz">here</a>.</p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2007/09/23/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus/&title=PyLan a GTD todo application written in python and PyGTK - part four context menus!&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2007/09/23/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Creating a game using python and Silverlight 1.1</title>
		<link>http://www.learningpython.com/2007/07/29/creating-a-game-using-python-and-silverlight-11/</link>
		<comments>http://www.learningpython.com/2007/07/29/creating-a-game-using-python-and-silverlight-11/#comments</comments>
		<pubDate>Sun, 29 Jul 2007 16:52:32 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=64</guid>
		<description><![CDATA[
			
				
			
		
This tutorial assumes that you have a passing understanding of Silverlight and Microsoft&#8217;s .NET technologies.  If you do you should have no trouble understanding everything in this code, and chances are you will understand some of it more then I do!
But to start it off here is a little bit of information straight from [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F07%2F29%2Fcreating-a-game-using-python-and-silverlight-11%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F07%2F29%2Fcreating-a-game-using-python-and-silverlight-11%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<p>This tutorial assumes that you have a passing understanding of Silverlight and Microsoft&#8217;s .NET technologies.  If you do you should have no trouble understanding everything in this code, and chances are you will understand some of it more then I do!</p>
<p>But to start it off here is a little bit of information straight from <a href="http://msdn2.microsoft.com/en-us/library/bb404300.aspx#startingwithsilverlight_topic1">Microsoft&#8217;s website</a>:</p>
<blockquote><p>
Silverlight is a new Web presentation technology that is created to run on a variety of platforms. It enables the creation of rich, visually stunning and interactive experiences that can run everywhere: within browsers and on multiple devices and desktop operating systems (such as the Apple Macintosh). In consistency with WPF (Windows Presentation Foundation), the presentation technology in Microsoft .NET Framework 3.0 (the Windows programming infrastructure), XAML (eXtensible Application Markup Language) is the foundation of the Silverlight presentation capability.<br />
This white paper will step you through the basics of Silverlight and how you can use the Microsoft stack of tools, including Microsoft Expression Blend, Microsoft Visual Studio 2005, and XAML to build rich graphical sites. First, let&#8217;s take a primer on the background leading up to Silverlight and where it stands on the development landscape.
</p></blockquote>
<p>What we are going to do is create a simple game with falling targets that they user has to click on in order to “hit” them.  Each time they hit a target they will get a point and another target will be created.</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/silver/silver_03.png" alt="Python silverlight" border="0"/></p>
<p>You can try the “finished” product out here: <a href="http://www.learningpython.com/silverpy/index.htm">http://www.learningpython.com/silverpy/index.htm</a></p>
<p><span id="more-64"></span></p>
<p>This first step is to download and install Silverlight 1.1 from here: <a href="http://msdn2.microsoft.com/en-us/silverlight/bb419317.aspx">http://msdn2.microsoft.com/en-us/silverlight/bb419317.aspx</a></p>
<p>Sadly at this point there is no plugin available for Linux, however the people over at the <a href="http://www.mono-project.com">mono project</a> are working on <a href="http://www.mono-project.com/Moonlight">moonlight</a> so we should see some movement in that direction soon.</p>
<p>The next step is to download the SilverLight 1.1 SDK from: <a href="http://go.microsoft.com/fwlink/?LinkID=89145&#038;clcid=0x409">http://go.microsoft.com/fwlink/?LinkID=89145&#038;clcid=0&#215;409</a></p>
<p>Once you have done that you should create a folder somewhere on your hard drive where you want to store your files.  I created a folder called SilverPy.</p>
<p>Then browse to the DLR console sample located in this directory:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre>...Silverlight1.1SDK\Silverlight 1.1 Alpha Samples\DLRConsole\python</pre></div></div>
<p><strong>Note:</strong> The DLR sample appears to have gone missing in recent SDK releases, but it can be found on the <a href="http://silverlight.net/themes/silverlight/community/gallerydetail.aspx?cat=4">samples page</a>.</p>
<p>Then copy all of the files from that folder into your SilverPy folder.  Now rename the DLRConsole.xaml to SilverPy.xaml and you can get rid of the DLRConsole.py, in its place create a SilverPy.py file.  This will be the file that will contain our python code.</p>
<p>So once you are done you should be left with the following:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/silver/silver_01.png" alt="Python Silverlight" border="0"/></p>
<p>Now we want to edit the index.html so that it doesn&#8217;t say that it&#8217;s the DLR sample.  Edit the html code to look something like:</p>
<div class="hl-surround" ><div class="hl-main"><pre>&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; &gt;
&lt;head&gt;
    &lt;title&gt;SilverPy&lt;/title&gt;
   &lt;script src=&quot;silverlight.js&quot; type=&quot;text/javascript&quot; &gt;&lt;/script&gt;
   &lt;script src=&quot;CreateSilverlight.js&quot; type=&quot;text/javascript&quot; &gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div id=&quot;WpfeControl1Host&quot;&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
				var pe = document.getElementById(&quot;WpfeControl1Host&quot;);
				createSilverlight();
    &lt;/script&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre></div></div>
<p>Now since we changed the name of our xaml file we need to edit the CreateSilverlight.js file:</p>
<p><code>function createSilverlight()<br />
{<br />
    Sys.Silverlight.createObject("SilverPy.xaml", pe, "wpf",<br />
                                 {width:"100%", height:"100%",<br />
                                  inplaceInstallPrompt:false, background:'white', isWindowless:'true',<br />
                                  framerate:'30', version:'0.95'},<br />
                                 {onError:null, onLoad:null},<br />
                                 null);<br />
}</code></p>
<p>We simply changed the first parameter to the createObject function to be “SilverPy.xaml” so that the correct file gets loaded.  CreateSilverlight.js calls  Silverlight.createObject to instantiate Silverlight and tell it to load our &#8220;Silver.xaml&#8221; file, it also controls other a few other option.  I don&#8217;t want to explain this in too much detail since Microsoft has already done this <a href="http://msdn2.microsoft.com/en-us/library/bb412401.aspx#Role_of_the_Helper_Files">for me</a>: </p>
<p>CreateSilverlight.js:</p>
<blockquote><p>
Defines the CreateSilverlight method, which invokes either the CreateObject or CreateObjectEx method, which are defined in the Silverlight.js file.
</p></blockquote>
<p>Silverlight.js:</p>
<blockquote><p>
Defines the CreateObject and CreateObjectEx methods, which provide version checking support and generate the <object> tag settings in the HTML file for hosting the Silverlight control.<br />
</object></p></blockquote>
<p>If you want more information on the nitty gritty of these these two files and the html file please read the <a href="http://msdn2.microsoft.com/en-us/library/bb412401.aspx">Microsoft website</a>.</p>
<p>The next step is to edit our XAML file, this is going to be pretty simple but I will explain it later:</p>
<p>This is our XAML file, it&#8217;s used to create our &#8220;GUI&#8221;.  The first step is to create the <a href="http://msdn2.microsoft.com/en-us/library/bb188312.aspx">Canvas element</a>: </p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-brackets">&lt;</span><span class="hl-reserved">canvas </span><span class="hl-var">x:Name</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">root_canvas</span><span class="hl-quotes">&quot;  </span><span class="hl-var">Width</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">500</span><span class="hl-quotes">&quot; </span><span class="hl-var">Height</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">300</span><span class="hl-quotes">&quot;
 </span><span class="hl-var">xmlns</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">http://schemas.microsoft.com/client/2007</span><span class="hl-quotes">&quot;
 </span><span class="hl-var">xmlns:x</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">http://schemas.microsoft.com/winfx/2006/xaml</span><span class="hl-quotes">&quot;
 </span><span class="hl-var">Background</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Purple</span><span class="hl-quotes">&quot;
</span><span class="hl-brackets">&gt;
  &lt;</span><span class="hl-reserved">x </span><span class="hl-var">:Code Source</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Silver.py</span><span class="hl-quotes">&quot; </span><span class="hl-var">Type</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">text/python</span><span class="hl-quotes">&quot; </span><span class="hl-brackets">/&gt;
  &lt;</span><span class="hl-reserved">canvas </span><span class="hl-var">x:Name</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">game_canvas</span><span class="hl-quotes">&quot;
         </span><span class="hl-var">Loaded</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">on_canvas_loaded</span><span class="hl-quotes">&quot;
          </span><span class="hl-var">Width</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">500</span><span class="hl-quotes">&quot; </span><span class="hl-var">Height</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">300</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">/&gt;
  &lt;</span><span class="hl-reserved">textblock </span><span class="hl-var">Name</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Score</span><span class="hl-quotes">&quot; </span><span class="hl-var">Text</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Targets Hit: 0</span><span class="hl-quotes">&quot;  </span><span class="hl-var">FontSize</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">10</span><span class="hl-quotes">&quot; </span><span class="hl-var">Canvas</span><span class="hl-code">.</span><span class="hl-var">Left</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">400</span><span class="hl-quotes">&quot; </span><span class="hl-var">Canvas</span><span class="hl-code">.</span><span class="hl-var">Top</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">305</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">/&gt;
&lt;/</span><span class="hl-reserved">canvas</span><span class="hl-brackets">&gt;</span></pre></div></div>
<blockquote><p>
Defines an area within which you can explicitly position child elements by using coordinates relative to the Canvas area.
</p></blockquote>
<p>So this where we will create all of our visible objects, you can think of it like the canvas that a painter uses.  You can see in the XML that we give our canvas object a name: &#8220;root_canvas&#8221;, a height, a width, and a background colour: &#8220;purple&#8221;.</p>
<p>The next element that you see is an <a href="http://msdn2.microsoft.com/en-us/library/ms750494.aspx">x:Code element</a> which we use to load the &#8220;Silver.py&#8221; python file.  Here we could load as many code files as we wanted.</p>
<p>The next element is another Canvas element named &#8220;game_canvas&#8221;, which serves no purpose except to provide us with the <a href="http://msdn2.microsoft.com/en-us/library/bb188274.aspx"Loaded event</a>.  The value that we assign to the loaded attribute is the name of the function in our python file that will be called when this canvas has been loaded.</p>
<p>For some reason (perhaps it is explained somewhere or someone can tell me why) I could not get the &#8220;root_canvas&#8221; to send the Loaded event, so I needed to created the sub-canvas as a work-around.</p>
<p>The next element is a </a><a href="http://msdn2.microsoft.com/en-us/library/bb188394.aspx">TextBlock</a> element that is used to display (yes you guessed it) text.  We use this TextBlock to display the user&#8217;s score as they play our little game.</p>
<p>Now it&#8217;s time to work on our python code.</p>
<p>If you load the index.html file into Internet Explorer (you have to use Internet Explorer as there currently are some issues with loading external python modules when running local files, I&#8217;ve read that it will be fixed soon) you will get an obscure error.  This is because we have not created the on_canvas_loaded function that we described in our xaml.</p>
<p>So let&#8217;s add this to our Silver.py file:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_canvas_loaded</span><span class="hl-brackets">(</span><span class="hl-identifier">sender</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-reserved">pass</span></pre></div></div>
<p>The first thing that you will notice about out Loaded event handler is that it has two parameters, which is common will all event handlers.  Sender is the object that fired the event, and e is the event arguments associated with the event.  What is contained in the event arguments changes depending on what event is being caught.</p>
<p>Now if you load index.html into Internet Explorer you should see the following:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/silver/silver_02.png" alt="Python Silverlight" border="0"/></p>
<p>So far so good! So now lets get into some serious python coding, now most of this code is simply Python/IronPython so if you are familiar with both you shouldn&#8217;t have any problem.</p>
<p>The fist step is to import all of the stuff that we are going to need:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">from </span><span class="hl-identifier">System </span><span class="hl-reserved">import</span><span class="hl-default"> *
</span><span class="hl-reserved">import </span><span class="hl-identifier">_random
</span><span class="hl-reserved">import </span><span class="hl-identifier">wpf
</span><span class="hl-reserved">from </span><span class="hl-identifier">wpf </span><span class="hl-reserved">import</span><span class="hl-default"> *
</span><span class="hl-reserved">import </span><span class="hl-identifier">clr
clr</span><span class="hl-default">.</span><span class="hl-identifier">AddReference</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">agclr</span><span class="hl-quotes">'</span><span class="hl-brackets">)
</span><span class="hl-identifier">clr</span><span class="hl-default">.</span><span class="hl-identifier">AddReference</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">System.Silverlight</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span></pre></div></div>
<p>Now we are going to work with two classes in our game, one class that will be the target that we are going to aim at and the other that will serve as out main game.</p>
<div class="hl-surround" ><div class="hl-main"><pre>def __init__(self, game_canvas):
    &quot;&quot;&quot;Init the Target Game
    @param game_canvas - The canvas for the game.
    &quot;&quot;&quot;
    #Create a random object
    self.random = _random.Random()
    #Save the game canvas
    self.game_canvas = game_canvas
    #The score
    self.score = 0
    #The list of targets that we have
    self.targets = []
    #Make sure that we have the minimum number of targets
    self.ensure_targets()
    #hook into the keydown event
    self.game_canvas.KeyDown += EventHandler(self.on_key_down)
    #Not done yet
    self.done = False</pre></div></div>
<p>Now the first thing that we do is we create a <a href="http://www.astro.rug.nl/~gipsy/pydoc/_random.html">random object</a> that we will use in the future to position our Target sprites.  The next step is to save the game_canvas that was passed in to the __init__ function, game_canvas corresponds to a canvas object.  Then we initialize our score to zero, this will be the number of canvas sprites that our user hits.  Then we create an empty list, which will store references to the targets that are currently on the screen.</p>
<p>Finally we hook up our member function on_key_down to the game canvas objects <a href="http://msdn2.microsoft.com/en-us/library/bb188394.aspx">KeyDown event</a> and set our done flag to False, since we aren&#8217;t done.</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_key_down</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">sender</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Check to see if they hit escape</span><span class="hl-quotes">&quot;&quot;&quot;

    </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">e</span><span class="hl-code">.</span><span class="hl-identifier">Key</span><span class="hl-code"> == </span><span class="hl-number">8</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over</span><span class="hl-brackets">()</span></pre></div></div>
<p>This handler is pretty simple, it gets called when there is a key down event on the game_canvas, if the key is the Escape key (e.Key == <img src='http://www.learningpython.com/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> then we called self.game_over() to end the game.  I added this so that someone could quit the game at any time.</p>
<p>The game_over function is as follows:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">game_over</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the game should end</span><span class="hl-quotes">&quot;&quot;&quot;
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over_text</span><span class="hl-default"> = </span><span class="hl-identifier">TextBlock</span><span class="hl-brackets">()
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over_text</span><span class="hl-default">.</span><span class="hl-identifier">FontSize</span><span class="hl-default"> = </span><span class="hl-number">50
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over_text</span><span class="hl-default">.</span><span class="hl-identifier">Text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">GAME OVER</span><span class="hl-quotes">&quot;
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default">.</span><span class="hl-identifier">Children</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">game_over_text</span><span class="hl-brackets">)
    </span><span class="hl-identifier">wpf</span><span class="hl-default">.</span><span class="hl-identifier">SetPosition</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">game_over_text</span><span class="hl-code">
        , </span><span class="hl-number">100</span><span class="hl-code">
        , </span><span class="hl-number">100</span><span class="hl-brackets">)
    </span><span class="hl-comment">#We are done
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">done</span><span class="hl-default"> = </span><span class="hl-reserved">True</span></pre></div></div>
<p>The first think that we do is create a <a href="http://msdn2.microsoft.com/en-us/library/bb188394.aspx">TextBlock object</a>, set some of its properties, and add it to the game_canvas&#8217;s children making the object visible. Then we use a helper function in the wpf module to set the position of the TextBlock object.  Finally we set done to True, done is simply a boolean flag that we use to know if the game is done or not.</p>
<p>The wpf modules SetPosition function is actually pretty simple and we could have done this ourselves:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">SetPosition</span><span class="hl-brackets">(</span><span class="hl-identifier">o</span><span class="hl-code">, </span><span class="hl-identifier">x</span><span class="hl-code">, </span><span class="hl-identifier">y</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-identifier">SetIntValue</span><span class="hl-brackets">(</span><span class="hl-identifier">o</span><span class="hl-code">, </span><span class="hl-identifier">Canvas</span><span class="hl-code">.</span><span class="hl-identifier">TopProperty</span><span class="hl-code">, </span><span class="hl-identifier">y</span><span class="hl-brackets">)
    </span><span class="hl-identifier">SetIntValue</span><span class="hl-brackets">(</span><span class="hl-identifier">o</span><span class="hl-code">, </span><span class="hl-identifier">Canvas</span><span class="hl-code">.</span><span class="hl-identifier">LeftProperty</span><span class="hl-code">, </span><span class="hl-identifier">x</span><span class="hl-brackets">)</span></pre></div></div>
<p>Another function that we called way back when in the __inti__ function is:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">ensure_targets</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-comment">#Make sure that we have enough targets
    </span><span class="hl-identifier">while </span><span class="hl-brackets">(</span><span class="hl-builtin">len</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">targets</span><span class="hl-brackets">)</span><span class="hl-code"> &lt; </span><span class="hl-identifier">NUM_TARGETS</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">targets</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">create_target</span><span class="hl-brackets">())</span></pre></div></div>
<p>Pretty simply stuff, while the number of targets stored in our list is less then NUM_TARGETS we create and add targets to our list.  NUM_TARGETS is defined as follows at the beginning of the source code:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">NUM_TARGETS</span><span class="hl-default"> = </span><span class="hl-number">10</span></pre></div></div>
<p>The ensure_targets function uses the create_target function to create new targets:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">create_target</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-comment">#Create a new target and return it
    
    #Init to random size and position
    </span><span class="hl-identifier">x</span><span class="hl-default"> = </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-brackets">()</span><span class="hl-code">*</span><span class="hl-number">400</span><span class="hl-brackets">)
    </span><span class="hl-identifier">width</span><span class="hl-default"> = </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-brackets">()</span><span class="hl-code">*</span><span class="hl-number">30</span><span class="hl-brackets">)</span><span class="hl-default"> + </span><span class="hl-number">20
    </span><span class="hl-identifier">height</span><span class="hl-default"> = </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-brackets">()</span><span class="hl-code">*</span><span class="hl-number">30</span><span class="hl-brackets">)</span><span class="hl-default"> + </span><span class="hl-number">20
    </span><span class="hl-identifier">y</span><span class="hl-default"> = </span><span class="hl-number">0</span><span class="hl-default"> - </span><span class="hl-identifier">height
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Init the velocity to a random number based off of the 
    score so that more targets are hit, the game gets harder.</span><span class="hl-quotes">&quot;&quot;&quot;
    </span><span class="hl-identifier">velocity</span><span class="hl-default"> = </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-brackets">()</span><span class="hl-code">*</span><span class="hl-brackets">(</span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">score</span><span class="hl-code"> / </span><span class="hl-number">15</span><span class="hl-brackets">)</span><span class="hl-code">+</span><span class="hl-number">1</span><span class="hl-brackets">))
    </span><span class="hl-comment">#The minimum velocity is 1
    </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">velocity</span><span class="hl-code">&lt;=</span><span class="hl-number">0</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-identifier">velocity</span><span class="hl-default"> = </span><span class="hl-number">1

    </span><span class="hl-reserved">return </span><span class="hl-identifier">TargetSprite</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_target_event</span><span class="hl-code">
            , </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">game_canvas</span><span class="hl-code">, </span><span class="hl-identifier">x</span><span class="hl-code">, </span><span class="hl-identifier">y</span><span class="hl-code">,</span><span class="hl-identifier">width</span><span class="hl-code">, </span><span class="hl-identifier">height</span><span class="hl-code">
            , </span><span class="hl-identifier">velocity</span><span class="hl-brackets">)</span></pre></div></div>
<p>This might seem slightly confusing, but basically what we are doing is using our random object to randomly position and size our new target sprite. We set the x position to be a random number between 0 and 400, the width and height a random number between 20 and 50.  Then the Y position to be 0 – height, this is simply done to start the target off of the screen.</p>
<p>Next we set the velocity of the Target sprite to be between 1 and the current score divided by 15.  This makes it so that the game increases in difficulty as the more targets are hit.</p>
<p>Finally we return the TargetSprite that we create.</p>
<p>Now that we have looked at how we create TargetSprites in the TargetGame class lets look at our TargetSprite object, here is the __init__ function from the Target Sprite class, notice that in create_target we pass the function self.on_target_event as the first parameter:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">notify_function</span><span class="hl-code">, </span><span class="hl-identifier">game_canvas</span><span class="hl-code">, </span><span class="hl-identifier">x</span><span class="hl-code">, </span><span class="hl-identifier">y</span><span class="hl-code">, </span><span class="hl-identifier">width</span><span class="hl-code">, </span><span class="hl-identifier">height</span><span class="hl-code">, </span><span class="hl-identifier">velocity</span><span class="hl-code">=</span><span class="hl-number">1</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize the target sprite.
    @param notify_function - function - The function to call when an event happens.
    @param game_canvas - Canvas object - The canvas that the 
    TargetSprite will be added to.
    @param x - int - X position
    @param y - int - Y position
    @param width - int - The width
    @param height - int - The height
    @param velocity = 1 - int - How fast we are going to move down.
    </span><span class="hl-quotes">&quot;&quot;&quot;
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">notify_function</span><span class="hl-default"> = </span><span class="hl-identifier">notify_function
    self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default"> = </span><span class="hl-identifier">game_canvas
    self</span><span class="hl-default">.</span><span class="hl-identifier">x</span><span class="hl-default"> = </span><span class="hl-identifier">x
    self</span><span class="hl-default">.</span><span class="hl-identifier">y</span><span class="hl-default"> = </span><span class="hl-identifier">y
    self</span><span class="hl-default">.</span><span class="hl-identifier">width</span><span class="hl-default"> = </span><span class="hl-identifier">width
    self</span><span class="hl-default">.</span><span class="hl-identifier">height</span><span class="hl-default"> = </span><span class="hl-identifier">height
    self</span><span class="hl-default">.</span><span class="hl-identifier">velocity</span><span class="hl-default"> = </span><span class="hl-identifier">velocity
            
    self</span><span class="hl-default">.</span><span class="hl-identifier">add_to_canvas</span><span class="hl-brackets">()</span></pre></div></div>
<p>This function is pretty easy to understand, we save a reference to each parameter and then we add ourself to the canvas that was passed in.  add_to_canvas is where we actually create the ellipse that will be displayed on the screen as our target:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">add_to_canvas</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Add yourself to the canvas</span><span class="hl-quotes">&quot;&quot;&quot;
    
    </span><span class="hl-comment">#Create the Ellipse
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ellipse</span><span class="hl-default"> = </span><span class="hl-identifier">System</span><span class="hl-default">.</span><span class="hl-identifier">Windows</span><span class="hl-default">.</span><span class="hl-identifier">XamlReader</span><span class="hl-default">.</span><span class="hl-identifier">Load</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">&lt;Ellipse Stroke=&quot;Black&quot; StrokeThickness=&quot;2&quot; Fill=&quot;SlateBlue&quot;/&gt;</span><span class="hl-quotes">'</span><span class="hl-brackets">)
    </span><span class="hl-comment">#Height, Width, and position
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ellipse</span><span class="hl-default">.</span><span class="hl-identifier">Height</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">height
    self</span><span class="hl-default">.</span><span class="hl-identifier">ellipse</span><span class="hl-default">.</span><span class="hl-identifier">Width</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">width
    </span><span class="hl-comment">#Add to canvase
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default">.</span><span class="hl-identifier">Children</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">ellipse</span><span class="hl-brackets">)
    </span><span class="hl-comment">#Set the position
    </span><span class="hl-identifier">wpf</span><span class="hl-default">.</span><span class="hl-identifier">SetPosition</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">ellipse</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-brackets">)
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Connect out click event handler with the Let button down
    event.</span><span class="hl-quotes">&quot;&quot;&quot;
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ellipse</span><span class="hl-default">.</span><span class="hl-identifier">MouseLeftButtonDown</span><span class="hl-default"> += </span><span class="hl-identifier">MouseEventHandler</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_ellipse_click</span><span class="hl-brackets">)</span></pre></div></div>
<p>Now here we do something interesting, we create an <a href="http://msdn2.microsoft.com/en-us/library/bb188394.aspx">ellipse object</a> using some in-line XAML code instead of creating the object directly like we did with the “game over” text.</p>
<p>After the ellipse has been created, we set the Height and Width, and then we add it to the canvas objects <a href="http://msdn2.microsoft.com/en-us/library/bb680308.aspx">children</a>.  Then we use the SetPosition helper function in the wpf module to set the position of our ellipse.</p>
<p>Then we add a handler to the ellipse&#8217;s <a href="http://msdn2.microsoft.com/en-us/library/bb188277.aspx">MouseLeftButtonDown event</a>.  We do this so that we know that the user has “hit” a target.</p>
<p>Our MouseLeftButtonDown function is pretty simple as well, we simply call the notify function that we were initialized with and tell them what happened:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_ellipse_click</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">sender</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">We have been clicked on, call the notify function
    and tell them.</span><span class="hl-quotes">&quot;&quot;&quot;
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">notify_function</span><span class="hl-brackets">(</span><span class="hl-identifier">TARGET_HIT</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-brackets">)</span></pre></div></div>
<p>Target hit is defined at the start of the program along with GAME_OVER like so:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">TARGET_HIT</span><span class="hl-default"> = </span><span class="hl-number">0
</span><span class="hl-identifier">GAME_OVER</span><span class="hl-default"> = </span><span class="hl-number">1</span></pre></div></div>
<p>These are simply defines that we use to pass into the notify function in order to tell it what event has happened.</p>
<p>Now we switch back to the TargetGame clasas and the notify function that we passed to the TargetSprite():</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_target_event</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-code">, </span><span class="hl-identifier">target_sprite</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when an event is sent from the target
    sprite
    @param event - number - What has happened?
    @param target_sprite -TargetSprite - The sprite that
    has sent this event</span><span class="hl-quotes">&quot;&quot;&quot;
    
    </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">done</span><span class="hl-code">==</span><span class="hl-reserved">True</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-comment">#We are already done don't bother
        </span><span class="hl-reserved">return
    
    </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code"> == </span><span class="hl-identifier">GAME_OVER</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-comment">#The game is over!
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over</span><span class="hl-brackets">()
    </span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code"> == </span><span class="hl-identifier">TARGET_HIT</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">A target has been hit
        Remove the hit target from the list and from
        the canvass</span><span class="hl-quotes">&quot;&quot;&quot;
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">targets</span><span class="hl-default">.</span><span class="hl-identifier">remove</span><span class="hl-brackets">(</span><span class="hl-identifier">target_sprite</span><span class="hl-brackets">)
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default">.</span><span class="hl-identifier">Children</span><span class="hl-default">.</span><span class="hl-identifier">Remove</span><span class="hl-brackets">(</span><span class="hl-identifier">target_sprite</span><span class="hl-code">.</span><span class="hl-identifier">ellipse</span><span class="hl-brackets">)
        </span><span class="hl-comment">#Update the score and the score text
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">score</span><span class="hl-default"> += </span><span class="hl-number">1
        </span><span class="hl-identifier">Score</span><span class="hl-default">.</span><span class="hl-identifier">Text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Targets Hit: %d</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">score</span><span class="hl-brackets">)
        </span><span class="hl-comment">#Now make sure that we have enough targets
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ensure_targets</span><span class="hl-brackets">()</span></pre></div></div>
<p>Now I hope you can see what is happening, we don&#8217;t have any game play just yet, but we have started working on the interaction between our sprites and the main game object.  This function is pretty straight forward, if we got the GAME_OVER event then we call the game_over function and everything finishes.</p>
<p>If the event is a TARGET_HIT event then we need to remove the target that was hit from the targets list and the game_canvas.  Then we need to update the score and the score text.  Now this is the first time that we have referenced our TextBlock object.  If you remember the XAML you&#8217;ll remember that we created a TextBlock object in order to display the score:</p>
<p>[code lang=”xml”]<br />
<textblock Name="Score" Text="Targets Hit: 0"  FontSize="10" Canvas.Left="400" Canvas.Top="305"/><br />
[/code]</p>
<p>So in order to set the text, we simply reference the object by it&#8217;s name and set its <a href=”http://msdn2.microsoft.com/en-us/library/bb188535.aspx”>text property</a>:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">Score</span><span class="hl-default">.</span><span class="hl-identifier">Text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Targets Hit: %d</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">score</span><span class="hl-brackets">)</span></pre></div></div>
<p>Which I think is some pretty cool and intuitive interaction between our xaml and our python code.</p>
<p>Now we have most of the game &#8220;architecture&#8221; in place, but we still need to create our game loop, and a way for outside callers to start the actual game, enter the run function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">run</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Start the game.</span><span class="hl-quotes">&quot;&quot;&quot;
    </span><span class="hl-comment">#initialize the elements
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">done</span><span class="hl-default"> = </span><span class="hl-reserved">False
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">score</span><span class="hl-default"> = </span><span class="hl-number">0
    </span><span class="hl-comment">#Our storyboard timer
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default"> = </span><span class="hl-identifier">Storyboard</span><span class="hl-brackets">()
   </span><span class="hl-comment">#Set the name property for the 1.1 refresh
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default">.</span><span class="hl-identifier">SetValue</span><span class="hl-brackets">[</span><span class="hl-identifier">System</span><span class="hl-code">.</span><span class="hl-identifier">String</span><span class="hl-brackets">](</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gameLoop</span><span class="hl-code">.</span><span class="hl-identifier">NameProperty</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">GameLoop</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
    </span><span class="hl-comment">#Add to the canvas
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default">.</span><span class="hl-identifier">Resources</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gameLoop</span><span class="hl-brackets">)
    </span><span class="hl-comment">#Add the completed event handler
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default">.</span><span class="hl-identifier">Completed</span><span class="hl-default"> += </span><span class="hl-identifier">EventHandler</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_game_timer</span><span class="hl-brackets">)
    </span><span class="hl-comment">#Start the game loop
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default">.</span><span class="hl-identifier">Begin</span><span class="hl-brackets">()</span></pre></div></div>
<p>Now because of the way that Silverlight works we cannot simply use a normal game loop, instead we use a <a href="http://msdn2.microsoft.com/en-us/library/bb188390.aspx">Storyboard object</a> which is generally used for animations.  What we do is tell the storyboard object to <a href="http://msdn2.microsoft.com/en-us/library/bb188390.aspx">Begin</a> its set of animations, but since there are no animations set up, it promptly quits and the <a href="http://msdn2.microsoft.com/en-us/library/bb190644.aspx">Completed event</a> fires, which we handle with the self.on_game_timer function.</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_game_timer</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">sender</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is the main game loop that we are going to be
        using.</span><span class="hl-quotes">&quot;&quot;&quot;

        </span><span class="hl-comment">#Update the sprites
        </span><span class="hl-reserved">for </span><span class="hl-identifier">sprite </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">targets</span><span class="hl-default">:
            </span><span class="hl-identifier">sprite</span><span class="hl-default">.</span><span class="hl-identifier">update</span><span class="hl-brackets">()
        </span><span class="hl-comment">#If we are not done, start the timer again    
        </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">done</span><span class="hl-brackets">)</span><span class="hl-default">:
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default">.</span><span class="hl-identifier">Begin</span><span class="hl-brackets">()</span></pre></div></div>
<p>What we do when our Storyboard ends is we update all of our targets, then if the game has not finished we restart the Storyboard, and the game loops.</p>
<p>The update function in the TargetSprite pretty simple, it updates the position of the Target and if the target has hit the bottom of the canvas then it fires the GAME_OVER event:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">update</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is called when the sprite is supposed to update
    itself.</span><span class="hl-quotes">&quot;&quot;&quot;
    </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">y</span><span class="hl-default"> += </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">velocity
    wpf</span><span class="hl-default">.</span><span class="hl-identifier">SetPosition</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">ellipse</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-brackets">)
    
    </span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">height</span><span class="hl-brackets">)</span><span class="hl-code"> &gt;= </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">game_canvas</span><span class="hl-code">.</span><span class="hl-identifier">Height</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-comment">#We have hit the bottom! Game over!
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">notify_function</span><span class="hl-brackets">(</span><span class="hl-identifier">GAME_OVER</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-brackets">)</span></pre></div></div>
<p>Now all we need is to do is start the game when the page loads, to do that we go back to our trusty on_canvas_loaded function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_canvas_loaded</span><span class="hl-brackets">(</span><span class="hl-identifier">sender</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-identifier">target_game</span><span class="hl-default"> = </span><span class="hl-identifier">TargetGame</span><span class="hl-brackets">(</span><span class="hl-identifier">root_canvas</span><span class="hl-brackets">)
    </span><span class="hl-identifier">target_game</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()</span></pre></div></div>
<p>Now if you&#8217;ve made it this far in the code there shouldn&#8217;t be anything surprising about this, we basically initialise our TargetGame using the root_canvas, and then we tell that game to run, that&#8217;s it.</p>
<p>So that&#8217;s it, you can go play the game here if you want: <a href="http://www.learningpython.com/silverpy/index.htm">http://www.learningpython.com/silverpy/index.htm</a> my highest score is 93.</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/silver/silver_03.png" alt="Python silverlight" border="0"/></p>
<p>Here is all of the code:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">from </span><span class="hl-identifier">System </span><span class="hl-reserved">import</span><span class="hl-default"> *
</span><span class="hl-reserved">import </span><span class="hl-identifier">_random
</span><span class="hl-reserved">import </span><span class="hl-identifier">wpf
</span><span class="hl-reserved">from </span><span class="hl-identifier">wpf </span><span class="hl-reserved">import</span><span class="hl-default"> *
</span><span class="hl-reserved">import </span><span class="hl-identifier">clr
clr</span><span class="hl-default">.</span><span class="hl-identifier">AddReference</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">agclr</span><span class="hl-quotes">'</span><span class="hl-brackets">)
</span><span class="hl-identifier">clr</span><span class="hl-default">.</span><span class="hl-identifier">AddReference</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">System.Silverlight</span><span class="hl-quotes">'</span><span class="hl-brackets">)

</span><span class="hl-identifier">TARGET_HIT</span><span class="hl-default"> = </span><span class="hl-number">0
</span><span class="hl-identifier">GAME_OVER</span><span class="hl-default"> = </span><span class="hl-number">1
</span><span class="hl-identifier">NUM_TARGETS</span><span class="hl-default"> = </span><span class="hl-number">10

</span><span class="hl-reserved">class </span><span class="hl-identifier">TargetSprite</span><span class="hl-brackets">(</span><span class="hl-identifier">object</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">The Target to hit</span><span class="hl-quotes">&quot;&quot;&quot;
    
    </span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">notify_function</span><span class="hl-code">, </span><span class="hl-identifier">game_canvas</span><span class="hl-code">, </span><span class="hl-identifier">x</span><span class="hl-code">, </span><span class="hl-identifier">y</span><span class="hl-code">, </span><span class="hl-identifier">width</span><span class="hl-code">, </span><span class="hl-identifier">height</span><span class="hl-code">, </span><span class="hl-identifier">velocity</span><span class="hl-code">=</span><span class="hl-number">1</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize the target sprite.
        @param notify_function - function - The function to call when an event happens.
        @param game_canvas - Canvas object - The canvas that the 
        TargetSprite will be added to.
        @param x - int - X position
        @param y - int - Y position
        @param width - int - The width
        @param height - int - The height
        @param velocity = 1 - int - How fast we are going to move down.
        </span><span class="hl-quotes">&quot;&quot;&quot;
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">notify_function</span><span class="hl-default"> = </span><span class="hl-identifier">notify_function
        self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default"> = </span><span class="hl-identifier">game_canvas
        self</span><span class="hl-default">.</span><span class="hl-identifier">x</span><span class="hl-default"> = </span><span class="hl-identifier">x
        self</span><span class="hl-default">.</span><span class="hl-identifier">y</span><span class="hl-default"> = </span><span class="hl-identifier">y
        self</span><span class="hl-default">.</span><span class="hl-identifier">width</span><span class="hl-default"> = </span><span class="hl-identifier">width
        self</span><span class="hl-default">.</span><span class="hl-identifier">height</span><span class="hl-default"> = </span><span class="hl-identifier">height
        self</span><span class="hl-default">.</span><span class="hl-identifier">velocity</span><span class="hl-default"> = </span><span class="hl-identifier">velocity
                
        self</span><span class="hl-default">.</span><span class="hl-identifier">add_to_canvas</span><span class="hl-brackets">()
        
    </span><span class="hl-reserved">def </span><span class="hl-identifier">add_to_canvas</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Add yourself to the canvas</span><span class="hl-quotes">&quot;&quot;&quot;
        
        </span><span class="hl-comment">#Create the Ellipse
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ellipse</span><span class="hl-default"> = </span><span class="hl-identifier">System</span><span class="hl-default">.</span><span class="hl-identifier">Windows</span><span class="hl-default">.</span><span class="hl-identifier">XamlReader</span><span class="hl-default">.</span><span class="hl-identifier">Load</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">&lt;ellipse Stroke=&quot;Black&quot; StrokeThickness=&quot;2&quot; Fill=&quot;SlateBlue&quot;/&gt;</span><span class="hl-quotes">'</span><span class="hl-brackets">)
        </span><span class="hl-comment">#Height, Width, and position
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ellipse</span><span class="hl-default">.</span><span class="hl-identifier">Height</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">height
        self</span><span class="hl-default">.</span><span class="hl-identifier">ellipse</span><span class="hl-default">.</span><span class="hl-identifier">Width</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">width
        </span><span class="hl-comment">#Add to canvase
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default">.</span><span class="hl-identifier">Children</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">ellipse</span><span class="hl-brackets">)
        </span><span class="hl-comment">#Set the position
        </span><span class="hl-identifier">wpf</span><span class="hl-default">.</span><span class="hl-identifier">SetPosition</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">ellipse</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-brackets">)
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Connect out click event handler with the Let button down
        event.</span><span class="hl-quotes">&quot;&quot;&quot;
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ellipse</span><span class="hl-default">.</span><span class="hl-identifier">MouseLeftButtonDown</span><span class="hl-default"> += </span><span class="hl-identifier">MouseEventHandler</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_ellipse_click</span><span class="hl-brackets">)
        
    </span><span class="hl-reserved">def </span><span class="hl-identifier">on_ellipse_click</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">sender</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">We have been clicked on, call the notify function
        and tell them.</span><span class="hl-quotes">&quot;&quot;&quot;
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">notify_function</span><span class="hl-brackets">(</span><span class="hl-identifier">TARGET_HIT</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-brackets">)
    
    </span><span class="hl-reserved">def </span><span class="hl-identifier">update</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is called when the sprite is supposed to update
        itself.</span><span class="hl-quotes">&quot;&quot;&quot;
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">y</span><span class="hl-default"> += </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">velocity
        wpf</span><span class="hl-default">.</span><span class="hl-identifier">SetPosition</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">ellipse</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-brackets">)
        
        </span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">height</span><span class="hl-brackets">)</span><span class="hl-code"> &gt;= </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">game_canvas</span><span class="hl-code">.</span><span class="hl-identifier">Height</span><span class="hl-brackets">)</span><span class="hl-default">:
            </span><span class="hl-comment">#We have hit the bottom! Game over!
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">notify_function</span><span class="hl-brackets">(</span><span class="hl-identifier">GAME_OVER</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-brackets">)
    
</span><span class="hl-reserved">class </span><span class="hl-identifier">TargetGame</span><span class="hl-brackets">(</span><span class="hl-identifier">Object</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">A Quick Target game</span><span class="hl-quotes">&quot;&quot;&quot;
    
    </span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">game_canvas</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Init the Target Game
        @param game_canvas - The canvas for the game.
        </span><span class="hl-quotes">&quot;&quot;&quot;
        </span><span class="hl-comment">#Create a random object
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">random</span><span class="hl-default"> = </span><span class="hl-identifier">_random</span><span class="hl-default">.</span><span class="hl-identifier">Random</span><span class="hl-brackets">()
        </span><span class="hl-comment">#Save the game canvas
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default"> = </span><span class="hl-identifier">game_canvas
        </span><span class="hl-comment">#The score
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">score</span><span class="hl-default"> = </span><span class="hl-number">0
        </span><span class="hl-comment">#The list of targets that we have
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">targets</span><span class="hl-default"> = </span><span class="hl-brackets">[]
        </span><span class="hl-comment">#Make sure that we have the minimum number of targets
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ensure_targets</span><span class="hl-brackets">()
        </span><span class="hl-comment">#hook into the keydown event
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default">.</span><span class="hl-identifier">KeyDown</span><span class="hl-default"> += </span><span class="hl-identifier">EventHandler</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_key_down</span><span class="hl-brackets">)
        </span><span class="hl-comment">#Not done yet
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">done</span><span class="hl-default"> = </span><span class="hl-reserved">False
    
    def </span><span class="hl-identifier">on_key_down</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">sender</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Check to see if they hit escape</span><span class="hl-quotes">&quot;&quot;&quot;

        </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">e</span><span class="hl-code">.</span><span class="hl-identifier">Key</span><span class="hl-code"> == </span><span class="hl-number">8</span><span class="hl-brackets">)</span><span class="hl-default">:
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over</span><span class="hl-brackets">()
    
    </span><span class="hl-reserved">def </span><span class="hl-identifier">game_over</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the game should end</span><span class="hl-quotes">&quot;&quot;&quot;
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over_text</span><span class="hl-default"> = </span><span class="hl-identifier">TextBlock</span><span class="hl-brackets">()
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over_text</span><span class="hl-default">.</span><span class="hl-identifier">FontSize</span><span class="hl-default"> = </span><span class="hl-number">50
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over_text</span><span class="hl-default">.</span><span class="hl-identifier">Text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">GAME OVER</span><span class="hl-quotes">&quot;
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default">.</span><span class="hl-identifier">Children</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">game_over_text</span><span class="hl-brackets">)
        </span><span class="hl-identifier">wpf</span><span class="hl-default">.</span><span class="hl-identifier">SetPosition</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">game_over_text</span><span class="hl-code">
            , </span><span class="hl-number">100</span><span class="hl-code">
            , </span><span class="hl-number">100</span><span class="hl-brackets">)
        </span><span class="hl-comment">#We are done
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">done</span><span class="hl-default"> = </span><span class="hl-reserved">True
            
    def </span><span class="hl-identifier">ensure_targets</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-comment">#Make sure that we have enough targets
        </span><span class="hl-identifier">while </span><span class="hl-brackets">(</span><span class="hl-builtin">len</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">targets</span><span class="hl-brackets">)</span><span class="hl-code"> &lt; </span><span class="hl-identifier">NUM_TARGETS</span><span class="hl-brackets">)</span><span class="hl-default">:
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">targets</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">create_target</span><span class="hl-brackets">())
            
    </span><span class="hl-reserved">def </span><span class="hl-identifier">create_target</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-comment">#Create a new target and return it
        
        #Init to random size and position
        </span><span class="hl-identifier">x</span><span class="hl-default"> = </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-brackets">()</span><span class="hl-code">*</span><span class="hl-number">400</span><span class="hl-brackets">)
        </span><span class="hl-identifier">width</span><span class="hl-default"> = </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-brackets">()</span><span class="hl-code">*</span><span class="hl-number">30</span><span class="hl-brackets">)</span><span class="hl-default"> + </span><span class="hl-number">20
        </span><span class="hl-identifier">height</span><span class="hl-default"> = </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-brackets">()</span><span class="hl-code">*</span><span class="hl-number">30</span><span class="hl-brackets">)</span><span class="hl-default"> + </span><span class="hl-number">20
        </span><span class="hl-identifier">y</span><span class="hl-default"> = </span><span class="hl-number">0</span><span class="hl-default"> - </span><span class="hl-identifier">height
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Init the velocity to a random number based off of the 
        score so that more targets are hit, the game gets harder.</span><span class="hl-quotes">&quot;&quot;&quot;
        </span><span class="hl-identifier">velocity</span><span class="hl-default"> = </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-code">.</span><span class="hl-identifier">random</span><span class="hl-brackets">()</span><span class="hl-code">*</span><span class="hl-brackets">(</span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">score</span><span class="hl-code"> / </span><span class="hl-number">15</span><span class="hl-brackets">)</span><span class="hl-code">+</span><span class="hl-number">1</span><span class="hl-brackets">))
        </span><span class="hl-comment">#The minimum velocity is 1
        </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">velocity</span><span class="hl-code">&lt;=</span><span class="hl-number">0</span><span class="hl-brackets">)</span><span class="hl-default">:
            </span><span class="hl-identifier">velocity</span><span class="hl-default"> = </span><span class="hl-number">1
    
        </span><span class="hl-reserved">return </span><span class="hl-identifier">TargetSprite</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_target_event</span><span class="hl-code">
                , </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">game_canvas</span><span class="hl-code">, </span><span class="hl-identifier">x</span><span class="hl-code">, </span><span class="hl-identifier">y</span><span class="hl-code">,</span><span class="hl-identifier">width</span><span class="hl-code">, </span><span class="hl-identifier">height</span><span class="hl-code">
                , </span><span class="hl-identifier">velocity</span><span class="hl-brackets">)
                
    </span><span class="hl-reserved">def </span><span class="hl-identifier">on_target_event</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-code">, </span><span class="hl-identifier">target_sprite</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when an event is sent from the target
        sprite
        @param event - number - What has happened?
        @param target_sprite -TargetSprite - The sprite that
        has sent this event</span><span class="hl-quotes">&quot;&quot;&quot;
        
        </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">done</span><span class="hl-code">==</span><span class="hl-reserved">True</span><span class="hl-brackets">)</span><span class="hl-default">:
            </span><span class="hl-comment">#We are already done don't bother
            </span><span class="hl-reserved">return
        
        </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code"> == </span><span class="hl-identifier">GAME_OVER</span><span class="hl-brackets">)</span><span class="hl-default">:
            </span><span class="hl-comment">#The game is over!
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_over</span><span class="hl-brackets">()
        </span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code"> == </span><span class="hl-identifier">TARGET_HIT</span><span class="hl-brackets">)</span><span class="hl-default">:
            </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">A target has been hit
            Remove the hit target from the list and from
            the canvass</span><span class="hl-quotes">&quot;&quot;&quot;
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">targets</span><span class="hl-default">.</span><span class="hl-identifier">remove</span><span class="hl-brackets">(</span><span class="hl-identifier">target_sprite</span><span class="hl-brackets">)
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default">.</span><span class="hl-identifier">Children</span><span class="hl-default">.</span><span class="hl-identifier">Remove</span><span class="hl-brackets">(</span><span class="hl-identifier">target_sprite</span><span class="hl-code">.</span><span class="hl-identifier">ellipse</span><span class="hl-brackets">)
            </span><span class="hl-comment">#Update the score and the score text
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">score</span><span class="hl-default"> += </span><span class="hl-number">1
            </span><span class="hl-identifier">Score</span><span class="hl-default">.</span><span class="hl-identifier">Text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Targets Hit: %d</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">score</span><span class="hl-brackets">)
            </span><span class="hl-comment">#Now make sure that we have enough targets
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ensure_targets</span><span class="hl-brackets">()
            
    </span><span class="hl-reserved">def </span><span class="hl-identifier">run</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Start the game.</span><span class="hl-quotes">&quot;&quot;&quot;
        </span><span class="hl-comment">#initialize the elements
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">done</span><span class="hl-default"> = </span><span class="hl-reserved">False
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">score</span><span class="hl-default"> = </span><span class="hl-number">0
        </span><span class="hl-comment">#Our storyboard timer
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default"> = </span><span class="hl-identifier">wpf</span><span class="hl-default">.</span><span class="hl-identifier">Storyboard</span><span class="hl-brackets">()
        </span><span class="hl-comment">#Set the name property for the 1.1 refresh
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default">.</span><span class="hl-identifier">SetValue</span><span class="hl-brackets">[</span><span class="hl-identifier">System</span><span class="hl-code">.</span><span class="hl-identifier">String</span><span class="hl-brackets">](</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gameLoop</span><span class="hl-code">.</span><span class="hl-identifier">NameProperty</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">GameLoop</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
        </span><span class="hl-comment">#Add to the canvas
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">game_canvas</span><span class="hl-default">.</span><span class="hl-identifier">Resources</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gameLoop</span><span class="hl-brackets">)
        </span><span class="hl-comment">#Add the completed event handler
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default">.</span><span class="hl-identifier">Completed</span><span class="hl-default"> += </span><span class="hl-identifier">EventHandler</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_game_timer</span><span class="hl-brackets">)
        </span><span class="hl-comment">#Start the game loop
        </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default">.</span><span class="hl-identifier">Begin</span><span class="hl-brackets">()
        
    </span><span class="hl-reserved">def </span><span class="hl-identifier">on_game_timer</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">sender</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-default">:
        </span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is the main game loop that we are going to be
        using.</span><span class="hl-quotes">&quot;&quot;&quot;

        </span><span class="hl-comment">#Update the sprites
        </span><span class="hl-reserved">for </span><span class="hl-identifier">sprite </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">targets</span><span class="hl-default">:
            </span><span class="hl-identifier">sprite</span><span class="hl-default">.</span><span class="hl-identifier">update</span><span class="hl-brackets">()
        </span><span class="hl-comment">#If we are not done, start the timer again    
        </span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">done</span><span class="hl-brackets">)</span><span class="hl-default">:
            </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gameLoop</span><span class="hl-default">.</span><span class="hl-identifier">Begin</span><span class="hl-brackets">()
            
</span><span class="hl-reserved">def </span><span class="hl-identifier">on_canvas_loaded</span><span class="hl-brackets">(</span><span class="hl-identifier">sender</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-default">:
    </span><span class="hl-identifier">target_game</span><span class="hl-default"> = </span><span class="hl-identifier">TargetGame</span><span class="hl-brackets">(</span><span class="hl-identifier">root_canvas</span><span class="hl-brackets">)
    </span><span class="hl-identifier">target_game</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()</span></pre></div></div>
<p>All in all it&#8217;s pretty simple to create something like this using Silverlight and python.  Hopefully this tutorial provides enough information so that all of you can create your own game or application, if you do drop me a line I&#8217;d love to check it out.</p>
<p>As always if you have any questions, comments, or spot a problem with the tutorial, add a comment below.</p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2007/07/29/creating-a-game-using-python-and-silverlight-11/&title=Creating a game using python and Silverlight 1.1&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2007/07/29/creating-a-game-using-python-and-silverlight-11/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>PyLan a GTD todo application written in python and PyGTK &#8211; part three</title>
		<link>http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/</link>
		<comments>http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/#comments</comments>
		<pubDate>Thu, 05 Jul 2007 01:20:31 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[PyGTK]]></category>
		<category><![CDATA[PyLan]]></category>
		<category><![CDATA[glade]]></category>
		<category><![CDATA[gui]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=62</guid>
		<description><![CDATA[
			
				
			
		
PyLan three
Hello welcome to the long-time-coming third article in this tutorial.  I apologize to everyone (anyone?) that was waiting for it.  I have been very busy as of late and have had much of my time taken up by a few other python projects, that I hope to be able to show you [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F07%2F04%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F07%2F04%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<h2>PyLan three</h2>
<p>Hello welcome to the long-time-coming third article in this tutorial.  I apologize to everyone (anyone?) that was waiting for it.  I have been very busy as of late and have had much of my time taken up by a few other python projects, that I hope to be able to show you all soon.</p>
<p>If you want to follow along with the code in detail, and have not done so already, you should read <a href="http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/">part one</a> and <a href="http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/">part two</a> of this series. </p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_03/pylan_03_01.png" alt="Python GTD pyGTK" border="0"/></p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_03.tar.gz">here</a>.</p>
<p>This tutorial will teach you the following things:</p>
<ol>
<li>How to construct a simple theme engine, or at least how I would, hopefully it will give you some ideas!</li>
<li>How to display icons in a gtk.TreeView</li>
<li>How to catch the selection event in a gtk.TreeView.</li>
<li>How to enable or disable widgets.</li>
<li>How to remove the selection from a gtk.TreeView if the user clicks on the gtk.TreeView but not on a tree item.</li>
</ol>
<p><span id="more-62"></span><br />
This tutorial is organized into the following sections:</p>
<ol>
<li><a href="#Theme">A Simple Theme Engine</a></li>
<li><a href="#ShowingIcons">Showing Icons</a></li>
<li><a href="#EnablingWidgets">Enabling and Disabling Widgets</a></li>
<li><a href="#RemoveSelection">Removing Unwanted Selection</a></li>
<li><a href="#Conclusion">Conclusion</a></li>
</ol>
<p>As with other tutorial in this series this will not go into all details and changes that were made in the code, instead it will deal with a few main subjects that will hopefully provide ideas and sample code to others interested in python and PyGtk programming.</p>
<h2><a href="#Theme">A Simple Theme Engine</a></h2>
<p>Now a while back I had an interesting idea that I would like to create a simple theme engine for the PyLan application.  I thought that it would be easy and let me (or other people) change the icons or colours that are used.</p>
<p>So my idea was to use a dictionary object indexed by constant keys, whose values would be &#8220;theme objects.&#8221;</p>
<p>I thought that this would be a simple enough idea that I could implement quickly and then expand in the future to have more features like the ability to save and load the theme from xml.</p>
<p>So to start we create a file called theme.py and filled it with all of the basics and some imports and some constants:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">try</span><span class="hl-default">:
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gtk
	</span><span class="hl-reserved">import </span><span class="hl-identifier">helper
</span><span class="hl-reserved">except</span><span class="hl-default">:
  	</span><span class="hl-reserved">print </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">import Error</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
  	
</span><span class="hl-identifier">PIXMAP</span><span class="hl-default"> = </span><span class="hl-number">0
</span><span class="hl-identifier">COLOUR</span><span class="hl-default"> = </span><span class="hl-number">1</span></pre></div></div>
<p>Next we create our Theme object that will serve as the applications theme.  In this version the Theme object is still very simple, here is it in its entirety:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">Theme</span><span class="hl-brackets">(</span><span class="hl-identifier">dict</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This object represents all of the necessary information needed
	to properly present information in a pyLan application...or any
	application
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">theme_dict</span><span class="hl-code"> = </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">initialize the theme
		@param theme_dict - dictionary of values.  If None it is
		ignored, if not none, it's values will be stored in the internal
		theme_dictionary.</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">load_from_dictionary</span><span class="hl-brackets">(</span><span class="hl-identifier">theme_dict</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">load_from_dictionary</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">theme_dict</span><span class="hl-code">, </span><span class="hl-identifier">initialize</span><span class="hl-code"> = </span><span class="hl-reserved">False</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function loads all of the theme values
		from the theme_dict into the internal theme dictionary.
		@param theme_dict - dictionary - A theme dictionary that
		describes theme items.
		@param initialize = False - boolean, do we want to blank
		out the internal dictionary before we load the items?
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-comment">#Make sure that the dict is not None
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">theme_dict</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-reserved">return
		</span><span class="hl-comment">#clear yourself out
		</span><span class="hl-identifier">dict</span><span class="hl-default">.</span><span class="hl-identifier">clear</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)

		</span><span class="hl-reserved">for </span><span class="hl-identifier">key</span><span class="hl-default">,</span><span class="hl-identifier">value </span><span class="hl-reserved">in </span><span class="hl-identifier">theme_dict</span><span class="hl-default">.</span><span class="hl-identifier">iteritems</span><span class="hl-brackets">()</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-brackets">[</span><span class="hl-identifier">key</span><span class="hl-brackets">]</span><span class="hl-default"> = </span><span class="hl-identifier">value</span></pre></div></div>
<p>So what is happening here?  Not that much, the Theme object uses the dict object as a base class and then lets you initialize the Theme using a dictionary, which is done using a helper function.  This was put for future usage and is not used yet.</p>
<p>The next item in the Theme setup is the ThemeItem object.  This is the object that will be used as the value for each item in our Theme dictionary.</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre>class ThemeItem(object):
	&quot;&quot;&quot;An item in the theme.  This is used to store all of the
	necessary theme information.
	&quot;&quot;&quot;

	&quot;&quot;&quot;Type property - Cannot be set, only set in the
	initializer.&quot;&quot;&quot;
	def __get_type(self):
		return self._m_type
	type = property(__get_type)

	&quot;&quot;&quot;Data Property&quot;&quot;&quot;
	def __get_data(self):
		return self._m_data
	data = property(__get_data)

	def __init__(self, type):
		&quot;&quot;&quot;Initialize yourself.
		@param type - number - The type of theme item.
		&quot;&quot;&quot;
		self._m_type = type
		self._m_data = None
		#now load the data
		self.load_data()

	def load_data(self):
		&quot;&quot;&quot;This function is call when the Theme item
		should load any data that it needs. i.e. if it
		is a pixmap it should load the image file.
		it should create the data.
		&quot;&quot;&quot;
		pass</pre></div></div>
<p>First you can see that there are two date members in the ThemeItem base class, the _m_type and _m_data.  The _m_type is simply used to let interested parties know what the type of theme object is.  I&#8217;m not sure if the _m_type is still needed, originally I was using it but after changing a few things it doesn&#8217;t really do much (anything?) anymore.</p>
<p>The next data member is that _m_data item that is meant to be private and accessed through the data property.  As you can see the data property cannot be set it can only be read.  This was done this way so that only the ThemeItem would be able to set its data.</p>
<p>Now the data member can be anything, it could be an image, a colour, whatever you want it to be.  The data member will generally be set by a subclass of the ThemeItem.  You&#8217;ll also notice that the data is &#8220;loaded&#8221; in the __init__ function.  By default the load_data() function does nothing, and should be overridden in the base class.</p>
<p>The only type that I have in use so far is the ThemePixmap object.  This is a ThemeItem that sets its data to be a <a href="http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html">gtk.gdk.pixbuf</a>:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">ThemePixmap</span><span class="hl-brackets">(</span><span class="hl-identifier">ThemeItem</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">A Them item that represents a pixmap to be displayed.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">file_name</span><span class="hl-code"> = </span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize the pixmap theme item.
		@param file_name - string - the path to the
		pixmap file.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">file_name</span><span class="hl-default"> = </span><span class="hl-identifier">file_name
		ThemeItem</span><span class="hl-default">.</span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">PIXMAP</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">load_data</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is where we load the pixmap based on the file name</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">_m_data</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">gdk</span><span class="hl-default">.</span><span class="hl-identifier">pixbuf_new_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">file_name</span><span class="hl-brackets">)
		</span><span class="hl-reserved">except </span><span class="hl-identifier">gerror</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error loading pixmap %s = %s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">
				% </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">file_name</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">))
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">_m_data</span><span class="hl-default"> = </span><span class="hl-reserved">None</span></pre></div></div>
<p>Pretty straightforward here, a simple subclass of the ThemeItem object that overrides the load_data() function and adds a new class member.  The load_data function simply loads a pixmap into the data using the <a href="http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#function-gdk--pixbuf-new-from-file">gtk.gdk.pixbuf_new_from_file</a> function.</p>
<p>Now how do we use this?</p>
<p>In the main pyLan.py file I added the following function to initalize the theme, it is called from the __init__ function and could theoretically be called from other locations:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">initialize_theme</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to initialise the
	theme.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">app_theme</span><span class="hl-default"> = </span><span class="hl-identifier">theme</span><span class="hl-default">.</span><span class="hl-identifier">Theme</span><span class="hl-brackets">()
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">app_theme</span><span class="hl-brackets">[</span><span class="hl-identifier">CATEGORY_ICON</span><span class="hl-brackets">]</span><span class="hl-default"> = </span><span class="hl-identifier">theme</span><span class="hl-default">.</span><span class="hl-identifier">ThemePixmap</span><span class="hl-brackets">(
		</span><span class="hl-identifier">os</span><span class="hl-code">.</span><span class="hl-identifier">path</span><span class="hl-code">.</span><span class="hl-identifier">join</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pixmaps</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">stock_book_blue.png</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">app_theme</span><span class="hl-brackets">[</span><span class="hl-identifier">TASK_ICON</span><span class="hl-brackets">]</span><span class="hl-default"> = </span><span class="hl-identifier">theme</span><span class="hl-default">.</span><span class="hl-identifier">ThemePixmap</span><span class="hl-brackets">(
		</span><span class="hl-identifier">os</span><span class="hl-code">.</span><span class="hl-identifier">path</span><span class="hl-code">.</span><span class="hl-identifier">join</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pixmaps</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">stock_task.png</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))</span></pre></div></div>
<p>So this is how I use the theme in the main PyLan application, I&#8217;m using it to determine what icon to display for tasks and what icon to use for categories.</p>
<p>As you can see I simply create a theme member in the PyLan class and the add two ThemePixmap items to the Theme, each index by constants that will be used to identify them later.  In the future I hope to use this function to load the information from a file.</p>
<p>The constants used in the function are defined as follows:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">CATEGORY_ICON</span><span class="hl-default"> 			= </span><span class="hl-number">1
</span><span class="hl-identifier">TASK_ICON</span><span class="hl-default">				= </span><span class="hl-number">2</span></pre></div></div>
<p>I will show you how the theme is used in the next section.</p>
<h2><a name="ShowingIcons"></a>Showing Icons</h2>
<p>So now that we have a simple theme engine that load graphics for us we need to figure out how to show images in our gtk.TreeView.</p>
<p>What we will do is we will use the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcellrendererpixbuf.html">gtk.CellRendererPixbuf</a> to render our image.  We will also pack the image into the same column as the Title column.  We do this so that the icon isn&#8217;t in a column of it&#8217;s own, which would seem quite strange.</p>
<p>Basically what we will do is create the gtk.TreeViewColumn in our normal way, using the gtk.CellRenberPixbuf, then when we use the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeviewcolumn.html#method-gtktreeviewcolumn--pack-start">gtk.TreeViewColumn.pack_start</a> function to add the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcellrenderertext.html">gtk.CellRendererText</a> (representing the Title Text) to add the text to column.  This means that we will have two cell renderers in the same column.</p>
<p>The actual code to accomplish this in the pyLan program is quite complicated as I attempted to use the todoColumn object as a generic way to order the columns.  This worked fine before but now it has become a more complicated and slightly hackish now that we want to be able to pack items into the same column.</p>
<p>Sufficed to say I accomplished this by adding a new share_column member to the totoColum that allows you to Pack Widgets.</p>
<p>We also have to update the get_column_list() function in the todo.Task and todo.Category items so that they returns the pixbuf from the theme.  This also means that we need to add a new member to the todo.todoBase object:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">type</span><span class="hl-code">, </span><span class="hl-identifier">app_theme</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">The only way to set the type is through the
	initialization</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_type</span><span class="hl-default"> = </span><span class="hl-identifier">type
	self</span><span class="hl-default">.</span><span class="hl-identifier">app_theme</span><span class="hl-default"> = </span><span class="hl-identifier">app_theme</span></pre></div></div>
<p>Where app_theme is an instance of our Theme object described in the previous section.</p>
<p>Then in the get_column_list() the todo.Category objects need to add the following:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_ICON</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">app_theme</span><span class="hl-brackets">[</span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">CATEGORY_ICON</span><span class="hl-brackets">]</span><span class="hl-code">.</span><span class="hl-identifier">data</span><span class="hl-brackets">)</span></pre></div></div>
<p>and the todo.Theme object needs to add the following:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_ICON</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">app_theme</span><span class="hl-brackets">[</span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">TASK_ICON</span><span class="hl-brackets">]</span><span class="hl-code">.</span><span class="hl-identifier">data</span><span class="hl-brackets">)</span></pre></div></div>
<p>Pretty simple, all we do is we get that Theme item in the applications theme and then return its data.  If this seems strange or you cannot understand it, please take a look at the previous tutorial and you you will be able to understand what the get_column_list() function does.</p>
<h2><a name="EnablingWidgets"></a>Enabling and Disabling Widgets</h2>
<p>One of the things that has been bothering me about the PyLan application was that all of the buttons on the toolbar were always enabled even when they cannot perform their function.</p>
<p>Now I&#8217;m used to the Enable/Disabled terminology except in GTK the terms sensitive and insensitive are used, so I will try to use them from now on, but if an enabled or a disabled slips in there please forgive me.</p>
<p>The first thing that we need to add is an initialize_widgets() function to the PyLan class, this function will gather widgets that we need and will set their default state.  This needs to be called early in the __init__ function before initialize_todo_tree() is called.  The function is as follows:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">initialize_widgets</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize any widgets that we want.  Basically
	grab widgets that you want to have access to later
	on in the program.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the widgets
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_button</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnEdit</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">delete_button</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnRemoveCategory</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">add_task_button</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnAddTask</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#disable them
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">delete_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">add_task_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)</span></pre></div></div>
<p>The code is pretty simple, we grab the widgets from the widget tree, and then we simply call the <a href="http://www.pygtk.org/docs/pygtk/class-gtkwidget.html#method-gtkwidget--set-sensitive">set_sensitive</a> function and tell them to be insensitive by passing False to the function.</p>
<p>The next step is to connect the application to the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeselection.html#signal-gtktreeselection--changed">&#8220;changed&#8221; signal</a> that is emitted by the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeselection.html">gtk.TreeSelection</a> that is associated with our gtk.TreeView.  To do so we need to add the following code to the initialize_todo_tree() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Enable the selection callback
</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
</span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">connect</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">changed</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_tree_selection_changed</span><span class="hl-brackets">)</span></pre></div></div>
<p>Pretty simple, we get the gtk.TreeSelection from the gtk.TreeView and then we connect the on_tree_selection_changed() function with the changed signal.</p>
<p>The on_tree_selection_changed() function is relatively simple as well:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_tree_selection_changed</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">selection</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the selection has changed in the
	tree.
	@param selection - gtk.TreeSelection - The selection
	object associated with the gtk.TreeView.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">get_selected</span><span class="hl-brackets">()
	</span><span class="hl-comment">#If there is a selection then enable these
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">delete_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">add_task_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))</span></pre></div></div>
<p>First we get the selection_iter from the gtk.TreeSelection and then we enable the edit, delete, and add_task buttons based on whether or not there is a selection in the gtk.TreeView.  If nothing is selected then we make the buttons insensitive.</p>
<h2><a href="#RemoveSelection">Removing Unwanted Selection</a></h2>
<p>One feature that I wanted to implement in the application was the ability to remove selection from the tree by clicking on an empty space in the tree.  As far as I can tell there is no simple method to enable a feature like this in PyGTK, which I found quite surprising.</p>
<p>As a result what I needed to do was connect to the gtk.TreeView&#8217;s <a href="http://www.pygtk.org/docs/pygtk/class-gtkwidget.html#signal-gtkwidget--button-press-event">button-press-event</a>.  Then we use the location where the user clicked and see if they clicked on an item in the tree.  If they did not click on an item in the tree then we remove the selection from the tree.  If they did click on something then we leave the selection as is.</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_todoTree_button_press_event</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">There has been a button press on the TodoTree
	for now we use this as a quick hack to remove
	the selection.  Perhaps there is a better way?
	@param widget - gtk.TreeView - The Tree View
	@param event - gtk.gdk.event - Event information
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the path at the specific mouse position
	</span><span class="hl-identifier">path</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_path_at_pos</span><span class="hl-brackets">(</span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-brackets">))
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">path</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">If we didn't get apath then we don't want anything
		to be selected.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
		</span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">unselect_all</span><span class="hl-brackets">()</span></pre></div></div>
<p>As you can see, we take position of the cursor where the button was pressed and then call the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html#method-gtktreeview--get-path-at-pos">get_path_at_pos()</a> function in the gtk.TreeView which returns a tuple containing information if an item in the tree can be found at the specified x,y position, and None if nothing in the tree was hit.</p>
<p>It&#8217;s not pretty but it works!</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_03/pylan_03_01.png" alt="Python GTD pyGTK" border="0"/></p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_03.tar.gz">here</a>.</p>
<h2><a name="Conclusion"></a>Conclusion</h2>
<p>Now one of the problems that I had writing this tutorial is that it&#8217;s getting very hard to detail all of the changes that are made to the project.  So I have tried to leave out as much extraneous detail as I possibly could, but then I start to wonder how much use anyone could get out of these articles if the details are left out.</p>
<p>Hopefully there is still enough in there so that people can get ideas and at least some hints as to how things work in some of the slightly more advanced areas of PyGTK.</p>
<p>I&#8217;m not sure if I am going to continue detailing everything in this test application, I might skip a few phases since detailing everything is getting to be more of a problem.  But what I really want to focus on soon is working with things like Preferences and distributions.  Sadly time is always a factor!</p>
<p>If you have any questions please ask away as always!</p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/&title=PyLan a GTD todo application written in python and PyGTK - part three&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>PyLan a GTD todo application written in python and PyGTK &#8211; part two</title>
		<link>http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/</link>
		<comments>http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/#comments</comments>
		<pubDate>Sun, 11 Mar 2007 22:48:07 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[PyGTK]]></category>
		<category><![CDATA[PyLan]]></category>
		<category><![CDATA[glade]]></category>
		<category><![CDATA[gui]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=58</guid>
		<description><![CDATA[
			
				
			
		
PyLan two
This is part two of the PyLan tutorial series, if you want to follow along with the code in detail, and have not done so already, you should read part one of this series. 
In this tutorial I will go over the following items:

Showing a popup window
Working with a gtk.Calendar widget
Working with gtk.ComboBox widgets
Working [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F03%2F11%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F03%2F11%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<h2>PyLan two</h2>
<p>This is part two of the PyLan tutorial series, if you want to follow along with the code in detail, and have not done so already, you should read <a href="http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/">part one</a> of this series. </p>
<p>In this tutorial I will go over the following items:</p>
<ul>
<li>Showing a popup window</li>
<li>Working with a <a href="http://www.pygtk.org/docs/pygtk/class-gtkcalendar.html">gtk.Calendar</a> widget</li>
<li>Working with <a href="http://www.pygtk.org/docs/pygtk/class-gtkcombobox.html">gtk.ComboBox</a> widgets</li>
<li>Working with Pango markup in a gtk.TreeView</li>
<li>Working with <a href="http://www.pygtk.org/docs/pygtk/class-gtkcheckbutton.html">gtk.CheckButton</a> widgets</li>
<li>Working with the <a href="http://docs.python.org/lib/module-datetime.html">DateTime</a> python module.</li>
</ul>
<p>This tutorial is organized into the following sections:</p>
<ol>
<li><a href="#TheGUI">The GUI</a></li>
<li><a href="#todoTask">The todo.Task Object</a></li>
<li><a href="#addedittodoTask">Adding a todo.Task object</a></li>
<li><a href="#calendarWindow">Showing the Calendar window</a></li>
<li><a href="#EditingItems">Editing todo.Category and todo.Task items</a></li>
<li><a href="#PangoMarkup">Pango markup in the gtk.TreeView</a></li>
<li><a href="#Conclusion">Conclusion</a></li>
</ol>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_08.png" alt="Python GTD pyGTK" border="0" /></p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_02.tar.gz">here</a>.</p>
<p><span id="more-58"></span></p>
<h2><a name="TheGUI"></a>The GUI</h2>
<p>I will be working with the same glade project as last time, except I will be adding a some new dialogs and buttons.  I will not go over all of the changes in the GUI since many of them are very simple changes, similar to changes that have been made in previous tutorials.  </p>
<p>For example I decided to get rid of the Dropdown menu for adding the Categories and the tasks, instead I decided to create separate buttons to do the two separate tasks.  I won&#8217;t describe the switch here, since adding toolbar buttons is pretty straightforward.  For anyone interested in why I decided to make this switch, the answer is pretty simple, I didn&#8217;t like using the drop down menu as much as I thought that I would.  Instead I found it confusing and prone to error.  As a result I made the switch to the separate buttons. </p>
<p>So here is a non-comprehensive list of the changes that I made to the GUI in case you were interested in seeing how something was done.</p>
<p><strong>The Task dialog</strong></p>
<p>This dialog is used to add or edit a todo.Task object.</p>
<ul>
<li>Create a Dialog with an Ok and a Cancel button.  Sets it&#8217;s name to be &#8220;taskItemDialog&#8221;, and its title to be &#8220;Task Item&#8221;.  Give it a width of 300 and a height of 225.</li>
<li>Add a Vertical Box to the dialog with 2 rows.  In the second row add a Check Button with the label &#8220;Completed&#8221; and the name &#8220;checkCompleted&#8221;.</li>
<li>In the first row add a table with two columns and four rows.  To the following to the table, adding vertical padding of 3 pixels to each space in the second column:
<ul>
<li>Add a label with the label &#8220;Title&#8221; in [0, 0].</li>
<li>Add a Text Entry in [0, 1] and call it enTitle</li>
<li>Add a label with the label &#8220;Details&#8221; in [1, 0], give it three pixel of horizontal padding.</li>
<li>Add a Text View in [1, 1] and call it tvDetails.  In the scrolled window&#8217;s properties set the H Policy to &#8220;Never&#8221; and the V Policy to &#8220;Automatic&#8221;.  This means that there will never be a horizontal scrollbar, and that there will be a vertical scrollbar only when one is necessary.</li>
<li>Add a label in [2, 0] with the Label &#8220;Due:&#8221;.</li>
<li>Add a horizontal box with three columns in [2, 1].  In the first add an entry labelled enDueDate, in the second add a button named btnDue add a clicked signal handler, and in the third add a combobox and give it the name &#8220;cmbTime&#8221;.  Add time entries to the combobox in the form: &#8220;&#8221;(blank),12:00AM, 12:30AM, 01:00AM&#8230;11:30PM.  Then right-click on the button and select it in the menu and then select &#8220;Remove Button Contents&#8221;.  Then add an arrow to the button and set its direction to down.  The button will be used to display a Calendar so that the people can select the due date.</li>
<li>Add a label in 3,0 and set its label to &#8220;Priority:</li>
<li>Add a Combo Box in 3,1 and set its name to &#8220;cmbPriority&#8221;.  Set its items to &#8220;High&#8221;, &#8220;Medium&#8221;, and &#8220;Low&#8221;.</li>
</ul>
</li>
</ul>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_02.png" alt="Python GTD pyGTK" border="0" /></p>
<p><strong>The Calendar Window</strong></p>
<p>This is a popup window that we will us to let the user select the due date for their tasks.</p>
<ul>
<li>Add another window, and call it &#8220;calendarWindow&#8221;.  Set its border width to 1, its title to &#8220;&#8221;, its type to &#8220;popup&#8221;, modal to &#8220;yes&#8221;, resizeable to &#8220;no&#8221;, and skip taskbar to &#8220;yes&#8221;.</li>
<li>Add a vertical box to the window with two rows.  </li>
<li>In the first row ad a calendar widget and call it &#8220;calendarWidget&#8221;</li>
<li>In the second row add a button with the name &#8220;btnNoDate&#8221;.  Set the label to be &#8220;No Date&#8221; and the icon to be gtk-no.  Add a clicked signal handler.</li>
</ul>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_03.png" alt="Python GTD pyGTK" border="0" /></p>
<h2><a name="todoTask"></a>The todo.Task object</h2>
<p>The todo.Task object is used to represent the task item in the same way that the todo.Category object represents a category item.  The astute among you will notice that I renamed the category object, I just thought that todo.Category looked so much better then todo.todoCategory.</p>
<p>Since we will be using the datetime and time python modules to represent the due date for tasks we need to import them in the todo file:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">import </span><span class="hl-identifier">datetime
</span><span class="hl-reserved">import </span><span class="hl-identifier">time</span></pre></div></div>
<p>The todo.Task class is relatively simple, if you&#8217;ve read the first tutorial it should be very easy to understand this code:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">Task</span><span class="hl-brackets">(</span><span class="hl-identifier">todoBase</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a task in the todoTree.  It represents
	something that needs to be done.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Name property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_name</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_name</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name</span><span class="hl-default"> = </span><span class="hl-identifier">name
	name</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_name</span><span class="hl-code">, </span><span class="hl-identifier">__set_name</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Due date property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_due_date</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_date
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_due_date</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">due_date</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_date</span><span class="hl-default"> = </span><span class="hl-identifier">due_date
	due_date</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_due_date</span><span class="hl-code">, </span><span class="hl-identifier">__set_due_date</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Due time property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_due_time</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_time
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_due_time</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">due_time</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_time</span><span class="hl-default"> = </span><span class="hl-identifier">due_time
	due_time</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_due_time</span><span class="hl-code">, </span><span class="hl-identifier">__set_due_time</span><span class="hl-brackets">)

	</span><span class="hl-comment">#priority property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_priority</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_priority
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_priority</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">priority</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_priority</span><span class="hl-default"> = </span><span class="hl-identifier">priority
	priority</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_priority</span><span class="hl-code">, </span><span class="hl-identifier">__set_priority</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:

		</span><span class="hl-comment">#init variables
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_date</span><span class="hl-default"> = </span><span class="hl-reserved">None
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_time</span><span class="hl-default"> = </span><span class="hl-reserved">None
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_priority</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;

		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">completed</span><span class="hl-default"> = </span><span class="hl-reserved">False
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">details</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;

		</span><span class="hl-comment">#set properties
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">name
		</span><span class="hl-comment">#init base
		</span><span class="hl-identifier">todoBase</span><span class="hl-default">.</span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">TASK</span><span class="hl-brackets">)

		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Format strings so that the date and time
		formats returns can easily be changed.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">date_format</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%Y-%m-%d</span><span class="hl-quotes">&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">time_format</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%I:%M%p</span><span class="hl-quotes">&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__str__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">todo .Task object: name = %s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the display list
		for the todoTree. The todoCOlumnList controls the
		order that the list will be returned in.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		@returns list - A list for the todoTree.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">lst_return</span><span class="hl-default"> = </span><span class="hl-brackets">[]
		</span><span class="hl-comment"># Loop through the columns and create the return list
		</span><span class="hl-reserved">for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">todoColumnList</span><span class="hl-default">:
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_TITLE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_DETAILS</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">details</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_DUE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_datetime_string</span><span class="hl-brackets">())
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_PRIORITY</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">priority</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_COMPLETED</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">completed</span><span class="hl-brackets">)</span><span class="hl-default">:
					</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">True</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
				</span><span class="hl-reserved">else</span><span class="hl-default">:
					</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">False</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
			</span><span class="hl-reserved">else</span><span class="hl-default">:
				</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error unknown column ID: %d</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-brackets">))
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)

		</span><span class="hl-reserved">return </span><span class="hl-identifier">lst_return

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_date_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the Date string. It will
		be returned in the format of self.date_format.
		@returns - string - The current Due date or &quot;&quot; if nothing
		has been set yet.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">due_date</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">due_date</span><span class="hl-default">.</span><span class="hl-identifier">strftime</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">date_format</span><span class="hl-brackets">)
		</span><span class="hl-reserved">return </span><span class="hl-identifier">date_string

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_time_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the time string. It will
		be returned in the format of self.time_format.
		@returns - string - The current Due time or &quot;&quot; if nothing
		has been set yet.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">due_time</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">due_time</span><span class="hl-default">.</span><span class="hl-identifier">strftime</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">time_format</span><span class="hl-brackets">)
		</span><span class="hl-reserved">return </span><span class="hl-identifier">date_string

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_datetime_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Used to get the date and the time in their
		specified formats.
		@returns - string - the date and the time.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_date_string</span><span class="hl-brackets">()
		</span><span class="hl-identifier">time_string</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_time_string</span><span class="hl-brackets">()
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-builtin">len</span><span class="hl-brackets">(</span><span class="hl-identifier">time_string</span><span class="hl-brackets">)</span><span class="hl-code">&gt;</span><span class="hl-number">0</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%s %s</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">date_string</span><span class="hl-code">, </span><span class="hl-identifier">time_string</span><span class="hl-brackets">)

		</span><span class="hl-reserved">return </span><span class="hl-identifier">date_string</span></pre></div></div>
<p>One thing that you may notice is how we use the datetime and time modules.  You should notice that we have two member variables: </p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">date_format</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%Y-%m-%d</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">time_format</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%I:%M%p</span><span class="hl-quotes">&quot;</span></pre></div></div>
<p>These variable store the date and time format that we will use to display the date and time in the tree.  We will pass the format strings to the<a href="http://docs.python.org/lib/strftime-behavior.html#strftime-behavior">strftime</a> function (from the python docs):</p>
<blockquote><p>
date, datetime, and time objects all support a strftime(format) method, to create a string representing the time under the control of an explicit format string. Broadly speaking, d.strftime(fmt) acts like the time module&#8217;s time.strftime(fmt, d.timetuple()) although not all objects support a timetuple() method.
</p></blockquote>
<p>We define them as members of the class so that they can be changed easily and even pickled with the object itself.</p>
<p>I won&#8217;t go into too much other detail about this class since it&#8217;s pretty much just a data holder for now, and is very similar to the todo.Category object explained in tutorial one except that it has a few more data members.</p>
<h2><a name="addedittodoTask"></a>Adding a todo.Task object</h2>
<p>For this we are going to have to use the task dialog that we created in the GUI stage.  We are going to encapsulate the handling of displaying the dialog in a class.  It made sense to me to do this since this dialog is far more complicated then many that we have used before.</p>
<p>The class is called TaskDialog and I created it in the todo.py file:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">TaskDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">object</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a class that is used to show a taskDialog.  It
	can be used to create or edit a todo.Task.  To create one
	simply initialize the class and do not pass a totoTask.  If you
	want to edit an object initialize with the object that
	you want to edit.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">glade_file</span><span class="hl-code">, </span><span class="hl-identifier">task</span><span class="hl-code"> = </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize the task dialog.
		@param glade_file - string - the glade file for this
		dialog.
		@param task - todo.Task - None to create a new
		todo.Task object, or the object that you wish to
		edit.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">glade_file</span><span class="hl-default"> = </span><span class="hl-identifier">glade_file
		self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default"> = </span><span class="hl-identifier">task

		</span><span class="hl-comment">#Get the widget tree
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">glade_file</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">taskDialog</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Connect with yourself
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">dialog</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">taskDialog</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#get the widgets from the dlg
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_title</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">enTitle</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">tv_details</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">tvDetails</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_due</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">enDue</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">btn_due</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnDue</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">cmbTime</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">cmbPriority</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">check_completed</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">checkCompleted</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#select the items in the combo boxes
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-default">.</span><span class="hl-identifier">set_active</span><span class="hl-brackets">(</span><span class="hl-number">0</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-default">.</span><span class="hl-identifier">set_active</span><span class="hl-brackets">(</span><span class="hl-number">2</span><span class="hl-brackets">)

		</span><span class="hl-identifier">wTreeDue</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">glade_file</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">calendarWindow</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default"> = </span><span class="hl-identifier">wTreeDue</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">calendarWindow</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">wTreeDue</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)

		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">update_dialog_from_object</span><span class="hl-brackets">()</span></pre></div></div>
<p>As you can see what happens here is the TaskDialog is initialized with the path to the glade file that contains the taskDialog, and an optional todo.Task object.  If the todo.Task is not specified (or None) when creating the TaskDialog then the TaskDialog instance is in &#8220;add&#8221; mode, which means that it will create a todo.Task object with the settings specified on the dialog if the user presses the Ok button.</p>
<p>If an instance of a todo.Task object is used when constructing the TaskDialog then the dialog is in &#8220;edit&#8221; mode, and it will modify the object that was passed if the user presses the Ok button.</p>
<p>So not much happens in the __init__ function except we load the dialog and the calendar window from the glade file (the calendar window must be set not to be initially visible in the glade file!  Otherwise it will be shown when it is loaded.) and we auto connect the signals from the dialog and the window with the TaskDialog class.</p>
<p>Then we get access to all of the important widgets on the task dialog.  You&#8217;ll also notice that we set the active item in both the time and priority gtk.ComboBox&#8217;s using the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcombobox.html#method-gtkcombobox--set-active">set_active()</a> function. </p>
<p>We do this so that the first item is selected in the time gtk.ComboBox (the blank)  and we select the third item in the priority gtk.ComboBox so that the low priority item is selected.</p>
<p>At the end of the function we call the update_dialog_from_object() function, this function is used to update what is displayed on the dialog based on the contents of the todo.Task.  There is a sister function named save_data_to_object() that is used to update the todo.Task item with the contents of the dialog:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">update_dialog_from_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Used to update the settings on the dialog</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Title
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_title</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Details
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">set_details</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">details</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Due Date
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_due</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">get_date_string</span><span class="hl-brackets">())
		</span><span class="hl-comment">#Due Time
		</span><span class="hl-identifier">found_iter</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_text_in_combo</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-code">
						, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">get_time_string</span><span class="hl-brackets">())
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">found_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-default">.</span><span class="hl-identifier">set_active_iter</span><span class="hl-brackets">(</span><span class="hl-identifier">found_iter</span><span class="hl-brackets">)
		</span><span class="hl-comment">#priority
		</span><span class="hl-identifier">found_iter</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_text_in_combo</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-code">
									, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">priority</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">found_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-default">.</span><span class="hl-identifier">set_active_iter</span><span class="hl-brackets">(</span><span class="hl-identifier">found_iter</span><span class="hl-brackets">)
		</span><span class="hl-comment">#completed
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">check_completed</span><span class="hl-default">.</span><span class="hl-identifier">set_active</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">completed</span><span class="hl-brackets">)


</span><span class="hl-reserved">def </span><span class="hl-identifier">save_data_to_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to read the data from the dialog
	and then store it in the todo.Task object.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default"> = </span><span class="hl-identifier">Task</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">en_title</span><span class="hl-code">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">())
	</span><span class="hl-reserved">else</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_title</span><span class="hl-default">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">()

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">details</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_details</span><span class="hl-brackets">()

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">set_due_date_from_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">en_due</span><span class="hl-code">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">())
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">set_due_time_from_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-code">.</span><span class="hl-identifier">get_active_text</span><span class="hl-brackets">())
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">priority</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-default">.</span><span class="hl-identifier">get_active_text</span><span class="hl-brackets">()
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">completed</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">check_completed</span><span class="hl-default">.</span><span class="hl-identifier">get_active</span><span class="hl-brackets">()</span></pre></div></div>
<p>Over all these two functions are pretty straightforward, they simply marshal the date between the dialog and the todo.Task.  You&#8217;ll see that there are some helper functions that are used in both functions in order to make saving and loading the data from the object to the dialog easier.  For example to set the text in the gtk.TextView we use the set_details() function, and then to get the text we use the get_details() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_details</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function gets the details from the TextView
	@returns string - The text in the gtk.TextView
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">txtBuffer</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">tv_details</span><span class="hl-default">.</span><span class="hl-identifier">get_buffer</span><span class="hl-brackets">()
	</span><span class="hl-reserved">return </span><span class="hl-identifier">txtBuffer</span><span class="hl-default">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">(</span><span class="hl-code">*</span><span class="hl-identifier">txtBuffer</span><span class="hl-code">.</span><span class="hl-identifier">get_bounds</span><span class="hl-brackets">())

</span><span class="hl-reserved">def </span><span class="hl-identifier">set_details</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">details</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function sets the text in the defails gtk.TextView
	@param details - string - The text that will be
	put into the gtk.TextView.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">txtBuffer</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">tv_details</span><span class="hl-default">.</span><span class="hl-identifier">get_buffer</span><span class="hl-brackets">()
	</span><span class="hl-identifier">txtBuffer</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-identifier">details</span><span class="hl-brackets">)</span></pre></div></div>
<p>These two function are very simple, we get the <a href="http://www.pygtk.org/docs/pygtk/class-gtktextbuffer.html">gkt.TextBuffer</a> associated with the gtk.TextView and then we use the <a href="http://www.pygtk.org/docs/pygtk/class-gtktextbuffer.html#method-gtktextbuffer--get-text">get_text()</a> and <a href="http://www.pygtk.org/docs/pygtk/class-gtktextbuffer.html#method-gtktextbuffer--set-text">set_text()</a> functions to get and set the text.</p>
<p>The next helper that we use is the find_text_in_combo() function:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">find_text_in_combo</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">combobox</span><span class="hl-code">, </span><span class="hl-identifier">text</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a helper function use to find text in
	a gtk.ComboBox.
	@param conbobox gtk.ComboBox - This should contain
	text.
	@param text - string - the text that we are looking
	to find.
	@returns - gtk.TreeIter - The iter at the found
	position or None if nothing was found.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">found_iter</span><span class="hl-default"> = </span><span class="hl-reserved">None </span><span class="hl-comment">#The Iter where text is found
	#Get the gtk.TreeModel associated with the combo
	</span><span class="hl-identifier">combo_model</span><span class="hl-default"> = </span><span class="hl-identifier">combobox</span><span class="hl-default">.</span><span class="hl-identifier">get_model</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">combo_model</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Get the first iter in the model
		</span><span class="hl-identifier">search_iter</span><span class="hl-default"> = </span><span class="hl-identifier">combo_model</span><span class="hl-default">.</span><span class="hl-identifier">get_iter_first</span><span class="hl-brackets">()
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Now loop through the model checking for
		matches until one is found.  Or until
		we have ran out of iters.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">while </span><span class="hl-brackets">((</span><span class="hl-identifier">found_iter</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)
			</span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">search_iter</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">text</span><span class="hl-code"> == </span><span class="hl-identifier">combo_model</span><span class="hl-brackets">[</span><span class="hl-identifier">search_iter</span><span class="hl-brackets">][</span><span class="hl-number">0</span><span class="hl-brackets">])</span><span class="hl-default">:
				</span><span class="hl-comment">#Found!
				</span><span class="hl-identifier">found_iter</span><span class="hl-default"> = </span><span class="hl-identifier">search_iter
			</span><span class="hl-reserved">else</span><span class="hl-default">:
				</span><span class="hl-identifier">search_iter</span><span class="hl-default"> = </span><span class="hl-identifier">combo_model</span><span class="hl-default">.</span><span class="hl-identifier">iter_next</span><span class="hl-brackets">(</span><span class="hl-identifier">search_iter</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-identifier">found_iter</span></pre></div></div>
<p>This function takes a gtk.ComboBox and a string as parameters and searches the gtk.TreeModel associated with the gtk.ComboBox for the text.  If the text is found then the gtk.TreeIter associated with that item is returned, otherwise None is returned.  The function is pretty simple, but I was slightly disappointed that there was no built in way to do this&#8230;perhaps I missed something or perhaps this will be addressed in a future release.</p>
<p>Then once we have the gtk.TreeIter we can use the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcombobox.html#method-gtkcombobox--set-active-iter">set_active_iter()</a> to set that item as the current item in the gtk.ComboBox.  </p>
<p>To get the date and time we use the todo.Task.get_time_string() and todo.Task.get_date_string() functions that we have already touched on. The setting of the due date and due time however is slightly more complicated and I have not gone over it yet.  What we need to do is generate datetime.date and datetime.time instances from strings.</p>
<p>The following two functions in the todo.Task are used to accomplish this:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">set_due_date_from_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">date_string</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to set the due_date based
	on a string. We will try to parse the string.  We will try
	to parse the following formats: YYYY-MM-DD
	, MM-DD-YYYY, or DD-MM-YYYY
	@param date_string - string - The string that we will
	turn into our datetime.date object.
	@returns boolean - success or failure</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">success</span><span class="hl-default"> = </span><span class="hl-reserved">False
	</span><span class="hl-comment">#Switch chars
	</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">date_string</span><span class="hl-default">.</span><span class="hl-identifier">replace</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">/</span><span class="hl-quotes">&quot;</span><span class="hl-code">,</span><span class="hl-quotes">&quot;</span><span class="hl-string">-</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">date_string</span><span class="hl-default">.</span><span class="hl-identifier">replace</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-special">\\</span><span class="hl-quotes">&quot;</span><span class="hl-code">,</span><span class="hl-quotes">&quot;</span><span class="hl-string">-</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">date_string</span><span class="hl-default">.</span><span class="hl-identifier">replace</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot; &quot;</span><span class="hl-code">,</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#All the possible formats
	</span><span class="hl-identifier">lst_formats</span><span class="hl-default"> = </span><span class="hl-brackets">[
		</span><span class="hl-quotes">&quot;</span><span class="hl-string">%Y-%m-%d</span><span class="hl-quotes">&quot;</span><span class="hl-code">
		, </span><span class="hl-quotes">&quot;</span><span class="hl-string">%m-%d-%Y</span><span class="hl-quotes">&quot;</span><span class="hl-code">
		, </span><span class="hl-quotes">&quot;</span><span class="hl-string">%d-%m-%Y</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]
	</span><span class="hl-comment">#Now loop through the formats and try to find a match
	</span><span class="hl-identifier">date</span><span class="hl-default"> = </span><span class="hl-reserved">None
	for </span><span class="hl-identifier">format </span><span class="hl-reserved">in </span><span class="hl-identifier">lst_formats</span><span class="hl-default">:
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">date</span><span class="hl-default"> = </span><span class="hl-identifier">datetime</span><span class="hl-default">.</span><span class="hl-identifier">datetime</span><span class="hl-brackets">(</span><span class="hl-code">*</span><span class="hl-identifier">time</span><span class="hl-code">.</span><span class="hl-identifier">strptime</span><span class="hl-brackets">(</span><span class="hl-identifier">date_string</span><span class="hl-code">
						, </span><span class="hl-identifier">format</span><span class="hl-brackets">)[</span><span class="hl-number">0</span><span class="hl-code">:</span><span class="hl-number">3</span><span class="hl-brackets">])
			</span><span class="hl-comment">#We found a matching format
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">due_date</span><span class="hl-default"> = </span><span class="hl-identifier">date
			</span><span class="hl-comment">#Save the format
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">date_format</span><span class="hl-default"> = </span><span class="hl-identifier">format
			</span><span class="hl-reserved">break
		except</span><span class="hl-default">:
			</span><span class="hl-comment">#failed
			</span><span class="hl-reserved">pass
	return </span><span class="hl-identifier">success

</span><span class="hl-reserved">def </span><span class="hl-identifier">set_due_time_from_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">time_string</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to set the due_time based
	on a string. We will try to parse the string.  We will try
	to parse some formats.
	@param time_string - string - A string representing the
	time.
	@returns - boolean success or failer
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">success</span><span class="hl-default"> = </span><span class="hl-reserved">False
	</span><span class="hl-comment">#strip whitespace
	</span><span class="hl-identifier">time_string</span><span class="hl-default"> = </span><span class="hl-identifier">time_string</span><span class="hl-default">.</span><span class="hl-identifier">replace</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot; &quot;</span><span class="hl-code">,</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#All the possible formats
	</span><span class="hl-identifier">lst_formats</span><span class="hl-default"> = </span><span class="hl-brackets">[
		</span><span class="hl-quotes">&quot;</span><span class="hl-string">%I:%M%p</span><span class="hl-quotes">&quot;</span><span class="hl-code">
		, </span><span class="hl-quotes">&quot;</span><span class="hl-string">%H:%M%p</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]
	</span><span class="hl-comment">#Now loop through the formats and try to find a match
	</span><span class="hl-identifier">due_time</span><span class="hl-default"> = </span><span class="hl-reserved">None
	for </span><span class="hl-identifier">format </span><span class="hl-reserved">in </span><span class="hl-identifier">lst_formats</span><span class="hl-default">:
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">time_struct</span><span class="hl-default"> = </span><span class="hl-identifier">time</span><span class="hl-default">.</span><span class="hl-identifier">strptime</span><span class="hl-brackets">(</span><span class="hl-identifier">time_string</span><span class="hl-code">
						, </span><span class="hl-identifier">format</span><span class="hl-brackets">)
			</span><span class="hl-identifier">due_time</span><span class="hl-default"> = </span><span class="hl-identifier">datetime</span><span class="hl-default">.</span><span class="hl-identifier">time</span><span class="hl-brackets">(</span><span class="hl-identifier">time_struct</span><span class="hl-code">.</span><span class="hl-identifier">tm_hour</span><span class="hl-code">
						, </span><span class="hl-identifier">time_struct</span><span class="hl-code">.</span><span class="hl-identifier">tm_min</span><span class="hl-brackets">)
			</span><span class="hl-comment">#Save the time
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">due_time</span><span class="hl-default"> = </span><span class="hl-identifier">due_time
			</span><span class="hl-comment">#Save the format that was used
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">time_format</span><span class="hl-default"> = </span><span class="hl-identifier">format
			success</span><span class="hl-default"> = </span><span class="hl-reserved">True
			break
		except</span><span class="hl-default">:
			</span><span class="hl-comment">#failed
			</span><span class="hl-reserved">pass
	return </span><span class="hl-identifier">success</span></pre></div></div>
<p>The functions are slightly difficult to understand I will take a little bit of time to explain how they work.  The general idea of the functions is to loop through a list of possible formats and try to create either a datetime.date or datetime.time instance using the current format.</p>
<p>If the creation throws an exception then it has failed, if it does not then it has succeeded and we need to save the format that we used (it becomes the format that we display things in, so if you type in the date in a certain way it will be displayed in that way,) and save the actual instance.</p>
<p>We use the time modules strptime function to create a struct_time, which we then use to create the date or time instance (from the <a href="http://docs.python.org/lib/module-time.html">python documentation</a>):</p>
<blockquote><p>
Parse a string representing a time according to a format. The return value is a struct_time as returned by gmtime() or localtime(). The format parameter uses the same directives as those used by strftime(); it defaults to &#8220;%a %b %d %H:%M:%S %Y&#8221; which matches the formatting returned by ctime(). If string cannot be parsed according to format, ValueError is raised. If the string to be parsed has excess data after parsing, ValueError is raised. The default values used to fill in any missing data when more accurate values cannot be inferred are (1900, 1, 1, 0, 0, 0, 0, 1, -1) .</p>
<p>Support for the %Z directive is based on the values contained in tzname and whether daylight is true. Because of this, it is platform-specific except for recognizing UTC and GMT which are always known (and are considered to be non-daylight savings timezones).
</p></blockquote>
<p>struct_time is simply a sequence of 9 integers that we can then use to create our date or time instances.  The only real difference between the two is that instead of always being able to use the first three numbers in the struct_time sequence when creating the date instance we need to reference the specific time members when creating the time object.</p>
<p>So the code is a bit complicated, but when you look the overview of what it&#8217;s doing it&#8217;s actually pretty simple.</p>
<p>The next thing we have to do is actually show do the dialog:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">run</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Show the dialog</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">break_out</span><span class="hl-default"> = </span><span class="hl-reserved">False
	</span><span class="hl-identifier">while </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">break_out</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">dialog</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">result</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Save the date to the object becuase the use pressed
			ok.</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">save_data_to_object</span><span class="hl-brackets">()
			</span><span class="hl-identifier">break_out</span><span class="hl-default"> = </span><span class="hl-reserved">True
			</span><span class="hl-comment">#Validate here eventually
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">break_out</span><span class="hl-default"> = </span><span class="hl-reserved">True

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">dialog</span><span class="hl-default">.</span><span class="hl-identifier">hide</span><span class="hl-brackets">()

	</span><span class="hl-reserved">return </span><span class="hl-identifier">result</span><span class="hl-default">;</span></pre></div></div>
<p>Another simple function (I seem to say that a lot don&#8217;t I?) we&#8217;re just showing the dialog, and if the users clicks on the OK button we save the data to our todo.Task object and then we leave.  You might wonder why this is done in a loop, the reason is so that in the future we will be able to validate what the user has entered.</p>
<p>So when if the user clicks on the OK button and the validation fails, then we would not set break_out to True, and the dialog would be shown again.  This is just an easy way to set up the dialog for future validation.</p>
<p>The last thing that we need to do is actually use the dialog!  We do this in the on_add_task() function in our main PyLan class:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_add_task</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when we want to add a task.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_cat</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_category_selected</span><span class="hl-brackets">()
	</span><span class="hl-comment">#Make sure that a category is selected
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">model</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_cat</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-identifier">task_dialog</span><span class="hl-default"> = </span><span class="hl-identifier">todo</span><span class="hl-default">.</span><span class="hl-identifier">TaskDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">task_dialog</span><span class="hl-code">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()</span><span class="hl-code"> == </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-comment">#Append to the tree
			</span><span class="hl-identifier">task_dialog</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-code">
				, </span><span class="hl-identifier">selection_iter</span><span class="hl-code">
				, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)
			</span><span class="hl-comment">#Add to the Category
			</span><span class="hl-identifier">todo_cat</span><span class="hl-default">.</span><span class="hl-identifier">add_child</span><span class="hl-brackets">(</span><span class="hl-identifier">task_dialog</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-brackets">)</span></pre></div></div>
<p>Pretty simple stuff here again (I&#8217;m like a broken record!) we get the selected category, if all of the variables come through then we create the todo.TaskDialog in &#8220;add&#8221; mode and then we run it.  If the response is gtk.RESPONSE_OK we add the task to the tree, and then add the task to the category.</p>
<p>If you are wondering about the last two steps there, then you should check out the first tutorial where those helpers are explained.</p>
<h2><a name="calendarWindow"></a>Showing the Calendar window</h2>
<p>This next step took me a long time to figure out even though the actual code is very short.  This step is getting the calendar window, that we created in our glade project, to display when the user clicks on the Due Date &#8220;dropdown&#8221; button.</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_07.png" alt="Python GTD pyGTK" border="0" /></p>
<p>So here is the code:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_btnDue_clicked</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the due button is clicked.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">rect</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_allocation</span><span class="hl-brackets">()
	</span><span class="hl-identifier">x</span><span class="hl-default">, </span><span class="hl-identifier">y</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">window</span><span class="hl-default">.</span><span class="hl-identifier">get_origin</span><span class="hl-brackets">()
	</span><span class="hl-identifier">cal_width</span><span class="hl-default">, </span><span class="hl-identifier">cal_height</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">get_size</span><span class="hl-brackets">()

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">move</span><span class="hl-brackets">((</span><span class="hl-identifier">x</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-code"> - </span><span class="hl-identifier">cal_width</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">width</span><span class="hl-brackets">)</span><span class="hl-code">
		, </span><span class="hl-brackets">(</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">height</span><span class="hl-brackets">))

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">show</span><span class="hl-brackets">()

	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Because some window managers ignore move before
	you show a window.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">move</span><span class="hl-brackets">((</span><span class="hl-identifier">x</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-code"> - </span><span class="hl-identifier">cal_width</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">width</span><span class="hl-brackets">)</span><span class="hl-code">
		, </span><span class="hl-brackets">(</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">height</span><span class="hl-brackets">))</span></pre></div></div>
<p>So the first thing we do is use the <a href="http://www.pygtk.org/docs/pygtk/class-gtkwidget.html#method-gtkwidget--get-allocation">gtk.Widget.get_allocation()</a> function to get the <a href="http://www.pygtk.org/docs/pygtk/class-gdkrectangle.html">gtk.gdk.Rectangle</a> representing the size of the btnDue button.</p>
<p>Then we get the X and Y screen coordinates of the <a href="http://www.pygtk.org/docs/pygtk/class-gdkwindow.html">gtk.gdk.Window</a> (the window where the widget is actually drawn) using the <a href="http://www.pygtk.org/docs/pygtk/class-gdkwindow.html#method-gdkwindow--get-origin">get_origin()</a> function.  This is in root window coordinates instead of being relative to the parent window.  So this is actually the top left corner of the TaskDialog.</p>
<p>Then we get the height and width of the calendar window, and finally move it into position so that the top right corner of the calendar window lines up with the bottom right corner of the btnDue widget.</p>
<p>So, we take the top left corner of the dialog, and then add onto it the x,y coordinates of the btnDue (which are relative to the top left cornet of the TaskDialog) and then we add to it the height and the width of the btnDue so that we get the X and Y of the bottom right corder of the btnDue.  Then we subtract the width of the calendar window, so that the right side of the calendar window lines up with the right side of the btnDue.</p>
<p>If this seems a bit confusing try playing with the numbers a little bit, commenting out parts of the equation, and then see where the calendar window shows up.  After playing with it a little bit it should be pretty straight forward.</p>
<p>So what happens when then calendar window is displayed?  Well it will stay visible until the user double-clicks on a date, or clicks on the &#8220;No Date&#8221; button.</p>
<p>So we need to add two signal handlers:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_btnNoDate_clicked</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the now date widget is
	clicked.  This means that they do not want
	a due date.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Hide the calendar window
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">hide</span><span class="hl-brackets">()
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_due</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)

</span><span class="hl-reserved">def </span><span class="hl-identifier">on_calendarWidget_day_selected_double_click</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the used has double-clicked on a date
	in the calendar widget</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Hide the calendar window
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">hide</span><span class="hl-brackets">()

	</span><span class="hl-identifier">year</span><span class="hl-default">, </span><span class="hl-identifier">month</span><span class="hl-default">, </span><span class="hl-identifier">day</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_date</span><span class="hl-brackets">()
	</span><span class="hl-identifier">month</span><span class="hl-default"> +=</span><span class="hl-number">1 </span><span class="hl-comment">#since it's 0 based
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_due</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">%d-%02d-%02d</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">year</span><span class="hl-code">, </span><span class="hl-identifier">month</span><span class="hl-code">, </span><span class="hl-identifier">day</span><span class="hl-brackets">))</span></pre></div></div>
<p>Pretty simple stuff here, if the &#8220;No Date&#8221; button is clicked then we blank out the due date edit field, and if a date is double clicked on, we get the date from the gtk.Calendar using the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcalendar.html#method-gtkcalendar--get-date">get_date()</a> function.  Then we set the date in the edit fields based on those values.</p>
<p>For now we use a standard format, but in the future we could easily work with the date_format stored in the todo.Task object.</p>
<h2><a name="EditingItems"></a>Editing todo.Category and todo.Task items</h2>
<p>The next step is letting the user edit a todo.Category or todo.Task item that they have already added to the list.  Fortunately the way that we have shown both the Category and Task dialogs makes this step very easy.</p>
<p>The first thing that we need to do is add an &#8220;edit&#8221; event handler in the PyLan class.  This function can be triggered from a menu item, or from the edit button in the main toolbar:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_edit_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when we want to edit the selected item</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment"># Get the selected object
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_selected_object</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">All right something and we have all the needed data</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_object</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-code">, </span><span class="hl-identifier">model</span><span class="hl-code">, </span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)</span></pre></div></div>
<p>Pretty simple, we call a helper function get_selected_object() which does exactly that, gets the selected object, the gtk.TreeIter associated with it, and the gtk.TreeModel that it is displayed in.  Then we call edit object with those parameters.  </p>
<p>get_selected_object() is a lot like the get_selected_category() function:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_selected_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Just a helper function that will give you the
	selected object, whether it is a todoItem or
	a todoTask.
	@returns A 3-tuple containing a reference to the
	gtk.TreeModel and a gtk.TreeIter pointing to the
	currently selected node. Just like
	gtk.TreeSelection.get_selected but with the todoObject
	being returned as well.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return None</span><span class="hl-default">,</span><span class="hl-reserved">None</span><span class="hl-default">,</span><span class="hl-reserved">None

	</span><span class="hl-comment">#Get the current selection in the gtk.TreeView
	</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
	</span><span class="hl-comment"># Get the selection iter
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">get_selected</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter </span><span class="hl-reserved">and </span><span class="hl-identifier">model</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Something is selected so get the object
		</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_ob</span></pre></div></div>
<p>The edit_object() function is equally as easy:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">edit_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todo_object</span><span class="hl-code">, </span><span class="hl-identifier">model</span><span class="hl-code">, </span><span class="hl-identifier">object_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Helper function used to edit an object in the tree.
	@param todo_object - todoBase - The object that we
	are editing.
	@param model - gtk.TreeModel - The model for the tree.
	@param object_iter - gtk.TreeIter representing the
	todo_object's position in the tree.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Just make sure that they are all correct
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">todo_object</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">object_iter</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-code"> == </span><span class="hl-identifier">todo</span><span class="hl-code">.</span><span class="hl-identifier">CATEGORY</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-comment">#Edit category
			</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">show_category_dialog</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">todo_object</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">name
				todo_object</span><span class="hl-default">.</span><span class="hl-identifier">set_tree_values</span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-code">
					, </span><span class="hl-identifier">object_iter</span><span class="hl-code">
					, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-comment">#Edit task
			</span><span class="hl-identifier">task_dialog</span><span class="hl-default"> = </span><span class="hl-identifier">todo</span><span class="hl-default">.</span><span class="hl-identifier">TaskDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">task_dialog</span><span class="hl-code">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()</span><span class="hl-code"> == </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">todo_object</span><span class="hl-default">.</span><span class="hl-identifier">set_tree_values</span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-code">
					, </span><span class="hl-identifier">object_iter</span><span class="hl-code">
					, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)</span></pre></div></div>
<p>So what we do is ensure that the parameters passed in are valid, then we check the type of the object, and then show the correct dialog.  If the user presses the Ok button then we update the data that is stored in the model by calling a new function set_tree_values():</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">set_tree_values</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">tree_model</span><span class="hl-code">, </span><span class="hl-identifier">iter</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is used to set the values in a tree.
	For whatever reason you cannot use the same list that you
	use to append items into the tree?  I don't know why.
	@param tree - gtk.TreeStore - The tree store that we will be
	setting the values in
	@param iter - gtk.TreeIter - The item in the tree
	@param todoColumnList - list - A list of todoColumn items.
	Their type member should use used to determine the order
	of the returned list.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">lst_values</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)
	</span><span class="hl-identifier">count</span><span class="hl-default"> = </span><span class="hl-number">0
	</span><span class="hl-reserved">for </span><span class="hl-identifier">value </span><span class="hl-reserved">in </span><span class="hl-identifier">lst_values</span><span class="hl-default">:
		</span><span class="hl-identifier">tree_model</span><span class="hl-default">.</span><span class="hl-identifier">set_value</span><span class="hl-brackets">(</span><span class="hl-identifier">iter</span><span class="hl-code">, </span><span class="hl-identifier">count</span><span class="hl-code">, </span><span class="hl-identifier">value</span><span class="hl-brackets">)
		</span><span class="hl-identifier">count</span><span class="hl-default"> += </span><span class="hl-number">1</span></pre></div></div>
<p>This function is defined in the todo.todoBase class, which is the base class for both the todo.Task and todo.Caegory.  It can be overwritten by either if they want to perform some special processing, but by default it does everything that we need.  It gets the list of values to display in the tree, and then loops through that list setting each value in the model.</p>
<p>So that&#8217;s basically editing items, not too difficult.  The only other feature that I added was allowing you to edit an item when you double-click on in the gtk.TreeView.  I was slightly surprised to find out that there was no &#8220;double-click&#8221; signal for the gtk.TreeView instead one has to handle the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html#signal-gtktreeview--row-activated">row-activated</a> signal:</p>
<blockquote><p>
The &#8220;row-activated&#8221; signal is emitted when the row_activated() method is called or the user double clicks a treeview row. &#8220;row-activated&#8221; is also emitted when a non-editable row is selected and one of the keys: Space, Shift+Space, Return or Enter is pressed.
</p></blockquote>
<p>So we can handle the &#8220;row-activated&#8221; signal like this:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_todoTree_row_activated</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">tree_view</span><span class="hl-code">, </span><span class="hl-identifier">path</span><span class="hl-code">, </span><span class="hl-identifier">tree_column</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is called when a row is &quot;activated&quot; in the tree
	view.  It happens when the user double clicks on an item
	in the tree.  We will use it to edit the item.
	@param tree_view gtk.TreeView - The Tree
	@param path - string - The path string
	@param tree_column - gtk.TreeViewColumn - The column that
	was clicked on.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the column of the object
	</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
	</span><span class="hl-identifier">model</span><span class="hl-default"> = </span><span class="hl-identifier">tree_view</span><span class="hl-default">.</span><span class="hl-identifier">get_model</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-comment">#Now get the selection iter from the path
		</span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_iter</span><span class="hl-brackets">(</span><span class="hl-identifier">path</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-comment">#Now that we have the selection let's get the object
			</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
			</span><span class="hl-comment">#Now lets edit the object
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_object</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-code">, </span><span class="hl-identifier">model</span><span class="hl-code">, </span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)</span></pre></div></div>
<p>First we get the model and the object column.  Then we use the path that was passed to the signal handler to get the gtk.TreeIter that matches it. Then we get the todo object and we edit it.  </p>
<p>Pretty simple, and now instead of having to find the edit button in the toolbar you can simple double-click on an item in order to edit it.</p>
<h2><a name="PangoMarkup"></a>Pango markup in the gtk.TreeView</h2>
<p>Since you currently cannot tell the difference between a category and a task I decided to make the category titles bold so that you can quickly tell the difference.</p>
<p>This is actually quite easy to do once you know <i>what</i> you need to do.  It took me a little while to find information on how to do this, but once I was able to find the information implementing it was pretty simple.</p>
<p>The first thing that we need to do is update the todoColumn object to have a new member variable: markup. This lets us know that this column will display markup instead of simple text.</p>
<p>So now the create_column() function in the todoColumn class, which was added to handle the creating of columns, looks like this:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">create_column</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:

	</span><span class="hl-identifier">column</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">visible</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">markup</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">column</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">TreeViewColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">
					, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-code">
					, </span><span class="hl-identifier">text</span><span class="hl-code"> = </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">column</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">TreeViewColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">
					, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-code">
					, </span><span class="hl-identifier">markup</span><span class="hl-code"> = </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)

	</span><span class="hl-reserved">return </span><span class="hl-identifier">column</span></pre></div></div>
<p>So if the member variable markup is set to True, then instead of getting the text from the specified position in the model, the column gets the markup from that position.</p>
<p>Then when the todo.Category populates the tree with it&#8217;s values in the get_coloumn_list() it returns the title with markup:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the display list
	for the todoTree. The todoCOlumnList controls the
	order that the list will be returned in.
	@param todoColumnList - list - A list of todoColumn items.
	Their type member should use used to determine the order
	of the returned list.
	@returns list - A list for the todoTree.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">lst_return</span><span class="hl-default"> = </span><span class="hl-brackets">[]
	</span><span class="hl-comment"># Loop through the columns and create the return list
	</span><span class="hl-reserved">for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">todoColumnList</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
		</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-brackets">)
		</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_TITLE</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">&lt;b&gt;%s&lt;/b&gt;</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-identifier">lst_return</span></pre></div></div>
<p>So pretty simple, we wrap the title in the bold tags and then it displays as bold.</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_08.png" alt="Python GTD pyGTK" border="0" /></p>
<h2><a name="Conclusion"></a>Conclusion</h2>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_02.tar.gz">here</a>.</p>
<p>So that&#8217;s it for this one, not as long or drawn out as the last one, but I think some interesting ground is covered.  Again this isn&#8217;t necessarily to teach you how to do everything that I&#8217;m doing, but to provide examples of how one <i>might</i> do things.</p>
<p>If you&#8217;re ever wanting to program something that you have never done before, I always think it&#8217;s nice to see examples of how other people do it.  Even if you don&#8217;t do it in the exact same manner, you will at least have an idea of how to approach the task.  Something that I really couldn&#8217;t find for a few features.  For example the  drop-down gtk.Calendar, which, come to think of it, would make a really nice custom widget if anyone was thinking of creating one.</p>
<p>As always if you find any errors or have any questions feel free to leave a comment.  If however you have a general question about python or PyGTK I would appreciate it if you ask it in the <a href="http://www.learningpython.com/forums/">LearningPython</a> forums so that a possible solution to someone elses problem will not get buried in an unrelated area.</p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/&title=PyLan a GTD todo application written in python and PyGTK - part two&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>PyLan a GTD todo application written in python and PyGTK &#8211; part one</title>
		<link>http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/</link>
		<comments>http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/#comments</comments>
		<pubDate>Sat, 17 Feb 2007 22:47:03 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[PyGTK]]></category>
		<category><![CDATA[PyLan]]></category>
		<category><![CDATA[glade]]></category>
		<category><![CDATA[gui]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=56</guid>
		<description><![CDATA[
			
				
			
		
Introduction
All right, many of you have probably heard of, or read, David Allen&#8217;s book Getting Things Done if not it&#8217;s a pretty interesting book about how to organize the things in your life.  
As I was reading it I thought that a simple todo list could be created using Python and PyGTK pretty easily, [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F02%2F17%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F02%2F17%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<h2>Introduction</h2>
<p>All right, many of you have probably heard of, or read, David Allen&#8217;s book <a href="http://en.wikipedia.org/wiki/Getting_Things_Done">Getting Things Done</a> if not it&#8217;s a pretty interesting book about how to organize the things in your life.  </p>
<p>As I was reading it I thought that a simple todo list could be created using Python and PyGTK pretty easily, so I decided to create the application and write a tutorial surrounding it.  Since the actual application is quite large I have decided to break it up into a series of tutorials, each highlighting a few specific tasks.  The full goal of this series is to show everything that is required when creating a python/PyGTK based application, for the GUI setup  all the way to distribution.</p>
<p>These tutorials assume that you have a basic knowledge of python and PyGTK.  If you have not already done so it is recommended that you take a look at some of my previous PyGTK based tutorials as I will be glossing over much of that which is explained there:</p>
<ul>
<li><a href="http://www.learningpython.com/2006/05/07/creating-a-gui-using-pygtk-and-glade/">Creating a GUI using PyGTK and Glade</a></li>
<li><a href="http://www.learningpython.com/2006/05/30/building-an-application-with-pygtk-and-glade/">Building an Application with PyGTK and Glade</a></li>
<li><a href="http://www.learningpython.com/2006/09/02/extending-our-pygtk-application/">Extending our PyGTK Application</a></li>
<li><a href="http://www.learningpython.com/2006/12/03/translating-your-pythonpygtk-application/">Translating your Python/PyGTK application</a></li>
<li><a href="http://www.learningpython.com/2006/07/25/writing-a-custom-widget-using-pygtk/">Writing a Custom Widget Using PyGTK</a></li>
<li><a href="http://www.learningpython.com/2006/08/19/wordpress-python-library/">WordPy offline blogging tool</a></li>
<li><a href="http://www.learningpython.com/2006/10/24/wordpy-02-using-xml-to-save-and-load-data/">WordPy 0.2 &#8211; Using XML to Save and Load Data</a></li>
</ul>
<h2>PyLan &#8211; part one</h2>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_01.png" alt="Python GTD pyGTK" border="0" /></p>
<p>So the application that we will be creating will be called PyLan, pronounced: plan.  In brief it will be used to create a tree of tasks that can be organized into categories and subcategories.</p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_01.tar.gz">here</a>.</p>
<p>Part one of this tutorial will introduce you to the idea of the application and create the basic shell for it.  It will outline the following:</p>
<ul>
<li>Creating the basic GUI in Glade</li>
<li>Working with a <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html">gtk.TreeView</a></li>
<li>Working with a <a href="http://www.pygtk.org/docs/pygtk/class-gtktreestore.html">gtk.TreeStore</a></li>
<li>Saving and loading the data from the tree using <a href="http://docs.python.org/lib/module-cPickle.html">cPickle</a>.</li>
<li>Using a <a href="http://www.pygtk.org/docs/pygtk/class-gtkmenutoolbutton.html">gtk.MenuToolButton</a></li>
</ul>
<p><span id="more-56"></span></p>
<p>The tutorial is organized into the following sections:</p>
<ol>
<li><a href="#TheGUI">The GUI</a></li>
<li><a href="#SettingItAllUp">The Code: Setting it all up</a></li>
<li><a href="#InitializingTheTree">The Code: Initializing the tree</a></li>
<li><a href="#TodoItems">The Code: todo items</a></li>
<li><a href="#AddingCategories">The Code: Adding Categories</a></li>
<li><a href="#RemovingCategories">The Code: Removing Categories</a></li>
<li><a href="#SavingAndLoadingWithcPickle">The Code: Saving and Loading with cPickle</a></li>
<li><a href="#ConnectingOurMenuWithThegtk.MenuToolButton">The Code: Connecting our menu with the gtk.MenuToolButton</a></li>
<li><a href="#Conclusion">Conclusion</a></li>
</ol>
<h2><a name="TheGUI"></a>The GUI</h2>
<p>The GUI will be created using Glade, it will be a relatively simple especially in this first part.  Since the glade project file is available I won&#8217;t go into too much detail about how to create this GUI, however I will outline the major steps that one could follow in case they would like to create their own GUI, or model a GUI after this one.</p>
<p><strong>The main window:</strong></p>
<ol>
<li>Create a new Glade Project and save it as pylan a folder named PyLan that you have created.</li>
<li>Create a window, and call it &#8220;mainWindow&#8221;, set its title to be PyLan.  If you are using Glade3 make sure that you set your window to be visible.  Add the GObject destroy signal handler like usual.  On the common tab set the width to be 400 and the height to be 300.</li>
<li>Add a vertical box to the window and give it 4 rows.</li>
<li>In the first row add a menu, call it &#8220;mainMenu&#8221;.  Make the Quit menu item&#8217;s menu handler the same as the Main Windows destroy signal handler.  For the rest of the File menu items, give them signal handlers using the following format: &#8220;on_file_new&#8221;, &#8220;on_file_open&#8221;, and so on.</li>
<li>In the second row add a tool bar with two items.</li>
<li>In the first spot add a GtkMenuToolButton, and set its name to &#8220;btnAdd&#8221;.  Make it a stock gtk-add button, and add a clicked signal handler with the name &#8220;on_add_category&#8221;.
</li>
<li>In the second spot at a GtkToolButton with the name &#8220;btnRemoveCategory&#8221;, being a stock gtk-remove button.  Set its clicked signal hander to be &#8220;on_remove_item&#8221;.</li>
<li>In the fourth row add a Status Bar.</li>
<li>In the Third row add a Tree View, set its name to be &#8220;todoTree&#8221;</li>
</ol>
<p><strong>The category dialog</strong></p>
<ol>
<li>Now create a Dialog with an Ok and a Cancel button.  Sets it&#8217;s name to be &#8220;categoryDialog&#8221;, and its title to be </li>
<li>&#8220;Category&#8221;.  Give it a default width and a width of 300.  Set its named icon to be: &#8220;stock_post-message&#8221;.</li>
<li>Add a GTKHBox to the dialog with two columns.</li>
<li>In the fist column add a GtkLabel with the label &#8220;Name:&#8221;. Give it an X Pad of 3 pixels.</li>
<li>In the second column add a GtkEntry with the name: &#8220;enName&#8221;</li>
</ol>
<p><strong>The Menu for the Add button</strong></p>
<p>Since we used a GtkMenuToolButton, we need to create the menu that we are going to associate with that button.  To do that we will use a GtkMenu.</p>
<ol>
<li>Create a GtkMenu and call it: &#8220;addMenu&#8221;</li>
<li>Add one Menu item to the menu with the label &#8220;Add _Category&#8221;.  Set the menu items handler &#8220;on_add_category&#8221;</li>
</ol>
<p>After all of that you should be left with something like this:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_01.png" alt="Python GTD pyGTK" border="0" /></p>
<h2><a name="SettingItAllUp">The Code: Setting it all up</a></h2>
<p>Much of this initial code is taken from previous <a href="http://www.learningpython.com/tutorial-index/">pyGTK tutorials</a>, so if you are confused about any of this starting code, I suggest you take a look at the previous PyGTK tutorials where it is explained in depth.  Create this in a file called pyLan.py in the same directory where you saved your glade project.</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

# PyLan - Python + PyGTK todo list
# Copyright (C) 2007 Mark Mruss &lt;selsine @gmail.com&gt;
# http://www.learningpython.com
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# If you find any bugs or have any suggestions email: selsine@gmail.com
# URL: http://www.learningpython.com

</span><span class="hl-identifier">__author__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Mark Mruss &lt;/selsine&gt;&lt;selsine @gmail.com&gt;</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">__version__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">0.1</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">__date__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Date: 2007/02/17</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">__copyright__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Copyright (c) 2007 Mark Mruss</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">__license__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">GPL</span><span class="hl-quotes">&quot;

</span><span class="hl-identifier">_</span><span class="hl-default"> = </span><span class="hl-reserved">lambda </span><span class="hl-identifier">x</span><span class="hl-default"> : </span><span class="hl-identifier">x
</span><span class="hl-reserved">try</span><span class="hl-default">:
 	</span><span class="hl-reserved">import </span><span class="hl-identifier">pygtk
  	pygtk</span><span class="hl-default">.</span><span class="hl-identifier">require</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">2.0</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-reserved">except</span><span class="hl-default">:
  	</span><span class="hl-reserved">pass
try</span><span class="hl-default">:
	</span><span class="hl-reserved">import </span><span class="hl-identifier">sys
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gtk
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gobject
	</span><span class="hl-reserved">import </span><span class="hl-identifier">os
	</span><span class="hl-reserved">import </span><span class="hl-identifier">locale
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gettext
	</span><span class="hl-reserved">import </span><span class="hl-identifier">cPickle
	</span><span class="hl-reserved">import </span><span class="hl-identifier">helper
	</span><span class="hl-reserved">import </span><span class="hl-identifier">todo
</span><span class="hl-reserved">except ImportError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
	</span><span class="hl-reserved">print </span><span class="hl-quotes">&quot;</span><span class="hl-string">Import error pyLan cannot start:</span><span class="hl-quotes">&quot;</span><span class="hl-default">, </span><span class="hl-identifier">e
	sys</span><span class="hl-default">.</span><span class="hl-identifier">exit</span><span class="hl-brackets">(</span><span class="hl-number">1</span><span class="hl-brackets">)

</span><span class="hl-identifier">FILE_EXT</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">pylan</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">APP_NAME</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">pyLan</span><span class="hl-quotes">&quot;


</span><span class="hl-reserved">class </span><span class="hl-identifier">pyLan</span><span class="hl-brackets">(</span><span class="hl-identifier">object</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">A simple python based GTD todo list</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:

		</span><span class="hl-comment">#Get the local path
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">local_path</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">realpath</span><span class="hl-brackets">(</span><span class="hl-identifier">os</span><span class="hl-code">.</span><span class="hl-identifier">path</span><span class="hl-code">.</span><span class="hl-identifier">dirname</span><span class="hl-brackets">(</span><span class="hl-identifier">sys</span><span class="hl-code">.</span><span class="hl-identifier">argv</span><span class="hl-brackets">[</span><span class="hl-number">0</span><span class="hl-brackets">]))
		</span><span class="hl-comment">#Translation stuff
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">initialize_translation</span><span class="hl-brackets">()
		</span><span class="hl-comment">#Set the Glade file
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gladefile</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">join</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">local_path</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">pylan.glade</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Get the Main Widget Tree
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">mainWindow</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Connect with yourself
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)

		</span><span class="hl-comment">#init todo file
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-reserved">None
		</span><span class="hl-comment">#Get the Main Window
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">main_window</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">mainWindow</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)

	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">&quot;
	************************************************************
	* Initialize
	************************************************************
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">initialize_translation</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function initializes the possible translations</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-comment"># Init the list of languages to support
		</span><span class="hl-identifier">langs</span><span class="hl-default"> = </span><span class="hl-brackets">[]
		</span><span class="hl-comment">#Check the default locale
		</span><span class="hl-identifier">lc</span><span class="hl-default">, </span><span class="hl-identifier">encoding</span><span class="hl-default"> = </span><span class="hl-identifier">locale</span><span class="hl-default">.</span><span class="hl-identifier">getdefaultlocale</span><span class="hl-brackets">()
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">lc</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-comment">#If we have a default, it's the first in the list
			</span><span class="hl-identifier">langs</span><span class="hl-default"> = </span><span class="hl-brackets">[</span><span class="hl-identifier">lc</span><span class="hl-brackets">]
		</span><span class="hl-comment"># Now lets get all of the supported languages on the system
		</span><span class="hl-identifier">language</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">environ</span><span class="hl-default">.</span><span class="hl-identifier">get</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">LANGUAGE</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-reserved">None</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">language</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">language comes back something like en_CA:en_US:en_GB:en
			on linuxy systems, on Win32 it's nothing, so we need to
			split it up into a list</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">langs</span><span class="hl-default"> += </span><span class="hl-identifier">language</span><span class="hl-default">.</span><span class="hl-identifier">split</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">:</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Now add on to the back of the list the translations that we
		know that we have, our defaults</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">langs</span><span class="hl-default"> += </span><span class="hl-brackets">[</span><span class="hl-quotes">&quot;</span><span class="hl-string">en_CA</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">en_US</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]

		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Now langs is a list of all of the languages that we are going
		to try to use.  First we check the default, then what the system
		told us, and finally the 'known' list</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">gettext</span><span class="hl-default">.</span><span class="hl-identifier">bindtextdomain</span><span class="hl-brackets">(</span><span class="hl-identifier">APP_NAME</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">local_path</span><span class="hl-brackets">)
		</span><span class="hl-identifier">gettext</span><span class="hl-default">.</span><span class="hl-identifier">textdomain</span><span class="hl-brackets">(</span><span class="hl-identifier">APP_NAME</span><span class="hl-brackets">)
		</span><span class="hl-comment"># Get the language to use
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">lang</span><span class="hl-default"> = </span><span class="hl-identifier">gettext</span><span class="hl-default">.</span><span class="hl-identifier">translation</span><span class="hl-brackets">(</span><span class="hl-identifier">APP_NAME</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">local_path</span><span class="hl-code">
			, </span><span class="hl-identifier">languages</span><span class="hl-code">=</span><span class="hl-identifier">langs</span><span class="hl-code">, </span><span class="hl-identifier">fallback</span><span class="hl-code"> = </span><span class="hl-reserved">True</span><span class="hl-brackets">)
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Install the language, map _() (which we marked our
		strings to translate with) to self.lang.gettext() which will
		translate them.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">gettext</span><span class="hl-default">.</span><span class="hl-identifier">install</span><span class="hl-brackets">(</span><span class="hl-identifier">APP_NAME</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">local_path</span><span class="hl-brackets">)

	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">&quot;
	********************************************************
	* Simple Helpers
	********************************************************
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Set the windows title, take it from todo_file.
		@param todo_file - string - The todo file name that we will
		base the window title off of
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">main_window</span><span class="hl-default">.</span><span class="hl-identifier">set_title</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">PyLan - %s</span><span class="hl-quotes">&quot;</span><span class="hl-code">
				% </span><span class="hl-brackets">(</span><span class="hl-identifier">os</span><span class="hl-code">.</span><span class="hl-identifier">path</span><span class="hl-code">.</span><span class="hl-identifier">basename</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)))
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">main_window</span><span class="hl-default">.</span><span class="hl-identifier">set_title</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">PyLan - Untitled</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))


	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">
	************************************************************
	* Signal Handlers
	************************************************************
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-reserved">def </span><span class="hl-identifier">on_mainWindow_destroy</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the application is going to quit</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">main_quit</span><span class="hl-brackets">()

	</span><span class="hl-reserved">def </span><span class="hl-identifier">on_add_category</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the Add Category button is clicked.
		Can also be generally used to add a category</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">on_remove_item</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">called then the remove category button is clicked.
		Can also be generally used to remove a category or
		item.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">on_file_new</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | New - Start a new project file, blank out
		the current project and start from scratch</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass


	def </span><span class="hl-identifier">on_file_open</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Function called to open a todo file</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">on_file_save</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | Save function - Save the Todo file</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">on_file_save_as</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | Save As function - Save the todo file</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

if </span><span class="hl-identifier">__name__</span><span class="hl-default"> == </span><span class="hl-quotes">&quot;</span><span class="hl-string">__main__</span><span class="hl-quotes">&quot;</span><span class="hl-default">:
	</span><span class="hl-identifier">plan</span><span class="hl-default"> = </span><span class="hl-identifier">pyLan</span><span class="hl-brackets">()
	</span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">main</span><span class="hl-brackets">()</span></pre></div></div>
<p>If you run the code you should be greeted with the following:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_04.png" alt="Python GTD pyGTK" border="0" /></p>
<p>If you are familiar with my other tutorials none of this code should be very surprising to you. The only exception is perhaps the way that we connect our functions with the signal handlers:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span></pre></div></div>
<p>So instead of creating a dict with our functions and then passing it to the signal_autoconnect() function we simply pass our class to the function, and then any of our functions that match the signal handlers in the widget tree will be connected.  A very slick way to handle this if you ask me.</p>
<h2><a name="InitializingTheTree">The Code: Initializing the tree</a></h2>
<p>The next thing that we have to do is initialize our tree, i.e. set up the columns, create the model for the gtk.TreeView, and so on.  I struggled with how to set up the columns for a while since I knew that I wanted them to be dynamic and for the application to function properly no matter what order the columns were in.</p>
<p>As a result I decided to use a simple class and a list of those objects to define what columns are available and what is in each column.  I&#8217;m still not sure if this is the best way to handle it, but it meets most of my requirements and was relatively simple to implement.</p>
<p>The first thing that we need to do is create some &#8220;constants&#8221; near the top of our code right underneath out APP_NAME define:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Column IDs</span><span class="hl-quotes">&quot;&quot;&quot;
</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-default"> = </span><span class="hl-number">0
</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-default"> = </span><span class="hl-number">1
</span><span class="hl-identifier">COL_TITLE</span><span class="hl-default"> = </span><span class="hl-number">2
</span><span class="hl-identifier">COL_DETAILS</span><span class="hl-default"> = </span><span class="hl-number">3
</span><span class="hl-identifier">COL_DUE</span><span class="hl-default"> = </span><span class="hl-number">4
</span><span class="hl-identifier">COL_PRIORITY</span><span class="hl-default"> = </span><span class="hl-number">5
</span><span class="hl-identifier">COL_COMPLETED</span><span class="hl-default"> = </span><span class="hl-number">6</span></pre></div></div>
<p>These are the IDs of the columns that we will have in our list.  For this tutorial most of these will remain unused, but as we progress more and more will be used.  The IDs are used to let us know what each column is.  So COL_OBJECT will be the column that holds the actual python object (as we did in the PyWine tutorial).  COL_OBJECT_TYPE will hold the objects type, and so on.</p>
<p>Then we need a simple class that will contain this information:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">object</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a class that represents a column in the todo tree.
	It is simply a helper class that makes it easier to inialize the
	tree.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">ID</span><span class="hl-code">, </span><span class="hl-identifier">type</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-code">, </span><span class="hl-identifier">pos</span><span class="hl-code">, </span><span class="hl-identifier">visible</span><span class="hl-code">=</span><span class="hl-reserved">False</span><span class="hl-code">, </span><span class="hl-identifier">cellrenderer</span><span class="hl-code"> = </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">
		@param ID - int - The Columns ID
		@param type - int  - A gobject.TYPE_ for the gtk.TreeStore
		@param name - string - The name of the column
		@param pos - int - The index of the column.
		@param visible - boolean - Is the column visible or not?
		@param cellrenderer - gtk.CellRenderer - a constructor function
		for the column
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ID</span><span class="hl-default"> = </span><span class="hl-identifier">ID
		self</span><span class="hl-default">.</span><span class="hl-identifier">type</span><span class="hl-default"> = </span><span class="hl-identifier">type
		self</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">name
		self</span><span class="hl-default">.</span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">pos
		self</span><span class="hl-default">.</span><span class="hl-identifier">visible</span><span class="hl-default"> = </span><span class="hl-identifier">visible
		self</span><span class="hl-default">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-default"> = </span><span class="hl-identifier">cellrenderer
		self</span><span class="hl-default">.</span><span class="hl-identifier">colour</span><span class="hl-default"> = </span><span class="hl-number">0

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__str__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-quotes">&quot;</span><span class="hl-string">&lt;todocolumn object: ID = %s type = %s name = %s pos = %d visible = %s cellrenderer = %s&gt;</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">visible</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-brackets">)</span></pre></div></div>
<p>This class should be created before the PyLan class.  Then at the beginning of the PyLan class we will create a hidden member at the beginnig of the __init__() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">The colum list, at one point this could be saved and loaded
		from a file.</span><span class="hl-quotes">&quot;&quot;&quot;
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-default"> = </span><span class="hl-brackets">[
			</span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_PYOBJECT</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">object</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-brackets">)</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_INT</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">object_type</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-number">1</span><span class="hl-brackets">)</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_TITLE</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Title</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">2</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_DETAILS</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Details</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">3</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_DUE</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Due</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">4</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_PRIORITY</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Priority</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">5</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_COMPLETED</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Completed</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">6</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())
				]</span></pre></div></div>
<p>So what we are doing is creating a list that defines the columns that will be added to our Tree.  As you can see when we create each todoColumn instance we specify everything that is needed to create that column in the tree.</p>
<p>Next we&#8217;ll add a function that we will use to initialize our tree.  This function will be called from our __init__() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Connect with yourself
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)

</span><span class="hl-comment">#Initialize the todo Tree
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">initialize_todo_tree</span><span class="hl-brackets">()</span></pre></div></div>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">initialize_todo_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when we want to initialize the tree.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">tree_type_list</span><span class="hl-default"> = </span><span class="hl-brackets">[] </span><span class="hl-comment">#For creating the TreeStore
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__column_dict</span><span class="hl-default"> = {} </span><span class="hl-comment">#For easy access later on

		#Get the treeView from the widget Tree
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">todoTree</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Make it so that the colours of each row can alternate
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">set_rules_hint</span><span class="hl-brackets">(</span><span class="hl-reserved">True</span><span class="hl-brackets">)

		</span><span class="hl-comment"># Loop through the columns and initialize the Tree
		</span><span class="hl-reserved">for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-default">:
			</span><span class="hl-comment">#Add the column to the column dict
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__column_dict</span><span class="hl-brackets">[</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-brackets">]</span><span class="hl-default"> = </span><span class="hl-identifier">item_column
			</span><span class="hl-comment">#Save the type for gtk.TreeStore creation
			</span><span class="hl-identifier">tree_type_list</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-brackets">)
			</span><span class="hl-comment">#is it visible?
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">visible</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-comment">#Create the Column
				</span><span class="hl-identifier">column</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">TreeViewColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">
					, </span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-code">
					, </span><span class="hl-identifier">text</span><span class="hl-code">=</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)

				</span><span class="hl-identifier">column</span><span class="hl-default">.</span><span class="hl-identifier">set_resizable</span><span class="hl-brackets">(</span><span class="hl-reserved">True</span><span class="hl-brackets">)
				</span><span class="hl-identifier">column</span><span class="hl-default">.</span><span class="hl-identifier">set_sort_column_id</span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
				</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">append_column</span><span class="hl-brackets">(</span><span class="hl-identifier">column</span><span class="hl-brackets">)

		</span><span class="hl-comment">#Create the gtk.TreeStore Model to use with the todoTree
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">TreeStore</span><span class="hl-brackets">(</span><span class="hl-code">*</span><span class="hl-identifier">tree_type_list</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Attache the model to the treeView
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">set_model</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todoTree</span><span class="hl-brackets">)</span></pre></div></div>
<p>So what we do in this function is first get our <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html">gtk.TreeView</a> widget from our widget tree. Then we loop through the column list that we created, and add the column&#8217;s type to the tree_type_list, which will be used to create our <a href="http://www.pygtk.org/docs/pygtk/class-gtktreestore.html">gtk.TreeStore</a>.  If the todoColum is visible we need to create a <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeviewcolumn.html">gtk.TreeViewColum</a> and then add it to the gtk.TreeView.</p>
<p>After we have looped through the column list we create the gtk.TreeStore (our model for the gtk.TreeView) based on all the types in our column list.  Then we set that model as the model for our gtk.TreeView.</p>
<p>This may seem a bit confusing and if you have any problems understanding take a look at the <a href="http://www.learningpython.com/2006/05/30/building-an-application-with-pygtk-and-glade/">Building an Application with PyGTK and Glade</a> tutorial where the relationship between gtk.TreeViews, gtk.TreeViewColumns, gtk.CellRenderers (which we define in our todoColumn), and gtk.TreeModels is described.  Basically the model (the gtk.TreeStore in this case) is the data.  The View (gtk.TreeView, gtk.TreeViewColumn, gtk.CellRenderer) is what is used to display the data.  </p>
<p>This means that you could have multiple views for the same data.  We&#8217;re not doing that in this application so far, but the idea is quite powerful.  We could, for example, use it to create a &#8220;simple&#8221; and &#8220;advanced&#8221; view for our data, or other &#8220;filtered&#8221; views.</p>
<p>Now if we run the code we get the following:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_01.png" alt="Python GTD pyGTK" border="0" /></p>
<p>It&#8217;s the same as it was before, except now we have columns in our gtk.TreeView.</p>
<h2><a name="TodoItems">The Code: todo items</a></h2>
<p>Now that we have our tree defined, we need to create the objects that will store the data.  The data will be divided into two types (for now) a category and an task.</p>
<p>A Category is simply a container for other categories or items.  An task is an actual task that you need to do.</p>
<p>So a category could be &#8220;Work&#8221; and in that category you might add another category called &#8220;Project X&#8221; and in &#8220;Project X&#8221; you may add the task &#8220;Implement feature y.&#8221;  For this tutorial we will not be working with tasks, we will simply be working with categories.</p>
<p>We will create a new file in the same directory where we created our pyLan.py file.  The file will be named todo.py.  We will start off be defining the todoBase class which we will use as the base class for both the Category and Task classes:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">import </span><span class="hl-identifier">pyLan
</span><span class="hl-reserved">import </span><span class="hl-identifier">helper

CATEGORY</span><span class="hl-default"> = </span><span class="hl-number">0
</span><span class="hl-identifier">TASK</span><span class="hl-default">= </span><span class="hl-number">1

</span><span class="hl-reserved">class </span><span class="hl-identifier">todoBase</span><span class="hl-brackets">(</span><span class="hl-identifier">object</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is the base class for the todoCategory and
	the todoTask.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Type property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_type</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_type
	type</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_type</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">type</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">The only way to set the type is through the
		initialization</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_type</span><span class="hl-default"> = </span><span class="hl-identifier">type

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the display list
		for the todoTree. The todoCOlumnList controls the
		order that the list will be returned in. Used as the
		second param in the gtk.TreeStore.append function.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		@returns list - A list for the todoTree.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">tree</span><span class="hl-code">, </span><span class="hl-identifier">parent</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to add an item to a
		gtk.TreeStore, usually when loading.  All
		children will be added as well
		@param tree - gtk.TreeStore - The tree store that
		we wil be adding to.
		@param parent gtk.TreeIter - The parent of this
		item.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">tree</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">parent</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">))</span></pre></div></div>
<p>So the todoBase is simply a class with a type property (either CATEGORY, or TASK) that can only be set in the constructor and two functions get_column_list() and add_to_tree().</p>
<p>get_column_list() is used to create the second parameter for the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreestore.html#method-gtktreestore--append">gtk.TreeStore.append()</a> function &#8220;a tuple or list containing ordered column values to be set in the new row.&#8221;</p>
<p>add_to_tree() is used to add the todo item to the actual tree.  For the category class that we are going to create this is used to ensure that any children (i.e. categories or tasks) will also be added to the tree at the same time.</p>
<p>The todoCategory class is defined as follows:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">todoCategory</span><span class="hl-brackets">(</span><span class="hl-identifier">todoBase</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a category in the todoTree.  It can have child categories
	or child tasks.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Name property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_name</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_name</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name</span><span class="hl-default"> = </span><span class="hl-identifier">name
	name</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_name</span><span class="hl-code">, </span><span class="hl-identifier">__set_name</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:

		</span><span class="hl-comment">#init variables
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">name
		</span><span class="hl-comment">#children
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_children</span><span class="hl-default"> = </span><span class="hl-brackets">[]
		</span><span class="hl-comment">#init base
		</span><span class="hl-identifier">todoBase</span><span class="hl-default">.</span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">CATEGORY</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__str__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">&lt;todocategory object: name = %s num_children = %d&gt;</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">, </span><span class="hl-builtin">len</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__m_children</span><span class="hl-brackets">))

	</span><span class="hl-reserved">def </span><span class="hl-identifier">add_child</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Add a child to the category.
		@param todo_object - Either a todoCategory or a
		todoTask.  This will be a child of the category.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_children</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">remove_child</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Removes a child from the category.
		@param todo_object - Either a todoCategory or a
		todoTask.  This will be a removed.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_children</span><span class="hl-default">.</span><span class="hl-identifier">remove</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)
		</span><span class="hl-reserved">except ValueError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error removing child %s = %s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">))


	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the display list
		for the todoTree. The todoCOlumnList controls the
		order that the list will be returned in.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		@returns list - A list for the todoTree.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">lst_return</span><span class="hl-default"> = </span><span class="hl-brackets">[]
		</span><span class="hl-comment"># Loop through the columns and create the return list
		</span><span class="hl-reserved">for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">todoColumnList</span><span class="hl-default">:
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_TITLE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
			</span><span class="hl-reserved">else</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
		</span><span class="hl-reserved">return </span><span class="hl-identifier">lst_return

	</span><span class="hl-reserved">def </span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">tree</span><span class="hl-code">, </span><span class="hl-identifier">parent</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to add an item to a
		gtk.TreeStore, usually when loading.  All
		children will be added as well
		@param tree - gtk.TreeStore - The tree store that
		we will be adding to.
		@param parent gtk.TreeIter - The parent of this
		item.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">insert_iter</span><span class="hl-default"> = </span><span class="hl-identifier">tree</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">parent</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">))
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">insert_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-reserved">for </span><span class="hl-identifier">child </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_children</span><span class="hl-default">:
				</span><span class="hl-identifier">child</span><span class="hl-default">.</span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">tree</span><span class="hl-code">, </span><span class="hl-identifier">insert_iter</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error loading category: %s</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">self</span><span class="hl-brackets">))</span></pre></div></div>
<p>You can see that it sets its type by initializing the base class and passing it the CATEGORY constant.  It also has some additional members, the name property and the private member __m_children.  Name is the name of the category and __m_children is a list of todoBase objects that are the children of this category.</p>
<p>It implements two functions add_child() and remove_child() that are pretty self explanatory, and it overrides the get_column_list() and add_to_tree() functions from the todoBase.</p>
<p>You can see that in the get_column_list() function that the todoCategory only specifies three columns, for the rest is passes empty strings.  It should be pretty obvious what the function is doing.</p>
<p>add_to_tree() is also overridden.  What it does is add itself to the tree, if that succeeds it then loops through all of its children and then adds them to the tree as well.  If that fails it calls the show_error_dlg() function from the helper module that has not been explained yet.  All you need to know is that show_error_dlg() pops up a simple error dialog.</p>
<h2><a name="AddingCategories">The Code: Adding Categories</a></h2>
<p>Now that we have our category classes defined we need to work on adding them to the actual tree.  To do that we will want to use our categoryDialog.  We will show that to the user and let them set the name of the category.  We will create a function called show_category_dialog() to do this for us:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">show_category_dialog</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function shows the category dialog.
	@param name - string - The name to display in
	category dialog by default.
	@returns - If OK is pressed the name typed on the
	dialog. If Cancel is pressed None is returned.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#init to cancel
	</span><span class="hl-identifier">name_return</span><span class="hl-default"> = </span><span class="hl-reserved">None

	</span><span class="hl-comment">#load the dialog from the glade file
	</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">categoryDialog</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Get the actual dialog widget
	</span><span class="hl-identifier">dlg</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">categoryDialog</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Get all of the Entry Widgets and set their text
	</span><span class="hl-identifier">enName</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">enName</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">enName</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-identifier">name</span><span class="hl-brackets">)

	</span><span class="hl-comment">#run the dialog and store the response
	</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-identifier">dlg</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">result</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#get the value of the entry fields
		</span><span class="hl-identifier">name_return</span><span class="hl-default"> = </span><span class="hl-identifier">enName</span><span class="hl-default">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">()
	</span><span class="hl-comment">#we are done with the dialog, destroy it
	</span><span class="hl-identifier">dlg</span><span class="hl-default">.</span><span class="hl-identifier">destroy</span><span class="hl-brackets">()

	</span><span class="hl-comment">#return the result
	</span><span class="hl-reserved">return </span><span class="hl-identifier">name_return</span></pre></div></div>
<p>This function simply shows the dialog and returns the name that the person typed or None if they cancelled.</p>
<p>We will call this function from the on_add_category() function in the PyLan class.  The on_add_category() function is called when you want to add a category to the Tree.  It is called from either the addButton or from a menu item on the menu that the addButton can display.  Here is the function:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_add_category</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the Add Category button is clicked.
	Can also be generally used to add a category</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">show_category_dialog</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment"># Get the selection category iter
		</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_cat</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_category_selected</span><span class="hl-brackets">()
		</span><span class="hl-comment">#Create the new Category
		</span><span class="hl-identifier">category</span><span class="hl-default"> = </span><span class="hl-identifier">todo</span><span class="hl-default">.</span><span class="hl-identifier">todoCategory</span><span class="hl-brackets">(</span><span class="hl-identifier">name</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Append to the tree
		</span><span class="hl-identifier">category</span><span class="hl-default">.</span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todoTree</span><span class="hl-code">
			, </span><span class="hl-identifier">selection_iter</span><span class="hl-code">
			, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_cat</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">something was selected so add the new category
			to the old category</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">todo_cat</span><span class="hl-default">.</span><span class="hl-identifier">add_child</span><span class="hl-brackets">(</span><span class="hl-identifier">category</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Nothing selected so add to the current project
			data</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">category</span><span class="hl-brackets">)</span></pre></div></div>
<p>The function is relatively simple as it relies on many helper functions.  The first thing that it does is show the category dialog.  If a valid name is returned then we continue adding the category.</p>
<p>We call the get_category_selected() function which is a helper function that is used to get the currently selected category, the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeiter.html">gtk.TreeIter</a> representing the selection, and the model associated with our gtk.TreeView.  The function wraps the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html#method-gtktreeview--get-selection">gtk.TreeView.get_selection()</a> and the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeselection.html#method-gtktreeselection--get-selected">gtk.TreeSelection.get_selected()</a> functions ensuring that todoCategory is selected.  This means that if a todoTask is selected then its parent category will be returned.</p>
<p>We then create the category based on the name and add it to the tree.  If there is a parent category (returned by get_category_selected()) then we add it to its children, otherwise we add it to a new private member self.__categories.  self.__categories is basically a list of all of the top level todoCategories, it is our representation of the data displayed in the tree.  It is created in the __init__ function:</p>
<div class="hl-surround" ><div class="hl-main"><pre>#init todo file
self.todo_file = None
#Get the Main Window
self.main_window = self.wTree.get_widget(&quot;mainWindow&quot;)
self.set_window_title_from_file(self.todo_file)
#No categories
self.__categories = []</pre></div></div>
<p>The get_category_selected() looks like this:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_category_selected</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is a wrapper for the
	gtk.TreeView.get_selection() function and the
	gtk.TreeSelection.get_selected() function. It returns
	the same as gtk.TreeSelection.get_selected(), but ensures
	that it is a category that is selected. So if a todoTask
	is selected then it's parent category will be returned.
	@returns A 3-tuple containing a reference to the
	gtk.TreeModel and a gtk.TreeIter pointing to the
	currently selected node. Just like
	gtk.TreeSelection.get_selected but with the todoObject
	being returned as well.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#First get the object column
	</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return None</span><span class="hl-default">,</span><span class="hl-reserved">None

	</span><span class="hl-comment">#Get the current selection in the gtk.TreeView
	</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
	</span><span class="hl-comment"># Get the selection iter
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">get_selected</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Something is selected so get the object
		</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-code"> != </span><span class="hl-identifier">todo</span><span class="hl-code">.</span><span class="hl-identifier">CATEGORY</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-comment">#Alright we need the parent, this is not a category
			</span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">iter_parent</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)
			</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_ob</span></pre></div></div>
<p>It relies on another helper function find_todoColumn which basically loops through the self.__tree_columns list looking for the todoColumn with the matching ID.  If is found it is returned, along with the position in the list that it was returned at.  This is partly done because I am unsure whether the order in the list will matter after initialization or whether the objects in the list should keep track of their position.  If it is the objects, then they could be moved into a dictionary later on (you&#8217;ll notice that one is already created) for faster access.</p>
<p>We use find_todoColum() so that we can get the column representing the Object. (We use the Object instead of the type since we may need to get the actual object later.  If we just wanted the type we could have used COL_OBJECT_TYPE)</p>
<p>Then what we do is we get the current gtk.TreeSelection and then get what (if anything) is actually selected within it.  If something is selected (selection_iter is not None) then we check to see if the selected item is a category or not.  If it is not a category we get the parent of the selecton iter, which we know is a category since tasks cannot have children.</p>
<p>Then we simply return all of the values: the current model, the gtk.TreeIter representing the selection category (may be None) and the todoCategory object (may also be none).</p>
<p>find_todoColumn() should be self explanatory:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">column_ID</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to search the __tree_columns
	list to find a specific todoColumn.
	@param column_ID - The ID of the column that we
	are looking for.
	@returns todoColumn, int - The column found and
	the position in the list. If todoColumn is None
	then the column was not found.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">count</span><span class="hl-default"> = </span><span class="hl-number">0
	</span><span class="hl-identifier">columnReturn</span><span class="hl-default"> = </span><span class="hl-reserved">None
	for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">column_ID</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">columnReturn</span><span class="hl-default"> = </span><span class="hl-identifier">item_column
			</span><span class="hl-reserved">break
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">columnReturn</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Something is really wrong we did not match
		</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error column data appears corrupted</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
	</span><span class="hl-comment">#Return the results
	</span><span class="hl-reserved">return </span><span class="hl-identifier">columnReturn</span><span class="hl-default">, </span><span class="hl-identifier">count</span></pre></div></div>
<p>After all that code, we are finally able to add things to our tree!</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_05.png" alt="Python GTD pyGTK" border="0" /></p>
<p>It may seem complicated or like a lot of work, but in reality it&#8217;s simply a large process broken up into smaller reusable bits that make more sense when looked at as a whole.</p>
<h2><a name="RemovingCategories">The Code: Removing Categories</a></h2>
<p>Now that we can add categories let&#8217;s add some code so that we can remove them.  We will do this in the on_remove_item() function which is triggered by the btnRemoveCategory button&#8217;s clicked signal:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_remove_item</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">called then the remove category button is clicked.
	Can also be generally used to remove a category or
	item.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Get the column of the object
	</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Get the current selection in the gtk.TreeView
	</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
	</span><span class="hl-comment"># Get the selection iter
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">get_selected</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">All right we have something to remove and we have the
		column that represents the todo object, first
		let's get the object from the selection_iter</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Allright everything worked, time to remove. Does
			this item have a parent</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">todo_parent</span><span class="hl-default">, </span><span class="hl-identifier">iter</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_parent_category</span><span class="hl-brackets">(
				</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
			</span><span class="hl-comment">#Remove from the tree
			</span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">remove</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)
			</span><span class="hl-comment">#if there is a parent, remove from the parent
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_parent</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">todo_parent</span><span class="hl-default">.</span><span class="hl-identifier">remove_child</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">)
			</span><span class="hl-reserved">else</span><span class="hl-default">:
				</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">There is no parent so remove from
				base list</span><span class="hl-quotes">&quot;&quot;&quot;
				</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default">.</span><span class="hl-identifier">remove</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">)</span></pre></div></div>
<p>If you understood how we added the columns, how we remove them should be pretty straight forward.  First we get the object todoColumn and the gtk.TreeSelection.  Then if they are both valid we get the object that is selected.  If nothing is selected then we can return because there is nothing to remove.</p>
<p>If something is selected then we call the helper get_parent_category() which simply gets us the item&#8217;s parent category.  We then remove the selected item from the tree, but since the object is still stored within our data tree (self.__categories) we need to remove it from there.  </p>
<p>If the item has a parent (todo_parent) we remove the item from the parent by calling remove_child().  If the item did not have a parent it means that it is a top level category and needs to be removed directly from self.__categories.</p>
<p>Here is get_parent_category():</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_parent_category</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">object_pos</span><span class="hl-code"> = </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Get the parent category of the selection_item
	@param selection_iter - gtk.TreeIter - A iter whose
	parent you want to get.
	@param object_pos - number - The index of the object
	column.  If None this will be calculated.
	@returns - todoCategory, gtk.TreeIter - The parent category of the
	iter on success, or None on failure. The parent gtk.TreeIter
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">object_pos</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">object_pos</span><span class="hl-default"> = </span><span class="hl-identifier">tcolumn</span><span class="hl-default">.</span><span class="hl-identifier">pos
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-comment">#Column Data Error
			</span><span class="hl-reserved">return None</span><span class="hl-default">, </span><span class="hl-reserved">None
			
	</span><span class="hl-identifier">todo_parent</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">selection_parent</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-comment">#Get the Model
	</span><span class="hl-identifier">model</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_model</span><span class="hl-brackets">()
	</span><span class="hl-comment">#Get the current selection in the gtk.TreeView
	</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">model</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">selection</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-identifier">selection_parent</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">iter_parent</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_parent</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">todo_parent</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_parent</span><span class="hl-code">, </span><span class="hl-identifier">object_pos</span><span class="hl-brackets">)

	</span><span class="hl-reserved">return </span><span class="hl-identifier">todo_parent</span><span class="hl-default">, </span><span class="hl-identifier">selection_parent</span></pre></div></div>
<h2><a name="SavingAndLoadingWithcPickle">The Code: Saving and Loading with cPickle</a></h2>
<p>Now that we can add and remove categories, the next thing that we want to do is be able to save and load our data to and from files.  This code is very similar to the method used in my <a href="http://www.learningpython.com/2006/09/02/extending-our-pygtk-application/">Extending our PyGTK Application</a> so I will gloss over the repeated code and only explain the new stuff.</p>
<p>You probably remember the helper module mention above and used a little bit in some of the previously mentioned code.  It&#8217;s simply a helper module that I have started to use so that I don&#8217;t always have to recode the same functions.  The file&#8217;s name is &#8220;helper.py&#8221; and it looks like this:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">try</span><span class="hl-default">:
 	</span><span class="hl-reserved">import </span><span class="hl-identifier">pygtk
  	pygtk</span><span class="hl-default">.</span><span class="hl-identifier">require</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">2.0</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-reserved">except</span><span class="hl-default">:
  	</span><span class="hl-reserved">pass
try</span><span class="hl-default">:
	</span><span class="hl-reserved">import </span><span class="hl-identifier">os
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gtk
</span><span class="hl-reserved">except ImportError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
	</span><span class="hl-reserved">print </span><span class="hl-quotes">&quot;</span><span class="hl-string">Import error in helper:</span><span class="hl-quotes">&quot;</span><span class="hl-default">, </span><span class="hl-identifier">e
	sys</span><span class="hl-default">.</span><span class="hl-identifier">exit</span><span class="hl-brackets">(</span><span class="hl-number">1</span><span class="hl-brackets">)

</span><span class="hl-reserved">def </span><span class="hl-identifier">file_browse</span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">, </span><span class="hl-identifier">filters</span><span class="hl-code">, </span><span class="hl-identifier">file_extension</span><span class="hl-code">=</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-code">, </span><span class="hl-identifier">file_name</span><span class="hl-code">=</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to browse for a file.
	It can be either a save or open dialog depending on
	what dialog_action is.
	The path to the file will be returned if the user
	selects one, however a blank string will be returned
	if they cancel or do not select one.
	dialog_action - The open or save mode for the dialog either
	gtk.FILE_CHOOSER_ACTION_OPEN, gtk.FILE_CHOOSER_ACTION_SAVE
	@param filters - list - list of  gtk.FileFilter() objects
	that will be added to the dialog.
	@param file_extension - string - The file extension that will be
	added to the filename when saving
	@param file_name - Default name when doing a save
	@returns - File Name, or None on cancel.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_OPEN</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">dialog_buttons</span><span class="hl-default"> = </span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">STOCK_CANCEL</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_CANCEL</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">STOCK_OPEN</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)
		</span><span class="hl-identifier">dlg_title</span><span class="hl-default"> = </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Open File</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-reserved">else</span><span class="hl-default">:
		</span><span class="hl-identifier">dialog_buttons</span><span class="hl-default"> = </span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">STOCK_CANCEL</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_CANCEL</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">STOCK_SAVE</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)
		</span><span class="hl-identifier">dlg_title</span><span class="hl-default"> = </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Save File</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)

	</span><span class="hl-identifier">file_dialog</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">FileChooserDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">title</span><span class="hl-code">=</span><span class="hl-identifier">dlg_title</span><span class="hl-code">
		, </span><span class="hl-identifier">action</span><span class="hl-code">=</span><span class="hl-identifier">dialog_action</span><span class="hl-code">
		, </span><span class="hl-identifier">buttons</span><span class="hl-code">=</span><span class="hl-identifier">dialog_buttons</span><span class="hl-brackets">)
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">set the filename if we are saving</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_SAVE</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">set_current_name</span><span class="hl-brackets">(</span><span class="hl-identifier">file_name</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Add filters
	</span><span class="hl-reserved">for </span><span class="hl-identifier">filter </span><span class="hl-reserved">in </span><span class="hl-identifier">filters</span><span class="hl-default">:
		</span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">add_filter</span><span class="hl-brackets">(</span><span class="hl-identifier">filter</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_OPEN</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Create and add the 'all files' filter</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">filter</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">FileFilter</span><span class="hl-brackets">()
		</span><span class="hl-identifier">filter</span><span class="hl-default">.</span><span class="hl-identifier">set_name</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">All files</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
		</span><span class="hl-identifier">filter</span><span class="hl-default">.</span><span class="hl-identifier">add_pattern</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">*</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">add_filter</span><span class="hl-brackets">(</span><span class="hl-identifier">filter</span><span class="hl-brackets">)

	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Init the return value</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-reserved">None
	if </span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()</span><span class="hl-default"> == </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-default">:
		</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">get_filename</span><span class="hl-brackets">()
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_SAVE</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">result</span><span class="hl-default">, </span><span class="hl-identifier">extension</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">splitext</span><span class="hl-brackets">(</span><span class="hl-identifier">result</span><span class="hl-brackets">)
			</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-identifier">result</span><span class="hl-default"> + </span><span class="hl-quotes">&quot;</span><span class="hl-string">.</span><span class="hl-quotes">&quot;</span><span class="hl-default"> + </span><span class="hl-identifier">file_extension
	file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">destroy</span><span class="hl-brackets">()

	</span><span class="hl-reserved">return </span><span class="hl-identifier">result

</span><span class="hl-reserved">def </span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">error_string</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This Function is used to show an error dialog when
	an error occurs.
	error_string - The error string that will be displayed
	on the dialog.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">error_dlg</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">MessageDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">type</span><span class="hl-code">=</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">MESSAGE_ERROR</span><span class="hl-code">
				, </span><span class="hl-identifier">message_format</span><span class="hl-code">=</span><span class="hl-identifier">error_string</span><span class="hl-code">
				, </span><span class="hl-identifier">buttons</span><span class="hl-code">=</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">BUTTONS_OK</span><span class="hl-brackets">)
	</span><span class="hl-identifier">error_dlg</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()
	</span><span class="hl-identifier">error_dlg</span><span class="hl-default">.</span><span class="hl-identifier">destroy</span><span class="hl-brackets">()</span></pre></div></div>
<p>These are both old functions (changed slightly) so I won&#8217;t go over them.</p>
<p>The same is true for the File menu signal handers:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_file_new</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | New - Start a new project file, blank out
	the currnet project and start from scratch</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default"> = </span><span class="hl-brackets">[]
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">reload_from_data</span><span class="hl-brackets">()


</span><span class="hl-reserved">def </span><span class="hl-identifier">on_file_open</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Function called to open a todo file</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">file_browse</span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_OPEN</span><span class="hl-code">
		, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_browse_filter_list</span><span class="hl-brackets">()</span><span class="hl-code">
		, </span><span class="hl-identifier">FILE_EXT</span><span class="hl-brackets">)
	</span><span class="hl-comment">#If we have a file
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">load_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Allright it all worked! save the current file and
			set the title.</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">todo_file
			self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)

</span><span class="hl-reserved">def </span><span class="hl-identifier">on_file_save</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | Save function - Save the Todo file</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment"># Let the user browse for the save location and name
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">file_browse</span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_SAVE</span><span class="hl-code">
		, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_browse_filter_list</span><span class="hl-brackets">()</span><span class="hl-code">
		, </span><span class="hl-identifier">FILE_EXT</span><span class="hl-brackets">)
	</span><span class="hl-comment">#If we have a todo file
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">save_to_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-comment">#Allright it all worked! Set the Title
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)

</span><span class="hl-reserved">def </span><span class="hl-identifier">on_file_save_as</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | Save As function - Save the todo file</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Untitled</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">basename</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)

	</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">file_browse</span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_SAVE</span><span class="hl-code">
		, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_browse_filter_list</span><span class="hl-brackets">()</span><span class="hl-code">
		, </span><span class="hl-identifier">FILE_EXT</span><span class="hl-brackets">)
	</span><span class="hl-comment">#If we have a xml_file
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">save_to_file</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Allright it all worked! save the current file and
			set the title.</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">todo_file
			self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span></pre></div></div>
<p>They are all taken almost verbatim from previous tutorials so I won&#8217;t explaining them in detail.  The do rely on one helper function: get_browse_filter_list() that simply creates a list of gtk.FileFilters to use when browsing:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_browse_filter_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Used to get the list of gtk.FileFilter objects
	to use when browsing for a file.
	@returns - list - List of gtk.FileFilter objects
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">filter</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">FileFilter</span><span class="hl-brackets">()
	</span><span class="hl-identifier">filter</span><span class="hl-default">.</span><span class="hl-identifier">set_name</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Todo file</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
	</span><span class="hl-identifier">filter</span><span class="hl-default">.</span><span class="hl-identifier">add_pattern</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">*.</span><span class="hl-quotes">&quot;</span><span class="hl-code"> + </span><span class="hl-identifier">FILE_EXT</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-brackets">[</span><span class="hl-identifier">filter</span><span class="hl-brackets">]</span></pre></div></div>
<p>The actual work of saving and loading the data happens in the save_to_file(), load_from_file(), and reload_from_data() functions.  We&#8217;ll go over the save_to_file() function first:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">save_to_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">filename</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Save the current todoproject to a filename
		@param filename - string - the file name to save
		the file too.
		@returns boolean - success or failure
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-builtin">open</span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">w</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
			</span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">dump</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__categories</span><span class="hl-code">, </span><span class="hl-identifier">todo_file</span><span class="hl-code">, </span><span class="hl-identifier">cPickle</span><span class="hl-code">.</span><span class="hl-identifier">HIGHEST_PROTOCOL</span><span class="hl-brackets">)
			</span><span class="hl-identifier">todo_file</span><span class="hl-default">.</span><span class="hl-identifier">close</span><span class="hl-brackets">()
			</span><span class="hl-reserved">return True
		except </span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">PicklingError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error saving file: %s</span><span class="hl-special">\r\n</span><span class="hl-string">%s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">))
			</span><span class="hl-reserved">return False
		except</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error saving file: %s</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">filename</span><span class="hl-brackets">))
			</span><span class="hl-reserved">return False</span></pre></div></div>
<p>Besides the exception handling, the actual code in this function is very simple:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-builtin">open</span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">w</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">dump</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__categories</span><span class="hl-code">, </span><span class="hl-identifier">todo_file</span><span class="hl-code">, </span><span class="hl-identifier">cPickle</span><span class="hl-code">.</span><span class="hl-identifier">HIGHEST_PROTOCOL</span><span class="hl-brackets">)
</span><span class="hl-identifier">todo_file</span><span class="hl-default">.</span><span class="hl-identifier">close</span><span class="hl-brackets">()
</span><span class="hl-reserved">return True</span></pre></div></div>
<p>First we open the file for writing, then we use <a href="http://docs.python.org/lib/module-cPickle.html">cPickle</a> to dump our __categories tree into the file, and then we close the file.  That&#8217;s it. </p>
<p>Loading the data is equally as simple:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">load_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">filename</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Try to a todo project from a
	specific file.
	@param filename - string - the file name to load
	from
	@returns boolean - success or failure
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-reserved">try</span><span class="hl-default">:
		</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-builtin">open</span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">rb</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default"> = </span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">load</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)
		</span><span class="hl-identifier">todo_file</span><span class="hl-default">.</span><span class="hl-identifier">close</span><span class="hl-brackets">()
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">reload_from_data</span><span class="hl-brackets">()
		</span><span class="hl-reserved">return True
	except </span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">UnpicklingError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
		</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error opening file: %s</span><span class="hl-special">\r\n</span><span class="hl-string">%s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">))
		</span><span class="hl-reserved">return False
	except</span><span class="hl-default">:
		</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error opening file: %s</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">filename</span><span class="hl-brackets">))
		</span><span class="hl-reserved">return False</span></pre></div></div>
<p>First we open the file for reading and in binary mode (as instructed by the <a href="http://docs.python.org/lib/pickle-example.html">Pickle documentation</a>) and then we load the file into our self.__categories tree.  After that we close the files and reload the tree from self.__categories using the reload_from_data() function.</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">reload_from_data</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when we want to reset everything based
	on internal data.  Probably called when a file has
	been loaded.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTree</span><span class="hl-default">.</span><span class="hl-identifier">clear</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__categories</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">for </span><span class="hl-identifier">todo_ob </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default">:
			</span><span class="hl-identifier">todo_ob</span><span class="hl-default">.</span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todoTree</span><span class="hl-code">, </span><span class="hl-reserved">None</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)
	</span><span class="hl-reserved">else</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default"> = </span><span class="hl-brackets">[]</span></pre></div></div>
<p>reload_from_data simply clears the gtk.TreeStore using the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreestore.html#method-gtktreestore--clear">gtk.TreeStore.clear()</a> function.  Then it loops through all of the toplevel categories in self.__categories and adds each category to the tree by calling the add_to_tree() function.  If self.__categories is None for some reason (perhaps a bad file?) we simply reset it to a blank list.</p>
<p>If you remember the add_to_tree() function you&#8217;ll remember that it will also add all children of the category (and their children recursively) to the tree.</p>
<h2><a name="ConnectingOurMenuWithThegtkMenuToolButton">The Code: Connecting our menu with the gtk.MenuToolButton</a></h2>
<p>Well we&#8217;re almost done here, all we have to do is connect our gtk.MenuToolButton with the menu that we created way back in the GUI section.  Up until now you may have noticed that the arrow beside the Add button has been greyed out or disabled, this is because we have not attached a menu to the button yet using the <a href="http://www.pygtk.org/docs/pygtk/class-gtkmenutoolbutton.html#method-gtkmenutoolbutton--set-menu">gtk.MenuToolButton.set_menu()</a> function.  We will connect the menu to the button in a function called initialize_menus() that will be called in the __init__ function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Initialize the todo Tree
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">initialize_todo_tree</span><span class="hl-brackets">()
</span><span class="hl-comment">#initialize menus
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">initialize_menus</span><span class="hl-brackets">()</span></pre></div></div>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">initialize_menus</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called to initialize the menus</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">add_button</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnAdd</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#load the menu from the glade file
	</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">addMenu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#connect the menu with the signals
	</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Get the menu dialog widget
	</span><span class="hl-identifier">menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">addMenu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">add_button</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">menu</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-identifier">add_button</span><span class="hl-default">.</span><span class="hl-identifier">set_menu</span><span class="hl-brackets">(</span><span class="hl-identifier">menu</span><span class="hl-brackets">)</span></pre></div></div>
<p>The first thing that we do is get the our gtk.MenuToolButton &#8220;btnAdd&#8221; from the widget tree.  Then we get the widget tree that represents the &#8220;addMenu&#8221;.  We then auto connect that widget tree with ourselves (this connects the &#8220;Add Category&#8221; menu item with our on_add_category() function.  Then we get the actual <a href="http://www.pygtk.org/docs/pygtk/class-gtkmenu.html">gtk.Menu</a> from the menu&#8217;s widget tree.</p>
<p>If all of the widgets have been returned properly we then connect the two using the <a href="http://www.pygtk.org/docs/pygtk/class-gtkmenutoolbutton.html#method-gtkmenutoolbutton--set-menu">gtk.MenuToolButton.set_menu()</a> function.</p>
<p>Now when you run the application you will be able to use the menu to add categories!</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_06.png" alt="Python GTD pyGTK" border="0" /></p>
<h2><a name="Conclusion">Conclusion</a></h2>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_01.tar.gz">here</a>.</p>
<p>Whew!  That was a lot of code and a lot of text to get through.  Hopefully you were able to understand and follow along with all of it, and hopefully the next parts won&#8217;t be as long!  The only reason that this part was so long was that it had so much ground to cover and because so much of it had been covered before.  Future tutorials should cover smaller and more discrete tasks.</p>
<p>You will also notice that none of the translation files are included with the source, this was simply left out for now since there will be more text added in the future.  There are also some extra dialogs in the glade project that will be used in future tutorials, if you want you could start implementing them.</p>
<p>Of course you will probably never find yourself creating an application that is identical to this pyLan application, but the idea is that you may find yourself creating an application that is <i>similar</i> or that requires <i>similar elements</i>.  In those situations hopefully you will be able to re-use or re-factor that code found in this, and future, tutorials.</p>
<p>As always if you find any errors or have any questions feel free to leave a comment.  If however you have a general question about python or PyGTK I would appreciate it if you ask it in the <a href="http://www.learningpython.com/forums/">LearningPython</a> forums so that a possible solution to someone elses problem will not get buried in an unrelated area.</p>
<p>Time for a some food!</todocategory></todocolumn></selsine></p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/&title=PyLan a GTD todo application written in python and PyGTK - part one&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Creating a GUI using Python, WxWidgets, and wxPython</title>
		<link>http://www.learningpython.com/2007/01/29/creating-a-gui-using-python-wxwidgets-and-wxpython/</link>
		<comments>http://www.learningpython.com/2007/01/29/creating-a-gui-using-python-wxwidgets-and-wxpython/#comments</comments>
		<pubDate>Mon, 29 Jan 2007 14:25:53 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[gui]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[wxPython]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=54</guid>
		<description><![CDATA[
			
				
			
		
After putting off this tutorial for as long as I possibly could (I&#8217;m not sure why) I have finally decided to buckle down and learn how to use WxWidgets using the WxPython Python bindings.
Installing
Getting WxWidgets and WxPython installed on my Debian Linux computer was as simple as installing the python-wxgtk2.6 Debian package.  If you [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F01%2F29%2Fcreating-a-gui-using-python-wxwidgets-and-wxpython%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F01%2F29%2Fcreating-a-gui-using-python-wxwidgets-and-wxpython%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<p>After putting off this tutorial for as long as I possibly could (I&#8217;m not sure why) I have finally decided to buckle down and learn how to use <a href="http://www.wxwidgets.org/">WxWidgets</a> using the <a href="http://www.wxpython.org/">WxPython</a> Python bindings.</p>
<h2>Installing</h2>
<p>Getting WxWidgets and WxPython installed on my Debian Linux computer was as simple as installing the python-wxgtk2.6 Debian package.  If you have any problems installing wxPython on your computer I suggest that you follow the instructions in the wxPython <a href="http://wiki.wxpython.org/index.cgi/Frequently_Asked_Questions#head-d0fc93e98b44817371f049e77c983ab8eff716c8">FAQ</a>.  Or you can follow the Getting Started instructions on the <a href="http://wiki.wxpython.org/index.cgi/Getting_Started#head-76c76195679b0098d0d34e2d28e2e8c55a9e087f">wxPython wiki</a>.</p>
<h2>Setting up the Window</h2>
<p>Now that you have WxWidgets and WxPython installed it&#8217;s time to write a quick wxPython application.  Start up your favourite python editor and enter the following:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">import </span><span class="hl-identifier">wx

</span><span class="hl-reserved">if </span><span class="hl-identifier">__name__</span><span class="hl-default"> == </span><span class="hl-quotes">&quot;</span><span class="hl-string">__main__</span><span class="hl-quotes">&quot;</span><span class="hl-default">:
	</span><span class="hl-identifier">app</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">App</span><span class="hl-brackets">()
	</span><span class="hl-identifier">app</span><span class="hl-default">.</span><span class="hl-identifier">MainLoop</span><span class="hl-brackets">()</span></pre></div></div>
<p>Save the file as wxHello.py, or whatever you would like.  You can run the file if you want but you won&#8217;t actually see anything.  The first thing that you will notice is that we import wx, this will import wxPython into your program.</p>
<p>The next thing that we do is create a <a href="http://wxpython.wxcommunity.com/docs/api/wx.App-class.html">wx.App</a> and then call it&#8217;s MainLoop function, which starts the main GUI event loop.  Here is a description of the wx.App class from the wxPython documentation : </p>
<blockquote><p>The wx.App class represents the application and is used to:</p>
<ul>
<li>bootstrap the wxPython system and initialize the underlying gui toolkit</li>
<li>set and get application-wide properties</li>
<li>implement the windowing system main message or event loop, and to dispatch events to window instances</li>
<li>etc.</li>
</ul>
<p>Every application must have a wx.App instance, and all creation of UI objects should be delayed until after the wx.App object has been created in order to ensure that the gui platform and wxWidgets have been fully initialized.</p>
<p>Normally you would derive from this class and implement an OnInit method that creates a frame and then calls self.SetTopWindow(frame).</p></blockquote>
<p>Notice the last little instruction there:</p>
<blockquote><p>Normally you would derive from this class and implement an OnInit method that creates a frame and then calls self.SetTopWindow(frame).</p></blockquote>
<p>So that is our next step, derive a class from wx.App and override the OnInit member:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">import </span><span class="hl-identifier">wx

</span><span class="hl-reserved">class </span><span class="hl-identifier">wxHelloApp</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">App</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">The wx.App for the wxHello application</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">OnInit</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Override OnInit to create our Frame</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">frame</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">Frame</span><span class="hl-brackets">(</span><span class="hl-reserved">None</span><span class="hl-code">, </span><span class="hl-identifier">title</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">wxHello</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">frame</span><span class="hl-default">.</span><span class="hl-identifier">Show</span><span class="hl-brackets">()
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">SetTopWindow</span><span class="hl-brackets">(</span><span class="hl-identifier">frame</span><span class="hl-brackets">)
		</span><span class="hl-reserved">return True

if </span><span class="hl-identifier">__name__</span><span class="hl-default"> == </span><span class="hl-quotes">&quot;</span><span class="hl-string">__main__</span><span class="hl-quotes">&quot;</span><span class="hl-default">:
	</span><span class="hl-identifier">app</span><span class="hl-default"> = </span><span class="hl-identifier">wxHelloApp</span><span class="hl-brackets">()
	</span><span class="hl-identifier">app</span><span class="hl-default">.</span><span class="hl-identifier">MainLoop</span><span class="hl-brackets">()</span></pre></div></div>
<p>Now instead of creating a wx.App we create a wxHelloApp that is derived from a wx.App.  All that the wxHelloApp does is override the OnInit() function.  In that function it creates a <a href="http://wxpython.wxcommunity.com/docs/api/wx.Frame-class.html">wx.Frame</a> (from the wxWidget docs):</p>
<blockquote><p>A frame is a window whose size and position can (usually) be changed by the user. It usually has thick borders and a title bar, and can optionally contain a menu bar, toolbar and status bar. A frame can contain any window that is not a frame or dialog.</p></blockquote>
<p>When we create the frame we set its parent to be nothing, and it&#8217;s title to be &#8220;wxHello&#8221;.  If you run the wxHello.py file now you will be greeted by the following:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/wxHello_01/wxHello_01png" alt="Python wxPython" border="0" /></p>
<p><span id="more-54"></span><br />
It&#8217;s not much but it&#8217;s a start.  Now we are going to do the same thing to the wx.Frame class that we did to the wx.App class:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">import </span><span class="hl-identifier">wx

</span><span class="hl-reserved">class </span><span class="hl-identifier">wxHelloFrame</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">Frame</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is the frame for our application, it is derived from
	the wx.Frame element.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, *</span><span class="hl-identifier">args</span><span class="hl-code">, **</span><span class="hl-identifier">kwargs</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize, and let the user set any Frame settings</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">Frame</span><span class="hl-default">.</span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, *</span><span class="hl-identifier">args</span><span class="hl-code">, **</span><span class="hl-identifier">kwargs</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">create_controls</span><span class="hl-brackets">()

	</span><span class="hl-reserved">def </span><span class="hl-identifier">create_controls</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the controls on Window are to be created</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

class </span><span class="hl-identifier">wxHelloApp</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">App</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">The wx.App for the wxHello application</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">OnInit</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Override OnInit to create our Frame</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">frame</span><span class="hl-default"> = </span><span class="hl-identifier">wxHelloFrame</span><span class="hl-brackets">(</span><span class="hl-reserved">None</span><span class="hl-code">, </span><span class="hl-identifier">title</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">wxHello</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">frame</span><span class="hl-default">.</span><span class="hl-identifier">Show</span><span class="hl-brackets">()
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">SetTopWindow</span><span class="hl-brackets">(</span><span class="hl-identifier">frame</span><span class="hl-brackets">)

		</span><span class="hl-reserved">return True

if </span><span class="hl-identifier">__name__</span><span class="hl-default"> == </span><span class="hl-quotes">&quot;</span><span class="hl-string">__main__</span><span class="hl-quotes">&quot;</span><span class="hl-default">:
	</span><span class="hl-identifier">app</span><span class="hl-default"> = </span><span class="hl-identifier">wxHelloApp</span><span class="hl-brackets">()
	</span><span class="hl-identifier">app</span><span class="hl-default">.</span><span class="hl-identifier">MainLoop</span><span class="hl-brackets">()</span></pre></div></div>
<p>Now if you run this code the result will be identical to the previous run, the only difference is in the internal code.  Instead of creating a wx.Frame directly we create an instance of our wx.Frame derived class wxHelloFrame.  </p>
<p>wxHelloFrame does nothing except initialize its parent class and then call the create_controls() function which is where we will create our widgets in the future but for now does nothing.</p>
<h2>Adding the Widgets</h2>
<p>Now we are going to start adding the widgets to the frame in the create_controls() function.  Since we want our window to be resizeable (which they are in wxPython by default) we are going to use <a href="http://wxpython.wxcommunity.com/docs/api/wx.Sizer-class.html">wx.Sizer</a> objects so that our widgets also resize (from the WxPython docs):</p>
<blockquote><p>wx.Sizer is the abstract base class used for laying out subwindows in a window. You cannot use wx.Sizer directly; instead, you will have to use one of the sizer classes derived from it such as wx.BoxSizer, wx.StaticBoxSizer, wx.GridSizer, wx.FlexGridSizer and wx.GridBagSizer.</p>
<p>The concept implemented by sizers in wxWidgets is closely related to layout tools in other GUI toolkits, such as Java&#8217;s AWT, the GTK toolkit or the Qt toolkit. It is based upon the idea of the individual subwindows reporting their minimal required size and their ability to get stretched if the size of the parent window has changed. This will most often mean that the programmer does not set the original size of a dialog in the beginning, rather the dialog will assigned a sizer and this sizer will be queried about the recommended size. The sizer in turn will query its children, which can be normal windows or contorls, empty space or other sizers, so that a hierarchy of sizers can be constructed. Note that wxSizer does not derive from wxWindow and thus do not interfere with tab ordering and requires very little resources compared to a real window on screen.</p></blockquote>
<p>We are going to use <a href="http://wxpython.wxcommunity.com/docs/api/wx.BoxSizer-class.html">wx.BoxSizer</a> objects to lay out our widgets (from the wxPython docs):</p>
<blockquote><p>The basic idea behind a box sizer is that windows will most often be laid out in rather simple basic geometry, typically in a row or a column or nested hierarchies of either. A wx.BoxSizer will lay out its items in a simple row or column, depending on the orientation parameter passed to the constructor.</p>
<p>It is the unique feature of a box sizer, that it can grow in both directions (height and width) but can distribute its growth in the main direction (horizontal for a row) unevenly among its children. This is determined by the proportion parameter give to items when they are added to the sizer. It is interpreted as a weight factor, i.e. it can be zero, indicating that the window may not be resized at all, or above zero. If several windows have a value above zero, the value is interpreted relative to the sum of all weight factors of the sizer, so when adding two windows with a value of 1, they will both get resized equally and each will receive half of the available space after the fixed size items have been sized. If the items have unequal proportion settings then they will receive a coresondingly unequal allotment of the free space.</p></blockquote>
<p>Whew, that&#8217;s a lot of documentation, fortunately wx.Sizer&#8217;s aren&#8217;t that difficult to use.  So first we need to create a horizontal wx.BoxSizer (so that our widgets will resize horizontally) and then add <a href="http://wxpython.wxcommunity.com/docs/api/wx.StaticText-class.html">wx.StaticText</a> and <a href="http://wxpython.wxcommunity.com/docs/api/wx.TextCtrl-class.html">wx.TextCtrl</a> widgets to the sizer.  After that we simply need to set  the wx.boxSizer as the frame&#8217;s sizer and we are done.</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">create_controls</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the controls on Window are to be created</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment"># Horizontal sizer
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">BoxSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">HORIZONTAL</span><span class="hl-brackets">)

	</span><span class="hl-comment"># Create the static text widget and set the text
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">StaticText</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">label</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Enter some text:</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Create the Edit Field (or TextCtrl)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">TextCtrl</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">size</span><span class="hl-code">=</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">Size</span><span class="hl-brackets">(</span><span class="hl-number">250</span><span class="hl-code">, -</span><span class="hl-number">1</span><span class="hl-brackets">))

	</span><span class="hl-comment">#Add to horizontal sizer
	#add the static text to the sizer, tell it not to resize
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">text</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">,</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Add 5 pixels between the static text and the edit
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">AddSpacer</span><span class="hl-brackets">((</span><span class="hl-number">5</span><span class="hl-code">,</span><span class="hl-number">0</span><span class="hl-brackets">))
	</span><span class="hl-comment">#Add Edit
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">edit</span><span class="hl-code">, </span><span class="hl-number">1</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Set the sizer
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">SetSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">h_sizer</span><span class="hl-brackets">)</span></pre></div></div>
<p>So, as you can see creating the wx.BoxSize and the wx.StaticText widgets is pretty straightforward.  When we create the wx.TextCtrl widget you&#8217;ll notice that we are setting the default size of the widget using a <a href="http://wxpython.wxcommunity.com/docs/api/wx.Size-class.html">wx.Size</a> object.  We are setting the default width to be 250 and the default height to be -1.  When you use -1 as the value for a parameter in wxWidgets it generally means that that parameter should be ignored.  So since we don&#8217;t want to set the height of the edit field, we want wxWidgets to do that for us automatically, we set the height to be -1.</p>
<p>You&#8217;ll also notice that the first parameter when we created the wx.StaticText and wx.TextCtrl widgets is self, or our wxHelloFrame.  This means that the wxHelloFrame will be the parent window of the widgets.</p>
<p>We then add the two widgets to the wx.BoxSizer using the <a href="http://wxpython.wxcommunity.com/docs/api/wx.Sizer-class.html#Add">wx.Sizer.Add</a> function. When we add the wx.Statictext we set the resize proportion to be 0 since we don&#8217;t want it to resize, and when we add the wx.TextCtrl we set its resize proportion to be 1, since we want it to resize directly with the window as it resizes. </p>
<p>You&#8217;ll also notice that we add a spacer in in between the wx.StaticText and wx.TextCtrl widgets using the <a href="http://wxpython.wxcommunity.com/docs/api/wx.Sizer-class.html#AddSpacer">wx.Sizer.AddSpacer()</a> function.  We do this to add a 5 pixel horizontal buffer between the two widgets just so that things look nicer.</p>
<p>Finally we set the wxHelloFrame&#8217;s sizer to be the horizontal sizer and we are done.  If you run this code you will see the following:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/wxHello_01/wxHello_02.png" alt="Python wxPython" border="0" /></p>
<p>So that&#8217;s pretty neat, you have a window with some widgets that resize.  The next thing that we are going to do is add a <a href="http://wxpython.wxcommunity.com/docs/api/wx.Button-class.html">wx.Button</a> underneath the wx.StaticText widget.  </p>
<p>To do this we will need to use another wx.BoxSizer, this one being a vertical sizer.  Then we will add our horizontal wx.BoxSizer to the vertical sizer and then add the button.  This will place the contents of the horizontal box sizer over top of the button.</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">create_controls</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the controls on Window are to be created</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Horizontal sizer
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">BoxSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">HORIZONTAL</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Vertical sizer
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">BoxSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">VERTICAL</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Widget Creation
	#Create the static text widget and set the text
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">StaticText</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">label</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Enter some text:</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Create the Edit Field (or TextCtrl)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">TextCtrl</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">size</span><span class="hl-code">=</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">Size</span><span class="hl-brackets">(</span><span class="hl-number">250</span><span class="hl-code">, -</span><span class="hl-number">1</span><span class="hl-brackets">))
	</span><span class="hl-comment">#Create the button
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">button</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">Button</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">label</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Press me!</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Add to horizontal sizer
	#add the static text to the sizer, tell it not to resize
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">text</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">,</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Add 5 pixels between the static text and the edit
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">AddSpacer</span><span class="hl-brackets">((</span><span class="hl-number">5</span><span class="hl-code">,</span><span class="hl-number">0</span><span class="hl-brackets">))
	</span><span class="hl-comment">#Add Edit
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">edit</span><span class="hl-code">, </span><span class="hl-number">1</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Add to the vertical sizer to create two rows
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">h_sizer</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">EXPAND</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Add button underneath
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">button</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Set the sizer
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">SetSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">v_sizer</span><span class="hl-brackets">)</span></pre></div></div>
<p>So now we create both a horizontal and vertical wx.BoxSizer and a wx.Button widget with specific label text.  We then add the horizontal size to the vertical sizer, and then we add the button creating two rows of widgets.  We set the resize proportion of both the button and the horizontal sizer to be 0 since we don&#8217;t want them resizing vertically.  However we set the horizontal sizer&#8217;s flag to be wx.EXPAND which means:</p>
<blockquote><p>
The item will be expanded to fill the space allotted to the item.</p></blockquote>
<p>We do this so that the horizontal sizer will continue to resize horizontally.  Finally we set the sizer of the wxHelloFrame to be the vertical sizer.  If you run the code you will see the following:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/wxHello_01/wxHello_03.png" alt="Python wxPython" border="0" /></p>
<p>One thing that you will notice when you run the program is that the window starts off too big for the widgets and you can resize the window smaller then the size of the widgets.  This isn&#8217;t very nice so we need to add in some code to set the initial size of the window and to set the minimum size of the window.  </p>
<p>The other thing that we need to do is do something when the button is clicked.  We will make it so that when the button is clicked a message box comes up displaying whatever text was typed in the wx.TextCtrl.</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">create_controls</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the controls on Window are to be created</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Horizontal sizer
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">BoxSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">HORIZONTAL</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Vertical sizer
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">BoxSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">VERTICAL</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Widget Creation
	#Create the static text widget and set the text
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">StaticText</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">label</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Enter some text:</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Create the Edit Field (or TextCtrl)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">TextCtrl</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">size</span><span class="hl-code">=</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">Size</span><span class="hl-brackets">(</span><span class="hl-number">250</span><span class="hl-code">, -</span><span class="hl-number">1</span><span class="hl-brackets">))
	</span><span class="hl-comment">#Create the button
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">button</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">Button</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">label</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Press me!</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#bind the button click to our press function
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">button</span><span class="hl-default">.</span><span class="hl-identifier">Bind</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">EVT_BUTTON</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_button_pressed</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Add to horizontal sizer
	#add the static text to the sizer, tell it not to resize
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">text</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">,</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Add 5 pixels between the static text and the edit
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">AddSpacer</span><span class="hl-brackets">((</span><span class="hl-number">5</span><span class="hl-code">,</span><span class="hl-number">0</span><span class="hl-brackets">))
	</span><span class="hl-comment">#Add Edit
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">edit</span><span class="hl-code">, </span><span class="hl-number">1</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Add to the vertical sizer to create two rows
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">h_sizer</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">EXPAND</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Add button underneath
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">button</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Set the sizer
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">SetSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">v_sizer</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Fit ourselves to the sizer
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Fit</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Set the Minumum size
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">SetMinSize</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">v_sizer</span><span class="hl-code">.</span><span class="hl-identifier">GetMinSize</span><span class="hl-brackets">())
	
</span><span class="hl-reserved">def </span><span class="hl-identifier">on_button_pressed</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the button is clicked.  It will
	show a simple dialog with the text from the
	edit field.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the message text
	</span><span class="hl-identifier">message_text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">You typed: %s</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">edit</span><span class="hl-code">.</span><span class="hl-identifier">GetValue</span><span class="hl-brackets">())
	</span><span class="hl-identifier">msg_box</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">MessageDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">
		, </span><span class="hl-identifier">message_text</span><span class="hl-code">
		, </span><span class="hl-quotes">&quot;</span><span class="hl-string">Hello!</span><span class="hl-quotes">&quot;</span><span class="hl-code">
		, </span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">OK</span><span class="hl-code"> | </span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">CENTRE</span><span class="hl-code"> | </span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">ICON_EXCLAMATION</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Show the Dialog
	</span><span class="hl-identifier">msg_box</span><span class="hl-default">.</span><span class="hl-identifier">ShowModal</span><span class="hl-brackets">()</span></pre></div></div>
<p>Binding the wx.Button to our function is pretty simple:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#bind the button click to our press function
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">button</span><span class="hl-default">.</span><span class="hl-identifier">Bind</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">EVT_BUTTON</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_button_pressed</span><span class="hl-brackets">)</span></pre></div></div>
<p>We simply call the <a href="http://wxpython.wxcommunity.com/docs/api/wx.EvtHandler-class.html#Bind">wx.Button.Bind()</a> function, bind it to the wx.EVT_BUTTON event, and tell it what function of ours to call when the button is pressed.</p>
<p>Then to initially size the window and set its minimum size we do the following:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Fit ourselves to the sizer
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Fit</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
</span><span class="hl-comment">#Set the Minumum size
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">SetMinSize</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">v_sizer</span><span class="hl-code">.</span><span class="hl-identifier">GetMinSize</span><span class="hl-brackets">())</span></pre></div></div>
<p>To size the frame to the sizer we call the <a href="http://wxpython.wxcommunity.com/docs/api/wx.Sizer-class.html#Fit">wx.Sizer.Fit()</a> function.  We then set the minimum size of the frame using the <a href="http://wxpython.wxcommunity.com/docs/api/wx.Window-class.html#SetMinSize">wx.Frame.SetMinSize()</a> function to the minimum size of the vertical sizer which we get using the <a href="http://www.learningpython.com/wp-admin/post.php?action=edit&#038;post=54">ws.Sizer.GetWinSize()</a> function.</p>
<p>Next we handle the button&#8217;s press event using the following function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_button_pressed</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the button is clicked.  It will
	show a simple dialog with the text from the
	edit field.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the message text
	</span><span class="hl-identifier">message_text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">You typed: %s</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">edit</span><span class="hl-code">.</span><span class="hl-identifier">GetValue</span><span class="hl-brackets">())
	</span><span class="hl-identifier">msg_box</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">MessageDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">
		, </span><span class="hl-identifier">message_text</span><span class="hl-code">
		, </span><span class="hl-quotes">&quot;</span><span class="hl-string">Hello!</span><span class="hl-quotes">&quot;</span><span class="hl-code">
		, </span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">OK</span><span class="hl-code"> | </span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">CENTRE</span><span class="hl-code"> | </span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">ICON_EXCLAMATION</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Show the Dialog
	</span><span class="hl-identifier">msg_box</span><span class="hl-default">.</span><span class="hl-identifier">ShowModal</span><span class="hl-brackets">()</span></pre></div></div>
<p>This function is pretty straight forward, first we get the text from the wx.TextCtrl widget using the wx.TextCtrl.GetValue() function.  Then we create  a <a href="http://wxpython.wxcommunity.com/docs/api/wx.MessageDialog-class.html">wx.MessageDialog</a> instance.  The wx.MessageDialog is &#8220;a simple dialog that shows a single or multi-line message, with a choice of OK, Yes, No and/or Cancel buttons.&#8221;  We set the parent, title, text of the dialog and use the following flags to control how it looks and functions:</p>
<ul>
<li>wx.OK &#8211; Show an OK button.</li>
<li>wx.ICON_EXCLAMATION &#8211; Shows an exclamation mark icon.</li>
<li>wx.CENTER &#8211; Is supposed to center the dialog on it&#8217;s parent.</li>
</ul>
<p>Then we show the dialog using the wx.Dialog.ShowModal() function.</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/wxHello_01/wxHello_04.png" alt="Python wxPython" border="0" /></p>
<p>Here is the all the code:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">import </span><span class="hl-identifier">wx

</span><span class="hl-reserved">class </span><span class="hl-identifier">wxHelloFrame</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">Frame</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is the frame for our application, it is derived from
	the wx.Frame element.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, *</span><span class="hl-identifier">args</span><span class="hl-code">, **</span><span class="hl-identifier">kwargs</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize, and let the user set any Frame settings</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">Frame</span><span class="hl-default">.</span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, *</span><span class="hl-identifier">args</span><span class="hl-code">, **</span><span class="hl-identifier">kwargs</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">create_controls</span><span class="hl-brackets">()

	</span><span class="hl-reserved">def </span><span class="hl-identifier">create_controls</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the controls on Window are to be created</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-comment">#Horizontal sizer
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">BoxSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">HORIZONTAL</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Vertical sizer
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">BoxSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">VERTICAL</span><span class="hl-brackets">)

		</span><span class="hl-comment">#Widget Creation
		#Create the static text widget and set the text
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">text</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">StaticText</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">label</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Enter some text:</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Create the Edit Field (or TextCtrl)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">TextCtrl</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">size</span><span class="hl-code">=</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">Size</span><span class="hl-brackets">(</span><span class="hl-number">250</span><span class="hl-code">, -</span><span class="hl-number">1</span><span class="hl-brackets">))
		</span><span class="hl-comment">#Create the button
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">button</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">Button</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">label</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">Press me!</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#bind the button click to our press function
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">button</span><span class="hl-default">.</span><span class="hl-identifier">Bind</span><span class="hl-brackets">(</span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">EVT_BUTTON</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_button_pressed</span><span class="hl-brackets">)

		</span><span class="hl-comment">#Add to horizontal sizer
		#add the static text to the sizer, tell it not to resize
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">text</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">,</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Add 5 pixels between the static text and the edit
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">AddSpacer</span><span class="hl-brackets">((</span><span class="hl-number">5</span><span class="hl-code">,</span><span class="hl-number">0</span><span class="hl-brackets">))
		</span><span class="hl-comment">#Add Edit
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">h_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">edit</span><span class="hl-code">, </span><span class="hl-number">1</span><span class="hl-brackets">)

		</span><span class="hl-comment">#Add to the vertical sizer to create two rows
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">h_sizer</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-code">, </span><span class="hl-identifier">wx</span><span class="hl-code">.</span><span class="hl-identifier">EXPAND</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Add button underneath
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">button</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-brackets">)

		</span><span class="hl-comment">#Set the sizer
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">SetSizer</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">v_sizer</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Fit ourselves to the sizer
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">v_sizer</span><span class="hl-default">.</span><span class="hl-identifier">Fit</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Set the Minumum size
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">SetMinSize</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">v_sizer</span><span class="hl-code">.</span><span class="hl-identifier">GetMinSize</span><span class="hl-brackets">())

	</span><span class="hl-reserved">def </span><span class="hl-identifier">on_button_pressed</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the button is clicked.  It will
		show a simple dialog with the text from the
		edit feld.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-comment">#Get the message text
		</span><span class="hl-identifier">message_text</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">You typed: %s</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">edit</span><span class="hl-code">.</span><span class="hl-identifier">GetValue</span><span class="hl-brackets">())
		</span><span class="hl-identifier">msg_box</span><span class="hl-default"> = </span><span class="hl-identifier">wx</span><span class="hl-default">.</span><span class="hl-identifier">MessageDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">
			, </span><span class="hl-identifier">message_text</span><span class="hl-code">
			, </span><span class="hl-quotes">&quot;</span><span class="hl-string">Hello!</spa