Blog

Page d’exemple

NumApps

Colors en python, NumWorks

Colors est un utilitaire conçu pour votre calculatrice, dont l’objectif est de vous fournir une interface simple, ergonomique, et complète, permettant d’afficher des rendus de couleur via le format RGB de cette couleur ! Vous avez besoin de violet pour effectuer votre plus belle rosace avec Turtle ? Vous ne connaissez pas le format RGB du violet ? Parfait ! Lancez Colors !

Fonctionnalités

  • Affichage du format hexadécimal et RGB de la couleur définie
  • Choix de teintes adaptées proposées automatiquement
  • Support du pavé numérique
  • Système d’impulsion intelligent, pour des déplacements rapides et précis

Captures d’écran

Commandes

△ et ▽◁ et ▷Chiffres
NaviguerModifier / RéglerChoisir / Se déplacer

Pour aller plus loin

Si vous souhaitez en savoir davantage sur le fonctionnement et le développement de cet utilitaire, vous pouvez lire l’article de présentation : Le projet Colors en python sur NumWorks

Télécharger

Nous vous proposons 2 liens distincts, le premier est le lien vers la source du créateur de l’application, le deuxième est un lien alternatif en cas de problème. Seul le premier lien garanti de disposer de la dernière version de l’application.

Projets

Le projet Colors en python sur NumWorks

Colors est un utilitaire développé en python pour la NumWorks. Il permet d’obtenir facilement les formats de couleur RGB et hexadécimal d’une couleur via les valeurs Red, Green, et Blue, qui sont à configurer.

Développement

Étant en train de réfléchir au fonctionnment d’un futur projet (paint.py 🤔🤫). J’avais besoin de fournir un utilitaire facultatif en complément de ce projet pour ne pas l’alourdir. Voici comment est né Colors.

Je commence donc le développement tranquillement, et en un petit week-end, le projet Colors est terminé.

Colors v1

De multiples problèmes m’ont fait perdre beaucoup de temps. Je voulais, à l’origine, afficher une large palette de couleurs, puis grâce à un curseur et des flèches, déplacer le curseur sur un pixel de la palette et nous renvoyer les informations sur la couleur selectionné, c’était palette.py. Problème : j’avais besoin au minimum de 255 pixels en hauteur, et 255 pixels en largeur. Mais l’écran de la NumWorks fait 222 pixels en hauteur. Il m’étais donc impossible d’effectuer la palette précise que je pensais avec une telle taille d’écran.

Parallèlement, en me balandant sur le net afin de comprendre le fonctionnement du format RGB et hexadécimal par rapport aux couleurs, je fus tombé sur un système de sélection de couleur grâce à des barres coulissantes, et j’ai adoré !

Je me suis dit que ce serait parfait pour Palette (qui deviendra Colors). J’ai donc commencé à développer un système reproduisant le fonctionnement d’une barre coulissante. Et comme je suis sympa, je vous mets à disposition la fonction documentée si vous voulez en intégrer vous même dans vos programmes ! 😎

Ayant fini, je demande ce qu’en pense cent20. Grave erreur…

Bon bah mon projet attendra, l’écriture du cahier des charges de Colors v2 est en cours.

La nouvelle fonctionnalité majeure (il n’y en a de nombreuses autres pas forcément visibles) de cette seconde version est l’ajout des teintes :

Colors v2

La v2 plus ou moins terminée, une v3 est en réflexion…

Colors, qui devait être à la base un petit projet abouti en 2 jours, deviendra un gros projet de 2 semaines (pas à temps plein🙄).

Cette troisième et dernière version améliore grandement le rafraichissement des données (en limitant le clignotement), l’interface graphique est également légèrement revu. Cette version supporte également le pavé numérique. Et oui, on fait pas les choses à moitié ! 😏

Colors !

À toi de colorer !

Cet utilitaire est disponible sur https://nsi.xyz/colors

Tutoriels

Développer une application pour la NumWorks sur un vrai…

Vous avez décidé de créer un script python et de porter ce script sur la couche graphique de la calculatrice NumWorks, vous serez vite limité par my.numworks.com qui ne propose qu’une interface très limité de développement.

Si vous codez un script python qui n’exploite que la console, vous pouvez le développer sur n’importe quel outil puis simplement copier / coller votre script dans votre espace de stockage en ligne proposé par NumWorks sur my.numworks.com/python/

Si vous souhaitez d’exploiter des modules propriétaires de la calculatrice NumWorks, tels que ion (gestion du clavier) ou kandinsky (pour gérer l’écran pixel par pixel) alors tout est plus compliqué, enfin tout était plus compliqué !

Il était une fois le workshop …

Le site officiel de NumWorks qui héberge les script s’appelle désormais my.numworks.com mais au départ, il y a fort longtemps, on parlait du workshop, il était accessible en ligne depuis cette adresse workshop.numworks.com et proposait une interface de programmation primitive, qui n’a malheureusement que peu évolué depuis 2017.

Si vous aimez les ascenseurs vous allez adorer cette interface de programmation !

Pas pratique, pas collaborative, bogué, bref on y a codé des jeux et ce fut épique.

La révolution Omega et son IDE en ligne

Le développement de petits jeux sur la NumWorks a été rendu possible par la sortie de la version 13 officielle, et lorsque nous avons commencé à faire des jeux, comme le démineur nous avons très vite suggéré l’idée de rendre possible de développement des projets avec Kandinsky sur PC sans passer par l’interface officielle de NumWorks.

En septembre 2020, l’équipe de Omega (un fork de Epsilon, l’Os de la calculatrice) lançait un IDE en ligne. Il est toujours utilisable à l’adresse https://getomega.dev/ide mais il nécessite un compte GitHub, car les fichiers .py qui y seront crées seront enregistrés sur GitHub.

Pour l’avoir utilisé et exploité avec les élèves en octobre / novembre 2020 pour leurs projets de spécialités NSI, nous pouvons certifier que c’est un superbe outil et une belle amélioration du workshop officiel.

Notre jeu Tetris a été développé sans cet IDE, tout aurait été tellement plus simple avec !

Le talent n’attend pas le nombre des années

Un développeur du nom de ZetaMap , lycéen en terminale STI2D option SIN au lycée Vauban de Brest a codé deux modules pour nous faciliter la vie :

Il est désormais possible d’utiliser un IDE classique (testé uniquement sous Windows) pour développer sur la NumWorks :

Ici le jeu Factors,, il tourne sur un PC alors qu’il exploite des modules spécifiques de la NumWorks.

Comment installer les modules de la NumWorks sur Thonny

Thonny est un IDE léger, simple et excellent pour débuter en python.

Nous allons voir ici comment installer des modules simplement sur Thonny, c’est-à-dire en se passant des traditionnels pip install dans un terminal.

Tout d’abord, il vous faut ouvrir Thonny, cela va de soit, ensuite accéder à l’onglet « Tools » ou « Outils » (selon votre langue), puis à la section « Manage packages… » ou « Gérer les paquets… ». Enfin, il suffit plus que de rechercher les modules « kandinsky » et « ion-Numworks » et de les installer !

Comment installer les modules de la NumWorks sur PyCharm

PyCharm est un IDE un peu lourd, mais très complet. Il peut-être notamment utile si vous gérez des projets avec Git.

Nous allons donc voir ici comment installer des modules encore une fois simplement sur PyCharm, c’est-à-dire en se passant des traditionnels pip install dans un terminal.

Tout d’abord, il vous faut évidemment ouvrir PyCharm, ensuite accéder à l’onglet « File », puis aux options « Settings ». À présent, rendez-vous dans la catégorie « Python Interpreter » dans votre Projet « Project: <project_name> ». Désormais, pour installer un module, appuyez sur le bouton « + » :

il suffit plus que de rechercher les modules « kandinsky » et « ion-Numworks » et de les installer !

Comment exploiter les modules ainsi installés

Pour exploiter les modules, rien de plus simple, il faut seulement les importer dans votre code :

from kandinsky import *
from ion import *

Votre code sera donc compatible avec votre IDE et la calculatrice, sans aucune modification requise.

Bugs et limite du portage

Évidemment, cette technique n’est pas sans limite. Notamment, si vous utilisez Turtle en plus de kandinsky. En installant ces deux modules et en les utilisant, deux émulateurs graphiques s’ouvriront, un exploitant kandinsky, et l’autre Turtle. C’est pour ça qu’il est déconseillé d’utiliser les deux en même temps, utiliser soit l’un soit l’autre.

De plus, est à éviter de changer de fenêtre pendant l’exécution du programme, cela risque de freeze l’émulateur :

Si vous souhaitez discuter de cet émulateur, faire remonter des bugs ou juste dire merci à son concepteur, tiplanet.org à bien voulu nous créer un salon dédié sur le serveur discord.

Lien direct vers ce salon : https://discord.gg/bBM7mgucjF

Projets

Factors Game en python sur NumWorks

Factors Game est à l’origine un jeu indépendant jouable en ligne, donc directement depuis un site web. Ceci dit, les Numworks ne peuvent pas encore se connecter à internet… Mais pas de panique, nous nous sommes occupés de l’adaptation du jeu sur calculatrice ! On est sacrément sympa nous…
Arriveras tu à atteindre le niveau 404 ?

Développement

02/04
🧐 Bon, maintenant que t’as fini ton nyan_cat, résolu deux de mes énigmes, corrigé les bugs sur laboHelp, aidé au développement de pixChoice. Ça te dit de faire un jeu sur la calculatrice ?
🤓 Pourquoi pas !

Voici le jeu qui était demandé : Factors Game – The 🐐 of Fun Math Games (mnito.github.io)

🧐 On va afficher les nombres dans des tuiles de 42 pixels par 42 pixels

(2 jours plus tard)

🤓 J’ai fini le système de mouvement, et le système de génération aléatoire de la grille. Il y a juste le front qui est à revoir…


🧐 Bon, pas très UX les déplacements du haut vers le bas comme sur le jeu original avec la résolution de l’écran des calculatrices. On va les faire de gauche à droite du coup, tu dois réadapter le système de mouvement.
🤓 … D’accord

Parallèlement le codage des nombres a été intégré, il est d’Eric Schrafstetter, il est explicité sur cette vidéo.

Ce codage, celui du jeu 2048, dont nous avons amélioré le rendu a été réutilisé pour écrire F A C T O R S en haut à gauche de l’écran !

Petit récap’, mouvements OK, grille OK, maintenant il faut faire le système de calcul entre le curseur et les cases de la grille (vous savez, les divisons, les additions, tout ça tout ça. Ça se fait pas par magie malheureusement).

Aussitôt commencé, aussitôt terminé ! Moi qui redoutait cette phase du développement, ça avait été plus facile que prévu. Plus qu’à faire le système de détection de fin du niveau. Fastoche ! Si le curseur est égal à 1, ou que le curseur est positionné dans la dernière colonne, niveau terminé ! Et on relance la génération de la grille sans oublier d’incrémenter le niveau et calculer la moyenne.

Voilà. En quelques jours, le jeu est théoriquement jouable.

🤓 Plus que le menu, et le système de sauvegarde. Mais le jeu est jouable !
🧐 Ok, pour le menu, on va faire ça, ça, mais il faut ça s’il y a ça, ça ça doit donc s’activer et du coup réactiver ça si ça a été désactivé seulement si ça avait été activé et puis…
🤓 Et si on faisait un cahier des charges ? 😅
🧐 Je m’en occupe.

🤓 Le menu est terminé, il faut sauvegarder le score de chaque niveau ?
🧐 Oui, on va utiliser un dictionnaire.
🤓 Larousse ou Le Petit Robert ?

Menu

🧐Le dictionnaire sert à rien, on aurait pu faire ça avec un tableau, mais laissons le dictionnaire ! 😂

🤓 Bon, je taffe sur une transition entre les niveaux, car les coups de sleep(3), ça va 2 secondes… (3 !)

🧐 Parfait !

Et voilà, en une bonne semaine, le jeu est terminé, il manque plus que le système de sauvegarde, enfin c’est ce que je pensais…

🧐 Bon, ton code est illisible on ne comprend rien. Tu me redéveloppes toute la fonction principale en respectant ces contraintes :

  • Le moins de if imbriqués possibles
  • Chaque if doit donner lieu à 2,3 traitements maximum
  • 61 lignes pour une fonction c’est trop
  • Tout abus de booléen est à éviter

🤓 Mais ça nécessite de redévelopper quasiment toutes les fonctions. Donc tout le jeu…
🧐 Oui mais sinon on comprend rien.
🤓 Oui mais le jeu marche.
🧐 Oui mais on comprend rien.
🤓 J’ai compris…

Vous vous comprenez hein rassurez moi. À moins que j’ai un problème.

def factors(): # Ceci est l'ancien code incompréhensible !
    global cursor, pos, level_current, retry
    gui()
    menu()
    level_in_progress, in_menu, re_menu, last_key, end, go, input_await = False, False, False, None, False, False, False
    while not keydown(5):
        if not level_in_progress:
            if not in_menu:
                menu(0)
                start_level(1)
                cursor, pos, end, input_await = level_current, [51 + 44 * 1, 13 + 44 * 1], False, False
                aff(level_current, pos[0] + 44 // 2 + center(level_current)[0],
                    pos[1] + 44 // 2 + center(level_current)[1], black_color)
                level_in_progress = True
            if not re_menu and in_menu:
                menu(1)
                start_level(0)
                re_menu = True
        if keydown(1) and pos[1] >= 51 and last_key != 1:
            if not in_menu:
                move(0, -1)
            if in_menu and level_current != level_max:
                level_current += 1
                re_menu = False
            last_key = 1
        if keydown(2) and pos[1] <= 51 + 44 * 2 and last_key != 2:
            if not in_menu:
                move(0, 1)
            if in_menu and level_current != 1:
                level_current -= 1
                re_menu = False
            last_key = 2
        if keydown(3) and last_key != 3:
            if not in_menu:
                move(1, 0)
            if in_menu:
                level_in_progress, in_menu, re_menu = False, False, False
            if input_await:
                go = True
                fill_rect(pos[0] + 42, pos[1] + 42, 0 - 220, 0 - 176, (255, 255, 255))
            last_key = 3
        if keydown(0) and last_key != 0:
            if pos[0] != 51 + 44 or input_await:
                level_in_progress = False
                retry = True
                if input_await:
                    fill_rect(pos[0] + 42, pos[1] + 42, 0 - 176, 0 - 176, (255, 255, 255))
            if not in_menu and pos[0] == 51 + 44:
                level_in_progress, in_menu = False, True
            last_key = 0
        if not (keydown(0) or keydown(1) or keydown(2) or keydown(3)):
            last_key = None
        if not (pos[0] != 51 + 44 * 5 and (cursor != 1 or pos[0] == 51 + 44)):
            end = True
        if end:
            if not input_await:
                level_transition(cursor)
                input_await = True
            if go:
                next_level()
                level_in_progress, retry, input_await, go = False, False, False, False

Finalement, presque tout le jeu a donc été redéveloppé pour améliorer la lisibilité des fonctions python.
Vous pouvez donc désormais comprendre le code ! Sauf le système de sauvegarde, ça vous vous débrouillez ! 🤫

🧐 Oui enfin le système de sauvegarde est codé pour être incompréhensible, c’est une fonctionnalité pour éviter qu’un joueur lambda ne génère trop facilement une clé de sauvegarde.

🤓 À noter, le code a été compressé pour passer de 10.2 ko à 8.42 ko, et désormais il ne respecte plus PEP 8 – Style Guide for Python Code (EnFr)

Fonctionnement

La plupart des différents événements sont lancés grâce à la liste pos[x, y]. Cette liste correspond aux coordonnées x, et y du curseur :

La position par défaut du curseur est donc [0, 1] ! Oui, l’axe vertical est inversé. 🙄

Ainsi, si pos vaut [-1, y], on lance le menu, si pos[4, 0], on termine le niveau, etc. L’affichage sur l’écran est géré par la fonction d_p(), qui va convertir pos en coordonnées réelles (celles de l’écran), car évidemment, les coordonnées de pos sont virtuelles ! Le (0 ; 0) de l’écran lui se situe tout en haut à gauche !

Fonctionnalités délaissées

Beaucoup de fonctionnalités ont été retirés pour réduire au plus la taille du fichier ainsi que la mémoire utilisée ou pour d’autres raisons.
Un histogramme dynamique avec le score des 20 derniers niveaux a été par exemple testé mais abandonné, le système de chargement d’une sauvegarde sur la couche graphique est lui aussi retiré, remplacé par une fonctionnalité équivalente mais exploitant le console python.

À toi de jouer !

Ce jeu est disponible sur https://nsi.xyz/factors

Nous te mettons au défi d’atteindre le niveau 404. Mais y arriveras tu ? 😱

NumApps

Factors en python, NumWorks

Un jeu qui mettra vos méninges au défi ! Sur Factors, vous ne devez pas réfléchir à comment vous allez pouvoir faire pour augmenter cette foutue moyenne générale, mais au contraire comment la baisser !

Règles du jeu

Avec une variante des règles de base de la division, Factors est un jeu de mathématiques amusant conçu pour être facile à comprendre, mais qui met de plus en plus à l’épreuve vos compétences mentales en mathématiques à mesure que vous progressez dans les niveaux.
Déplacez votre numéro vers la droite à travers la grille des numéros pour vous rapprocher le plus possible de 1. Mais attention, si la division de vos nombres ne forment pas un nombre entier, ils s’additionnent !
Votre objectif est de maintenir votre moyenne globale aussi basse que possible !

Ce jeu est une adaptation du jeu original Factors Game.

Fonctionnalités

  • Support des couleurs des systèmes d’exploitations Epsilon et Omega
  • Réinitialisation des mouvements pendant un niveau
  • Menu de sélection du niveau
  • Stockage du meilleur score de chaque niveau
  • Sauvegarde de sa progression
  • Et bien plus…

Captures d’écran du jeu

Commandes

△ et ▽Ans
NaviguerAccéder / CalculerRéinitialiser / MenuSauvegarder / Charger

Pour aller plus loin

Si vous souhaitez en savoir davantage sur le fonctionnement du jeu, vous pouvez lire l’article de présentation : Factors Game en python sur NumWorks

Télécharger

Nous vous proposons 2 liens distincts, le premier est le lien vers la source du créateur de l’application, le deuxième est un lien alternatif en cas de problème. Seul le premier lien garanti de disposer de la dernière version de l’application.

Projets

Binnerto ©, un système de gestion de bases de…

Il y a quelque mois de cela, nous vous avions laissé bien pantois. En effet, sur le site Binnerto©, un site très qualitatif de produits geek, il était jusque-là impossible de commander le moindre petit produit, et nous en sommes grandement désolés.

Mais aujourd’hui est un jour nouveau, nous venons de sortir du sable, enfin !

Vous allez désormais (dans un temps prochain (soumis à condition et à l’acceptation du crédit par votre banque)) pouvoir acheter (dans la limite des stocks disponibles et des vendeurs disponibles pour réaliser les commandes) tous les produits vendus par notre site dès maintenant grâce à un SGBDR !

Quelques petits rappels utiles et informations nécessaires à la compréhension

Vous vous demandez bien qu’est-ce qu’un SGBDR et à quoi cela peut bien servir pour commander votre produit préféré (et fort bien utile). Et bien pour une fois cette acronyme est en français (ou DBRMS dans la langue de Shakespeare), il signifie littéralement Système de Gestion de Bases de Données Relationnelles. Euuuuh quèsaco ? En fait c’est un logiciel qui permet de mettre en relation différents fichiers contenant de nombreuses données. Voyons à quoi cela ressemble dans notre cas, cela apportera plus de clarté.

Imaginons que vous vous appeliez Antonin Kroyable et que vous ayez commandé une Souris révolutionnaire pour votre tout nouvel appareil à la poire le 14 février 2022. Et bien le SGBDR ; nommons le affectueusement S&Co pour la suite pour plus de simplicité et de proximité, permet de lier trois fichiers pour les unifier. Dans un fichier vous trouverez vos informations personnelles, ce sera le fichier « client », dans un second, vous aurez toutes les informations sur cette souris, c’est-à-dire dans le fichier « produit ». Et pour la commande que vous avez faites ? Et bien elle se trouve dans le fichier « commande » évidemment. Tout le travail du S&Co et donc de lier ces trois fichiers pour avoir les informations les plus utiles pour chaque besoin, c’est-à-dire pour vous clients, et pour nous gestionnaires du site et responsables des stocks et livraisons produits, sans avoir des fichiers de 3 Km de long avec toutes les informations, dont certaines inutiles à certains mais utiles à d’autres.

Rentrons maintenant dans le cœur de la bête pour mieux l’appréhender.

Il faut savoir que ce S&Co, étant user-friendly, a une interface utilisateur (ou UI en anglais) graphique, permettant une meilleure expérience utilisateur (ou UX encore une fois en anglais), en limitant de perdre ce dernier, qui n’a pas forcément les connaissances nécessaires pour affronter la peur d’un terminal sombre et peu ragoûtant. Il est au moins rassuré, mais cela nous complexifie bien la tâche, comme nous allons le voir.

Dans cette quête de la rose-amère de la perfection du design, ce S&Co ne fera que pâle figure car étant codé extrêmement en Python avec comme interface graphique Tkinter, les possibilités de design sont amoindries comparé à d’autres langages mieux prévus pour les interfaces graphiques. Nonobstant, vous avez quand-même un produit a minima fini.

Il y aura donc, vous l’aurez compris deux parties majeures pour appréhender ce S&Co, la partie graphique, en Tkinter, qui n’est que la rustine de ce qui fait tourner la machine, ce qui est à l’intérieur, c’est-à-dire les fonctions mères pour mettre en relation SQL (le langage qui permet de parler aux tables de données ; le charmeur de données), et Python.

Le vif du sujet SQL-Python

Sans plus de divagations, voyons d’où tout est parti : SQLite. En effet, il est impossible de discuter directement avec les données en Python, ou alors cela serait très complexe.

Pour plus de facilité, on utilise à la place un autre langage, le SQL (qui est d’une facilitée incroyable en comparaison). Mais pour lier un programme Python avec du SQL il faut une bibliothèque, et c’est la que SQLite vient nous sauver ! En effet on peut rentrer des commandes SQL dans une fonction Python et avoir tous les bénéfices du SQL en ayant les retours en Python pour être réutilisés, c’est presque magique !

Réalisation des trois bases de données dans un fichier CSV

Pour commencer avec des données à chaque démarrage sans partir de rien, nous avons créé 3 fichiers CSV (où les éléments sont séparés par des virgules) que l’on récupère ensuite pour l’importer (on verra cela plus tard). Donc, comme on l’a dit plus tôt, 3 tables seront liées, il y aura donc 3 fichiers CSV qui contiendront quelques éléments pour chaque table (environ une dizaine).

Tout d’abord, il y a la table PRODUITS, dans le fichiers produits.csv. Dans cette table on présente comme suit les principales caractéristiques du produits :

id_produitnom_produitprixstock
6Binnerto en acier0.001

Toutes les données sont présentées comme cela sauf, que d’une colonne à l’autre, c’est un virgule qui les sépare. L’id_produit est un identifiant unique permettant à coup sur de retrouver le produit sans risque de se tromper (par exemple si 2 produits ont un nom identique).

Il en est de même pour la table CLIENTS sur le fichier clients.csv :

id_clientnomprenomadresse_mailadressedate_naissancedate_inscriptionvip
8KroyableAntoninantonin.kroyable@lol.mdr13 chemin des Rippes, Salle-à-Sac10-03-200711-11-2011True

De la même manière, id_client est l’identifiant unique qui correspond au client.

Passons maintenant à la dernière table, la plus importante, la table COMMANDES, dans le fichier commandes.py :

id_commandeid_client_commandeid_produitdate_commandedate_livraisonenvoyequantiteprix_total
308614-02-202219-02-2022True30.00

Encore une fois, id_commande est l’identifiant unique de la commande mais, il y a une petite subtilité encore. En effet, on va lier les deux autres tables à celle-ci avec 2 attributs : id_client_commande et id_produit, qui correspondent respectivement à la ligne de chaque table. Ainsi, avec une moindre écriture, on arrive à avoir toutes les informations pertinentes sur une seule ligne !

CRUD, la clé de voûte du projet

CRUD, de l’anglais Create, Read, Update, Delete, a été notre expression clé durant ce projet, notre guide suprême, car pour un S&Co, cela les 4 points les plus importants. Il faut pouvoir Créer des tables et des éléments dans ces tables, les Lire, les Mettre-à-Jour, mais aussi les supprimer. Voyons comment cela a pu être réalisé en Python/SQL.

1. Create

Deux choses sont à créer dans ce projet, les tables, que ce soit PRODUITS, CLIENTS ou encore COMMANDES, mais aussi les éléments qui composent ces tables, les lignes si vous vous rappelez de nos tableaux de tout-à-l’heure.

Pour créer une table, rien de plus simple comme on le voit ici avec la création de la table PRODUITS :

def create_table_produits():
    curseur.execute("CREATE TABLE IF NOT EXISTS PRODUITS(id_produit INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, nom_produit TEXT, prix NUMERIC, stock INTEGER)")
    connection.commit() #On envoie la modif dans la base de données

Le SQL est ce qui est dans la méthode .execute()

Cette fonction permet donc de créer la table PRODUITS, en vérifiant bien sûr qu’elle n’existe pas pour éviter les erreurs. Si vous vous rappelez de l’id_produit de tout à l’heure, qui permet de retrouver avec certitude un produit, et bien en SQL, c’est une PRIMARY KEY, soit une clé primaire ; une sorte de numéro d’identité du produit (qui est donc unique).

Mais on peut aussi avoir besoin de créer un enregistrement, comme suit :

def add_produits(produits_ajout):
    curseur.executemany("INSERT INTO PRODUITS(nom_produit, prix, stock) VALUES (?,?,?)", produits_ajout)
    make()

En vérifiant bien sûr que le tuple en entrée soit composé de 3 éléments.

2. Read

Pour lire, ça se corse, on peut vouloir lire tout ou partie, il a donc fallu faire des choix en réfléchissant à chaque fois au besoin le plus utile de lecture.

Ainsi on peut tout lire comme ici :

def select_all_produits():
    curseur.execute("SELECT * FROM PRODUITS")
    return [("id_produit", "nom_produit", "prix", "stock")] + curseur.fetchall()

On retourne en plus les noms des attributs afin de pouvoir les afficher comme il faut dans le tableau en Tkinter

Mais aussi comme cela :

def select_all_commandes():
    curseur.execute("SELECT nom, prenom, nom_produit, date_commande, date_livraison, envoye, quantite FROM COMMANDES AS co INNER JOIN PRODUITS AS p ON co.id_produit = p.id_produit LEFT JOIN CLIENTS AS cl ON co.id_client_commande = cl.id_client")
    return [("nom", "prenom", "nom_produit", "date_commande", "date_livraison", "envoye", "quantite")] + curseur.fetchall()

Ici, on fait une double jointure pour afficher à la place de l’id_client et de l’id_produit, le nom du client et du produit pour plus de clarté.

En jouant avec le SQL, il y a aussi des fonctions plus spécifiques comme celle qui suit permettant d’afficher toutes les commandes d’un même client :

def toutes_commandes_clients(id_client):
    curseur.execute("SELECT nom, prenom, nom_produit, date_commande, date_livraison, envoye, quantite FROM COMMANDES AS co INNER JOIN PRODUITS AS p ON co.id_produit = p.id_produit LEFT JOIN CLIENTS AS cl ON co.id_client_commande = cl.id_client WHERE id_client_commande=?",(id_client,))
    return [("nom", "prenom", "nom_produit", "date_commande", "date_livraison", "envoye", "quantite")] + curseur.fetchall()

3. Update

Pour mettre à jour, nous nous sommes demandé ce que nous aurions le plus besoin de mettre à jour dans chaque enregistrement de chaque table, et pour cela nous avons pour chaque table créé une fonction update qui change uniquement l’élément qui a le plus besoin d’être changé :

def update_commandes(id_commande, envoye: bool):
    curseur.execute("UPDATE COMMANDES SET envoye=? WHERE id_commande=?", (envoye, id_commande))
    make()

On change ici l’état de la commande avec un Booléen (Vrai/Faux), car c’est la commande que l’on est le plus amenés à réaliser.

4. Delete

Pour la suppression, afin d’être sûr de ne pas faire d’erreurs, cette dernière se base uniquement sur l’id unique de chaque enregistrement dans une table.

Ainsi :

def delete_clients(id_client):
    curseur.execute("SELECT * FROM COMMANDES WHERE id_client_commande=?",(id_client,))
    temp = curseur.fetchall()
    if str(temp) == "[]":
        curseur.execute("DELETE FROM CLIENTS WHERE id_client=?", (id_client,))
    make()

Ici, on supprime un produit en fonction de son id_produit, tout en vérifiant qu’il n’est pas utilisé dans la table commande, sinon cela pourrait poser problème.

Un affichage graphique : Tkinter

CComme dit plutôt, il faut bien interagir avec toutes ces bases de données si complexes (qu’on appellera BDD), et ça avec une interface graphique en Tkinter. Après avoir réfléchi à plusieurs croquis de ce que pourrait être l’UI (dont on vous ne donnera pas d’exemple pour ne pas nous faire voler nos maquettes), on a réussi à trouver l’UI la plus simple pour nos futurs employés, qui devront se servir de cette interface pour gérer les commandes, pendant que nous serons à Ibiza en train d’empocher un maximum d’argent.

Tous les produits de chez Binnerto en un clic

N’oublions pas le maître-mot de tout ce que l’on peut produire : LA FACILITÉ ! Il est donc inutile lorsqu’on veut sélectionner un produit d’écrire chaque lettre de ce dernier (sans oublier les potentielles erreurs de frappes ou maladresses). Nous avons donc opter pour une liste des produits qu’il suffit de sélectionner. Avec Tkinter, l’outil se nomme « Combobox » et c’est bien pratique.

from tkinter import *
from tkinter import ttk

def action(recup):
    #on appelle la fonction qui lie Python et SQL pour interagir avec la TABLE

listeproduits = ["Parpaing externe", "Clé USHellB", "Clavier Pasteur STL", "Voiture à Hydrogène", "CPU Nucléaire Leif", "Bouton d'allumage automatique", "Binnerto en acier", "Souris révolutionnaire"]
choix_prod = Label(racine, text = "Enlever Stock :")
choix_prod.place(x=300, y=130)
aff_prod = ttk.Combobox(racine, state = "readonly", values = listeproduits)
aff_prod.bind("<<ComboboxSelected>>", action)
aff_prod.place(x=265, y=170)

Comme une bonne nouvelle n’arrive jamais seule, certes l’outil « Combobox » est parfait pour ce que nous voulons faire, mais il n’est pas inclus lors de l’importation de Tkinter *. Il faut donc le rajouter à part, au péril d’un peu plus de mémoire. 

C’est bien beau de pouvoir sélectionner un produit dans une liste, mais il faut bien le récupérer pour pouvoir l’exploiter un peu. Heureusement, la méthode « .get() » permet de récupérer le choix fait par l’utilisateur, et à l’aide de la fonction ci-dessus qui affiche ce choix, on est sûr d’avoir bien récupéré le produit. Maintenant que l’on peut sélectionner un produit, il ne reste plus qu’à décider s’il faut le retirer du stock en cas de commande, ou l’ajouter en cas de fabrication (même si ce dernier cas n’arrive jamais 🤫).

Un accès aux commandes plus pratique

Nous suivons avec soin chaque commande pour la meilleure satisfaction de nos clients. C’est pour cela qu’il faut savoir à l’aide du numéro de commande : les produits qu’elle contient, le nom et prénom du client, le jour de l’envoi, si le colis a été reçu, etc…

Il faut donc qu’à l’aide de « id_commande », on trouve toutes ces informations, et cela, de façon la plus lisible possible… et pourquoi pas un tableau ?! Mais il faut d’abord récupérer le numéro d’une commande saisit dans un input :

def num_commande(event):
	n_fen = Toplevel(racine)
    t = Tableau(n_fen, select_client_specifique(int(entree.get()))) #on ouvre une nouvelle fenêtre avec le tableau représentant les données

def valide(test):
    return test.isdigit()

com_liv = Label(racine, text = "Afficher la commande d'un client (rentrez son ID)")
com_liv.place(x=900, y=130)
choix_com = racine.register(valide)
value = StringVar(racine)
entree = Entry(racine, textvariable = value, width = 30, validate = 'key', validatecommand = (choix_com,'%S'))
entree.place(x=865, y=170)
entree.bind("<Return>", num_commande)

Comme pour les produits, on récupère le numéro de la commande à l’aide de la méthode « .get() », mais cette fois-ci, uniquement lorsque nous validerons en appuyant sur la touche « Entrée » du clavier. Mais imaginons que lorsque notre employé utilise cette interface, il s’endorme sur le clavier ! Malheur ! Il faut redoubler de sécurité. C’est pour cela que dans cet input, on peut seulement y renseigner des chiffres, et cela, grâce à la fonction « valide » qui vérifie à chaque saisie si celui la est un chiffre.

Le Tkinter a pu grandement avancer grâce au tutoriel d’Aël D. sur Tkinter

Vous trouverez ci-dessous le projet, qui est en constante évolution :

Projets

Système de gestion de base de données relationnelle sur…

Venez découvrir tout au long de ce compte rendu comment nous avons créé un programme en python permettant à l’utilisateur d’interagir avec la base de donnée que nous avons créé.

Dans un premier, on a importé toutes les bibliothèques nécessaires à la création du programme.

from tkinter import *
from tkinter import ttk
import tkinter as tk
import sqlite3
import pandas
import os

La bibliothèque « tkinter » va servir à créer l’interface graphique ( vous pouvez en apprendre plus grâce à ce tutoriel, créé par Aël, élève en Spé NSI en classe de 1ère ).

La bibliothèque sqlite3 permet d’interagir avec une base de donnée.

La bibliothèque pandas permet de récupérer des données dans un ficher csv.

Et enfin la bibliothèque os permet de supprimer des fichiers dans le cadre de ce programme.

I. Création de la page d’accueil

Nous avons d’abord réfléchi à l’interface graphique que nous souhaitions réaliser.

Il nous fallait d’abord une page d’accueil, avec quatre boutons permettant d’effectuer les quatre fonctions nécessaires à l’utilisation d’une base de données : créer la base, lire la base, modifier la base, et enfin supprimer la base.

Le code ci-dessous permet de créer la page d’accueil, contenant un titre et 4 boutons.

window = Tk() # page d'accueil avec les 4 boutons

window.title("Gérer une base de donnée sur les jeux vidéos")
window.geometry("1280x1024")
window.maxsize(1280,1024)
window.config(bg="#7EBDC2")
window.iconbitmap("manette.ico")

titre = Label(window, text="4 boutons pour intéragir avec la base de données", font=("Consolas",20), bg="#d1fdff", fg="black")
titre.pack(pady=45)

boite = Frame(window, bg="#7EBDC2")
boite.pack(pady=200)

boutonC = Button(boite, text="CREATE", font=("Consolas",15), bg="white", fg="black", command=create, width=10, height=3)
boutonC.grid(row = 1, column = 0, padx = 15, pady=15)

boutonR = Button(boite, text="READ", font=("Consolas",15), bg="white", fg="black", command=read, width=10, height=3)
boutonR.grid(row = 1, column = 1, padx = 15, pady=15)

boutonU = Button(boite, text="UPDATE", font=("Consolas",15), bg="white", fg="black", command=update, width=10, height=3)
boutonU.grid(row = 3, column = 0, padx = 15, pady=15)

boutonD = Button(boite, text="DROP\n DATABASE", font=("Consolas",15), bg="white", fg="black", command=delete, width=10, height=3)
boutonD.grid(row = 3, column = 1, padx = 15, pady=15)

window.mainloop()

Visuel graphique :

II. Comment utiliser nos fonctions

Lier une interface graphique à des fonctions nécessite l’emploi de boutons.

Il nous fallait donc créer 4 fonctions permettant d’interagir avec la base de données.

A. La fonction create()

Nos fichiers à exploiter sont au format .csv. Avec la bibliothèque pandas, nous avons stockés les fichiers csv dans des variables pour pouvoir les exploiter.

ed = pandas.read_csv("relation_editeur.csv")
jv = pandas.read_csv("base_principale.csv")

Puis nous avons dû créer un fichier au format .db (Data Base).

connection = sqlite3.connect('base.db')
curseur = connection.cursor()

Nous avons créé les deux relations en indiquant les attributs et leur type.

curseur.execute("CREATE TABLE IF NOT EXISTS ED(Id_Editeur INTEGER, Editeur TEXT, PRIMARY KEY(Id_Editeur AUTOINCREMENT))")
curseur.execute("CREATE TABLE IF NOT EXISTS JV(Id_Jeu INTEGER, Jeu TEXT, Annee INTEGER, Prix FLOAT, Plateforme TEXT, Id_Editeur INTEGER, PRIMARY KEY(Id_Jeu AUTOINCREMENT), FOREIGN KEY(Id_Editeur) REFERENCES ED(Id_Editeur))")

Et enfin, nous avons créé deux boucles « for » pour ajouter les enregistrements des fichiers .csv dans la base de données automatiquement.

for i in range(len(ed)):
    data = [ed.loc[i, "Editeur"]]
    curseur.execute("INSERT INTO ED(Editeur) VALUES (?)", data)
    
for i in range(len(jv)):
    data = []
    data2 = list(jv.loc[i, ["Jeu", "Annee", "Prix", "Plateforme", "Id_Editeur" ]])
    data2[1] = int(data2[1])
    data2[4] = int(data2[4])
    data.append(tuple(data2))
    curseur.executemany("INSERT INTO JV(Jeu, Annee, Prix, Plateforme, Id_Editeur) VALUES (?, ?, ?, ?, ?)", data)

Pour finir, nous avons mis chacun de ces éléments dans une seule fonction : create(), appelée par le premier bouton de l’accueil. Nous avons décidé d’afficher une phrase pour indiquer à l’utilisateur que la base de données a bien été créé. Un simple Label nous a suffit (allez voir le tutoriel d’Aël pour plus de détails).

B. La fonction drop_database()

En SQL, la commande « DROP DATABASE » permet de supprimer la base de données. En python, il est impossible d’utiliser cette commande. On a donc importé le module os qui permet dans ce cas de supprimer un fichier.

Ainsi, la structure de la fonction drop_database() serait :

os.remove("base.db")

Cependant, si le fichier n’existe pas, tenter de le supprimer affichera, dans l’IDE python, un message d’erreur. Pour éviter ce problème, nous avons créé une variable globale « test » qui prend la valeur 0 si la base n’existe pas, et 1 si la base existe. Nous avons donc testé avec un « if » la valeur de « test », et le fichier ne sera supprimé que si « test » est égal à 1 et un message de confirmation s’affichera, sinon un message apparaît sur la fenêtre tkinter pour indiquer que la base n’existe pas, ce qui nous donne la fonction suivante.

def drop_database(): # supprime le fichier de la base de donnée s'il existe
    global test
    global message
    global texte
    
    if test == 1:
        os.remove("base.db")
        test -= 1
        supmes()
        message = "La base de donnée a bien été suprimée"
        texte = Label(window, text=message, font=("Helvetica",15), bg="#d1fdff", fg="black")
        texte.pack()
    elif test == 0:
        supmes()
        message = "La base de donnée n'existe actuellement pas"
        texte = Label(window, text=message, font=("Helvetica",15), bg="#d1fdff", fg="black")
        texte.pack()

C. La fonction read()

Pour la santé mentale de tout lecteur, nous ne montrerons pas ici l’intégralité de notre fonction (sinon, le fichier entier est téléchargeable en bas de page).

En SQL, pour sélectionner des éléments d’une base de données, on utilise la commande « SELECT Attribut_1, Attribut_2, … FROM DB ». En python, avec la bibliothèque sqlite3, la structure est exactement la même. Or il faut récupérer ce que contient le curseur et le stocker dans une variable, pour ensuite l’afficher. Par exemple, pour afficher tous les attributs d’une relation dans la console de l’IDE Python, on utilise :

curseur.execute("SELECT * FROM RELATION")
lecture = curseur.fetchall()#récupère les données obtenues par la ligne 1 en 'str'
print(lecture)

Lorsque l’on clique sur le bouton « read » de la page d’accueil, une nouvelle fenêtre tkinter apparaît. Sur cette fenêtre, on peut choisir de lire la relation principale (relation Jeux Vidéo), la relation secondaire (relation Editeurs) ou de retourner au menu, soit à l’accueil.

Le bouton « Retour Menu » supprime simplement la fenêtre, avec la commande tkinter :

window_r.destroy()

La lecture de la relation Editeurs est assez simple. En effet, la relation Editeurs ne contient que deux attributs : la clé primaire « Id_Editeur » et le nom de l’éditeur, « Editeur ». On a donc choisi de montrer par défaut toute la relation dans la même fenêtre que celle contenant les boutons de lecture, et donc supprimer les boutons. Nous avons donc dû globaliser nos boutons, afin de les supprimer ainsi :

global bouton
bouton.pack_forget()

Enfin, il a fallu sélectionner tous les éléments et les afficher dans un Label.

curseur.execute("SELECT * FROM ED")#fonction simplifiée
affichage = curseur.fetchall()
affiche = Label(text=affichage)#plus de détails sur le tutoriel
affiche.pack()

Pour finir, il nous a fallu afficher le contenu de la relation principale selon les demandes de l’utilisateur.

Pour cela, nous avons créé, grâce à des recherches supplémentaires sur internet, des checkbutton (des cases à cocher), qui peuvent être sélectionnés ou non pour choisir si l’on affiche l’attribut.

De plus, nous avons permis à l’utilisateur de choisir de spécifier sa demande avec la commande SQL « WHERE Attribut = Valeur ». Cela nous permet donc de faire une sélection très précise d’éléments à afficher.

D. La fonction update()

La dernière fonction à créer !

Modifier la base de données implique 3 actions : ajouter un enregistrement, supprimer un enregistrement, et modifier une valeur d’un des attributs de l’enregistrement.

Nous avons décidé qu’il était impossible, grâce à l’interface, d’ajouter directement un éditeur dans la relation « Editeur ». Ainsi lors de l’ajout ou de la modification d’un enregistrement de la relation Jeux Vidéo, si l’éditeur renseigné n’existe pas dans la relation correspondante, il y est créé. Cet ajout se fait simplement :

#Selon les spécificités de la bibliothèque sqlite3, avec "Editeur" renseigné par l'utilisateur
curseur.execute("SELECT Id_Editeur FROM ED WHERE Editeur = ?",(Editeur,))
temp = curseur.fetchall()
if temp == [] : #si l'éditeur n'existe pas
  curseur.execute("INSERT INTO JV (Editeur) VALUES (?)",(Editeur,))
  curseur.execute("SELECT Id_Editeur FROM ED WHERE Editeur = ?",(Editeur,))
  id_editeur = curseur.fetchall()#après ajout dans ED, on récupère l'Identifiant pour l'ajout dans JV

Pour la fonction ajouter(), nous avons créé 5 entrées correspondant aux valeurs du jeu à ajouter à la relation, et un bouton pour confirmer l’ajout.

Tant que le bouton de confirmation n’est pas cliqué, l’enregistrement n’existe pas dans la base de données.

Lorsque l’utilisateur confirme son ajout, une fonction ajouter_bis() est lancée, exécutant simplement :

valeur_1 = entree_1.get()
valeur_2 = entree_2.get()
valeur_3 = entree_3.get()
valeur_4 = entree_4.get()
#Id_Editeur récupéré par comme précédemment
data = (valeur_1, valeur_2, valeur_3, valeur_4, Id_Editeur)
curseur.execute("INSERT INTO JV (Jeu, Annee, Prix, Plateforme, Id_Editeur) VALUES (?,?,?,?,?)",data)

Ensuite, nous avons créé la fonction modifier(). Nous avons créé deux boutons permettant de modifier soit la relation Jeux Vidéo, soit la relation Editeurs.

Pour modifier la relation Editeur, on peut choisir l’éditeur à modifier soit par son Id_Editeur, soit par son nom actuel grâce à un bouton déroulant. Nous avons donc créé ce bouton déroulant et deux entrées correspondant d’abord au nouveau nom de l’éditeur, et ensuite à l’editeur à modifier. La commande SQL qui s’exécute est la suivante :

if bouton_attribut.get() == "Editeur"	
  curseur.execute("UPDATE ED SET Editeur = ? WHERE Editeur = ?",(entree_1.get(),entree_2.get()))
else :
  curseur.execute("UPDATE ED SET Editeur = ? WHERE Id_Editeur = ?",(entree_1.get(),entree_2.get())  

Si l’éditeur indiqué par son Id_Editeur ou son nom existe, alors l’enregistrement est modifié et un message de confirmation est affiché. Sinon il est indiqué que l’éditeur n’existe pas.

La fonction pour modifier un enregistrement de la relation principale est, dans les grandes lignes la même, mais l’utilisateur doit choisir l’attribut à modifier, avec un bouton déroulant. Ainsi :

curseur.execute("UPDATE ED SET Attribut_1 = ? WHERE Attribut_2 = ?",(entree_1.get(),entree_2.get())

« Attribut_1 » et « Attribut_2 » sont des valeurs fixes, testés par les boutons déroulants (demandant de nombreux tests « if » et « elif »)

Pour finir, il fallait pouvoir supprimer des éléments de la relation principale (la relation secondaire Editeurs ne peut que être lue ou modifiée). Deux attributs permettent d’identifier un jeu : son identifiant unique, et son nom (qui peut ne pas être unique). Pourtant nous avons choisi qu’il serait possible de supprimer un jeu grâce à son nom pour un utilisateur qui ne connaîtrait pas l’identifiant du jeu. Si le jeu indiqué par son Id_Jeu ou son nom existe, alors l’enregistrement est modifié et un message de confirmation est affiché. Sinon il est indiqué que le jeu n’existe pas.

Par la suite, quelque soit le choix de l’utilisateur, le fonction est le même : une entrée apparaît, dans laquelle il est possible de renseigner soit le jeu, soit l’id du jeu. Si le jeu indiqué par son Id_Jeu ou son nom existe, alors l’enregistrement est supprimé et un message de confirmation est affiché. Sinon il est indiqué que le jeu n’existe pas.

Nous avons donc créé les quatre fonctions pour interagir avec une base de données, soit la création, la lecture, la modification et la suppression de la base.

III. Conclusion

Ce compte-rendu touche maintenant à sa fin. N’hésitez pas à aller voir le tutoriel de Aël pour en apprendre plus sur la bibliothèque tkinter. Le fichier zip contenant tous les éléments nécessaires au bon fonctionnement du programme est disponible ci-dessous.

Projets

Agence de voyage et base de données

Une base de données sur des destinations paradisiaques tropicales. Consulter et réserver un voyage en exploitant une base de données dans python. L’interface utilisateur est gérée par tkinter

1 – Organiser les idées

Tout bon projet commence par un plan, afin de pouvoir poser et organiser l’idée de ce que l’on veut créer. Nous avons donc commencé par dessiner la base de notre projet :

2 – Création de nos tables

Une fois l’idée posée, il est temps de passer au programme !

Avant toute chose nous avons créé nos 4 tables et leurs attributs pour y ajouter après nos fichiers .csv créés à l’avance :

#création des tables
curseur.execute("CREATE TABLE IF NOT EXISTS DESTINATION (Id_Destination INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, Nom TEXT, Continent TEXT, Temp_Moy INT, Note INT)")
curseur.execute("CREATE TABLE IF NOT EXISTS CLIENT(Id_Client INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, Prenom TEXT, Nom TEXT, Lieu_depart TEXT)")
curseur.execute("CREATE TABLE IF NOT EXISTS VOL(Id_Vol INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, Id_Destination INT, Lieu_Depart TEXT, Date_Loc_Depart DATE, Heure_Loc_Depart TIME, Temps_Vol TIME, Prix INT, FOREIGN KEY (Id_Destination) REFERENCES DESTINATION(Id_Destination), FOREIGN KEY (Lieu_Depart) REFERENCES CLIENT(Id_Client))")
curseur.execute("CREATE TABLE IF NOT EXISTS RESERVATION(Id_Reservation INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, Id_Client INT, Id_Destination INT, Id_Vol INT, Num_Siege INT,FOREIGN KEY (Id_Client) REFERENCES CLIENT(Id_Client), FOREIGN KEY (Id_Destination) REFERENCES DESTINATION(Id_Destination), FOREIGN KEY (Id_Vol) REFERENCES VOL(Id_Vol))")
connection.commit()

Une fois les tables créées ont les a rempli avec les enregistrements contenus dans les fichiers .csv grâce au module panda:

#ajout des enregistrements .csv
pandas.read_csv("Client.csv").to_sql("CLIENT", connection, if_exists='replace', index=False)
pandas.read_csv("Destination.csv").to_sql("DESTINATION", connection, if_exists='replace', index=False)
pandas.read_csv("Vol.csv").to_sql("VOL", connection, if_exists='replace', index=False)
pandas.read_csv("Reservation.csv").to_sql("RESERVATION", connection, if_exists='replace', index=False)
connection.commit()

3 – La fenêtre d’accueil

A partir de là a commencé la création de la page d’accueil (dans les règles de l’art !)

Ici on définit l’aspect de notre fenêtre d’accueil, qui servira de modèle par la suite aux autres fenêtres.

#création de la fenêtre principale
window = Tk()
window.title("Agence de voyage : Partir un Jour sans Retour")
window.geometry("1080x720")
window.minsize(1080,775)
window.iconbitmap("island.ico")
window.config(background = "#B5D7F1")

Dans cette fenêtre on ajoute également 3 boutons, “destinations”, “réserver” et “supprimer son compte client” où les grandes actions s’effectuent.

4 – Fenêtre des destinations

Notre bouton destination mène donc à une fenêtre où les clients pourront découvrir les destinations proposées.

Les destinations sont d’abord triées par continent et rangées dans les boîtes correspondantes.

Ouvertes, ces boîtes affichent les destinations possibles du continent, rangées en tableau grâce à Treeview.

    tableau_europe = ttk.Treeview(boite_europe, columns=('Nom', 'Températures Moyennes', 'Note'), show = 'headings')
    tableau_europe.heading('Nom', text='Nom')
    tableau_europe.heading('Températures Moyennes', text='Températures Moyennes')
    tableau_europe.heading('Note', text='Note')
    
    for row in curseur.execute("SELECT Nom, Temp_Moy, Note FROM DESTINATION WHERE Continent = 'Europe' ORDER BY Nom"):
        tableau_europe.insert('', tk.END, values = row)
   
    tableau_europe.grid(row=0, column=0, sticky='nsew')

Nous avons ensuite utilisé Style() afin de personnaliser nos tableaux avec tous les attributs servant à les modifier comme sur l’image ci-dessous :

    #Style tableau europe
    
    tableau_europe = ttk.Style()
    #Prendre un theme
    tableau_europe.theme_use("clam")
    #configurer les couleurs du treeview
    tableau_europe.configure("Treeview",
        background = "#FEF3EA",
        foreground = "#206093",
        rowheight = 30,
        fieldbackground = "#FEF3EA"             
        )
    #Changer la couleur sélectionné par la souris
    tableau_europe.map('Treeview',
        background=[('selected', '#FFEE93')])

Ainsi qu’un bouton retour afin de fermer la boîte ouverte et de nouveau afficher les autres.

5 – Fenêtre réservation

Pour réserver un vol, il faut pouvoir choisir sa destination et s’inscrire dans la table Client.

Le plus simple a été de relier notre menu déroulant à la base de données. 

choix_destination = curseur.execute("SELECT Nom FROM DESTINATION")
    option_destination = OptionMenu(reservation, variable_destination, *choix_destination)
    option_destination.config(width=35, font=('Consolas', 12))

C’est au niveau du bouton de validation où cela s’est légèrement corsé.

Pas de soucis pour récupérer les textes entrés par l’utilisateur, ni son identifiant, qui constitueront son enregistrement dans la table Client.

        temp_client = (variable_prenom.get(), variable_nom.get())
        curseur.execute("INSERT INTO CLIENT(Prenom, Nom) VALUES (?,?)", temp_client)
        
        curseur.execute("SELECT MAX(Id_Client) FROM CLIENT")
        tempclient = curseur.fetchone()

C’est la récupération de l’identifiant de la destination qui aura posé le souci majeur puisque la donnée récupérée du menu déroulant se présentait comme un tuple sans en être un, enfin rien d’insurmontable un rien de bricolage suffit à régler le souci !

        temp_tempdestination = variable_destination.get()
        temp_bricodestination = (temp_tempdestination[2:-3],)
        curseur.execute("SELECT Id_Destination FROM DESTINATION WHERE Nom = ?", temp_bricodestination)
        temp_destination = curseur.fetchone()

On récupère également l’identifiant du vol

curseur.execute("SELECT Id_Vol FROM VOL WHERE Id_Destination = ?", temp_destination)
        temp_vol = curseur.fetchone()

Et une fois tous les attributs nécessaires à un enregistrement dans la relation réservation récupérés, on peut les y ajouter :

temp_reservation = (tempclient[0], temp_destination[0], temp_vol[0], randint(1, 600))
        curseur.execute("INSERT INTO RESERVATION(Id_Client, Id_Destination, Id_Vol, Num_Siege) VALUES (?,?,?,?)", temp_reservation)
        connection.commit()

6 – Fenêtre suppression de client

 Enfin si un client souhaite supprimer son compte nous avons la fenêtre “supprimer”.

Elle est composée d’une entrée utilisateur, où le client pourra renseigner son identifiant et d’un bouton “Valider” qui exécutera la suppression.

    def valider_suppression():
        temp_supprimer = variable_idclient.get()
        curseur.execute("DELETE FROM CLIENT WHERE Id_Client = ?", temp_supprimer)

Interface Tkinter réalisée avec l’aide du tutoriel d’Aël D.

Voici notre code compressé au format 7zip :

Boucle Tutoriels

Différentes utilisations de la boucle bornée for en Python…

Essayons de dompter le tigre… ou plutôt le serpent en l’occurrence. D’ailleurs en parlant d’occurrence, plongeons dans le monde pantagruélique de la programmation et voyons aujourd’hui la boucle for.

A – Mais qu’est ce qu’une boucle, et a fortiori une boucle for ?

Et non ce n’est pas une formule magique, mais presque !

Mais d’abord l’essentiel serait de savoir ce qu’est une boucle en Python puis ensuite de l’adapter à la boucle for (c’est for en chocolat).

Alors comment dire, quand votre petit frère vous énerve tout particulièrement et que vous ne voulez pas rester trop longtemps dans cette géhenne ni faire trop d’escarmouche, alors vous avez une option, non pas la fuite, mais faire tourner en boucle ce personnage qui hante éblouit vos vies.

En lui promettant quelque chose puis en retirant cette promesse, tout en le répétant à de multiples reprises, vous parvenez par la magie du langage, d’objectiver votre conscience, pour qu’ensuite elle l’atteigne au cœur même de sa subjectivité.

Le mal étant fait, profitez de votre œuvre ! Bravo, vous avec compris le concept de boucle et ici c’est une boucle infinie. Super Mince ! Bon, il manque quelque chose pour que la boucle fonctionne vraiment et soit exécutable, c’est à dire pour que ce chérubin fasse ce que vous voulez (sinon il va rester planté là).

Par exemple quand on a peur de vous entendre dire encore une fois que les personnes âgées n’utilisant pas leurs appareils mobiles à bon escient devraient être emprisonnées à vie sur l’île de la Pêche au Sirop, on va dire : « Avant de nous dire cette frivolité tu es priés d’exercer une rotation dans le sens trigonométrique, de ta langue en faisant 7 tours ».

Ainsi vous connaissez déjà les boucles, et ici en plus c’est une boucle for, trop for ! (elle était facile j’avoue)

Donc, vous voyez le cerveau est surprenant de plasticité, vous savez dorénavant quelque chose que vous ne pensiez pas savoir, alors que vous n’avez rien appris de nouveau.

Mais alors que veut dire le mot for, que nos congénères anglicans apprécient tant ?

Selon toute vraisemblance, la traduction la plus logique serait pour, ou bien sur.

Rentrons maintenant que nous appréhendons ces points importants dans le cœur du sujet, et je peux vous dire qu’on est pas sorti du sable.

Alors, il faut savoir qu’en Python (et nous ne parlerons que du Python même si certains éléments seront présents chez d’autres espèces, sélection naturelle oblige), la boule for est une boucle conditionnelle, c’est-à-dire que comme son nom l’indique, elle est soumise à une condition. C’est pourtant clair non ?

Il faut qu’une condition sine qua none se présente pour que la boucle arrête de boucler et que votre frère vous écoute donc on fera attention à cela pour que tout se passe bien.

Pour qu’elle s’arrête il faut aussi un début. Il peut être indiqué explicitement, ou implicitement avec le sens du code.

A savoir que for ne peut pas marcher tout seul comme un grand, il doit obligatoirement être associé à un parent majeur comme une variable ou certaines fonctions.

B – Les différents usages de la boucle for

1. L’association boucle for et fonction range()

Commençons par le plus classique des points, l’appairage avec la fameuse fonction range() !

Donc vous avez un code tel qu’il suit

for i in range(debut, fin, pas):
    # je fais des choses tralalalala

On retrouve donc la structure clé ; l’instruction for, et ensuite un bazar sans nom avec la fonction range().

Décryptons tout cela en partant de la droite.

Alors range() c’est tout bête, c’est juste une fonction qui va aller de la valeur entière donnée de départ à la valeur d’arrivée en répétant cette tâche un nombre certain de fois. Et les pas seront l’écart entre deux valeurs données.

Et en fait i sera une variable temporaire de la boucle automatiquement créée par Python pour récupérer la valeur de la fonction range car sinon elle se perd.

Ainsi si l’on résume, on va parcourir toutes les valeurs entre 2 entiers avec un pas donné !

Ainsi, résumons :

for i in range(42, 50, 2):
	print(i)

Donnera :

42
44
46
48

Car oui il manquait un détail, on ne prend pas la valeur finale, mais la valeur strictement inférieure comme dernière valeur.

Par conséquent, cette boucle peut s’écrire de différentes manières en fonction du niveau de raffinement voulu :

Mode auto :

for i in range(fin):
	# laziza

Ce mode a par défaut un pas de 1 et un début à 0.

Et ici :

for i in range(debut, fin):
	# laziza

Pareil que tout à l’heure sauf qu’on donne explicitement le début.

Et donc tout cela, c’est bien magique, mais voyons un cas concret pour mieux comprendre l’utilisation.

Imaginons que j’ai une liste de matières préférées, classée par ordre de préférence décroissant ; c’est-à-dire que la matière préférée sera en premier, etc…

J’ai donc une liste comme suit :

matieres_preferees = ["NSI", "Maths Expertes", "Maths", "Physique-Chimie", "Philo", "Ma LV2", "Enseignement Scientifique", "SES"] 

Je vais donc dire au grand jour l’ordre de mes matières :

for id_matiere in range(len(matieres_preferees)):
    print("La matiere", matieres_preferees[id_matiere], "est au rang", id_matiere + 1, "dans mon ordre de préférence")
    #ou bien :  print("La matiere {} est au rang {} dans mon ordre de préférence",.format(matieres_preferees[id_matiere], id_matiere + 1) 

En fait ici la fonction len, très utile, donne la longueur de la liste, on parcourt donc la liste de son id 0 (son premier élément), jusqu’à l’id juste inférieur à la longueur de la liste, soit l’id du dernier élément de la liste.

Pour l’affichage, on rajoute un 1 à l’id de la matière, pour donner le rang, car sinon le premier élément aurait le rang 0, peu parlant en langage franchouillard.

Ce code va donc rendre :

La matiere NSI est au rang 1 dans mon ordre de préférence
La matiere Maths Expertes est au rang 2 dans mon ordre de préférence
La matiere Maths est au rang 3 dans mon ordre de préférence
La matiere Physique-Chimie est au rang 4 dans mon ordre de préférence
La matiere Philo est au rang 5 dans mon ordre de préférence
La matiere Ma LV2 est au rang 6 dans mon ordre de préférence
La matiere Enseignement Scientifique est au rang 7 dans mon ordre de préférence
La matiere SES est au rang 8 dans mon ordre de préférence

Et voila vous savez parcourir des nombres à l’aide de for et de range !

2. Le parcours d’éléments autonome (sans valeur chiffrée)

Maintenant, reprenons l’exemple précédant, et affinons le un peu pour le rendre plus élégant.

On va s’avouer quand même que l’écriture de tout à l’heure pour dire l’ordre de nos matières préférées était un peu lourd, redondant, et inutile. Il faut en effet passer par la valeur chiffrée de l’id de l’élément sur la liste pour ensuite arriver à l’élément en lui même. Or, on a vu en philosophie que le fait de traduire sa pensée subjective vers quelque chose d’objectif, comme le langage ou ici la valeur chiffrée, trahissait notre pensée. Donc ce n’est pas bon car cela ne reflète pas exactement ce qu’on veut faire, il faut donc essayer de rester dans notre idée, sans devoir passer par un élément externe pour y arriver.

Or, c’est magique, Python a parfaitement compris cela et nous propose une solution quasiment optimale pour cela ; on parcourt la liste mais sans dire d’autres éléments en utilisant la structure suivante :

for elem in groupe_d_elem:
  	#tralalilala

L’écriture est très simple, et même enfantine, parce que littéralement on dit « Pour chaque élément dans le groupe d’éléments »

A savoir que la variable plus haut nommée elem sera automatiquement créée et mise à jour par Python pour chaque valeur ; rien à faire 😉 !

Donc revenons à notre exemple, cela va donc faire comme suit :

for matiere in matieres_preferees:
  	print("La matiere est :", matiere)

Ce qui rend donc après exécution :

La matiere est : NSI
La matiere est : Maths Expertes
La matiere est : Maths
La matiere est : Physique-Chimie
La matiere est : Philo
La matiere est : Ma LV2
La matiere est : Enseignement Scientifique
La matiere est : SES

On conviendra que c’est bien pratique a écrire et ce de façon simple mais, problème, on a perdu la numérotation des matières pour savoir l’ordre.

C’est là qu’arrive une fonction encore une fois bien pratique de Python ; enumerate.

3. Enumerate, notre sauveur

On reprend donc exactement ce qu’on a écrit tout à l’heure avec le parcours simple sans le range en rajoutant quelques petits détails :

for rang_matiere, matiere in enumerate(matieres_preferees, start=1):
  	print("La matiere est :", matiere, "au rang de preference :", rang_matiere)

Et là, magie, on retrouve notre rang tant manqué !!

La matiere est : NSI au rang de preference : 1
La matiere est : Maths Expertes au rang de preference : 2
La matiere est : Maths au rang de preference : 3
La matiere est : Physique-Chimie au rang de preference : 4
La matiere est : Philo au rang de preference : 5
La matiere est : Ma LV2 au rang de preference : 6
La matiere est : Enseignement Scientifique au rang de preference : 7
La matiere est : SES au rang de preference : 8

En fait ici Python va créer 2 variables ; la variable matière vu comme tout à l’heure et une variable rang_matière, qu’il incrémente à chaque fois de 1 au fur et à mesure du passage à la matière suivante. On lui indique même un bonne valeur de départ pour être certain qu’il parte du bon nombre comme vu tout à l’heure.

Donc si on résume, pour faire ce que l’on a fait c’est-à-dire afficher le rang et la matière deux options s’offrent à nous ; la méthode « Pattes d’Ours » grossière, brutale et peu élégante avec for et la fonction range, ou bien celle avec enumerate, ou la valeur donnée et l’objet sont tous deux présents dans des variables et donc plus facilement utilisables (pour des vérification par exemple avec des tests conditionnels).

En parlant de tests conditionnels d’ailleurs, on peut sortir de la boucle for au bout d’un certain moment si on veut en utilisant break.

Prenons ici notre même exemple et imaginons qu’on veut juste afficher le top 3 des matières, cela fait donc :

for rang_matiere, matiere in enumerate(matieres_preferees, start=1):
    if rang_matiere > 3:
        break
    else:
        print("La matière", matiere, "est au rang de preference :", rang_matiere)

Cela rend donc après exécution :

La matière NSI est au rang de preference : 1
La matière Maths Expertes est au rang de preference : 2
La matière Maths est au rang de preference : 3

Magique non ?

Bien sur, l’inverse est aussi possible avec continue, c’est-à-dire que même si quelque chose est vérifié, on ne sort pas de la boucle, on continue encore.

Passons maintenant à un autre côté magique de Python, une petite astuce sur les chaînes de caractères ; en effet pour lui, ces dernières sont comme des listes, on peut donc les parcourir de la même manière.

Ainsi la phrase :

phrase = "D'apres une etude de l'INSEE la totalite des gens ayant fait NSI en Premiere et en Terminale vivraient heureux et plus longtemps que les autres"

Donnerait ceci en faisant un petit booster pour n’afficher que les mots :

for id_lettre, lettre in enumerate(phrase):
    if lettre == " ":
        pass
    else:
        print(lettre, end="")
        if id_lettre == len(phrase) - 1 or phrase[id_lettre + 1] == " ":
          print("\n")

Cela donnerait donc :

D'apres

une

etude

de

l'INSEE

la

totalite

des

gens

ayant

fait

NSI

en

Premiere

et

en

Terminale

vivraient

heureux

et

plus

longtemps

que

les

autres

On remarquera ici encore quelques petites astuces sur les boucles for. Il y a tout d’abord le pass, qui permet de sauter une répétition si jamais il se passe quelque chose (ici s’il y a un espace), mais aussi les vérifications d’id de la phrase pour savoir si c’est la fin d’un mot ou non.

4. Un petit plus, l’usage de yield associé à la boucle for

yield en Python est un petit peu particulier. Pour le définir, on pourrait le qualifier comme un return, mais qui s’incrémenterait de 1 tout seul à chaque appel. Comme pour return, il ne peut donc être utilisé que dans une fonction.

Voyons un exemple pour mieux l’appréhender :

def nombre_ex():
    for i in range(40,43):
        print("Nouvelle valeur !")
        yield i

On associe donc à yield, la valeur de i comprise entre 40 et 42.

Si on appelle juste la fonction telle qu’elle dans un terminal Python, on obtient un retour étrange :

>>> nombre_ex()
<generator object nombre_ex at 0x100e2a490>

Etrange, la fonction n’est pas perçue comme une fonction, mais comme un générateur, et elle n’est pas exécutée ! C’est tout simplement parce que yield à la place de return joue la place d’un générateur, vu qu’il s’incrémente d’une valeur.

On peut donc utiliser la boucle for sur ce générateur :

temp_iter = nombre_ex()
for elem in temp_iter:
  print(elem)

Ce qui nous fait donc :

Nouvelle valeur !
40
Nouvelle valeur !
41
Nouvelle valeur !
42

C – L’instanciation d’un itération

1. L’itération d’un objet

Pour les adeptes de la POO (Programmation Orientée Objet), n’oublions pas qu’il existe une méthode, pour pouvoir rajouter à votre classe la possibilité d’être itérative selon votre volonté !

Il s’agit de la méthode __iter__ ; comme indiqué dans son nom, elle permet à votre classe de devenir … itérative !

Mais comment concrètement cela marche ?

Voyons déjà sa structure de base et son explication à l’aide d’un exemple neutre.

class maClasse:
    def __init__(self):
        #J'initie ma classe
    #[...]
    def __iter__(self): #autres arguments si voulu
        #Je retourne mon objet itératif
    def __next__(self):
        if condition is verifie:
      		#Je passe à l'élément suivant dans mon itération en suivant certaines conditions
        else:
            raise StopIteration #on stoppe l'itération si la condition n'est pas vérifiée
        
temp = maClasse("""Tartampion""")
for elem in temp:
    #Réaliser une action

Comme vous le voyez, comme pour les méthodes __init__, ou bien __str__ (qui permet d’utiliser la fonction print()), les méthode __iter__ et __next__ sont implicites. Sachez que l’on reconnait ces méthodes dites implicites mais qui sont bien utiles par la présence de doubles underscores (_) avant et après le terme de la méthode.

Ici __iter__ et __next__ sont au cœur même du concept d’itération pour Python. Et c’est ici qu’il faut comprendre quelque chose d’important dans le fonctionnement de for (que je n’exprime que maintenant supposant que si vous êtes ici, c’est que vous maîtrisez mieux tous les concepts de programmation de base).

En effet, pour fonctionner, la boucle for appelle à chaque fois la fonction iter(), sur l’objet sur lequel on est. En ajoutant une méthode __iter__ à notre objet, on le rend donc « itératif » et on fait donc fonctionner la fonction iter(), et ainsi la boucle for. Mais pour l’instant cette boucle va toujours afficher le même élément, car on n’a pas expliqué comment aller à l’élément suivant ; c’est ce qui se passe avec la méthode __next__, on explique à Python comment dans une boucle il pourra aller à l’élément suivant !

Donc voilà, on a pu créer un comportement itératif pour notre classe !

Mais attention, pour pouvoir le faire, il faut bien comprendre et assimiler le fonctionnement de cette dernière, en connaissant bien les conditions de passage d’un élément à l’autre ; en prenant en quelque sorte du recul sur notre objet, pour essayer de se le représenter virtuellement, au risque d’avoir quelques surprises !

2. Des objets itératifs dans des packages

Bien évidemment, vous vous en doutez, s’il est possible de réaliser l’itération dans ses propres classes, de grands packages de classes en sont dotés, comme par exemple le package os.

Ce package présente, comme son nom l’indique, tout ce qui est en lien avec l’OS (ou système d’exploitation en français). Or dans un ordinateur, il y a quelque chose qu’on peut avoir besoin dans un programme Python, qui est présent en nombre et souvent très mal rangé. Et oui, il s’agit des documents présents dans des « directories » (ou dossiers), que la boucle for permet donc aisément de parcourir, comme suit avec ce petit exemple très simple :

import os

for filename in os.listdir("un_dossier/mon_directory/"):
    print(filename)
    if filename.endswith(".py"):
        print("Ohhh un fichier Python !!")

Comme vous le voyez, on a itéré sur les fichiers de notre directory à l’aide de cette classe (qui fonctionne moyennement sur Linux, attention), et cela est faisable sur toute classe sur laquelle le développeur en a laissé la possibilité.

Conclusion

Et voilà, vous êtes enfin arrivés au terme de ce tuto plutôt didactif, votre calvaire et enfin terminé !

Dans tout les cas j’espère que celui-ci vous aura été aussi utile à vous qu’à moi, me permettant de découvrir des talents cachés de la boucle for que je ne vais cesser d’utiliser.

La programmation et l’algorithmique prennent aujourd’hui une place toujours plus prépondérante dans nos vies, et cela ne va cesser de s’accroître. Maîtriser ces concepts de base autour de la programmation peut vous permettre de mieux appréhender ce nouveau domaine en pleine croissance, et ainsi de vous rendre compte qu’il est beaucoup plus éloigné des geeks solitaires à lunettes que vous pensiez, mais plutôt le fruit de logique, d’expériences, d’idées, et de savoir ; se rapprochant en fait d’une logique algorithmique ; mathématique.

Maintenant la boucle for n’aura (presque) plus de secrets pour vous en Python !

Tux, mascotte de Linux Tutoriels

Comment adopter Linux sans perdre son utilisation de Windows

Vous êtes heureux car Windows 11 est sorti, à vous les toutes dernières nouveautés, une nouvelle fenêtre s’ouvre sur votre vie et votre avenir, vous êtes encore plus heureux que le 25 au matin quand vous ouvrez vos cadeaux. En effet, aujourd’hui c’est un jour de fête, vous allez enfin pouvoir avoir le design tant voulu de macOS Big Sur, avec ses bords si arrondis, ses effets transparents, son Dock centré, et même son mode sombre !

Sauf que le joug du marketing et de l’obsolescence programmée vient de tomber. Vous êtes déjà trop vieux, à moins que ce soit les composants de votre PC… Votre Ryzen 5 de première génération qui marche à la perfection et parvient même à faire tourner le Démineur n’est pas accepté dans les nouvelles conditions d’installation de Windows 11, contrairement à un Intel Atom qui lui, est mis à jour.

C’est alors que descendu du ciel, vous voyez apparaître comme un oiseau de bonne augure (sauf qu’il ne vole pas, la faute à la sélection naturelle mise en exergue par Darwin), …, un pingouin !

Mais ce pingouin est particulier parce qu’au fin fond de son iris, vous pouvez voir un Gnou ?!

C’est alors que votre cerveau a un déclic ! Mais oui, il s’agit de GNU/Linux, un système d’exploitation à part entière !

Mais bon, à quoi ça sert d’installer des distributions Linux, elles sont avariées et vieillottes.

C’est alors qu’au détour d’une recherche sur l’Internet, vous apprenez que Linux est utilisé par des milliards d’appareils dans le monde, que ce soit dans les serveurs, ou alors dans tous les appareils mobiles, que ce soit les fruits ou les sucreries à la voix robotique.

Alors, si on laissait une chance à Linux ? (à moins que ce soit Linux qui nous laisse une chance)

Début sur Linux ou qu’est-ce-qu’un gestionnaire de paquets

Pour la suite du tutoriel, j’utiliserai la distribution Linux nommée Manjaro avec comme interface de bureau KDE Plasma ; il existe d’autre distribution toutes aussi nombreuses, comme les plus connues Ubuntu avec son interface de bureau Gnome, qui est tiré de Debian et que je vous recommande d’utiliser de par sa facilité.

Mais alors pourquoi est-ce que j’utilise Manjaro ?

C’est très simple, car cela me permet d’interagir avec PacMan, mais aussi pour pouvoir me vanter car cette distribution Linux est basée sur Arch, (ce même est en référence à l’apparente complexité d’utilisation d’Arch, qui était réputée à son départ extrêmement dure).

Mais donc cette histoire de PacMan, d’où ça vient ?

C’est très simple : Sur Windows vous allez avoir le Microsoft Store, et sur vos téléphones, l’App Store ou bien le Google Store, et bien, en quelque sorte, sur Linux il existe ce que l’on appelle des dépôts (ou gestionnaires de paquets) qui jouent à peu près le même rôle (bien qu’il existe des alternatives directes au Microsoft Store sur Linux, mais nous en reparlerons peut-être).

Et donc pour utiliser ces dépôts, pas d’interface graphique disgracieuse, non on utilise le terminal, cette boîte noire qui s’ouvrait discrètement quand un virus essayait d’accéder à vos données sur le bon vieux Windows.

Et donc pour donner l’ordre à des fichiers issus du dépôt de s’installer, on utilise pacman sur les distributions Arch par exemple, ainsi que apt-get sur Debian/Ubuntu (il en existe d’autre mais je ne parlerais que de ces deux là, les plus réprésentatives).

Pour pouvoir télécharger des paquets, il faut passer en super-utilisateur en précédant la commande pacman ou apt-get du fameux sudo (rien avoir avec le sport traditionnel japonais) ; c’est une sorte de mode Admin de Linux.

Bien, maintenant rentrons dans le cœur du sujet, si vous voulez bien installer Linux, vous souhaitez surtout pouvoir utiliser tout ce que vous faisiez avant avec le moins de problèmes possibles.

Et alors, bonne nouvelle, aujourd’hui tout passe par le Web, et vous avez par défaut installé le navigateur Firefox qui marche comme sur sa version Windows !

Donc c’est bon le problème est réglé, on peut utiliser la Suite Office en ligne, du cloud, du cloud gaming, toute la suite Google, etc… C’est super !

Conclusion

Ce tutoriel est fini, merci beaucoup de l’avoir suivi jusqu’au bo…

Les drivers, la clé de voûte du fonctionnement idéal d’un OS

Sauf que non ! Plusieurs problèmes se posent, même si la majorité de nos besoins est en ligne aujourd’hui, certains logiciels, ou drivers peuvent nous êtres nécessaires ou ne pas être présents en ligne, il faut donc plus aller en profondeur en commençant par les drivers pour imprimer, utiliser la connexion sans fil, etc…

Avant d’aller plus loin, la plupart des logiciels exprimés par la suite seront open-source et libres (par volonté). En effet, si l’on passe sur Linux qui est un logiciel open-source, c’est à dire dont le code est visible est modifiable par n’importe quel individu, ce qui crée une communauté d’entraide, beaucoup plus soudée que sur d’autres OS. Ainsi si vous avez le moindre problème, n’hésitez pas à demander à ces communautés qui vous répondront avec plaisir. De même et c’est un avantage indéniable, la plupart des solutions fournies qui sont donc open-source sont gratuites (vous pouvez bien sûr, et ça ne peut être que positif, faire des dons à ces fournisseurs de solutions logicielles pour les remercier dans leur dur travail). C’est toute cette éthique qui fait le cœur de Linux et que je trouve très intéressante.

Bien, revenons à nos moutons. Pour la connexion Wifi ou Bluetooth, ne croyez pas que Linux c’est l’âge de pierre ! Cela marche aussi aisément que sur Windows ou tout autre OS dans les paramètres.

Par contre pour des drivers, ça devient plus dur, prenons par exemple les imprimantes.

La plupart des imprimantes que nous avons aujourd’hui sont Bluetooth ou marchent en réseau local. Lorsque le PC que j’utilisais était encore sur Windows, les impressions buggaient à chaque fois et j’étais obligé de me connecter en filaire à l’imprimante, une galère.

Et bien sur Linux, tout est transparent et marche excellemment bien.

Prenons un exemple. Je possède une imprimante et plus particulièrement, une HP Envy, donc malheureusement il n’existe qu’un driver propriétaire pour qu’elle fonctionne.

Une fois dans les paramètres on clique donc sur Imprimantes

Puis arrive le moment du choix, étant connecté au Wifi, mon imprimante est découverte en réseau :

Il ne me suffit plus qu’à la sélectionner, et à installer le pilote.

En l’occurence celui-ci pour mon imprimante HP.

Une fois cela fait le driver est installé et magie l’impression marche du premier coup sans aucun réglage extérieur (contrairement à Windows).

Maintenant qu’on sait imprimer, on voudrait aussi regarder du contenu en streaming sur Netflix, Disney+, Apple TV+ ou encore Amazon Prime. Sauf que vous le savez peut-être mais ces vidéos ne vous appartient pas, elles vous sont juste « prêtées » en quelque sorte le temps du visionnage. Et bien pour éviter durant votre visionnage que vous ne voliez le contenu de cette vidéo (en faisant un enregistrement d’écran par exemple de tout le film), il existe ce qu’on appelle des DRM, c’est-à-dire grosso modo des sécurités (pas open-source du tout) qui vous empêche de filmer ou d’enregistrer tout contenu issu de ces vidéos. C’est d’ailleurs pour cela que si vous prenez une capture d’écran de votre smartphone par exemple en train de regarder une vidéo en streaming, la seule chose que vous verrez c’est un écran noir et rien de plus.

Sur Linux ces DRM ne sont par défaut pas activées, et vu que les services de streaming s’accèdent tous par le Web, c’est sur un navigateur comme Firefox qu’il faudra les imprimer.

Pour ce faire, rien de plus simple : Prenons l’exemple de Netflix.

Après s’être connecté à son compte sur le navigateur, une petite notification apparaît en haut de la page, comme suit :

Pour les utiliser, il suffit donc tout simplement de cliquer sur « Activer les DRM ». Après un petit chargement ça marche !

Super donc on peut regarder des vidéos en streaming sur Linux !

On a d’ailleurs presque fini avec tous les drivers, il n’en manque plus qu’un, le plus critique et le plus important, le driver de la carte graphique.

Il faut savoir que lors de l’installation, la plupart des distribution Linux installent le pilote graphique nécessaire pour votre carte graphique (en la détectant de façon autonome et automatique), ces pilotes sont donc open-source, mais il peut arriver que pour certains usage il faille utiliser le pilote issu du constructeur surtout pour les cartes graphiques Nvidia. Dans ce cas, rien de plus simple, il suffit de se rendre sur le site du constructeur et de télécharger le driver compatible Linux adapté pour sa carte graphique Nvidia, dont voici le lien.

Pour vérifier que ses drivers open-source sont bien installés, on peut se rendre dans les paramètres et vérifier automatiquement les drivers adaptés aux composants :

On clique ensuite pour vérifier, et magie les composants sont installés (ou mis à jour le cas échéant). Pour la faible puissance de mes composants, cela rend ça :

Maintenant que la plupart des composants sont au point et tournent sans aucun problème (et surtout la carte graphique), pourquoi, alors ne pas envisager de jouer.

Jouer sur Linux ?!

Et oui, car Linux permet aujourd’hui à ses utilisateurs de jouer à des jeux triples A, comme à des Open-World optimisés pour Linux et même mieux car on peut faire tourner des jeux seulement jouables sur Windows !

Tout cela se passe grâce au launcher Steam, que l’on peut préinstaller lors de l’installation de sa distribution Linux. Sinon, il suffit sur Debian/Ubuntu d’entrer dans le terminal la commande « sudo apt-get install steam » et de suivre les instructions, ou sous Arch d’écrire la commande « sudo pacman -S steam ». Si vous êtes sur d’autre OS, ou encore sur ces derniers et que le terminal vous fait peur, ouvrer la Bibliothèque d’installation de logiciels (qui a un nom différent à chaque distribution) et recherchez puis installez Steam.

Une fois cela fait, il suffit de l’ouvrir, et de se connecter à son compte. Vous retrouvez alors votre bibliothèque de jeux que vous pouviez avoir utilisé et acheté sur Windows. Et bonne nouvelle la plupart marcheront sur Linux !

En effet nombreux sont ceux qui ont été optimisés pour Linux ! Mais comment le savoir ?

C’est très simple, c’est ceux qui en plus d’avoir le logo Windows (et hypothétiquement macOS si le jeu tourne sur cet OS) ont le logo de Steam, comme sur l’exemple ci-dessous :

Il suffit juste de l’installer pour y jouer !

En revanche, il s’avèrent que certains jeux sont optimisés seulement pour Windows (ou macOS), on ne peut donc supposément pas y jouer :

Quel dommage, je ne peux pas jouer à The Witcher 3

Si on clique pour y jouer quand même, on a une erreur d’exécution qui est assez claire :

Le système nous dit que l’on est sur une plateforme invalide !

C’est alors qu’arrive Steam Play avec Proton. Steam Play permet dans Steam de faire tourner la plupart des jeux Windows grâce à Proton. Il faut savoir que Proton est basé sur Wine, vous verrez nous y reviendrons…, et qu’il n’émule pas Windows, il permet de faire tourner en natif les jeux Windows, avec donc moins de perte de performances.

Pour les jeux Windows qui ont été testé (donc souvent les plus grosses ventes / succès) Steam Play est activé par défaut. En revanche, on peut souhaiter jouer à des jeux qui n’ont pas été testé et qui n’activent donc pas par défaut Steam Play.

Pour l’activer dans tous les cas il suffit de se rendre dans les paramètres :

On remarque que par défaut Steam Play est activé pour les « jeux supportés », il suffit de cocher « Activer Steam Play pour tous les autres titres » pour que cela marche dans la plupart des autres cas, et de dire d’exécuter ces jeu avec la dernière version de Proton (6.3-8 dans mon cas), ou la version bêta, pour être sur que le plus de jeux possible fonctionnent !

Une app Windows sur Linux ? Ceci n’est pas un émulateur !

Tout à l’heure j’ai évoqué Wine, un acronyme pour « Wine Is Not an Emulator », lui même un acronyme pour « Wine Is Not an Emulator »… (vous avez compris le petit clin d’œil récursif). Et bien, sachez que ce logiciel très ancien permet de faire tourner nombre d’applications Windows sous Linux ! Magique, au moins les applications que vous utilisiez jadis et qui ne sont pas optimisées pour Linux peuvent être utiles en utilisant ce logiciel magique.

On va installer deux composants ici, Wine donc, mais aussi PlayOnLinux, qui n’est d’autre qu’un solution graphique pour Wine, pour ceux qui sont frileux d’utiliser le terminal et de se débrouiller seuls.

Pour installer Wine, rien de plus simple : Sur Debian/Ubuntu, c’est : « sudo apt-get install wine », et sur les distributions Arch : « sudo pacman -S wine » ; vous avez compris la mécanique ! Pour tous les autres, ça se passe sur votre bibliothèque d’app à moins de connaître la commande pour utiliser votre dépôt.

De même pour PlayOnLinux, ou la commande Debian est : « sudo apt-get install playonlinux » et pour Arch : « sudo pacman -S playonlinux ». On peut aussi retrouver cette app dans la bibliothèque d’app.

Ensuite, pour utiliser les fonctionnalités de Wine, il suffit de télécharger un fichier .exe et de l’exécuter depuis le gestionnaire de fichier (Clic droit / Ouvrir avec Wine). S’il ne manque pas des bibliothèques, alors l’exécuteur de l’app s’ouvrira et vous pourrez procéder à l’installation.

Par exemple, l’émulateur Casio 90E+ disponible uniquement sur Windows et macOS, tourne parfaitement sur Linux :

On retrouve ici l’utilitaire d’installation qui va installer l’app dans une zone de Linux, ou le format des dossiers de Windows est reproduit.

L’installation finie, Wine crée un lien de cette app vers votre bureau et vous pouvez l’utiliser !

En revanche, certaines grosses apps comme par exemple celle de la suite Adobe, peuvent nécessiter l’installation de composants externes, c’est pour cela que pour ce genre d’app, je vous recommande de passer par PlayOnLinux qui possède pour les apps les plus usités, un installateur adapté qui en plus d’installer l’exécutable avec Wine, va aussi installer tous les composants externes nécessaires. Pour ouvrir PlayOnLinux, il suffit de taper dans une page de terminal la commande : « playonlinux » et l’app s’ouvrira :

Il suffit ensuite de cliquer sur Installer pour choisir les apps à installer, logique !

Et voilà vous pouvez ensuite indiquer les apps que vous souhaitez avoir et, sous réserve d’avoir le .exe de l’app, vous pourrez lancer l’installation. Bien évidemment certaines apps ne marcheront malheureusement pas, si c’est le cas, faites un tour sur les communautés de Wine et de PlayOnLinux, pour savoir si le problème est connu ou non, ou si une solution alternative existe.

Conclusion « brève » mais intéressante

Bien ce tutoriel touche bientôt à sa fin et vous vous disez que l’on n’a toujours pas évoqué l’essentiel. En effet je suppose que les seules apps nécessaires aujourd’hui possèdent toutes des alternatives open-source comme Libre Office par exemple en opposition à l’Office de Microsoft, mais je ne souhaitais pas faire une liste exhaustive trop redondante de toutes ces apps, si vous en avez besoin, libre à vous de faire des recherches pour trouver ces alternatives, qui sont très connues et souvent aussi pratiques et puissantes que leurs cousines privées. Encore mieux certaines apps comme Blender par exemple pour la modélisation 3D sont open-source et sont leaders dans leur domaine ; tout le monde les utilise ! Alors bien évidemment, des versions Linux existent. L’essentiel étant de savoir ce que l’on a besoin (par exemple un logiciel de traitement de texte) et de taper sur votre moteur de recherche favori « alternative Linux [Nom de l’app privée] ». Bien sur, s’il n’existe pas d’alternatives pour vos besoins, tournez vous vers Wine, il y a de forte chance que cela fonctionne.

Linux au fil de ces années s’est beaucoup démocratisé, de part la volonté des individus à avoir plus de contrôle sur leur vie privée, leurs données, plus de possibilité de modularité, etc… tous les désavantages d’OS payants comme Windows. C’est donc forcément que des alternatives ont vu le jour par des passionnés qui voulaient que cela corresponde exactement aux besoins de la communauté.

Un seul bémol si je puis dire sur ces alternatives, qui est dans les idées reçues autour de Linux, est le design des logiciels, souvent très vieillot. Et bien c’est vrai, ce n’est pas qu’une idée reçue, mais cela tend à changer de part la volonté des utilisateurs. De même la communauté open-source se développe, même à l’aide d’acteurs privés, Apple s’est très récemment engagé auprès Blender pour l’aider dans son développement aussi bien économique que logiciel, soutenant cette communauté open-source (et permettant d’avoir plus d’amélioration de Blender pour son système).

Nous sommes donc arrivés à la fin, j’espère que cela vous aura convaincu d’installer et d’utiliser Linux au lieu de Windows, car vous avez vu que vous n’aurez pas à drastiquement changer votre utilisation, grâce aux solutions mises en place par des passionnés, car après tout l’humanité n’est-elle pas que le fruit d’échange entre les individus, ce que l’on retrouve dans l’essence même de Linux et de l’open-source.