<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<h1>D�velopper des Applications Gnome avec Python (Partie 3)</h1>

<h4>ArticleCategory:</h4>

Software Development 

<h4>AuthorImage:</h4>

<img src="../../common/images/article266/HilaireFernandes.png" width=124 height=172 alt="Hilaire Fernandes">

<H4>TranslationInfo:[Author + translation history. mailto: or
    http://homepage]</H4>

<p>original in fr <a href="mailto:hilaire(at)ofset.org">Hilaire
Fernandes</a></p> 

<h4>AboutTheAuthor</h4>

<p>Hilaire Fernandes est le vice-pr�sident d'<a
href="http://www.ofset.org">OFSET</a>, une organisation pour
promouvoir le d�veloppement de logiciels �ducatifs libres pour le
bureau Gnome. Il a aussi �crit Dr.&nbsp;Geo, un logiciel prim� de
g�om�trie dynamique, et il est actuellement occup� avec
Dr.&nbsp;Genius un autre logiciel �ducatif de math�matiques pour le
bureau Gnome.</p>

<h4>Abstract:</h4>

<p>Cette s�rie d'articles est sp�cialement �crite pour des d�butants
en programmation sous Gnome et GNU/Linux. Le langage de d�veloppement
choisi, Python, �vite la surcharge habituelle avec des langages
compil�s comme le C. Avant d'�tudier cet article quelques notions de
programmation sous Python sont n�cessaires. Plus d'informations sur
Python et Gnome sont disponbibles aux adresses <a
href="http://www.python.org">http://www.python.org</a> et <a
href="http://www.gnome.org">http://www.gnome.org</a>.</p>
<p>
Articles pr�c�dents dans la s�rie :<br>
<A href="../July2000/article160.shtml">premier article</A><br>
<A href="../January2002/article224.shtml">second article</A>
<h4>ArticleIllustration:</h4>

<img src="../../common/images/article266/gnome.png" width=48 height=48 alt="Gnome" hspace="10"> 

<h4>ArticleBody:</h4>

<h2>Needed tools</h2>

<p>Pour les besoins logiciels � l'ex�cution du programme d�crit dans
cet article, vous pouvez vous r�f�rer � la liste de la m�me rubrique
de la partie I de cette s�rie d'articles.


<p>Aussi vous aurez besoin&nbsp;:</p>
<ul>
  <li>Du fichier .glade original [&nbsp;<a
href="../../common/src/article266/drill.glade.txt">drill.glade</a>&nbsp;]&nbsp;. Ce
fichier a �t� l�g�rement modifi� depuis la derni�re fois pour
incorporer des ascenseurs dans la zone exercice de l'interface. </li>


  <li>Du code source en Python. Il est cette fois-ci �clat� en trois
fichiers&nbsp;:
      <ol>
	<li>[&nbsp;<a href="../../common/src/article266/drill1.py.txt">drill1.py</a>&nbsp;].</li>
	<li>[&nbsp;<a href="../../common/src/article266/templateExercice.py.txt">templateExercice.py</a>&nbsp;].</li>
	<li>[&nbsp;<a href="../../common/src/article266/colorExercice.py.txt">colorExercice.py</a>&nbsp;].</li>
	<li>[&nbsp;<a href="../../common/src/article266/labelExercice.py.txt">labelExercice.py</a>&nbsp;].</li>	   
      </ol>
</ul>

<p>Pour l'installation et l'utilisation de Python-Gnome et LibGlade
vous pouvez aussi vous r�f�rer � la partie&nbsp;I.</p>

<br clear=all>

<h2>Mod�le de d�veloppement des exercices</h2>

<p>Lors de la derni�re partie nous avions mis en place l'interface
utilisateur -- <strong>Drill</strong> -- devant servir de cadre pour
le d�ploiement d'exercices. Cette fois-ci, nous allons nous int�resser
de plus pr�s au mod�le de d�veloppement interne des exercices devant
s'ins�rer dans <strong>Drill</strong>. Ce sera l'occasion d'explorer
plus en d�tail les possibilit�s de d�veloppement orient� objet du
langage Python. Pour l'essentiel, cette partie traitera donc plus de
d�veloppement Python pur que de d�veloppement Gnome en Python.</p>


<p>La derni�re fois, j'avais laiss� un exercice pratique en suspens. �
savoir la transformation du petit jeu de couleur, r�alis� lors de la
premi�re partie de cette s�rie d'articles, en un exercice � ins�rer
dans <strong>Drill</strong>. Nous nous servirons de cet exemple pour
illustrer notre expos� et, par la m�me occasion, nous donnerons une
solution � cette exercice.</p>

<h3>Le d�veloppement orient� objet</h3>

<p>En quelques mots et sans pr�tention d'�tre exhaustif, le
d�veloppement objet s'attache � caract�riser et cat�goriser -- en
g�n�ral -- par des relations du type <strong>est-une-sorte-de</strong>
des objets du monde r�el ou non. Cela peut �tre per�u comme une
conceptualisation de ces objets par rapport � une probl�matique �
laquelle nous nous int�ressons. Nous pouvons les comparer dans
d'autres domaines, aux cat�gories d'Aristote, aux taxinomies ou
ontologies.  Dans tout ces cas il s'agit bien d'appr�hender, par une
r�duction conceptuelle, une situation complexe.  Ce mod�le de
d�veloppement aurait aussi bien pu s'appeler d�veloppement orient�
cat�gorie.</p>

<p>Dans ce mod�le de d�veloppement, les objets manipul�s par le
programme, ou constituant le programme, sont appel�s des
<strong>classes</strong> et des repr�sentants de ces objets
conceptuels des <strong>instances</strong>. Les objets sont
caract�ris�s par des <strong>attributs</strong> (des valeurs en
g�n�ral) et des <strong>m�thodes</strong>. Les objets peuvent ne pas
�tre totalement caract�ris�s, dans ce cas nous parlons de classes
abstraites, c'est par exemple le cas lorsqu'une m�thode est d�clar�e
mais non d�finie (nous parlons de m�thode virtuelle pure, le corps de
la m�thode est vide). Pour cr�er une instance d'une classe, celle-ci
ne doit pas �tre abstraite. Les classes abstraites permettent de
sp�cifier la forme prise par les classes h�riti�res. Classes dans
lesquelles les m�thodes virtuelles seront d�finies.  Les classes sont
rang�es entre elles par une relation du type
<strong>est-une-sorte-de</strong>, dite relation d'h�ritage, nous
parlons dans ce cas de classe(s) parente(s) d'une classe donn�e.</p>

<p>Selon les langages, il existe une plus o� moins grande finesse dans
la caract�risation des objets. Cependant le plus petit d�nominateur
commun semble �tre celui-ci&nbsp;:

<ol>
  <li>H�ritage des attributs et des m�thodes de la classe parente par
la classe h�riti�re.</li>

  <li>Dans une classe h�riti�re, possibilit� de surcharger les
m�thodes h�rit�es de la classe parente (i.e. red�finir une m�thode
h�rit�e).</li>

  <li>Polymorphisme, une classe donn�e peut avoir plusieurs classes
parentes. </li>
</ol> </p>

<h3>Python et le d�veloppement orient� objet</h3>

<p>En ce qui concerne Python, c'est ce plus petit d�nominateur commun
qui a �t� choisi. Cela permet de s'initier au d�veloppement objet sans
se perdre dans les d�tails de ce type de d�veloppement.</p>

<p>En Python, les m�thodes d'un objet sont toujours virtuelles. Cela
signifie qu'elles peuvent toujours �tre surcharg�es par une classe
h�riti�re -- ce que nous souhaitons faire en g�n�ral en d�veloppement
objet -- cela simplifie l�g�rement la syntaxe mais ne permet pas de
distinguer rapidement ce qui est effectivement surcharg� de ce qui ne
l'est pas. Ensuite il n'est pas possible de rendre obscur un objet,
c'est � dire rendre impossible l'acc�s � des attributs ou m�thodes
depuis l'ext�rieur de l'objet. Les attributs d'un objet Python sont
accessibles aussi bien en lecture qu'en �criture depuis l'ext�rieur de
l'objet.</p>

<h3>La classe parente <tt>exercice</tt></h3>

<p>Dans notre exemple (voir le fichier <tt>templateExercice.py</tt> ,
nous souhaitons caract�riser des objets de type exercice. Nous
d�finissons donc naturellement un objet de type <tt>exercice</tt>. Cet
objet sert de base conceptuel aux autres types d'exercices
 que nous cr�erons par la suite. L'objet <tt>exemple</tt> est la
classe parente de tous les autres types d'exercices cr��s. Ces types
d'exercices auront ainsi au minimum les m�mes attributs et m�thodes
que la classe <tt>exercice</tt>. Ce minimum commun nous permettra de
manipuler identiquement toutes les instances d'exercices, m�me dans
leur plus grande diversit�, quelque soit l'objet dont ils sont une
instance.</p>

<p>Par exemple, pour cr�er une instance de la classe <tt>exercice</tt>
nous pourrions �crire&nbsp;:

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
from templateExercice import exercice

monExercice = exercice ()
monExercice.activate (ceWidget)
</pre></td></tr></table>

<p>En fait il n'y a pas d'int�r�t � cr�er des instance de la classe
<tt>exercice</tt> car elle n'est qu'un mod�le � partir duquel
d'autre classes sont d�riv�es.</p>


<p><b>Les attributs</b></p>

<ul>
  <li><tt>exerciceWidget</tt> : le widget contenant l'interface
      utilisateur de l'exercice&nbsp;;</li>
  <li><tt>exerciceName</tt> : le nom de l'exercice.</li>
</ul>

<p>Si nous devions nous int�resser � d'autres aspects d'un exercice
nous pourrions lui ajouter des attributs. Je pense par exemple au
score sur un exercice, au nombre de fois qu'il a �t� fait, etc.</p>

<p><b>Les m�thodes</b></p>
<ul>
  <li><tt>__init__ (self)</tt>: cette m�thode a un r�le tr�s pr�cis
dans un objet Python. Celle-ci est automatiquement appel�e lors de la
cr�ation d'une instance de cet objet. Pour cette raison elle est aussi
nomm�e constructeur. L'argument <tt>self</tt> est une r�f�rence de
l'instance de la classe <tt>exercice</tt> d'o� est appel�e la m�thode
<tt>__init__</tt>. Il est toujours n�cessaire dans des m�thodes de
sp�cifier cet argument, cela veut donc dire qu'une m�thode ne peut
avoir z�ro argument. Attention cet argument est aliment�
automatiquement par Python, il n'est donc pas n�cessaire de le placer
lors de l'appel d'une m�thode. L'argument <tt>self</tt> permet
d'acc�der aux attributs et autres m�thodes d'une instance. Sans lui il
est impossible d'y avoir acc�s. Nous verrons cela plus en d�tail par
la suite.</li>
  <li><tt>activate (self, area)</tt> : active l'exercice -- repr�sent�
par l'instance d'o� est appel�e cette m�thode -- en pla�ant son widget
dans la zone exercice de <strong>Drill</strong>. L'argument
<tt>area</tt> est en fait cet emplacement dans <strong>Drill</strong>,
c'est un container GTK+. Sachant que l'attribut
<tt>exerciceWidget</tt> contient le widget de l'exercice, il suffit de
l'appel <tt>area.add (self.exerciceWidget)</tt> pour empaqueter
l'exercice dans <strong>Drill</strong>.</li>
  <li><tt>unactivate (self, area)</tt> : enl�ve le widget de
l'exercice du container de <strong>Drill</strong>. Ici en terme de
mise en paquet, c'est l'op�ration contraire, donc un <tt>area.remove
(self.exerciceWidget)</tt> suffit.</li>
  <li><tt>reset (self)</tt> : remet � z�ro l'exercice.</li>
</ul>

<p>En terme de code Python cela donne la chose suivante&nbsp;:

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
class exercice:
    "A template exercice"
    exerciceWidget = None
    exerciceName = "No Name"
    def __init__ (self):
        "Create the exericice widget"
    def activate (self, area):
        "Set the exercice on the area container"
        area.add (self.exerciceWidget)
    def unactivate (self, area):
        "Remove the exercice fromt the container"
        area.remove (self.exerciceWidget)
    def reset (self):
        "Reset the exercice"
</pre>
</td>
</tr>
</table>

<p> Ce code est inclus dans son propre fichier
<tt>templateFichier.py</tt>, cela nous permet de clarifier les r�les
sp�cifiques de chaque objet. Les m�thodes sont d�clar�es � l'int�rieur
de la classe <tt>exercice</tt>, ce sont en fait des fonctions.</p>

<p>� propos de l'argument <tt>area</tt>, nous verrons par la suite que
c'est une r�f�rence d'un widget GTK+ construit par LibGlade, c'est une
fen�tre avec ascenseurs.</p>

<p>Dans cet objet, les m�thodes <tt>__init__</tt> et <tt>reset</tt>
sont vides, elle seront surcharg�es par des classes h�riti�res si
n�cessaire.</p>


<h3><tt>labelExercice</tt>, premier exemple d'h�ritage</h3>

<p>Cet exercice est presque un exercice vide. Il ne fait qu'une
chose&nbsp;: afficher le nom de l'exercice dans la zone exercice de
<strong>Drill</strong>. Il nous sert de pis-aller pour les exercices
qui peuplent l'arbre de gauche de <strong>Drill</strong> mais qui ne
sont pas encore cr��s.</p>

<p>Comme pour l'objet <tt>exercice</tt>, l'objet
<tt>labelExercice</tt> est plac� dans son propre fichier,
<tt>labelExercice.py</tt>. Ensuite, �tant donn� que cet objet est un
h�ritier de l'objet <tt>exercice</tt>, nous avons besoin de lui
indiquer les d�finitions de ce dernier. Cela ce fait simplement par
une importation&nbsp;:</p>

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
from templateExercice import exercice
</pre>
</td>
</tr>
</table>

<p>Cela signifie litt�ralement que la d�finition de la classe
<tt>exercice</tt> qui est dans le fichier <tt>templateExercice.py</tt>
est import�e dans le code courant.</p>

<p>Nous arrivons maintenant � l'aspect le plus important, la
d�claration de la classe <tt>labelExercice</tt> en tant que classe
h�riti�re de <tt>exercice</tt>. Lors de la d�claration de
<tt>labelExercice</tt>, cela se fait de la fa�on suivante&nbsp;:</p>

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
class labelExercice(exercice):
</pre>
</td>
</tr>
</table>

<p>Voil�, cela suffit pour que <tt>labelExercice</tt> h�rite de tous
les attributs et toutes les m�thodes de <tt>exercice</tt>.</p>

<p>Bien s�r il nous reste du travail � faire, en particulier
initialiser le widget de l'exercice. Nous le faisons en surchargeant
la m�thode <tt>__init__</tt> (i.e. en la red�finissant dans la classe
<tt>labelExercice</tt>), celle-ci est appel�e lorsqu'une instance est
cr��e. Aussi ce widget devra �tre r�f�renc� dans l'attribut
<tt>exerciceWidget</tt>, de cette fa�on nous n'aurons pas besoin de
surcharger les m�thodes <tt>activate</tt> et <tt>unactivate</tt> de
la classe <tt>exercice</tt>.</p>

<table width="100%" bgcolor="#f4ee9c"
border="0"> <tr> <td> <pre>
    def __init__ (self, name):
        self.exerciceName = "Un exercice vide"
        self.exerciceWidget = GtkLabel (name)
        self.exerciceWidget.show ()</pre>
</td>
</tr>
</table>

<p>C'est la seule m�thode que nous surchargeons. Pour cr�er une
instance de <tt>labelExercice</tt> il suffit de faire l'appel&nbsp;:</p>

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
monExercice = labelExercice ("Un exercice qui ne fait rien")
</pre>
</td>
</tr>
</table>

<p>Pour acc�der � ses attributs ou ses m�thodes&nbsp;:</p>

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
# Le nom de l'exercice
print monExercice.exerciceName

# Placer le widget de l'exercice dans le container "area"    
monExerice.activate (area)
</pre>
</td>
</tr>
</table>

<h3><tt>colorExercice</tt>, deuxi�me exemple d'h�ritage</h3>

<p>Ici nous abordons la transformation du jeu de couleur, vu dans le
premier article de cette s�rie, en une classe de type <tt>exercice</tt>,
plus pr�cis�ment nous nommons cette classe <tt>colorExercice</tt>, il est
plac� dans son propre fichier <tt>colorExercice.py</tt> dont le code
source complet est en annexe de cet article.</p>

<p>Par rapport au code source initial, il s'agit essentiellement d'une
redistribution des fonctions et variables en m�thodes et attributs
dans la classe <tt>colorExercice</tt>.</p>

<p>Les variables globales sont transform�es en attributs d�clar�s au
d�but de la classe&nbsp;:</p>

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
class colorExercice(exercice):
    width, itemToSelect = 200, 8
    selectedItem = rootGroup = None
    # to keep trace of the canvas item
    colorShape = []
</pre>
</td>
</tr>
</table>

<p>Comme pour la classe <tt>labelExercice</tt>, la m�thode
<tt>__init__</tt> est surcharg�e pour contenir la construction des
widgets de l'exercice&nbsp;:</p>
<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
    def __init__ (self):
        self.exerciceName = "Le jeu de couleur"
        self.exerciceWidget = GnomeCanvas ()
        self.rootGroup = self.exerciceWidget.root ()
        self.buildGameArea ()
        self.exerciceWidget.set_usize (self.width,self.width)
        self.exerciceWidget.set_scroll_region (0, 0, self.width, self.width)
        self.exerciceWidget.show ()
</pre>
</td>
</tr>
</table>

<p>Rien de nouveau par rapport au code initial, si ce n'est que le
<tt>GnomeCanvas</tt> est r�f�renc� dans l'attribut
<tt>exerciceWidget</tt>.</p>

<p>L'autre m�thode surcharg�e est <tt>reset</tt>, elle remet � z�ro le
jeu, elle doit donc �tre sp�cialis�e au jeu de couleur&nbsp;:</p>

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
    def reset (self):
        for item in self.colorShape:
            item.destroy ()
        del self.colorShape[0:]
        self.buildGameArea ()
</pre>
</td>
</tr>
</table>

<p>Les autres m�thodes sont la transcription directe des fonctions,
avec en plus l'utilisation de la variable <tt>self</tt> pour acc�der
aux attributs et m�thodes de l'instance. Il existe juste une exception
dans les m�thodes <tt>buildStar</tt> et <tt>buildShape</tt> o� le
param�tre d�cimal <tt>k</tt> a �t� remplac� par un param�tre
entier. J'ai not� un comportement �trange dans le document
<tt>colorExercice.py</tt> o� les nombres d�cimaux saisis dans le code
source sont tronqu�s. Ce probl�me semble �tre li� au module
<tt>gnome.ui</tt> et au locale fran�ais (o� les nombres d�cimaux ont
leur partie enti�re et leur partie d�cimale d�limit�es par une virgule
et non un point). Je t�cherai de trouver la source du probl�me d'ici
le prochain article.</p>

<h3>Derniers ajustements dans <strong>Drill</strong></h3>

<p>Nous avons deux types d'exercice -- <tt>labelExercice</tt> et
<tt>colorExercice</tt>. Nous en cr�ons des instances depuis les
fonctions <tt>addXXXXExercice</tt> dans le code
<tt>drill1.py</tt>. Les instances sont r�f�renc�es dans un
dictionnaire <tt>exerciceList</tt> dont les cl�s sont �galement
stock�es comme arguments des feuilles de chaque exercice dans l'arbre
de gauche&nbsp;:</p>

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
def addExercice (category, title, id):
    item = GtkTreeItem (title)
    item.set_data ("id", id)
    category.append (item)
    item.show ()
    item.connect ("select", selectTreeItem)
    item.connect ("deselect", deselectTreeItem)
[...]    
def addGameExercice ():
    global exerciceList
    subtree = addSubtree ("Jeux")
    addExercice (subtree, "Couleur", "Games/Color")
    exerciceList ["Games/Color"] = colorExercice ()
</pre>
</td>
</tr>
</table>

<p>La fonction <tt>addGameExercice</tt> cr�e, par l'appel � la
fonction <tt>addExercice</tt> une feuille dans l'arbre avec comme
attribut <tt>id="Games/Color"</tt>, ce m�me attribut est utilis� comme
cl� de l'instance de l'exercice couleur -- cr��e par la commande
<tt>colorExercice()</tt> -- dans le dictionnaire
<tt>exerciceList</tt>.</p>

<p>Ensuite, et c'est l� toute l'�l�gance du polymorphisme dans le
d�veloppement orient� objet, nous pouvons manipuler, depuis les
fonctions de traitement qui utilisent les diff�rents objets exercices,
les exercices quelque soit leur architecture interne. Seules les
m�thodes d�finies dans la classe virtuelle de base <tt>exercice</tt>
sont utilis�es, et elles font, par exemple, des choses diff�rentes
dans chaque classe colorExercice ou labelExercice. Le programmeur
"parle" � tous les exercices de la m�me fa�on, m�me si ces exercices
sont un peu diff�rents. Pour ce faire nous combinons � la fois
l'utilisation de l'attribut <tt>id</tt> des feuilles de l'arbre et le
dictionnaire <tt>exerciceList</tt> ou la variable <tt>exoSelected</tt>
qui r�f�rence l'exercice en cours d'utilisation. �tant donn� que tous
les exercices sont des h�ritiers de la classe <tt>exercice</tt>, nous
utilisons ses m�thodes comme autant de point de contr�le des
exercices, dans toutes leurs vari�t�s.</p>

<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
def on_new_activate (obj):
    global exoSelected
    if exoSelected != None:
        exoSelected.reset ()

def selectTreeItem (item):
    global exoArea, exoSelected, exerciceList
    exoSelected = exerciceList [item.get_data ("id")]
    exoSelected.activate (exoArea)

def deselectTreeItem (item):
    global exoArea, exerciceList
    exerciceList [item.get_data ("id")].unactivate (exoArea)
</pre>
</td>
</tr>
</table>
<p>
<center>
<img src="../../common/images/article266/python3-0.png">
<br><strong>Fig. 1 - Fen�tre principale de Drill, avec l'exercice couleur</strong>
</center>
</p>

<p>Cela cl�t ici notre article. Nous avons donc d�couvert les attraits
du d�veloppement orient� objet en Python dans le cadre d'application
avec interface graphique. Dans les prochains articles nous
continuerons la d�couverte des widgets Gnome � travers la r�alisation
de nouveaux exercices que nous ins�rerons dans
<strong>Drill</strong>.</p>




<h3>Appendice: Le source complet</h3>
<p><b>drill1.py</b>
<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
#!/usr/bin/python
# Drill - Teo Serie
# Copyright Hilaire Fernandes 2001
# Release under the terms of the GPL licence
# You can get a copy of the license at http://www.gnu.org


from gnome.ui import *
from libglade import *

# Import the exercice class
from colorExercice import *
from labelExercice import *

exerciceTree = currentExercice = None
# The exercice holder
exoArea = None
exoSelected = None
exerciceList = {}
 
def on_about_activate(obj):
    "display the about dialog"
    about = GladeXML ("drill.glade", "about").get_widget ("about")
    about.show ()
    
def on_new_activate (obj):
    global exoSelected
    if exoSelected != None:
        exoSelected.reset ()

def selectTreeItem (item):
    global exoArea, exoSelected, exerciceList
    exoSelected = exerciceList [item.get_data ("id")]
    exoSelected.activate (exoArea)

def deselectTreeItem (item):
    global exoArea, exerciceList
    exerciceList [item.get_data ("id")].unactivate (exoArea)

def addSubtree (name):
    global exerciceTree
    subTree = GtkTree ()
    item = GtkTreeItem (name)
    exerciceTree.append (item)
    item.set_subtree (subTree)
    item.show ()
    return subTree

def addExercice (category, title, id):
    item = GtkTreeItem (title)
    item.set_data ("id", id)
    category.append (item)
    item.show ()
    item.connect ("select", selectTreeItem)
    item.connect ("deselect", deselectTreeItem)
    

def addMathExercice ():
    global exerciceList
    subtree = addSubtree ("Math�matiques")
    addExercice (subtree, "Exercice 1", "Math/Ex1")
    exerciceList ["Math/Ex1"] = labelExercice ("Exercice 1")
    addExercice (subtree, "Exercice 2", "Math. Ex2")
    exerciceList ["Math/Ex2"] = labelExercice ("Exercice 2")

def addFrenchExercice ():
    global exerciceList
    subtree = addSubtree ("Fran�ais")
    addExercice (subtree, "Exercice 1", "French/Ex1")
    exerciceList ["French/Ex1"] = labelExercice ("Exercice 1")
    addExercice (subtree, "Exercice 2", "French/Ex2")
    exerciceList ["French/Ex2"] = labelExercice ("Exercice 2")

def addHistoryExercice ():
    global exerciceList
    subtree = addSubtree ("Histoire")
    addExercice (subtree, "Exercice 1", "Histoiry/Ex1")
    exerciceList ["History/Ex1"] = labelExercice ("Exercice 1")
    addExercice (subtree, "Exercice 2", "Histoiry/Ex2")
    exerciceList ["History/Ex2"] = labelExercice ("Exercice 2")

def addGeographyExercice ():
    global exerciceList
    subtree = addSubtree ("G�ographie")
    addExercice (subtree, "Exercice 1", "Geography/Ex1")
    exerciceList ["Geography/Ex1"] = labelExercice ("Exercice 1")
    addExercice (subtree, "Exercice 2", "Geography/Ex2")
    exerciceList ["Geography/Ex2"] = labelExercice ("Exercice 2")

def addGameExercice ():
    global exerciceList
    subtree = addSubtree ("Jeux")
    addExercice (subtree, "Couleur", "Games/Color")
    exerciceList ["Games/Color"] = colorExercice ()

    
def initDrill ():
    global exerciceTree, label, exoArea
    wTree = GladeXML ("drill.glade", "drillApp")
    dic = {"on_about_activate": on_about_activate,
           "on_exit_activate": mainquit,
           "on_new_activate": on_new_activate}
    wTree.signal_autoconnect (dic)           
    exerciceTree = wTree.get_widget ("exerciceTree")
    # Temporary until we implement real exercice
    exoArea = wTree.get_widget ("exoArea")
    # Free the GladeXML tree
    wTree.destroy ()
    # Add the exercice
    addMathExercice ()
    addFrenchExercice ()
    addHistoryExercice ()
    addGeographyExercice ()
    addGameExercice ()
    
initDrill ()
mainloop ()
</pre>
</td>
</tr>
</table>
</p>

<p><b>templateExercice.py</b>
<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
# Exercice pure virtual class
# exercice class methods should be override
# when exercice class is derived
class exercice:
    "A template exercice"
    exerciceWidget = None
    exerciceName = "No Name"
    def __init__ (self):
        "Create the exericice widget"
    def activate (self, area):
        "Set the exercice on the area container"
        area.add (self.exerciceWidget)
    def unactivate (self, area):
        "Remove the exercice fromt the container"
        area.remove (self.exerciceWidget)
    def reset (self):
        "Reset the exercice"
</pre>
</td>
</tr>
</table>
</p>

<p><b>labelExercice.py</b>
<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
# Dummy Exercice - Teo Serie
# Copyright Hilaire Fernandes 2001
# Release under the terms of the GPL licence
# You can get a copy of the license at http://www.gnu.org

from gtk import *
from templateExercice import exercice

class labelExercice(exercice):
    "A dummy exercie, it just prints a label in the exercice area"
    def __init__ (self, name):
        self.exerciceName = "Un exercice vide"
        self.exerciceWidget = GtkLabel (name)
        self.exerciceWidget.show ()
</pre>
</td>
</tr>
</table>
</p>

<p><b>colorExercice.py</b>
<table width="100%" bgcolor="#f4ee9c" border="0">
<tr>
<td>
<pre>
# Color Exercice - Teo Serie
# Copyright Hilaire Fernandes 2001
# Release under the terms of the GPL licence
# You can get a copy of the license at http://www.gnu.org

from math import cos, sin, pi
from whrandom import randint
from GDK import *
from gnome.ui import *

from templateExercice import exercice
       

# Exercice 1 : color game

class colorExercice(exercice):
    width, itemToSelect = 200, 8
    selectedItem = rootGroup = None
    # to keep trace of the canvas item
    colorShape = []
    def __init__ (self):
        self.exerciceName = "Le jeu de couleur"
        self.exerciceWidget = GnomeCanvas ()
        self.rootGroup = self.exerciceWidget.root ()
        self.buildGameArea ()
        self.exerciceWidget.set_usize (self.width,self.width)
        self.exerciceWidget.set_scroll_region (0, 0, self.width, self.width)
        self.exerciceWidget.show ()
    def reset (self):
        for item in self.colorShape:
            item.destroy ()
        del self.colorShape[0:]
        self.buildGameArea ()
    def shapeEvent (self, item, event):
        if event.type == ENTER_NOTIFY and self.selectedItem != item:        
            item.set(outline_color = 'white') #highligh outline
        elif event.type == LEAVE_NOTIFY and self.selectedItem != item:
            item.set(outline_color = 'black') #unlight outline
        elif event.type == BUTTON_PRESS:
            if not self.selectedItem:
                item.set (outline_color = 'white')
                self.selectedItem = item
            elif item['fill_color_gdk'] == self.selectedItem['fill_color_gdk'] \
                 and item != self.selectedItem:
                item.destroy ()
                self.selectedItem.destroy ()
                self.colorShape.remove (item)
                self.colorShape.remove (self.selectedItem)
                self.selectedItem, self.itemToSelect = None, self.itemToSelect - 1
                if self.itemToSelect == 0:
                    self.buildGameArea ()
        return 1    

    def buildShape (self,group, number, type, color):
        "build a shape of 'type' and 'color'"
        w = self.width / 4
        x, y, r = (number % 4) * w + w / 2, (number / 4) * w + w / 2, w / 2 - 2
        if type == 'circle':
            item = self.buildCircle (group, x, y, r, color)
        elif type == 'squarre':
            item = self.buildSquare (group, x, y, r, color)
        elif type == 'star':
            item = self.buildStar (group, x, y, r, 2, randint (3, 15), color)
        elif type == 'star2':
            item = self.buildStar (group, x, y, r, 3, randint (3, 15), color)
        item.connect ('event', self.shapeEvent)
        self.colorShape.append (item)

    def buildCircle (self,group, x, y, r, color):
        item = group.add ("ellipse", x1 = x - r, y1 = y - r,
                          x2 = x + r, y2 = y + r, fill_color = color,
                          outline_color = "black", width_units = 2.5)
        return item

    def buildSquare (self,group, x, y, a, color):
        item = group.add ("rect", x1 = x - a, y1 = y - a,
                          x2 = x + a, y2 = y + a, fill_color = color,
                          outline_color = "black", width_units = 2.5)
        return item

    def buildStar (self,group, x, y, r, k, n, color):
        "k: factor to get the internal radius"
        "n: number of branch"
        angleCenter = 2 * pi / n
        pts = []
        for i in range (n):            
            pts.append (x + r * cos (i * angleCenter))
            pts.append (y + r * sin (i * angleCenter))
            pts.append (x + r / k * cos (i * angleCenter + angleCenter / 2))
            pts.append (y + r / k * sin (i * angleCenter + angleCenter / 2))
        pts.append (pts[0])
        pts.append (pts[1])
        item = group.add ("polygon", points = pts, fill_color = color,
                          outline_color = "black", width_units = 2.5)
        return item

    def getEmptyCell (self,l, n):
        "get the n-th non null element of l"
        length, i = len (l), 0
        while i &lt; length:
            if l[i] == 0:
                n = n - 1
            if n &lt; 0:
                return i
            i = i + 1
        return i

    def buildGameArea (self):
        itemColor = ['red', 'yellow', 'green', 'brown', 'blue', 'magenta',
                     'darkgreen', 'bisque1']
        itemShape = ['circle', 'squarre', 'star', 'star2']
        emptyCell = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
        self.itemToSelect, i, self.selectedItem = 8, 15, None
        for color in itemColor:
            # two items of same color
            n = 2
            while n > 0:
                cellRandom = randint (0, i)
                cellNumber = self.getEmptyCell (emptyCell, cellRandom)
                emptyCell[cellNumber] = 1
                self.buildShape (self.rootGroup, cellNumber, 
		itemShape[randint (0, 3)], color)
                i, n = i - 1, n - 1
</pre>
</td>
</tr>
</table>
</p>
</html>