Radiotray, une application toute simple pour écouter les webradios

Petit mot de Benoît alias Ordinosor

Bonjour à tous

Il y a quelques semaines, j’avais lancé un appel pour annoncer que j’ouvrais les portes de Miamondo à toutes celles et tous ceux qui souhaitaient y publier des articles en rapport avec la galaxie du Libre et la planète Linux. Je ne voulais plus continuer à travailler tout seul dans mon coin et je souhaitais que ce blog évolue vers quelque chose de plus élaboré.

Eh bien, figurez-vous que j’ai été entendu puisque je viens d’être rejoint par le Castillan et que ce dernier publie ici-même son premier article. L’introduction est identique au mot près, à un court article paru sur framalibre mais il ne s’agit nullement d’un plagiat puisque c’est lui-même qui l’avait rédigé.

L’article qu’il publie aujourd’hui est beaucoup plus complet. Merci donc au Castillan que je suis heureux d’accueillir sur mes terres. Il va falloir que je modifie la bannière du site mais également que je remplace la page « À propos de l’auteur » par « À propos des auteurs ».

Le Castillan a publié de nombreux articles sur IT-Connect.fr. Je lui laisse le clavier…

Radio Tray

Radio Tray est une petite application légère d’une extrême simplicité et qui permet d’écouter les radios Internet. Cette application écrite en Python s’exécute et s’intègre directement dans le tableau de bord (ou barre des tâches) d’un système Linux. Ces caractéristiques sont :

  • hyper simple à utiliser et à paramétrer,
  • s’adapte à la plupart des formats audio (s’appuie sur la librairie « gstreamer »),
  • supporte le « drag & drop » d’URLs,
  • supporte les « playlist » au format PLS (Shoutcast/Icecast), M3U, ASX, WAX, WVX,
  • extensible par le biais de plugins.

NB : On entend par « Radio Internet » des radios FM qui diffusent également au travers d’Internet ou des Radios qui n’émettent pas sur la bande FM (ou AM) et qui ne sont disponibles qu’au travers d’Internet.

radiotray

Installation

Cette application (radiotray) est présente dans les dépôts officiels des principales distributions Linux. Sinon, vous trouverez les sources ici : http://radiotray.sourceforge.net/.

Lancement de l’application

Au lancement de l’application (/usr/bin/radiotray) il n’y a pas d’interface graphique qui s’ouvre mais juste une icône qui vient se placer dans le tableau de bord. En cliquant sur l’icône, on obtient un menu permettant d’accéder aux stations de radios pré-enregistrées, aux préférences de l’application, aux plugins ainsi qu’à la fermeture de l’application. Ajoutez ce programme à la liste des applications qui s’exécutent au démarrage de votre session, c’est tellement plus pratique !

Capture du 2017-03-23 14-45-54

NB : En fonction de l’aménagement de votre environnement de bureau, vous pouvez choisir l’endroit où l’icône de l’application apparaît : soit une icône dans la zone de notification (valeur par défaut) ou soit un indicateur d’application (techniquement « systray » ou « appindicator »). Pour paramétrer cela, ouvrez un terminal et lancez radiotray –config, puis suivez les instructions.

Paramétrage

Le paramétrage se fait au travers d’une interface graphique minimaliste et efficace qui permet :

– d’ajouter/modifier/retirer un flux radio (Menu Préférences / Configurer les radios) et d’agencer les flux radio en les regroupant éventuellement par « famille » (par groupes), exemple : Radios Françaises, Radios étrangères,

– de sélectionner les plugins à activer ou à désactiver.

Ce diaporama nécessite JavaScript.

Plugins

Les plugins sont à activer par le biais du menu (Plugins / Configurer les plugins). Les plugins livrés par défaut sont :

  • Sleep Timer qui permet de s’endormir en musique. Radiotray stoppera la diffusion à la fin du compte à rebours (à paramétrer, en minutes, manuellement dans /radiotray/plugins/sleeptimer.config qui est un fichier qui doit se trouver dans vos préférences locales (.local/share/radiotray pour un système debian par exemple),
  • StationSwitcher, gadget qui permet en un seul clic à partir du menu, de passer à la station suivante, bref de zapper,
  • HelloWorld, gadget qui permet juste de s’assurer que les notifications fonctionnent bien dans votre environnement de bureau,
  • Notifications, plugin activé par défaut (c’est le seul) et qui affiche, dans votre « Zone de notifications », le titre du morceau joué,
  • Mate Media Keys, plugin qui comme son nom l’indique, permet d’utiliser les fonctions (start, play , pause,…) spécifiques à l’environnement de bureau Mate,
  • Gnome Media Keys, idem ci-dessus mais pour Gnome,
  • History, qui affiche l’historique des morceaux écoutés au cas où vous n’auriez pas eu le temps de noter le titre de la chanson qui vient de vous « mettre les poils » !

En pratique

L’application Radio Tray est livrée avec quelques stations de radios pré-programmées. Bien qu’il y en ait d’excellentes dans le lot (telles « Radio Paradise » ou « New Dance Radio » pour les teufeurs…) vous ne trouverez pas de stations françaises. Pas de panique ! Vous allez pouvoir rajouter très facilement vos radios préférées ou, encore plus simple, récupérer ici un fichier (bookmarks.xml) contenant des centaines de radios francophones (mais pas que) dont les plus généralistes telles RTL, Europe1, FranceInfo, etc. Une fois récupéré, ce fichier est à copier vers votre « home directory » dans /.local/share/radiotray (attention dans certaines distributions ce répertoire qui contient les paramètres de Radiotray, peut être ailleurs…).

Sinon, pour n’en rajouter que quelques-unes, trouvez sur internet l’adresse (l’URL) du flux correspondant à votre radio favorite (ex : http://direct.franceinter.fr/live/franceinter-midfi.mp3 pour France Inter) et ajouter cette radio manuellement en utilisant le menu (Préférences / Configurer les radios / Ajouter). Les plus téméraires d’entre vous éditeront le fichier bookmarks.xml à la main et effectueront leurs modifications. A noter que le fichier bookmarks.xml n’est pas chargé de façon dynamique après une modification manuelle, il faudra soit relancer l’application pour le recharger ou passer par le menu (Préférences / Recharger les signets). Et voilà !

Enfin, je vous propose d’ajouter la Webradio Radiowiki (https://radiowiki.fr) qui est une webradio française qui diffuse, en plus de la musique, des infos autour de l’Informatique Libre et rediffuse des podcasts sélectionnés autour de Linux et du développement informatique en général. L’adresse du flux à intégrer dans le lecteur Radiotray est : http://radiowiki.club:8000/flux_128.

Comment je suis devenu un biffin du numérique grâce à Emmabuntüs

biffin (nom masculin) : 1. Chiffonnier, 2. Militaire de l’infanterie

Bonjour,

Il y a deux semaines, j’ai eu l’heureuse surprise de découvrir dans ma boite à courriels, une missive de Patrick d’Emmabuntüs me demandant si j’étais disposé à participer aux tests de la prochaine version de cette distribution solidaire permettant le reconditionnement d’ordinosaures abandonnés. Ces derniers sont ensuite proposés à des associations œuvrant dans le domaine de la solidarité internationale telles que :

Vous pensez bien que je n’ai pas hésité longtemps avant de lui répondre JAWOHL!  Me voilà donc devenu testeur et le moins qu’on puisse dire, c’est que je ne regrette pas ma décision. Comme c’est tout nouveau tout beau, j’y consacre plusieurs heures par jour ce qui explique que le dernier article de mon blogue date d’il y a deux semaines. Je n’ai pas de clone pour me seconder et il faut bien que je dorme un peu!

emmabuntus_fond_ecran_accueil_4

Pourquoi cela me plaît?

  • Parce que dans une ancienne vie, j’ai fait pas mal de contrôle qualité et d’amélioration continue. Or, dans la fonction de testeur, je retrouve le même état d’esprit, c’est-à dire se mettre, autant que faire se peut, dans la peau du futur utilisateur pour juger si tel défaut va le faire sortir de ses gonds ou bien s’il ne va même pas le remarquer.
  • En outre, l’idée d’utiliser plusieurs mois avant sa diffusion officielle, une version que presque personne ne possède sur son ordinateur, me procure de la joie.
  • Enfin, je voudrais rajouter que c’est pour moi l’occasion de découvrir de nouvelles fonctionnalités et de me coucher moins bête le soir, ce qui m’aide à trouver le sommeil. Quelques exemples à l’appui de mes dires :

J’ai toujours pensé que le swap était un genre musical inventé par les Forbans, un groupe mythique qui a sévi durant les années 80 et qui, croyez-le ou non, tourne encore! Eh bien pas du tout! Le swap est une espèce de déversoir qui se vide dans la mémoire de masse pour soulager la RAM lorsque le taux d’occupation de cette dernière atteint un seuil critique. Et ça, ce sont les tests qui me l’ont appris! Swap! swap! swap… Swap babedouwa!

J’ai également appris à utiliser ./configure, make et make install pour installer un logiciel qui n’est pas dans les dépôts officiels de Debian.

Pour un autodidacte de mon espèce, cette fonction de testeur, quoique modeste, est une incomparable source d’enrichissement personnel et je voudrais encore une fois remercier chaleureusement Patrick d’Emmabuntüs pour m’accompagner quotidiennement dans cette tâche. Lorsque je suis bloqué, il me prodigue juste les quelques conseils nécessaires pour continuer mon chemin et il me laisse me débrouiller par moi-même pour trouver la solution. je trouve que c’est une excellente démarche.

Bon week-end les pingouins!

pingouin.png

À la découverte de l’informatique dans les nuages avec Seafile

Bonjour,

Quand j’étais petit, je me souviens que la télévision en noir et blanc ne diffusait que trois chaînes : TF1, Antenne 2 et FR3. Dans le temps, y’avait pas Linternet et c’était pas plus mal comme ça. On manquait de rien. On était heureux comme tout.

On partait jamais en vacances. On passait nos étés à battre le blé au fléau avant de le vanner mais on manquait de rien, on était vrai heureux. À Noël, quelle joie de découvrir dans mon sabot une orange que je partageais avec mes douze frères et soeurs. Le soir du réveillon, on écoutait Tino Rossi sur un vieux mange-disques mais pas trop longtemps pour pas user les piles. À minuit, on allait à la messe de minuit avec Jacquou le croquant, notre voisin qui avait été amputé des deux jambes après avoir sauté sur une mine en Indochine. C’était le bon temps.

Les téléphones n’étaient pas portatifs mais on manquait de rien, on était heureux comme tout. À la télé, tous les morveux regardaient Le Village dans les nuages. C’était une série avec des extrathérèses réfugiés dans le hameau du Glaude et du Bombé. C’était poilant! Qu’est-ce qu’on était heureux de manquer de rien!

Aujourd’hui, à cause du réchauffement climatique, le ciel est aussi bleu qu’un monochrome d’Yves Klein et il n’y a plus de village dans les nuages. Cela dit, l’esprit de ce lieu singulier n’a pas complètement disparu puisque de nos jours, il n’est pas rare de stocker ses données personnelles dans un nuage. On appelle ça l’informatique en nuage ou cloud computing en anglais. D’aucuns prétendent qu’il s’agit d’informatique dématérialisée mais c’est une illusion! Les données sont, de toute façon stockées quelques part, que ce soit sur un strato-cumulus, au fond d’une mine, dans le cul d’une vache ou bien dans un Raspberry pi!

Tiens justement, pour mes dernières vacances en France, j’ai eu la bonne idée d’emporter mon Raspberry pi. Il se trouve que j’ai également acheté le magazine Linux inside consacré à ce drôle de petit ordinateur. Au passage, je suis moyennement satisfait de mon acquisition. Je trouve que les tutoriaux sont parfois d’une précision toute relative (en termes de pédagogie). À 12,90€, je m’attendais quand-même à quelque chose de plus consistant. Notez qu’il est fort possible que ce soit aussi mon cerveau qui soit d’une précision toute relative.

rasp_guide

Bref, je suis tombé sur un tuto qui explique comment transformer son « Rasp » en nuage avec Owncloud. Je me suis lancé dans l’aventure et après moult déboires, j’ai réussi à créer mon propre nuage sur mon propre serveur. Cerise sur le gâteau, les données étaient stockées non pas sur la carte micro-SD du Raspberry mais déportées sur une clé USB de 31 GO. La grande classe!

Sauf que le nuage owncloud, je le trouvais bien lourd à l’usage. Le téléversement de mes documents prenaient des plombes, à tel point que je n’ai même pas osé essayer avec des images. J’avais grand peur de faire fondre mon rasp! Était-ce la faute d’Owncloud ou du Raspberry? Je ne saurai jamais le fin mot de l’histoire puisque tout a planté après quelques jours d’utilisation. Je me suis retrouvé devant une page blanche et d’une certaine manière, j’étais soulagé. Pour celles et ceux que ça intéresse quand-même, voici le tutoriel que j’ai suivi pour installer owncloud :

https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-owncloud-on-ubuntu-16-04

Installation de Seafile

Je me suis donc mis en quête de solutions alternatives et j’ai jeté mon dévolu sur Seafile, un cloud certes un peu plus modeste en termes de capacités mais qui me comble de joie. C’est ici que ça se passe :

https://www.seafile.com/en/download/

Il faut scroller vers le bas et cliquer sur Server for Raspberry Pi. Après avoir téléchargé et décompressé seafile-server_6.1.1_stable_pi.tar.gz, placez-vous dans le dossier seafile-server-6.1.1 et entrez la commande suivante :

./setup-seafile

Laissez-vous guider. L’installation est très facile.

Ensuite, pour démarrer le serveur Seafile, il faut entrer cette commande :

seafile.sh start

Il faut également démarrer la partie hub qui permet les connexions :

seahub.sh start

N’ayant nullement envie d’entrer ces deux commandes à chaque connexion, je les ai paramétrées dans l’onglet Applications au démarrage d’Ubuntu Mate (le système d’exploitation de mon raspberry) afin qu’elles se lancent automatiquement à l’ouverture de session. Attention toutefois de ne pas lancer la commande Seahub en même temps que la commande Seafile! Ça ne fonctionnera pas. Il faut la lancer avec un léger temps de retard. Pour ma part, j’ai choisi soixante secondes.

Donc, pour résumer, ça nous donne ceci :

Système > Préférences > Personnel >Applications au démarrage

  • Démarrage de Seafile à l’ouverture de session :
/home/ordinosor/seafile-server-6.1.1/seafile.sh start
  • Démarrage de Seahub 60 secondes après l’ouverture de session :
sh -c "sleep 60; /home/ordinosor/seafile-server-6.1.1/seahub.sh start"

L’interface graphique de Seafile

Si tout s’est déroulé comme prévu, vous allez arriver sur une page qui vous invitera à vous connecter et à profiter pleinement des fonctionnalités de votre cumulo-nimbus. Le téléversement des documents est très rapide (grâce au glisser-déposer), le téléchargement aussi.

 

 

Ce diaporama nécessite JavaScript.

Petit bémol toutefois par rapport à owncloud, il n’y a pas d’extensions telles qu’un agenda ou un répertoire d’adresses téléphoniques mais En dehors de ça, je suis tout à fait satisfait de mon nouveau cumulo-nimbus!

seafile_2
C’est moi…

J’ai basculé ma messagerie sur Mail.Lilo.org

Étant un adepte convaincu de la distribution solidaire Emmabuntüs que j’ai installée sur Volgor mon fidèle ordinateur de bureau, je connaissais déjà le métamoteur de recherche Lilo. Du reste, je lui avais même consacré un article pour en dire tout le bien que j’en pensais. Je rappelle que grâce à lui, les recherches effectuées par les internautes sont comptabilisées en gouttes d’eau puis converties en argent avant d’être reversé à des projets sociaux et environnementaux. En ce qui me concerne, j’ai choisi de reverser mes gouttes d’eau au projet Emmabuntüs. Continuer à lire … « J’ai basculé ma messagerie sur Mail.Lilo.org »

Python: Variables et espaces de noms

Pour une lecture plus agréable (page plus large), je vous invite à cliquer sur ce lien et à lire ce chapitre dans la rubrique consacrée au langage Python.

Introduction

Dans le chapitre précédent, nous avons pu constater que grâce à la programmation orientée objet, deux développeurs, Briface et Jobriel, pouvaient coder un module chacun de leur côté et que ces deux modules pouvaient être « assemblés » in fine pour donner naissance au programme de notre choix.

Même si ces deux modules renfermaient un objet ou une variable dont le nom était identique, il n’y avait pas de risques que le programme se comporte de manière erratique puisque chaque objet évoluait dans son propre espace de noms. C’est la raison pour laquelle  une commande telle que self.random_choice.random_choice ne levait pas d’exception. 

La notion d’espace de noms dans le langage Python

La notion d’espace de noms est très importante dans le langage Python. Lorsque nous définissons une fonction avec des variables à l’intérieur, ces dernières ne peuvent vivre que dans l’espace de noms de cette fonction. Dès que celle-ci a exécuté sa dernière ligne d’instruction, les variables qui y séjournent deviennent hors de portée. Voici un exemple :

#!/usr/bin/env python3
# -*- coding: utf8 -*-

def first_names():
    lady_1 = "Gabiche"
    print(lady_1)

first_names() #appel de fonction

Résultat : Gabiche.

La fonction affiche bien la valeur contenue dans la variable définie localement.

Maintenant, nous allons modifier la dernière ligne du programme. Au lieu d’appeler la fonction, nous allons tenter de faire un print() de la variable lady_1.

#!/usr/bin/env python3
# -*- coding: utf8 -*-

def first_names():
    lady_1 = "Gabiche"
    print(lady_1)

print(lady_1)

Traceback (most recent call last):
File « /home/ordinosor/1_exemple.py », line 8, in
print(lady_1)
NameError: name ‘lady_1’ is not defined

Godverdomme! Keskispasse? Eh bien, nous avons tout simplement essayé d’afficher la valeur d’une variable qui est hors de portée puisqu’elle est définie à l’intérieur de la fonction.

À présent, nous allons essayer de faire le contraire. Nous allons définir une variable lady_2  dite globale c’est-à-dire à l’extérieur de toute fonction, et dans la fonction first_names, nous allons tenter de faire un print(lady_2).

#!/usr/bin/env python3
# -*- coding: utf8 -*-

lady_2 = "Amandale"

def first_names():
    print(lady_2)

first_names() #Appel de fonction

Résultat : Amandale.

Là, dans cet exemple, lady_2 n’est pas définie à l’intérieur de la fonction, et pourtant le programme ne plante pas! Warum?

En fait, Python va d’abord chercher dans l’espace local une variable portant le nom de lady_2. S’il ne la trouve pas, alors il va poursuivre sa recherche à l’extérieur de la fonction, c’est-à-dire dans l’espace global où il existe bien une variable définie avec le nom lady_2. Par conséquent, la fonction print() peut récupérer la valeur de cette variable dite globale.

Maintenant, définissons deux variables portant le même nom mais ne stockant pas la même valeur… Une variable globale lady_2 et une variable locale lady_2 dans la fonction. Reprenons le code précédent:

#!/usr/bin/env python3
# -*- coding: utf8 -*-

lady_2 = "Amandale"

def first_names():
    lady_2 = "Mandy-Bulle"
    print(lady_2)

first_names() #Appel de fonction

Résultat : Mandy-Bulle.

Python a d’abord effectué une recherche en local, dans l’espace de noms de la fonction. Il a réussi à trouver une variable nommé lady_2. Donc, la recherche s’est immédiatement interrompue et la fonction print() a récupéré la valeur contenue dans cette variable locale, à savoir Mandy-Bulle.

Le mot-clé global

Il n’est pas possible de modifier la valeur de la variable globale lady_2 à l’intérieur de la fonction… A moins de lui affecter au préalable le mot-clé global mais cette technique est parfaitement déconseillée car dans un gros programme, si quelqu’un modifie la valeur stockée dans la variable, il y a un gros risque que ce changement impacte sans le vouloir d’autres parties du programme. Gros risque de bugs en perspective!

#!/usr/bin/env python3
# -*- coding: utf8 -*-

lady_2 = "Amandale"

def first_names():
    global lady_2
    lady_2 = "Mandy-Bulle"

print(lady_2) #Variable globale

Résultat : Mandy-Bulle.

Amandale a disparu du programme…

Et avec la méthode append() ?

Créons une liste ladies_list et essayons voir…

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list.append("Mandy-Bulle")

first_names() #Appel de fonction
print(ladies_list) #Variable globale

Résultat : [« Amandale », « Gabiche », « Mandy-Bulle »].

Nous avons réussi à modifier la liste malgré le fait que la méthode append() soit présente à l’intérieur de la fonction. Pourquoi donc? Parce que nous avons fait appel à une méthode qui appartient à l’objet ladies_list. En agissant ainsi, aucune barrière d’espace de noms ne peut nous empêcher de mener à bien notre modification.

Mais il est impossible de modifier la variable globale ladies_list en lui affectant une nouvelle valeur à l’intérieur de la fonction.

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list = ["Mandy-Bulle", "Dominille"]
    print(ladies_list)

first_names() #Appel de fonction
print(ladies_list) #Variable globale

[« Mandy-Bulle », « Dominille »] : Résutat qui correspond au print() de la variable locale ladies_list dans la fonction first_names (à la ligne n° 10).

[« Amandale », « Gabiche »] : Résultat qui correspond au print() de la variable globale ladies_list (à la ligne n° 11). Nous n’avons pas réussi à modifier cette dernière.

Avec le slicing

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list[1:1] = ["Mandy-Bulle"]

first_names() #Appel de fonction
print(ladies_list) #Variable globale

Résultat : [« Amandale », « Mandy-Bulle », « Gabiche »]

Avec la technique du slicing, le résultat est positif car en fait, sans le savoir, nous utilisons la méthode constructeur de la classe slice. Elle agit directement sur l’objet et là encore, aucune barrière d’espace de noms ne peut nous empêcher de mener à bien notre modification. C’est comme si nous avions écrit ce code (ligne n° 7) :

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list[slice(1,1)] = ["Mandy-Bulle"]

first_names() #Appel de fonction
print(ladies_list) #Variable globale

Attributs d’instance et attributs de classe

Il existe également une hiérarchie entre les espaces de noms des instances et des classes.

  • Les instances et les classes peuvent utiliser les variables définies au niveau global mais elles ne peuvent pas les modifier.

Dans le code ci-dessous, nous avons trois types de variables :

  • Une variable globale
  • Un attribut de classe
  • Un attribut d’instance
#!/usr/bin/env python3
# -*- coding: utf8 -*-

man_1 = "Dentifritz_1" #Variable globale

class FirstName :
    """Test avec des prénoms"""

    man_1 = "Dentifritz_2" #Attribut de classe

    def first_name(self):
        """test des variables"""

        man_1 = "Sébanislas"
        self.man_1 = "Barnabulle"

#===== MAIN ===================================================================

if __name__ == '__main__':

    test = FirstName()
    test.first_name()
    print(man_1) #Variable globale
    print(FirstName.man_1) #Attribut(ou variable) de classe
    print(test.man_1) #Attribut (ou variable) d'instance

Ligne n° 23 : Dentifritz_1

Ligne n° 24 : Dentifritz_2

Ligne n° 25 : Barnabulle

Je vous invite à modifier ce code et à faire autant de tests que nécessaire pour bien comprendre le concept d’espaces de noms et la hiérarchie qui les gouverne.

#Python : classes et méthodes (partie 2) – mise en pratique

Pour une lecture plus agréable (page plus large), je vous invite à cliquer sur ce lien et à lire ce chapitre dans la rubrique consacrée au langage Python.

Nous allons confier à deux programmeurs en herbe, Briface et Jobriel, le soin de rédiger le code d’une petite application à caractère pédagogique. Elle consiste à faire apparaître des formes générées aléatoirement.

Jobriel va rédiger le code nécessaire à la création de l’environnement graphique, c’est-à-dire les widgets tandis que Briface, de son côté, va rédiger le module permettant de faire apparaître de manière aléatoire, des formes qui sont soit des triangles, soit des cercles, soit des carrés. La couleur de ces formes est également définie de manière aléatoire.

Au final, voici ce que nos deux gugusses doivent produire :

Le code de Jobriel

Commençons par le code de notre ami Jobriel :


#!/usr/bin/env python3
# -*- coding: utf8 -*-

from tkinter import*
import choice

class MainProg :
    """Création de l'environnement graphique de l'application"""

    def __init__(self, main_window, h = 300, w = 300, color = 'white'):
        """Méthode constructeur"""

        self.main_window = main_window
        self.h = h
        self.w = w
        self.color = color

    def widgets(self):
        """Création des widgets"""

        self.main_frame = Frame(self.main_window, height=self.h,\
                      width=self.w, bg=self.color)
        self.main_frame.pack()

        self.canevas = Canvas(self.main_frame, height=400, width=self.w,\
                   bg=self.color)
        self.canevas.pack(side=TOP)

        self.frame_1 = Frame(self.main_frame, height=100, width=self.w,\
                   bg=self.color)
        self.frame_1.pack(side=BOTTOM)

        self.random_choice = choice.RandomObjects(self.canevas)

        self.button = Button(self.frame_1, height=1, width=5, text='Afficher',\
                  relief='ridge', bd=3, bg='navy', fg='white',\
                  font=('Times', 14, 'bold'), padx=20,\
                  command = self.random_choice.random_choice)
        self.button.pack(padx=20, pady=10)

#===== MAIN ===================================================================

if __name__ == '__main__':

    main_window = Tk()
    main_window.title('Une forme au hasard')

    main_page = MainProg(main_window, 500, 500)
    main_page.widgets()

    main_window.mainloop()

ligne n° 4 : importation du module tkinter.
ligne n° 5 : importation du module choice qui va nous permettre de faire apparaître de manière aléatoire, différentes formes telles que des carrés, des ronds, des triangles. Les couleurs de ces formes sont également définies de manière aléatoire. Pour les deux formes d’importation, je vous renvoie au chapitre sur les modules. Personnellement, je préfère la forme d’importation ci-dessous car il n’y a pas de risques de conflits entre des variables portant le même nom. En outre, elle permet de raccourcir le nom du module. tkinter devient tk :

import tkinter as tk 

Pour de plus amples renseignements sur la bibliothèque tkinter, je vous invite à consulter cette documentation en français.

Ligne n° 43 : Nous trouvons une condition introduisant du code qui va s’exécuter uniquement si le programme est lancé de manière indépendante et non pas comme un module. Ici, c’est le cas. Par conséquent, cette partie du code s’exécute.

Ligne n° 45 : Création de l’objet main_window (fenêtre principale) par instanciation de la classe Tk() issue du module tkinter. Si j’avais écrit ceci à la ligne n° 4 : import tkinter as tk, alors la ligne n° 45 aurait été : main_window = tk.Tk().

Ligne n° 46 : application de la méthode title() sur l’objet main_window. Elle donne un titre à la fenêtre.

À ce stade, si on exécute le programme, voici ce qu’on obtient :

main_window

Ligne n° 48 : Création de l’objet main_page par instanciation de la classe MainProg(). Nous lui passons trois arguments qui sont main_window (la fenêtre mère), 500 (la hauteur de l’application) et 500 (la largeur). Nous choisissons de ne pas lui passer de paramètre de couleur. Ce sera donc la couleur par défaut qui va s’appliquer.
Ligne n° 49 : Application de la méthode widgets() sur l’objet main_page.

Ligne n° 51 : Application de la méthode mainloop() sur l’objet main_window ce qui a pour effet de déclencher le réceptionnaire d’événements et de permettre l’exécution du programme.

Ligne n° 7 : On remonte tout en haut! Définition d’une classe fondamentale baptisée MainProg
Ligne n° 10 : Méthode constructeur qui prend quatre paramètres:

  • self qui correspond à la référence de l’instance, c’est-à-dire l’objet main_page que nous avons instancié à la ligne n° 48. je rappelle qu’une méthode d’instance prend toujours au moins cet argument et que par convention, il est nommé self.
  • main_window qui correspond à la fenêtre principale et dont nous avons besoin pour instancier les widgets enfants.
  • h, w et color sont des paramètres qui possèdent une valeur par défaut. Si nous décidons de les ignorer, ce seront donc ces valeurs qui vont s’appliquer. C’est ce que nous avons fait avec color. Nous avons ignoré ce paramètre. Pour ce qui est des autres valeurs par défaut (h=300, w=300), nous avons choisi de les remplacer par 500 (voir ligne n° 48). Si nous décidons de ne pas respecter l’ordre de déclaration, il faut alors préciser le paramètre. Par exemple :

main_page = MainProg(main_window, color = ‘blue’, w=260, h=600)

Ligne n° 11 : Docstring

Lignes n° 13 à 16 : Création des attributs d’instance
Ligne n° 18 : Méthode widgets (création de tous les widgets de l’application)
Lignes n° 21 et 22 : Création de l’objet self.main_frame par instanciation de la classe Frame. Cette dernière créé un cadre que l’on peut remplir avec d’autres widgets. Nous pouvons lui passer plusieurs arguments. Notez bien la largeur (width) et la hauteur (height). Normalement, vous devez être capables de retrouver leurs valeurs. Notez également la barre oblique (antislash) qui permet d’écrire une instruction sur plusieurs lignes. La fondation Python préconise de ne pas dépasser 79 caractères par ligne, ce qui est assez strict. Dans la mesure du possible, il faut respecter cette convention.

Ligne n° 23 : Application de la méthode pack(). Cette dernière place le widget. Elle peut prendre des paramètres tels que TOP, BOTTOM, LEFT ou RIGHT qui poussent le widget dans la direction donnée.

À ce stade, si nous exécutons le programme, voici ce que nous obtenons. J’ai volontairement et provisoirement coloré en rouge, le fond du widget :

main_frame

Lignes n° 25 et 26 : Création de l’objet self.canevas par instanciation de la classe Canvas. C’est ce widget qui va nous permettre de placer les formes aléatoires grâce à différentes méthodes qui lui sont liées.
Ligne n° 27 : Méthode de placement pack(). Cette fois-ci, elle prend un paramètre (side=TOP) pour pousser le widget vers le haut.
Lignes n° 29 à 31: Nous créons un nouvel objet de type Frame que nous plaçons tout en bas de sa fenêtre parente (side=BOTTOM). Dans ce widget, nous placerons le bouton Afficher.

Ligne n° 33: Création de l’objet random_choice par instanciation de la classe RandomObjects du module importé choice. Nous lui passons un paramètre qui est self.canevas. Donc, cela nous donne:

self.random_choice = choice.RandomObjects(self.canevas)

Je rappelle que l’utilisation du point en Python signifie l’appartenance. Ainsi, la classe RandomObjects appartient au module choice.

Lignes n° 35 à 38: Création du bouton afficher par instanciation de la classe Button. Celle-ci prend plusieurs paramètres qui sont :

  • La hauteur
  • La largeur
  • Le texte à afficher
  • Le relief de la bordure
  • L’épaisseur de la bordure
  • La couleur de fond
  • La couleur du texte
  • La police et la fonte de caractères
  • L’espacement horizontal du texte à l’intérieur du widget
  • La commande que le bouton déclenche.

Pour ce dernier paramètre, nous appliquons la méthode random_choice issue du module importé choice, sur l’objet que nous avons créé (random_choice). Cela nous donne :

command=self.random_choice.random_choice

Alors là, vous allez me dire : « Mais Ordinosor! Tu bé, tu bé-bé, tu bégayes? »

Absolument pas! Il n’y a aucun risque de collision ou de confusion puisque ces deux noms identiques n’évoluent pas dans les mêmes espaces.

Notez bien que la commande déclenche une méthode lorsque nous cliquons sur le bouton. Il ne faut donc pas mettre les parenthèses () à la fin de la commande car cela aurait pour effet de shunter le bouton et d’activer la méthode dès le lancement du programme! Donc, il ne faut pas écrire :

command=self.random_choice.random_choice()

Ligne n° 39: La méthode pack() place le bouton dans sa fenêtre parente en réservant un espace vertical (pady=20) et horizontal (padx=20).

J’ai coloré provisoirement les différents widgets pour mieux les visualiser. Si nous exécutons le programme à ce stade, voici ce que nous obtenons:

  • En rouge, le widget self.main_frame
  • En blanc, le widget self.canevas
  • En jaune, le widget self.frame_1
  • En bleu, le widget self.button

button2

Merci pour ce travail, Jobriel! À présent, remettons tous les fonds des widgets en blanc Cliquons sur le bouton et voyons ce que notre ami Briface a codé…

Le code de Briface


#!/usr/bin/env python3
# -*- coding: utf8 -*-

from tkinter import*
import random

class RandomObjects :
    """Instancie aléatoirement les formes (triangles, cercles, carrés).
    Les couleurs de ces formes sont également définies de manière aléatoire"""

    def __init__(self, canevas):
        """Constructeur"""

        self.canevas = canevas

    def square(self):
        """Création du carré"""

        self.square_object = self.canevas.create_rectangle(200, 150, 300, 250,\
                             fill=self.random_color)

    def circle(self):
        """Création du cercle"""

        self.circle_object = self.canevas.create_oval(200, 150, 300, 250,\
                             fill=self.random_color)

    def triangle(self):
        """Création du triangle"""

        self.polygon = self.canevas.create_polygon(250, 150, 200, 250, 300,\
                       250,fill=self.random_color)

    def random_choice(self):
        """cf docstring class RandomObjects"""

        self.canevas.delete('all')
        self.random_color=random.choice(['green','red','yellow','blue','black'])
        random.choice([self.square, self.circle, self.triangle])()

Ligne n° 5 : importation du module random qui va nous permettre de faire des choix aléatoires.
Ligne n° 7: Création la classe RandomObjects.
Ligne n° 11: Méthode constructeur avec deux paramètres, la référence d’instance self et canevas.
Ligne n° 13: Déclaration d’une variable d’instance.
Ligne n° 16: Définition d’une méthode qui dessine un carré.
Ligne n° 19: Pour cela, nous utilisons la méthode create_rectangle qui prend quatre coordonnés en arguments ainsi qu’une couleur de remplissage.
Ligne n° 22: Définition d’une méthode qui dessine un cercle plein.
Ligne n° 25: Pour cela, nous utilisons la méthode create_oval qui prend quatre coordonnés en arguments ainsi qu’une couleur de remplissage.
Ligne n° 28: Définition d’une méthode qui dessine un triangle.
Ligne n° 31: Pour cela, nous utilisons la méthode create_polygon qui prend six coordonnés en arguments ainsi qu’une couleur de remplissage.

Pour de plus amples détails, je vous invite à consulter cette documentation en français.

Ligne n° 34: Définition de la méthode random_choice.
Ligne n° 37: Nous appliquons la méthode delete(‘all’) sur le widget self.canevas pour effacer une éventuelle forme avant que la suivante ne prenne sa place.
Ligne n° 38: Déclaration de la variable self.random_color. La valeur qui lui est affectée est une couleur choisie au hasard dans la liste passée en argument à la méthode random.choice.

Là encore, attention de ne pas confondre la méthode random_choice que nous avons nous-même définie et la méthode random.choice, c’est-à-dire la méthode choice du module importé random (ligne n° 5)!

Ligne n° 39: Cette fois-ci, random.choice choisit au hasard la méthode qui va matérialiser la forme. Pour que cette méthode exécute ses instructions, nous rajoutons tout à la fin, deux parenthèses. Sans ces deux parenthèses, rien ne se passerait:
random.choice([self.square, self.circle, self.triangle])()

Merci à toi , Briface, pour ce module qui exécute à la perfection la tâche qui lui a été impartie.

Ce diaporama nécessite JavaScript.

Python : classes et méthodes (partie 1), avec un peu de menuiserie en prime.

Pour une lecture plus agréable (page plus large), je vous invite à cliquer sur ce lien et à lire ce chapitre dans la rubrique consacrée au langage Python.

En programmation orientée objet (POO) et notamment dans le langage Python, tout est objet ! En fait, c’est un peu comme dans le monde réel… Nous sommes entourés d’objets de toutes sortes. Continuer à lire … « Python : classes et méthodes (partie 1), avec un peu de menuiserie en prime. »