Outils pour utilisateurs

Outils du site


issue49:tutopython

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
issue49:tutopython [2011/06/21 19:15] andre_domenechissue49:tutopython [2011/07/06 12:19] (Version actuelle) peji
Ligne 15: Ligne 15:
 Maintenant il est temps de terminer notre projet. Nous commencerons à coder là où nous en étions resté le mois dernier. Maintenant il est temps de terminer notre projet. Nous commencerons à coder là où nous en étions resté le mois dernier.
  
-La première chose que je veux faire est de modifier le code de la classe DialogueFichier. Si vous vous souvenez de la dernière fois, si l'utilisateur cliquait le bouton Annuler, il se produisait une erreur. Nous allons commencer par corriger ça. À la fin de la routine, vous avez le code ci-dessus.+La première chose que je veux faire est modifier le code de la classe DialogueFichier. Si vous vous souvenez de la dernière fois, si l'utilisateur cliquait le bouton Annuler, il se produisait une erreur. Nous allons commencer par corriger ça. À la fin de la routine, vous avez le code ci-dessus.
  
-Comme vous pouvez le supposer, cela regarde simplement la valeur de chaque touche enfoncée lorsque l'utilisateur se trouve dans le champ de texte txtNomFichier et la compare à la valeur 65293, qui est le code attribué à la touche Entrée. Si cela  correspond, alors il appelle la fonction SauvegarderListe. L'utilisateur n'a même pas besoin de cliquer sur le bouton.+Comme vous pouvez le supposer, cela regarde simplement la valeur de chaque touche enfoncée lorsque l'utilisateur se trouve dans le champ de texte txtNomFichier et la compare à la valeur 65293, qui est le code attribué à la touche Entrée. Si cela correspond, alors il appelle la fonction SauvegarderListe. L'utilisateur n'a même pas besoin de cliquer sur le bouton.
  
 **Now on to new code. Let's deal with the toolbar button ClearAll. When the user clicks this button, we want the treeview and the ListStore to be cleared. This is a simple one-liner that we can put into the on_tbtnClearAll_clicked routine. **Now on to new code. Let's deal with the toolbar button ClearAll. When the user clicks this button, we want the treeview and the ListStore to be cleared. This is a simple one-liner that we can put into the on_tbtnClearAll_clicked routine.
Ligne 44: Ligne 44:
 The first line creates the TreeSelection object. We use that to get the rows selected (which is only one because we didn't set the model to support multiple selections), fill that into a list called iters, and then walk it removing (like the .clear method). We also decrement the variable RowCount, and then display the number of files in the status bar.** The first line creates the TreeSelection object. We use that to get the rows selected (which is only one because we didn't set the model to support multiple selections), fill that into a list called iters, and then walk it removing (like the .clear method). We also decrement the variable RowCount, and then display the number of files in the status bar.**
  
-Je sais que vous pensez : « mais bon sang, qu'est-ce qu'un itérateur ? ». Eh bien, vous en avez déjà utilisé sans même le savoir. Regardez le code suivant (ci-dessus à droite) provenant de la fonction AjouterFichiers du mois dernier.+Je sais que vous pensez : « Mais bon sang, qu'est-ce qu'un itérateur ? ». Eh bien, vous en avez déjà utilisé sans même le savoir. Regardez le code suivant (ci-dessus à droite) provenant de la fonction AjouterFichiers du mois dernier.
  
 Regardez la boucle for. On utilise un itérateur pour parcourir la liste ListeFichiers. Dans ce cas, l'itérateur passe tout simplement d'une entrée de la liste à la suivante, renvoyant chaque élément séparément. Nous allons créer un itérateur, le remplir avec les lignes de la vue arborescente sélectionnées et l'utiliser comme une liste. Voici donc le code (au milieu à droite) pour on_boBtnSupprimer. Regardez la boucle for. On utilise un itérateur pour parcourir la liste ListeFichiers. Dans ce cas, l'itérateur passe tout simplement d'une entrée de la liste à la suivante, renvoyant chaque élément séparément. Nous allons créer un itérateur, le remplir avec les lignes de la vue arborescente sélectionnées et l'utiliser comme une liste. Voici donc le code (au milieu à droite) pour on_boBtnSupprimer.
Ligne 66: Ligne 66:
 We can now start work on the move functions. Let's start with the Move To Top routine. Like we did when we wrote the delete function, we get the selection and then the selected row. Next we have to step through the rows to get two variables. We will call them path1 and path2. Path2, in this case will be set to 0, which is the “target” row. Path1 is the row the user has selected. We finally use the model.move_before() method to move the selected row up to row 0, effectively pushing everything down. We'll put the code (below right) directly in the on_tbtnMoveToTop_clicked routine.** We can now start work on the move functions. Let's start with the Move To Top routine. Like we did when we wrote the delete function, we get the selection and then the selected row. Next we have to step through the rows to get two variables. We will call them path1 and path2. Path2, in this case will be set to 0, which is the “target” row. Path1 is the row the user has selected. We finally use the model.move_before() method to move the selected row up to row 0, effectively pushing everything down. We'll put the code (below right) directly in the on_tbtnMoveToTop_clicked routine.**
  
-Maintenant que l'on a un chemin (cf) et un nom de fichier (nf), on peut ouvrir le fichier, imprimer notre en-tête M3U et parcourir la liste de lecture. Le chemin est stocké (si vous vous souvenez) dans la colonne 2, le nom du fichier dans la colonne 0et l'extension dans la colonne 1. On crée simplement (à droite) une chaîne, puis on l'écrit dans le fichier et enfin on ferme le fichier.+Maintenant que l'on a un chemin (cf) et un nom de fichier (nf), on peut ouvrir le fichier, imprimer notre en-tête M3U et parcourir la liste de lecture. Le chemin est stocké (si vous vous souvenez) dans la colonne 2, le nom du fichier dans la colonne 0 et l'extension dans la colonne 1. On crée simplement (à droite) une chaîne, puis on l'écrit dans le fichier et enfin on ferme le fichier.
  
 On peut maintenant commencer à travailler sur les fonctions de déplacement. Commençons par la routine Haut. Comme nous l'avons fait en écrivant la fonction Supprimer, on récupère la sélection puis la ligne sélectionnée. Ensuite on doit parcourir les lignes pour récupérer 2 variables. Nous les appellerons chemin1 et chemin2. chemin2 sera réglé à 0 dans ce cas, car c'est la ligne de « destination ». chemin1 est la ligne que l'utilisateur a sélectionnée. On utilise enfin la méthode modele.move_before() pour déplacer la ligne sélectionnée sur la ligne 0, en poussant d'office tout vers le bas. Nous placerons le code (ci-dessous à droite) directement dans la routine on_boBtnHaut_clicked. On peut maintenant commencer à travailler sur les fonctions de déplacement. Commençons par la routine Haut. Comme nous l'avons fait en écrivant la fonction Supprimer, on récupère la sélection puis la ligne sélectionnée. Ensuite on doit parcourir les lignes pour récupérer 2 variables. Nous les appellerons chemin1 et chemin2. chemin2 sera réglé à 0 dans ce cas, car c'est la ligne de « destination ». chemin1 est la ligne que l'utilisateur a sélectionnée. On utilise enfin la méthode modele.move_before() pour déplacer la ligne sélectionnée sur la ligne 0, en poussant d'office tout vers le bas. Nous placerons le code (ci-dessous à droite) directement dans la routine on_boBtnHaut_clicked.
Ligne 74: Ligne 74:
 Now let's take a look at what it will take to do the MoveUp routine. Once again, it is fairly similar to the last two functions we created. This time, we get path1 which is the selected row and then assign that row number–1 to path2. Then IF path2 (the target row) is greater than or equal to 0, we use the model.swap() method (second down, right).** Now let's take a look at what it will take to do the MoveUp routine. Once again, it is fairly similar to the last two functions we created. This time, we get path1 which is the selected row and then assign that row number–1 to path2. Then IF path2 (the target row) is greater than or equal to 0, we use the model.swap() method (second down, right).**
  
-Pour la fonction Bas, nous utiliserons presque le même code que pour la routine Haut, mais au lieu d'utiliser la méthode modele.moveBefore(), nous utiliserons la méthode modele.moveAfter()et au lieu de régler chemin2 à 0 on le réglera à self.NombreDeLignes-1. Maintenant vous comprenez à quoi sert la variable NombreDeLignes. Souvenez-vous que les lignes sont numérotées à partir de 0, donc il faut utiliser NombreDeLignes-1 (ci-dessus à droite).+Pour la fonction Bas, nous utiliserons presque le même code que pour la routine Haut, mais au lieu d'utiliser la méthode modele.moveBefore(), nous utiliserons la méthode modele.moveAfter() etau lieu de régler chemin2 à 0on le réglera à self.NombreDeLignes-1. Maintenant vous comprenez à quoi sert la variable NombreDeLignes. Souvenez-vous que les lignes sont numérotées à partir de 0, donc il faut utiliser NombreDeLignes-1 (ci-dessus à droite).
  
 Maintenant regardons ce que donne la fonction Monter. À nouveau, elle est très ressemblante aux deux fonctions que nous venons de créer. Cette fois-ci, on a chemin1 qui contient la ligne sélectionnée, et on règle chemin2 à NumeroLigne-1. Ensuite, SI chemin2 (la ligne de destination) est supérieur ou égal à 0, on utilise la méthode modele.swap() (deuxième en bas à droite). Maintenant regardons ce que donne la fonction Monter. À nouveau, elle est très ressemblante aux deux fonctions que nous venons de créer. Cette fois-ci, on a chemin1 qui contient la ligne sélectionnée, et on règle chemin2 à NumeroLigne-1. Ensuite, SI chemin2 (la ligne de destination) est supérieur ou égal à 0, on utilise la méthode modele.swap() (deuxième en bas à droite).
Ligne 88: Ligne 88:
 C'est la même chose pour la fonction Descendre. Cette fois-ci, on vérifie que chemin2 est plus PETIT ou égal à self.NombreDeLignes-1 (troisième en bas à droite). C'est la même chose pour la fonction Descendre. Cette fois-ci, on vérifie que chemin2 est plus PETIT ou égal à self.NombreDeLignes-1 (troisième en bas à droite).
  
-Maintenant, modifions quelques fonctionnalités de notre liste de lecture. Dans l'article du mois dernier, je vous ai montré le format basique d'une liste de lecture (en bas).+Maintenant, modifions quelques fonctionnalités de notre liste de lecture. Dans l'article du mois dernier, je vous ai montré le format de base d'une liste de lecture (en bas).
  
 Cependant, je vous ai indiqué qu'il y avait aussi un format étendu. Dans le format étendu, il y a une ligne supplémentaire que l'on peut ajouter au fichier avant chaque chanson, contenant des informations supplémentaires sur la chanson. Le format de cette ligne est le suivant : Cependant, je vous ai indiqué qu'il y avait aussi un format étendu. Dans le format étendu, il y a une ligne supplémentaire que l'on peut ajouter au fichier avant chaque chanson, contenant des informations supplémentaires sur la chanson. Le format de cette ligne est le suivant :
Ligne 98: Ligne 98:
 Again, to refresh your memory, I'll walk through the code. First we clear the three return variables so that if anything happens they are blank upon return. We then pass in the filename of the MP3 file we are going to look at. Next we pull the keys into (yes, you guessed it) an iterator, and walk through that iterator looking for two specific tags. They are 'TPE1' which is the artist name, and 'TIT2' which is the song title. Now, if the key doesn't exist, we would get an error, so we wrap each get call with a 'try|except' statement. We then pull the song length from the audio.info.length attribute, and return the whole shebang.** Again, to refresh your memory, I'll walk through the code. First we clear the three return variables so that if anything happens they are blank upon return. We then pass in the filename of the MP3 file we are going to look at. Next we pull the keys into (yes, you guessed it) an iterator, and walk through that iterator looking for two specific tags. They are 'TPE1' which is the artist name, and 'TIT2' which is the song title. Now, if the key doesn't exist, we would get an error, so we wrap each get call with a 'try|except' statement. We then pull the song length from the audio.info.length attribute, and return the whole shebang.**
  
-Vous vous demandez peut-être pourquoi on a inclus la bibliothèque mutagen depuis le début alors qu'on ne l'a jamais utilisée. Eh bien, nous allons l'utiliser maintenant. Pour vous rafraîchir la mémoire, la bibliothèque mutagen permet d'avoir accès aux informations des balises ID3 des fichiers MP3. Pour lire la discussion complète là-dessus, reportez-vous au numéro 35 de Full Circle qui contient la partie 9 de cette série. Nous créerons une fonction pour gérer la lecture d'un fichier MP3 et renvoyer le nom de l'artiste, le titre de la chanson et sa longueur en secondes, qui sont les trois informations dont nous avons besoin pour la ligne des informations étendues. Placez cette fonction après la fonction APropos dans la classe CreateurListeDeLecture (page suivante, en haut à droite).+Vous vous demandiez peut-être pourquoi on a inclus la bibliothèque mutagen depuis le début alors qu'on ne l'a jamais utilisée. Eh bien, nous allons l'utiliser maintenant. Pour vous rafraîchir la mémoire, la bibliothèque mutagen permet d'avoir accès aux informations des balises ID3 des fichiers MP3. Pour lire la discussion complète là-dessus, reportez-vous au numéro 35 du Full Circle qui contient la partie 9 de cette série. Nous créerons une fonction pour gérer la lecture d'un fichier MP3 et renvoyer le nom de l'artiste, le titre de la chanson et sa longueur en secondes, qui sont les trois informations dont nous avons besoin pour la ligne des informations étendues. Placez cette fonction après la fonction APropos dans la classe CreateurListeDeLecture (page suivante, en haut à droite).
  
-À nouveau, pour vous rafraîchir la mémoire, je vais parcourir le code. Tout d'abord nous effaçons les trois variables de retour pour qu'elles soient renvoyées vides si quelque chose se passe de travers. Ensuite on passe le nom du fichier MP3 que nous allons examiner. Puis on place les clés dans (vous avez deviné) un itérateur et on parcourt cet itérateur en cherchant les deux balises spécifiques. Ce sont TPE1 pour le nom de l'artiste et TIT2 pour le titre de la chanson. Si jamais la clé n'existe pas, on obtiendra une erreur, donc on entoure chaque appel avec une instruction try|except. Ensuite on va chercher la longueur de la chanson dans l'attribut audio.info.length  et on retourne tout ça.+À nouveau, pour vous rafraîchir la mémoire, je vais parcourir le code. Tout d'abord nous effaçons les trois variables de retour pour qu'elles soient renvoyées vides si quelque chose se passe de travers. Ensuite on passe le nom du fichier MP3 que nous allons examiner. Puis on place les clés dans (vous l'avez deviné) un itérateur et on parcourt cet itérateur en cherchant les deux balises spécifiques. Ce sont TPE1 pour le nom de l'artiste et TIT2 pour le titre de la chanson. Si jamais la clé n'existe pas, on obtiendra une erreur, donc on entoure chaque appel avec une instruction try|except. Ensuite on va chercher la longueur de la chanson dans l'attribut audio.info.length et on retourne tout ça.
  
 **Now, we will want to modify the SavePlaylist function to support the extended information line. While we are there, let's check to see if the filename exists, and, if so, flag the user and exit the routine. Also, to make things a bit easier for the user, since we don't support any other filetype, let's automatically append the extension '.m3u' to the path and filename if it doesn't exist. First add an import line at the top of the code importing os.path between the sys import and the mutagen import (bottom right). **Now, we will want to modify the SavePlaylist function to support the extended information line. While we are there, let's check to see if the filename exists, and, if so, flag the user and exit the routine. Also, to make things a bit easier for the user, since we don't support any other filetype, let's automatically append the extension '.m3u' to the path and filename if it doesn't exist. First add an import line at the top of the code importing os.path between the sys import and the mutagen import (bottom right).
Ligne 110: Ligne 110:
    self.MessageBox("error","The file already exists. Please select another.")**    self.MessageBox("error","The file already exists. Please select another.")**
  
-On va maintenant modifier la fonction SauvegarderListe pour qu'elle supporte la ligne d'informations étendues. Tant que nous y sommes, vérifions si le nom de fichier existe et si c'est le cas prévenons l'utilisateur et sortons de la routine. Aussi, pour rendre les choses un peu plus faciles pour l'utilisateuret puisqu'on ne supporte aucun autre type de fichier, ajoutons automatiquement l'extension .m3u au chemin et au nom de fichier si elle n'y est pas déjà. Commençons par ajouter une ligne « import os.path » au début du code entre les import de sys et de mutagen. (en bas à droite).+On va maintenant modifier la fonction SauvegarderListe pour qu'elle supporte la ligne d'informations étendues. Tant que nous y sommes, vérifions si le nom de fichier existe etsi c'est le casprévenons l'utilisateur et sortons de la routine. Aussi, pour rendre les choses un peu plus faciles pour l'utilisateur etpuisqu'on ne supporte aucun autre type de fichier, ajoutons automatiquement l'extension .m3u au chemin et au nom de fichier si elle n'y est pas déjà. Commençons par ajouter une ligne « import os.path » au début du code entre les import de sys et de mutagen. (en bas à droite).
  
 Tout comme pour la fonction AjouterFichiers, nous utiliserons la méthode rfind pour trouver la position du dernier point (« . ») dans le nom du fichier nf. S'il n'y en a pas, la valeur renvoyée sera -1. Donc nous vérifions si la valeur retournée est -1 et si c'est le cas on ajoute l'extension et on replace le nom du fichier dans le champ de texte pour être sympa. Tout comme pour la fonction AjouterFichiers, nous utiliserons la méthode rfind pour trouver la position du dernier point (« . ») dans le nom du fichier nf. S'il n'y en a pas, la valeur renvoyée sera -1. Donc nous vérifions si la valeur retournée est -1 et si c'est le cas on ajoute l'extension et on replace le nom du fichier dans le champ de texte pour être sympa.
Ligne 124: Ligne 124:
 Line 2 opens the file we are going to write. Line 3 puts the M3U header in. Line 4 sets up for a walk through the playList ListStore. Line 5 creates the filename from the three columns of the ListStore. Line 6 calls GetMP3Info and stores the return values into variables. Line 7 then checks to see if we have values in all three variables. If so, we write the extended information line in line 8, otherwise we don't try. Line 9 writes the filename line as before. Line 10 closes the file gracefully, and line 11 pops up the message box letting the user know the process is all done.** Line 2 opens the file we are going to write. Line 3 puts the M3U header in. Line 4 sets up for a walk through the playList ListStore. Line 5 creates the filename from the three columns of the ListStore. Line 6 calls GetMP3Info and stores the return values into variables. Line 7 then checks to see if we have values in all three variables. If so, we write the extended information line in line 8, otherwise we don't try. Line 9 writes the filename line as before. Line 10 closes the file gracefully, and line 11 pops up the message box letting the user know the process is all done.**
  
-Ensuite on veut entourer le reste de la fonction dans une clause IF|ELSE (en haut à droite) pour que si le fichier existe déjà on puisse simplement sortir de la routine. On utilise os.path.exists(nom du fichier) pour cette vérification.+Ensuite on veut entourer le reste de la fonction dans une clause IF|ELSE (en haut à droite) pour quesi le fichier existe déjàon puisse simplement sortir de la routine. On utilise os.path.exists(nom du fichier) pour cette vérification.
  
 Le reste du code sert principalement à sauvegarder comme précédemment, mais regardons-le quand même. Le reste du code sert principalement à sauvegarder comme précédemment, mais regardons-le quand même.
  
-La ligne 2 ouvre le fichier dans lequel nous allons écrire. La ligne 3 y place l'en-tête M3U. La ligne 4 règle un parcours à travers la liste de lecture ListStore. La ligne 5 crée le nom du fichier à partir des trois colonnes de ListStore. La ligne 6 appelle RecupererInfoMP3 et stocke les valeurs renvoyées dans des variables. La ligne 7 vérifie ensuite si nous avons des valeurs dans toutes ces variables. Si c'est le cas, on écrit la ligne d'informations étendues à la ligne 8, sinon on n'essaie pas. La ligne 9 écrit la ligne du nom du fichier comme précédemment. La ligne 10 ferme le fichier gentiment et la ligne 11 affiche un message à l'utilisateur indiquant que tout est terminé.+La ligne 2 ouvre le fichier dans lequel nous allons écrire. La ligne 3 y place l'en-tête M3U. La ligne 4 règle un parcours à travers la liste de lecture ListStore. La ligne 5 crée le nom du fichier à partir des trois colonnes de ListStore. La ligne 6 appelle RecupererInfoMP3 et stocke les valeurs renvoyées dans des variables. La ligne 7 vérifie ensuite si nous avons des valeurs dans toutes ces variables. Si c'est le cas, on écrit la ligne d'informations étendues à la ligne 8, sinon on n'essaie pas. La ligne 9 écrit la ligne du nom du fichier comme précédemment. La ligne 10 ferme gentiment le fichier et la ligne 11 affiche un message à l'utilisateur indiquant que tout est terminé.
  
 **Go ahead and save your code and give it a test drive. **Go ahead and save your code and give it a test drive.
Ligne 136: Ligne 136:
 We are using the widget references we set up earlier, and then setting the text for the tooltip via the (you guessed it) set_tooltip_text attribute. Next we need to add the call to the routine. Back in the __init__ routine, after the self.SetWidgetReferences line, add: We are using the widget references we set up earlier, and then setting the text for the tooltip via the (you guessed it) set_tooltip_text attribute. Next we need to add the call to the routine. Back in the __init__ routine, after the self.SetWidgetReferences line, add:
  
-self.SetupBullesAide()**+self.SetupToolTops()** 
  
 Allez, sauvegardez votre code et essayez-le. Allez, sauvegardez votre code et essayez-le.
  
-À ce point, la seule chose qu'on pourrait encore ajouter serait des bulles d'aide lorsque l'utilisateur survole nos contrôles avec sa souris. Cela ajoute cet air professionnel (ci-dessous). Créons maintenant une fonction pour faire cela.+À ce stade, la seule chose qu'on pourrait encore ajouter serait des bulles d'aide lorsque l'utilisateur survole nos contrôles avec sa souris. Cela ajoute cet air professionnel (ci-dessous). Créons maintenant une fonction pour faire cela.
  
-Nous utilisons le widget references que nous avons réglé plus haut, puis on règle le texte pour la bulle d'aide avec (vous l'aurez deviné) l'attribut set_tooltip_text. Ensuite on doit ajouter l'appel à la routine. Retournez dans la routine <nowiki>__init__</nowiki> après la ligne self.ReferencesWidgets, ajoutez :+Nous utilisons le widget references que nous avons réglé plus haut, puis on règle le texte pour la bulle d'aide avec (vous l'aurez deviné) l'attribut set_tooltip_text. Ensuite on doit ajouter l'appel à la routine. Retournez dans la routine <nowiki>__init__</nowiki>après la ligne self.ReferencesWidgets, ajoutez :
  
-self.SetupToolTops()+self.SetupBullesAide()
  
 **Last, but certainly not least, we want to put our logo into our About box. Just like everything else there, there's an attribute for that. Add the following line to the ShowAbout routine. **Last, but certainly not least, we want to put our logo into our About box. Just like everything else there, there's an attribute for that. Add the following line to the ShowAbout routine.
Ligne 156: Ligne 157:
 Until next time, enjoy your new found skills.** Until next time, enjoy your new found skills.**
  
-Pour finir, mais est-ce vraiment la fin, on veut placer notre logo dans la boîte APropos. Comme tout le reste ici, il y a un attribut pour faire cela. Ajoutez la ligne suivante à la routine APropos.+Enfin et surtout (!), on veut placer notre logo dans la boîte APropos. Comme tout le reste ici, il y a un attribut pour faire cela. Ajoutez la ligne suivante à la routine APropos :
  
 apropos.set_logo(gtk.gdk.pixbuf_new_from_file("logo.png")) apropos.set_logo(gtk.gdk.pixbuf_new_from_file("logo.png"))
  
-Et voilà. Vous avez maintenant une application complète et fonctionnelle et jolie, qui fait un travail merveilleux de création de liste de lecture pour vos fichiers de musique.+Et voilà. Vous avez maintenant une application complètefonctionnelle et jolie, qui fait un travail merveilleux de création de liste de lecture pour vos fichiers de musique.
  
 Le code complet, incluant le fichier glade que nous avons créé le mois dernier, est disponible ici : http://pastebin.com/ZfZ69zVJ Le code complet, incluant le fichier glade que nous avons créé le mois dernier, est disponible ici : http://pastebin.com/ZfZ69zVJ
issue49/tutopython.1308676559.txt.gz · Dernière modification : 2011/06/21 19:15 de andre_domenech