Contents

Een schilderapplicatie maken met Python

Een eenvoudig verfgereedschap is een van de meest gebruikte apps op de meeste computers. Je kunt er zonder angst fouten mee maken, met één klik op de knop een kleur kiezen en de grootte van je penseelstreken direct aanpassen. Je kunt het gebruiken om merklogo’s te maken, gebruikersinterfaces te conceptualiseren en diagrammen te annoteren.

Op welke manier kun je een schildersoftwareprogramma maken?

De modules Tkinter en Pillow

Om een schildertoepassing met Python te ontwikkelen, moeten zowel de modules Tkinter als Pillow in het systeem geïnstalleerd zijn. Het Tkinter raamwerk is een van de meest populaire keuzes als het gaat om het ontwerpen van grafische gebruikersinterfaces (GUI) voor Python-gebaseerde desktopapplicaties. Dit framework biedt een breed scala aan ingebouwde widgets zoals labels, tekstvakken, doeken en knoppen waarmee ontwikkelaars snel en eenvoudig visueel aantrekkelijke en interactieve interfaces kunnen maken.

Pillow, een afgeleide van de eerbiedwaardige Python Imaging Library (PIL), dient als een veelzijdige beeldverwerkingstoolkit voor Python-toepassingen. Door gebruik te maken van de mogelijkheden zijn gebruikers in staat om verschillende bewerkingen uit te voeren op digitale visuele media, zoals het openen, verkleinen, roteren en bijsnijden van afbeeldingen. Daarnaast vergemakkelijkt deze bibliotheek formaatconversie, maakt het de ontwikkeling van complexe algoritmen mogelijk, zoals aanbevelingssystemen voor recepten, en biedt functionaliteit om willekeurig afbeeldingen uit een database te halen.

Voer het volgende uit om deze modules te installeren:

 pip install tk pillow 

De structuur van de Paint-toepassing definiëren

De volledige broncode voor dit project is beschikbaar op onzeGitHub repository, waartoe u toegang kunt krijgen door te navigeren naar de bovenvermelde URL.

Om te beginnen importeren we de benodigde modules. Vervolgens maken we een instantie van de klasse DrawApp en stellen we de eigenschappen in, zoals de titel van het venster, de kleur van de aanwijzer en de kleur van de gum. We zullen er ook voor zorgen dat de applicatie opent in volledig scherm modus door de setup_widgets() methode aan te roepen.

 import tkinter as tk
from tkinter.ttk import Scale
from tkinter import colorchooser, filedialog, messagebox
import PIL.ImageGrab as ImageGrab

class DrawApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Kids' Paint App")
        self.root.attributes("-fullscreen", True)
        self.pointer = "black"
        self.erase = "white"
        self.setup_widgets()

Om een interface met widgets te maken, maak je een functie met de naam setup_widgets . Genereer in deze functie een gelabelde component die een titel weergeeft door de ouderlijke relatie, het bericht dat moet worden weergegeven, de lettertypeconfiguratie, de achtergrondkleur en de tint van de tekstinhoud op te geven. Construeer bovendien een kader rond een kleurkeuzepaneel door verantwoordelijkheden toe te wijzen zoals het definiëren van het ouderelement, het opschrift dat moet verschijnen, de lettertype-instellingen en de randafmetingen.Configureer ten slotte de grens met een reeks golvingen en stel de achtergrondtint in op wit.

     def setup_widgets(self):
        self.title_label = tk.Label(
            self.root,
            text="Kids' Paint App",
            font=("Comic Sans MS", 30),
            bg="lightblue",
            fg="purple",
        )
        self.title_label.pack(fill=tk.X, pady=10)
        self.color_frame = tk.LabelFrame(
            self.root,
            text="Colors",
            font=("Comic Sans MS", 15),
            bd=5,
            relief=tk.RIDGE,
            bg="white",
        )
        self.color_frame.place(x=10, y=80, width=90, height=180) 

Maak een lijst om een reeks kleuren voor het kleurenpalet te definiëren. Gebruik iteratie om voor elke tint een knop te genereren, rekening houdend met de bijbehorende RGB-waarde. Specificeer de bovenliggende container, achtergrondkleur, randdikte, stijleigenschappen en breedte voor elke knop. Bepaal bovendien de actie die wordt uitgevoerd als er op elke knop wordt geklikt. Rangschik alle onderdelen met geschikte marges en rangschik de kleuren in paren.

         colors = [
            "blue",
            "red",
            "green",
            "orange",
            "violet",
            "black",
            "yellow",
            "purple",
            "pink",
            "gold",
            "brown",
            "indigo",
        ]
        i, j = 0, 0
        for color in colors:
            tk.Button(
                self.color_frame,
                bg=color,
                bd=2,
                relief=tk.RIDGE,
                width=3,
                command=lambda col=color: self.select_color(col),
            ).grid(row=i, column=j, padx=2, pady=2)
            i \\+= 1
            if i == 4:
                i = 0
                j = 1 

Laten we op dezelfde manier knoppen afbakenen voor de gum, een om het scherm schoon te maken en een om de illustratie te bewaren.

         self.eraser_btn = tk.Button(
            self.root,
            text="Eraser",
            bd=4,
            bg="white",
            command=self.eraser,
            width=9,
            relief=tk.RIDGE,
            font=("Comic Sans MS", 12),
        )
        self.eraser_btn.place(x=10, y=310)
        self.clear_screen_btn = tk.Button(
            self.root,
            text="Clear Screen",
            bd=4,
            bg="white",
            command=self.clear_screen,
            width=12,
            relief=tk.RIDGE,
            font=("Comic Sans MS", 12),
        )
        self.clear_screen_btn.place(x=10, y=370)
        self.save_as_btn = tk.Button(
            self.root,
            text="Save Drawing",
            bd=4,
            bg="white",
            command=self.save_as,
            width=12,
            relief=tk.RIDGE,
            font=("Comic Sans MS", 12),
        )
        self.save_as_btn.place(x=10, y=430)
        self.bg_btn = tk.Button(
            self.root,
            text="Background",
            bd=4,
            bg="white",
            command=self.canvas_color,
            width=12,
            relief=tk.RIDGE,
            font=("Comic Sans MS", 12),
        )
        self.bg_btn.place(x=10, y=490)
        self.pointer_frame = tk.LabelFrame(
            self.root,
            text="Size",
            bd=5,
            bg="white",
            font=("Comic Sans MS", 15, "bold"),
            relief=tk.RIDGE,
        ) 

Om een aangepaste schaalwidget te maken die de grootte van zowel de aanwijzer als de gum kan aanpassen binnen een gespecificeerd bereik en pixellengte, is het nodig om een schaalwidget te definiëren. Deze widget moet een parent element, een oriëntatie en een bereik in pixels krijgen, evenals een lengte voor de schuifbalk. Daarnaast zou het nuttig zijn om een Canvas element op te nemen met zijn eigen parent, achtergrondkleur, randbreedte en een gegroefd reliëf met specifieke afmetingen.

Plaats het canvas op geschikte coördinaten en configureer de verankering ervan in de noordwestelijke hoek (de linkerbovenhoek). Koppel vervolgens de B1-Motion event handler aan de aangewezen paint-functie. In deze context betekent “B1” de ingedrukte status van de linkermuisknop, terwijl “Beweging” de daaropvolgende beweging aangeeft die voortvloeit uit de invoer van de gebruiker. In wezen maakt deze opzet het mogelijk muisbewegingen te volgen terwijl de linkerknop continu wordt ingedrukt.

         self.pointer_frame.place(x=10, y=580, height=150, width=70)
        self.pointer_size = Scale(
            self.pointer_frame, orient=tk.VERTICAL, from_=48, to=1, length=120
        )
        self.pointer_size.set(1)
        self.pointer_size.grid(row=0, column=1, padx=15)
        self.canvas = tk.Canvas(
            self.root, bg="white", bd=5, relief=tk.GROOVE, height=650, width=1300
        )
        self.canvas.place(x=160, y=120, anchor="nw")
        self.canvas.bind("<B1-Motion>", self.paint) 

De functies van de Paint-toepassing definiëren

Om het schilderproces in onze toepassing uit te voeren, hebben we een methode met de naam “paint” geïmplementeerd. Deze aanpak bestaat uit het continu tekenen van kleine elliptische vormen op het scherm. Om dit te bereiken, berekenen we de linkerbovenhoek van elke ellips door twee af te trekken van zowel de X- als Y-coördinaten van de meest recente muisgebeurtenis. Omgekeerd wordt de hoek rechtsonder bepaald door twee op te tellen bij de respectieve waarden van X en Y. Uiteindelijk bepalen deze grenzen de vorm van de ellips die tot nader order voor elk volgend frame wordt gemaakt.

Pas de vulkleur, contourkleur en lijndikte aan volgens de keuze van de gebruiker voor de cursor.

     def paint(self, event):
        x1, y1 = (event.x - 2), (event.y - 2)
        x2, y2 = (event.x \\+ 2), (event.y \\+ 2)
        self.canvas.create_oval(
            x1,
            y1,
            x2,
            y2,
            fill=self.pointer,
            outline=self.pointer,
            width=self.pointer_size.get(),
        ) 

select_color , eraser , en clear_screen .Elk van deze methoden dient zijn eigen unieke doel bij het manipuleren van het uiterlijk en de inhoud van het canvas.De functie select_color accepteert een enkel argument dat een specifieke kleurwaarde vertegenwoordigt, die vervolgens wordt gebruikt om de huidige kleur in te stellen die wordt getekend door de aanwijzer. Dit maakt het mogelijk om eenvoudig verschillende kleuren te selecteren als dat nodig is.pythondef select_color(self, color):self.selected_color = colorVolgende hebben we de eraser functie, die ook slechts één invoerparameter nodig heeft. Deze functie is verantwoordelijk voor het creëren van een “gum”-effect tijdens het tekenen op het canvas, wat resulteert in semi-transparante lijnen die in elkaar overlopen

     def select_color(self, col):
        self.pointer = col

    def eraser(self):
        self.pointer = self.erase

    def clear_screen(self):
        self.canvas.delete("all") 

Integreer de functionaliteit van de canvas_color methode in de TurtleScreen klasse zodat deze een kleurkiezer opent die verschillende tinten weergeeft voor selectie door de gebruiker. Zodra een keuze is gemaakt, gebruik je de methode configure om de achtergrondkleur van het canvas te bepalen en deze kleur vervolgens toe te passen op het uiterlijk van de gum.

     def canvas_color(self):
        color = colorchooser.askcolor()
        if color:
            self.canvas.configure(background=color[1])
            self.erase = color[1] 

Verwerk de gegeven stappen in een elegant Engels antwoord:“Definieer een methode genaamd ‘save\_as’, die de gebruiker vraagt om een bestandsnaam en locatie te selecteren voor het opslaan van de gemaakte schermafbeelding. Gebruik de klasse ImageGrab van Pillow om het hele scherm vast te leggen door een dialoogvenster met bestanden weer te geven. Eenmaal geselecteerd, gebruik je bijsnijdtechnieken met behulp van de gespecificeerde coördinaten om het gewenste canvasgebied te verkrijgen. Pas zo nodig de coördinaten iteratief aan om het specifieke interessegebied te bereiken.

Zeker! Hier is mijn poging om je code te parafraseren in meer formele taal:pythondef save_image(filepath):try:p = PILImage.create(filename=filepath)if isinstance(p, ImageGrab.InvalidGrab):raise Exception(“Mislukt de afbeelding te laden”)# Sla de afbeelding op en toon een bevestigingsbericht boxp.save(str(bestandspad))tkinter.messagebox.showinfo(‘Succes’, ‘De afbeelding is opgeslagen’)except Exception as e:# Behandel uitzonderingen en toon een foutbericht boxtkinter.messagebox.showerror(‘Error’, str(e))

     def save_as(self):
        file_path = filedialog.asksaveasfilename(
            defaultextension=".jpg", filetypes=[("Image files", "*.jpg")]
        )
        if file_path:
            try:
                y = 148
                x = 200
                y1 = 978
                x1 = 1840
                ImageGrab.grab().crop((x, y, x1, y1)).save(file_path)
                messagebox.showinfo("Save Drawing", "Image file saved successfully!")
            except Exception as e:
                messagebox.showerror("Error", f"Failed to save the image file: {e}") 

Maak gebruik van de mogelijkheden van de module Tkinter door instanties van zowel de klassen Tk als DrawApp te instantiëren, terwijl de functionaliteit van de methode mainloop wordt benut om de Tkinter-gebeurtenislus te starten en voortdurend gebruikersinteracties met de grafische interface te controleren totdat deze wordt gesloten.

 if __name__ == "__main__":
    root = tk.Tk()
    app = DrawApp(root)
    root.mainloop() 

Verschillende schilderfuncties testen met Python

Na het uitvoeren van de Paint-toepassing krijgen gebruikers een grafische gebruikersinterface te zien met een kleurselectiegereedschap, vier functietoetsen, een schuifregelaar en een leeg canvasoppervlak waarop ze een kunstwerk kunnen maken:

/nl/images/initial-screen-of-paint-application.jpg

Selecteer een tint door erop te klikken en gebruik vervolgens de linkermuisknop om een kunstwerk in de gekozen tint op het canvasoppervlak te maken:

/nl/images/drawing-using-different-paint-colors.jpg

Als je op de optie “Gum” klikt en de verticale schuifregelaar omhoog schuift, kun je ervoor kiezen om het gumgereedschap te vergroten. Om de functionaliteit te testen, teken je met het geselecteerde penseel en gebruik je de gum om de lijnen uit je werk te verwijderen.

/nl/images/increasing-size-and-erasing-in-middle.jpg

Als je op de optie “Scherm wissen” klikt, wist de software alle eerder uitgevoerde illustraties. Om de tint van de achtergrond aan te passen, tik je op het tabblad “Achtergrond”, waardoor een spectrum van kleuren verschijnt waaruit je kunt kiezen.

/nl/images/clearing-the-screen-and-adding-background-color.jpg

Nadat je de optie “Tekening opslaan” hebt geselecteerd, verschijnt er een venster waarin je een gewenste locatie kunt selecteren en een titel kunt toekennen aan je opgeslagen bestand. De software slaat het bestand dan automatisch op in de opgegeven map.

/nl/images/saving-the-paint-as-an-image.jpg

De Paint-toepassing verbeteren

Om de veelzijdigheid van de schildersoftware te vergroten, wordt aanbevolen een functie te implementeren waarmee gebruikers geometrische vormen in hun kunstwerk kunnen opnemen. Daarnaast zouden opties voor het selecteren van de penseelstijl en transparantie-instellingen de mogelijkheden van het programma verder uitbreiden. Verder zou de integratie van een functie voor het invoegen van tekst en grafische stickers nuttig kunnen zijn bij het uitbreiden van het aantal mogelijke creaties. Tot slot zou de integratie van functies zoals de mogelijkheid om afbeeldingen ongedaan te maken, opnieuw te doen, te schalen of te roteren het tekenproces aanzienlijk stroomlijnen.

Om verschillende visuele elementen te genereren, is het mogelijk om verschillende technieken te gebruiken met de methodes create_rectangle, create_oval, create_line en create_polygon. Voor het toevoegen van geschreven inhoud of afbeeldingen kunnen de functies create_text en create_image gebruikt worden. Verder kunnen, indien gewenst, Pillow’s resize en transpose functies gebruikt worden om de afmetingen en oriëntatie van afbeeldingen te wijzigen.