PyPaint - MissonO/Dev-II-2023 GitHub Wiki

Vidéo de présentation d'août :

Vidéo

Le titre "script en ligne de commande" n'est pas bon, il s'agit du nom de la réunion que j'ai utilisé pour mes enregistrements.

scriptOO1.mp4

PyPaint

Pypaint est une application de dessin sur canva blanc. Elle permet de dessiner ce que l'on souhaite avec sa souris en utilisant un pinceau ou bien un spray. Si une erreur est commise, l'utilisateur peut effacer son trait. La taille du trait ainsi que la couleur sont personnalisable et une fois fini, l'utilisateur peut enregistrer son dessin en format jpeg, png ou gif au nom choisit et dans le dossier souhaité.

Exemple de dessin fait sur l'application

image

Lien de téléchargement de l'application

Application orienté objet

L'application PyPaint est séparée en plusieurs classes ayant chacune une fonction bien précise et pour certaines des classes dérivées qui héritent des propriétés de la classe parent.

Classes de l'application :

  • Brush
    • PencilBrush
    • SprayBrush
    • EraserBrush
  • Canvas (hérite de tk.Canvas)
  • DrawingApp
  • Buttons (hérite de tk.button)
    • EraserButton
    • SizeButton
    • SprayButton
    • ColorButton
    • SaveButton
Diagramme de classe UML

image

Août : Programmation par contrat :

Afin de répondre à la compétence ANALYSE3, j'ai intégré des PRE, POST et RAISE dans le code.

Exemple pour draw :

def draw(self, event):
        """
        Draw on the canvas
        PRE: event is a tkinter event with x and y coordinates
             self is an instance of Canvas with eraser_mode,
             brush_size and current_brush
        POST: the brush draws on the canvas on the selected x and y coordinates
              self.current_brush is updated
        RAISE: tk.messagebox.showerror if an error occurs
        """
        try:

            # Récupère les coordonnées de la souris
            x, y = event.x, event.y

            # Si le mode gomme est activé, on utilise le pinceau gomme
            if self.eraser_mode:
                self.current_brush = EraserBrush(self, size=self.brush_size)
            # Sinon, on utilise le crayon
            elif isinstance(
                self.current_brush,
                PencilBrush
            ) and not self.eraser_mode:
                self.current_brush = PencilBrush(self, size=self.brush_size)
            # Sinon, on utilise le  spray
            elif isinstance(
                self.current_brush,
                SprayBrush
            ) and not self.eraser_mode:
                self.current_brush = SprayBrush(self, size=self.brush_size)

            self.current_brush.draw(x, y)

        except Exception as e:
            tk.messagebox.showerror(  # type: ignore
                "Error",
                f"An error occurred: {str(e)}"
            )

De plus, des arguments ont été ajouté avec argparse afin de pouvoir changer manuellement la couleur du canva lors du lancement de l'application.

Fichiers

pypaint.py :

Fichier principal de l'application qui utilise la librairie tkinter afin de créer une interface graphique et utilise DrawingApp pour créer l'application.

drawing_app.py :

Utilise la librairie tkinter pour initialiser l'application de dessin. Le fichier contient la classe DrawingApp qui définit la fenêtre de dessin de l'utilisateur. La classe utilise des boutons ainsi que le canvas importés des fichiers canvas.py et buttons.py. De plus, la classe a une fonction qui met à jour l'indicateur de la taille du pinceau en allant le chercher dans le canvas.

canvas.py :

Définit le canvas utilisé pour dessiner ainsi que l'utilisation des différents outils utilisés pour dessiner. La fonction draw(self, event) "imprime" sur le canvas ce que l'on souhaite dessiner en fonction du pinceau qui est utilisé. Les autres fonctions sont la pour activer et définir des variables utilisées dans le dessin.

buttons.py :

Boutons affichés

image

Le fichier contient la classe Button principale qui définit un bouton et les différentes sous-classes qui en héritent. La classe Button crée le bouton classique avec sa couleur lorsqu'il est sélectionné et une fonction pour désélectionner les autres boutons lorsqu'un est cliqué.

La classe EraserButton(button) est utilisée pour la gomme. Pour l'activer il faut cliquer sur le bouton et la désactiver recliquer dessus.

La classe SizeButton(button) permet de changer la taille du trait via une fenêtre de sélection.

Fenêtre de sélection

image

La classe SprayButton(button) active le spray.

La classe ColorButton(button) permet de changer la couleur du trait via une interface de sélection.

Fenêtre de sélection

image

La classe SaveButton(button) permet de sauvegarder le dessin fait sur le canva via la fonction save_image qui utilise la librairie PIL.
Enregistrement

image

brushes.py :

Le fichier contient les classes de pinceaux avec une classe parent nommée Brush qui définit le pinceau de base.

La classe PencilBrush(Brush) est utilisée pour le pinceau classique qui dessine un cercle de taille x sur le canvas.

La classe SprayBrush(Brush) est utilisée comme spray. A chaque appel de la fonction draw des points sont envoyés aléatoirement sur le canva dans la zone de taille choisie.

La classe EraserBrush(Brush) est utilisée comme gomme. Elle dessine en blanc sur le canva.

Testing, linter et CI/CD

Testing

L'application est testée avec des tests unitaires via pytest. Les différentes fonction sont testées avec un code coverage général de 83%.

Code coverage

image

Linter

Fluke8 est utilisé afin de maintenir une cohésion et structure dans le code. En plus d'une vérification dans l'environnement de programmation (VSCode), une vérification est faite lorsque le code est envoyé sur Github.

CI/CD

Un workflow Github est mis en place avec l'aide de Github actions et certaines modifications ma part pour vérifier du bon fonctionnement de l'application lorsque celle-ci est push sur Github.

Le workflow se compose de :

  • Set up jobs
  • Run actions/checkout@v3
  • Set up Python 3.10
  • Install dependencies
    • Les dépendances sont centralisées dans un fichier nommé requirements.txt
  • Run flake8
  • Test with pytest
  • Post Set up Python 3.10
  • Post Run actions/checkout@v3
  • Complete job
⚠️ **GitHub.com Fallback** ⚠️