Miamondo "dieu n'a pas voulu autre chose que la liberté" (commandant massoud)
http://miamondo.e-monsite.com

Python

  • Python: La programmation parallèle avec le module threading

    Bonjour, 

    Aujourd'hui, j'ai envie de vous parler du module threading. Ce dernier gère la programmation parallèle dans le langage Python et il est fort utile. Je l'ai utilisé pour créer un bouton dont la finalité est d'afficher l'heure à la seconde près, et d'ouvrir un calendrier. Ce bouton a donc deux fonctions et pour remplir sa mission, il a besoin de deux boucles:

     

     Clockbutton2

             

    • une boucle qui surveille les événements de l'utilisateur. C'est la boucle mainloop() de l'environnement graphique tkinter. Par exemple, Si le pointeur de la souris survole le widget Button, la couleur de ce dernier change.
    • une boucle infinie de type while, qui tourne toutes les secondes et qui permet d'afficher l'heure exacte sur le bouton.

    Si nous ne lançons pas ces deux boucles en parallèle, alors soit le code affichera le défilement des secondes mais le bouton sera inactif, soit le bouton sera actif mais les secondes seront figées dans l'éternité... Enfin, jusqu'à l'arrêt forcé du programme.

    Voici un exemple de code qui ne fonctionne pas. Il y a dans ce code deux boucles : while 1 qui est une boucle infinie et mainloop() réceptionnaire d'événements du GUI tkinter. Lorsque le programme pénètre dans la boucle infinie, il n'a plus aucun moyen d'en sortir. Certes, il affichera le défilement des secondes jusqu'à la fin des temps, mais comme la boucle mainloop() se trouve en dehors, nous n'avons plus accès aux événements du bouton. Celui-ci est complètement pétrifié. Comme je l'explique plus bas dans la vidéo en lien avec ce billet, il n'est même pas possible de cliquer sur la croix pour fermer le programme.

    Si nous déplaçons la toute dernière instruction (button.mainloop) à l'intérieur de la boucle while, une seule seconde va défiler puis le programme va "sauter" dans la boucle mainloop() et quitter la boucle infinie. Nous aurons accès aux fonctionnalités du bouton mais l'heure restera figée.

    La solution

    Elle est fort simple. Voici le code qui fonctionne. Il suffit de créer deux objets de la classe threading et de les démarrer en parallèle presque simultanément grâce à la méthode start(). Celle-ci va ensuite passer le relais à la méthode self.run(). Les noms de ces deux méthodes sont génériques. Ils ne peuvent pas être remplacés par d'autres termes. Les deux processus ne démarrent pas exactement au même moment. Il y a une différence de 200 millièmes de secondes. Dans ce cas précis, cet intervalle est nécessaire si on ne veut pas que le programme se crashe lamentablement juste après le décollage.

    Une fois lancé, chaque "thread" vit sa vie. Ils ont toutefois la possibilité d'accéder à des instructions communes comme par exemple les variables de classe. C'est le cas dans mon programme. La boucle infinie a besoin de la variable qui stocke l'objet fenêtre principale. Mais pour éviter qu'ils se mélangent les pinceaux et qu'ils modifient au même moment des données vitales pour la stabilité du programme, nous importons la classe Lock() du module threading.

    Lock() signifie verrou. Je déclare donc une variable (lock = Lock()) en tout début de programme, et je verrouille le premier thread grâce à l'instruction with lock. Avec cet outil, le second thread ne ne démarrera que lorsque le premier aura terminé son travail et lui aura passé la main. En clair, le premier thread fait ce qu'il a à faire, tandis que le second qui n'est pas verrouillé, reste sur le seuil de la porte. Lorsque le premier est prêt, il ouvre la porte et laisse entrer le second thread. Si le premier doit reprendre son travail pour modifier je ne sais quel bouton, il prie le second de bien vouloir sortir de la pièce. C'est très pratique! Bien évidemment, comme le second thread est une boucle infinie, il n'est pas possible de le verrouiller. Il ne passerait jamais la main à son collègue. Voilà donc pour le module threading que je vous invite à découvrir. Si vous avez des remarques ou des interrogations, n'hésitez pas. Ma porte est ouverte.

     

  • Un environnement de bureau codé en Python

    1ère partie : la barre des tâches

     

    Taskbar3

    Bonjour,

    Il y a un peu plus d'un an, je m'étais lancé dans un projet ambitieux, en l'occurrence la programmation d'un environnement de bureau en langage Python. Le résultat n'avait pas été à la hauteur de mes espérances. Si j'ai réussi à coder le menu des applications, je n'ai jamais réussi à coder proprement la barre des tâches et le fond d'écran.

    Les boutons de la barre des tâches tremblotaient ou disparaissaient inopinément ce qui n'était pas un signe de stabilité. Mais ça, c'était avant. Aujourd'hui, je peux annoncer que j'ai réussi à coder une barre des tâches stable et fonctionnelle. Voici une petite vidéo pour illustrer mes propos:

     

     

    Vous trouverez le code sur mon dépôt git, à cette adresse.Le fichier qui lance l'application, se nomme miamondo.py. Il est mis à jour quotidiennement.

    Points à corriger ou à améliorer

    • Le placement des fenêtres. Lorsque l'une d'entre elles est maximisée et couvre les autres, je dois iconifier et désiconifier ces dernières pour les faire apparaitre au-dessus. Ce n'est pas satisfaisant.
    • Les icônes des boutons. J'ai prévu une icône par défaut, pour éviter de faire planter l'application. Mais cette icône apparait bien trop souvent à mon goût. Elle signifie que je n'ai pas réussi à automatiser mon système d'icônes de manière satisfaisante. La raison en est que je ne maîtrise pas suffisamment les expressions régulières (regex). Je dois donc travailler ce point en priorité. Les icônes sont toutes présentes dans mon système de fichiers Archlinux, soit sous /usr/share/icons ou bien sous /usr/share/pixmaps. Les applications sont toutes répertoriées sous /usr/share/applications. J'ai tout ce qu'il faut pour bien faire. Le problème vient donc de mes lacunes en regex.

    Points de satisfaction

    • Stabilité du code. Dans la barre des tâches, les boutons des applications ouvertes ne scintillent pas ou pire encore, ne disparaissent pas de manière inopinée. À l'ouverture d'une fenêtre, le bouton se matérialise immédiatement. À la fermeture de cette même fenêtre, le bouton qui lui est lié, disparait immédiatement de la barre des tâches. Cela prouve que les boucles fonctionnent. 
    • Découverte de la programmation parallèle avec le module threading.
    • Découverte et prise en compte de l'importance du module regex.
    • Le nombre de processus zombies ne dépasse pas 2, ce qui est le signe que le programme est plutôt bien codé, me semble-t-il.

    À bientôt pour la deuxième partie qui vous présentera le menu principal.

  • Un dé numérique codé en langage Python

    Cette après-midi, il ne faisait pas très beau. J'en ai donc profité pour coder une application que mon amie m'avait réclamée, en l'occcurrence un dé numérique. Bien évidemment, j'ai utilisé le langage Python et la bibliothèque Tkinter pour réaliser ce modeste projet. Rien de bien compliqué dans ce code qui comporte moins de 80 lignes. vous le trouverez ici sur mon dépot git. Le fichier lanceur se nomme dices.py.

    À noter l'utilisation du module random pour générer un nombre aléatoire à chaque fois que le dé est lancé. L'application comprend:

    • une fenêtre principale (tk.Tk),
    • un widget Frame (cadre),
    • un widget Label,
    • un widget Button (bouton).

    Ce code est sous licence libre. Vous pouvez donc vous l'approprier et l'améliorer. J'ai mis en ligne une vidéo Youtube qui vous donnera des explications plus détaillées.

     

  • Calculatrice programmée en Python

    Bonjour,

    Aujourd'hui, j'ai terminé la programmation d'une calculatrice en langage Python. J'ai également utilisé la bibliothèque Tkinter. Le code se trouve ici, sur mon dépôt git. Je vous invite à le télécharger pour en faire ce que bon vous semble. Il est bien évidemment sous licence libre. Ce n'est pas une calculatrice scientifique. Elle est toute simple mais elle fait le travail.

    C'est de la programmation orientée objet (POO). J'ai créé les diférents widgets par instanciation de la classe Calculator() et en appliquant deux méthodes:

    • La méthode calculator() "construit" les touches et l'afficheur.
    • La méthode action() crée les fonctionnalités pour les connecter aux touches respectives. 

    J'ai créé moi-même la classe Calculator() et les méthodes calculator() et action()

     

    Voici une petite vidéo où je donne quelques explications succinctes sur mon code.