Jak stworzyć aplikację do malowania w Pythonie
Proste narzędzie do malowania to jedna z najpopularniejszych aplikacji, jakie można znaleźć na większości komputerów. Pozwala artyście popełniać błędy bez obaw, wybierać dowolny kolor jednym kliknięciem przycisku i natychmiast zmieniać rozmiar pociągnięć pędzla. Można go używać do tworzenia logo marki, konceptualizacji interfejsów użytkownika i dodawania adnotacji do diagramów.
W jaki sposób można skonstruować program do malowania?
Moduł Tkinter i Pillow
Aby stworzyć aplikację malarską przy użyciu Pythona, konieczne jest zainstalowanie w systemie modułów Tkinter i Pillow. Framework Tkinter jest jednym z najpopularniejszych wyborów, jeśli chodzi o projektowanie graficznych interfejsów użytkownika (GUI) dla aplikacji desktopowych opartych na Pythonie. Framework ten zapewnia szeroką gamę wbudowanych widżetów, takich jak etykiety, pola tekstowe, płótna i przyciski, które umożliwiają programistom szybkie i łatwe tworzenie atrakcyjnych wizualnie i interaktywnych interfejsów.
Pillow, pochodna czcigodnej biblioteki Python Imaging Library (PIL), służy jako wszechstronny zestaw narzędzi do przetwarzania obrazu dla aplikacji Python. Wykorzystując jej możliwości, użytkownicy mogą z łatwością wykonywać różne operacje na cyfrowych mediach wizualnych, takie jak otwieranie, zmiana rozmiaru, obracanie i przycinanie obrazów. Ponadto biblioteka ta ułatwia konwersję formatów, umożliwia tworzenie złożonych algorytmów, takich jak systemy rekomendacji przepisów kulinarnych, a także zapewnia funkcjonalność losowego pobierania obrazów z bazy danych.
Aby zainstalować te moduły, uruchom:
pip install tk pillow
Define the Structure of the Paint Application
Kompletny kod źródłowy tego projektu jest dostępny w naszym repozytoriumGitHub, do którego można uzyskać dostęp, przechodząc pod wyżej wymieniony adres URL.
Aby rozpocząć, zaimportujemy niezbędne moduły. Następnie utworzymy instancję klasy DrawApp
, ustawimy jej właściwości, takie jak tytuł okna, kolor wskaźnika i kolor gumki. Upewnimy się również, że aplikacja otworzy się w trybie pełnoekranowym, wywołując metodę setup_widgets()
.
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()
Aby utworzyć interfejs z widżetami, utwórz funkcję o nazwie setup_widgets
. W ramach tej funkcji wygeneruj oznaczony komponent wyświetlający tytuł, określając jego relację rodzicielską, komunikat do wyświetlenia, konfigurację kroju pisma, odcień tła i odcień treści tekstowej. Dodatkowo, skonstruuj szkielet wokół panelu wyboru koloru, przypisując obowiązki, takie jak definiowanie elementu nadrzędnego, wyświetlanego napisu, ustawień kroju pisma i wymiarów obramowania.Na koniec skonfiguruj granicę za pomocą serii pofałdowań i ustaw odcień tła na biały.
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)
Utwórz listę, aby zdefiniować zestaw kolorów dla palety kolorów. Wykorzystaj iterację, aby wygenerować przycisk dla każdego odcienia, biorąc pod uwagę odpowiadającą mu wartość RGB. Określ kontener nadrzędny, odcień tła, grubość obramowania, właściwości stylu i szerokość dla każdego przycisku. Dodatkowo ustal akcję, która zostanie wykonana po kliknięciu każdego z nich. Rozmieść wszystkie komponenty przy użyciu odpowiednich marginesów i uporządkuj kolory parami.
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
W podobnym duchu wyznaczmy przyciski dla gumki, jeden do czyszczenia wyświetlacza, a drugi do zachowania ilustracji.
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,
)
Aby utworzyć niestandardowy widżet skali, który może dostosować rozmiar zarówno wskaźnika, jak i gumki w określonym zakresie i długości pikseli, konieczne jest zdefiniowanie widżetu skali. Widżet ten powinien mieć element nadrzędny, orientację i zakres w pikselach, a także długość paska suwaka. Dodatkowo korzystne byłoby dołączenie elementu Canvas z własnym rodzicem, kolorem tła, szerokością obramowania i rowkowanym reliefem o określonych wymiarach.
Umieść płótno w odpowiednich współrzędnych i skonfiguruj jego zakotwiczenie w północno-zachodnim rogu (lewa górna krawędź). Następnie skojarz obsługę zdarzenia B1-Motion z wyznaczoną funkcją malowania. W tym kontekście “B1” oznacza stan wciśniętego lewego przycisku myszy, podczas gdy “Motion” oznacza ruch wynikający z danych wprowadzonych przez użytkownika. Zasadniczo wykorzystanie tej konfiguracji umożliwia monitorowanie ruchów myszy, gdy lewy przycisk jest stale wciśnięty.
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)
Definiowanie funkcji aplikacji Paint
Aby wykonać proces malowania w naszej aplikacji, zaimplementowaliśmy metodę o nazwie “paint”. Podejście to polega na ciągłym rysowaniu małych eliptycznych kształtów na ekranie. Aby to osiągnąć, obliczamy lewy górny róg każdej elipsy, odejmując dwa od współrzędnych X i Y ostatniego zdarzenia myszy. I odwrotnie, prawy dolny róg jest określany przez dodanie dwóch do odpowiednich wartości X i Y. Ostatecznie granice te definiują kształt elipsy, która będzie tworzona dla każdej kolejnej klatki aż do odwołania.
Dostosuj kolor wypełnienia, kolor konturu i grubość linii zgodnie z wyborem użytkownika dla kursora.
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
, and clear_screen
.Każda z tych metod służy własnemu unikalnemu celowi w manipulowaniu wyglądem i zawartością płótna. select_color
funkcja przyjmuje pojedynczy argument reprezentujący określoną wartość koloru, która jest następnie używana do ustawienia bieżącego koloru rysowanego przez wskaźnik. Pozwala to na łatwy wybór różnych kolorów w razie potrzeby.pythondef select_color(self, color):self.selected_color = colorNastępnie mamy funkcję eraser
, która również wymaga tylko jednego parametru wejściowego. Jest ona odpowiedzialna za tworzenie efektu “gumki” podczas rysowania na płótnie, co skutkuje półprzezroczystymi liniami, które mieszają się
def select_color(self, col):
self.pointer = col
def eraser(self):
self.pointer = self.erase
def clear_screen(self):
self.canvas.delete("all")
Włącz funkcjonalność zapewnianą przez metodę canvas_color
do klasy TurtleScreen
, tak aby otwierała selektor kolorów wyświetlający różne odcienie do wyboru przez użytkownika. Po dokonaniu wyboru należy użyć metody configure
, aby ustalić kolor tła płótna, a następnie zastosować ten kolor do wyglądu gumki.
def canvas_color(self):
color = colorchooser.askcolor()
if color:
self.canvas.configure(background=color[1])
self.erase = color[1]
Włącz podane kroki do eleganckiej odpowiedzi w języku angielskim: “Zdefiniuj metodę o nazwie ‘save\_as’, która monituje użytkownika o wybranie nazwy pliku i lokalizacji do zapisania przechwyconego zrzutu ekranu. Wykorzystaj klasę ImageGrab Pillow do przechwycenia całego ekranu, prezentując okno dialogowe pliku. Po wybraniu, zastosuj techniki przycinania przy użyciu określonych współrzędnych, aby uzyskać pożądany region płótna. Iteracyjnie dostosuj współrzędne w razie potrzeby, aby uzyskać określony obszar zainteresowania.
Jasne! Oto moja próba sparafrazowania twojego kodu w bardziej formalnym języku:pythondef save_image(filepath):try:p = PILImage.create(filename=filepath)if isinstance(p, ImageGrab.InvalidGrab):raise Exception(“Nie udało się załadować obrazu”)# Zapisz obraz i wyświetl komunikat potwierdzenia boxp.save(str(filepath))tkinter.messagebox.showinfo(‘Success’, ‘Obraz został zapisany’)except Exception as e:# Obsługuj wyjątki i wyświetl komunikat błędu 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}")
Wykorzystaj możliwości modułu Tkinter, instancjonując instancje klas Tk i DrawApp, jednocześnie wykorzystując funkcjonalność zapewnianą przez metodę mainloop do inicjowania pętli zdarzeń Tkinter i ciągłego monitorowania interakcji użytkownika z interfejsem graficznym aż do jego zamknięcia.
if __name__ == "__main__":
root = tk.Tk()
app = DrawApp(root)
root.mainloop()
Testowanie różnych funkcji malarskich przy użyciu Pythona
Po uruchomieniu aplikacji Paint, użytkownikom prezentowany jest graficzny interfejs użytkownika z narzędziem wyboru koloru, czterema przyciskami funkcyjnymi, przesuwaną regulacją i pustą powierzchnią płótna, na której można tworzyć grafikę:
Wybierz odcień, klikając go, a następnie użyj lewego przycisku myszy, aby utworzyć grafikę w wybranym odcieniu na powierzchni płótna:
Po kliknięciu opcji “Gumka” i przesunięciu pionowego suwaka w górę, można powiększyć narzędzie gumki. Aby przetestować jego funkcjonalność, po prostu narysuj wybranym pędzlem, a następnie użyj gumki, aby usunąć linie z grafiki.
Kliknięcie opcji “Wyczyść ekran” spowoduje usunięcie wcześniej wykonanej grafiki. Aby zmodyfikować odcień tła, należy dotknąć zakładki “Tło”, co spowoduje wyświetlenie spektrum kolorów do wyboru.
Po wybraniu opcji “Zapisz rysunek” pojawi się okno umożliwiające wybranie żądanej lokalizacji i przypisanie tytułu do zapisanego pliku. Oprogramowanie automatycznie zapisze plik w określonym katalogu.
Ulepszanie aplikacji Paint
Aby zwiększyć wszechstronność oprogramowania do malowania, zaleca się zaimplementowanie funkcji umożliwiającej użytkownikom włączanie form geometrycznych do swoich dzieł. Dodatkowo, udostępnienie opcji wyboru stylu pędzla i ustawień przezroczystości jeszcze bardziej rozszerzyłoby możliwości programu. Co więcej, zintegrowanie funkcji umożliwiającej wstawianie tekstu i naklejek graficznych mogłoby okazać się korzystne dla rozszerzenia zakresu potencjalnych kreacji. Wreszcie, włączenie funkcji takich jak możliwość cofania, ponawiania, skalowania lub obracania obrazów znacznie usprawniłoby cały proces rysowania.
W celu wygenerowania różnych elementów wizualnych możliwe jest zastosowanie różnych technik przy użyciu metod create\_rectangle, create\_oval, create\_line i create\_polygon. Dodatkowo, w celu włączenia treści pisanych lub obrazów, można wykorzystać funkcje create\_text i create\_image. Ponadto, w razie potrzeby, funkcje zmiany rozmiaru i transpozycji Pillow mogą być wykorzystane do zmiany wymiarów i orientacji obrazów.