<!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. Geo, un logiciel prim� de g�om�trie dynamique, et il est actuellement occup� avec Dr. 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 :</p> <ul> <li>Du fichier .glade original [ <a href="../../common/src/article266/drill.glade.txt">drill.glade</a> ] . 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 : <ol> <li>[ <a href="../../common/src/article266/drill1.py.txt">drill1.py</a> ].</li> <li>[ <a href="../../common/src/article266/templateExercice.py.txt">templateExercice.py</a> ].</li> <li>[ <a href="../../common/src/article266/colorExercice.py.txt">colorExercice.py</a> ].</li> <li>[ <a href="../../common/src/article266/labelExercice.py.txt">labelExercice.py</a> ].</li> </ol> </ul> <p>Pour l'installation et l'utilisation de Python-Gnome et LibGlade vous pouvez aussi vous r�f�rer � la partie 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 : <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 : <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 ;</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 : <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 : 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 :</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 :</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 :</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 :</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 :</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 :</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 :</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 :</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 < length: if l[i] == 0: n = n - 1 if n < 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>