Contents

Cách xây dựng ứng dụng Paint bằng Python

Công cụ vẽ đơn giản là một trong những ứng dụng phổ biến nhất mà bạn có thể tìm thấy trên hầu hết các máy tính. Nó cho phép nghệ sĩ mắc lỗi mà không sợ hãi, chọn bất kỳ màu nào chỉ bằng một nút bấm và thay đổi kích thước nét vẽ của họ ngay lập tức. Bạn có thể sử dụng nó để tạo logo thương hiệu, khái niệm hóa giao diện người dùng và chú thích sơ đồ.

Người ta có thể xây dựng một chương trình phần mềm vẽ tranh theo cách nào?

Mô-đun Tkinter và Gối

Để phát triển một ứng dụng vẽ tranh bằng Python, cần phải cài đặt cả mô-đun Tkinter và Pillow trong hệ thống. Khung Tkinter là một trong những lựa chọn phổ biến nhất khi thiết kế giao diện người dùng đồ họa (GUI) cho các ứng dụng máy tính để bàn dựa trên Python. Khung này cung cấp một loạt các tiện ích tích hợp sẵn như nhãn, hộp văn bản, khung vẽ và nút cho phép nhà phát triển tạo giao diện tương tác và hấp dẫn trực quan một cách nhanh chóng và dễ dàng.

Pillow, một dẫn xuất của Thư viện hình ảnh Python (PIL) đáng kính, đóng vai trò là bộ công cụ xử lý hình ảnh linh hoạt cho các ứng dụng Python. Tận dụng khả năng của nó, người dùng được trao quyền thực hiện các thao tác khác nhau trên phương tiện hình ảnh kỹ thuật số như mở, thay đổi kích thước, xoay và cắt xén hình ảnh một cách dễ dàng. Ngoài ra, thư viện này còn hỗ trợ chuyển đổi định dạng, cho phép phát triển các thuật toán phức tạp như hệ thống đề xuất công thức nấu ăn và cung cấp chức năng truy xuất hình ảnh ngẫu nhiên từ cơ sở dữ liệu.

Để cài đặt các mô-đun này, hãy chạy:

 pip install tk pillow 

Xác định cấu trúc của ứng dụng Paint

Mã nguồn hoàn chỉnh cho dự án này có sẵn trên kho lưu trữ GitHub của chúng tôi mà bạn có thể truy cập bằng cách điều hướng đến URL đã đề cập ở trên.

Để bắt đầu, chúng tôi sẽ nhập các mô-đun cần thiết. Sau đó, chúng ta sẽ tạo một thể hiện của lớp DrawApp, đặt các thuộc tính của nó như tiêu đề của cửa sổ, màu con trỏ và màu tẩy. Chúng tôi cũng sẽ đảm bảo rằng ứng dụng mở ở chế độ toàn màn hình bằng cách gọi phương thức 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()

Để tạo giao diện với các widget, hãy thiết lập một hàm có tên setup\_widgets. Trong hàm này, tạo thành phần được gắn nhãn hiển thị tiêu đề bằng cách chỉ định mối quan hệ gốc của nó, thông báo sẽ được hiển thị, cấu hình kiểu chữ, màu nền và màu sắc của nội dung văn bản. Ngoài ra, hãy xây dựng khung xung quanh bảng chọn màu bằng cách chỉ định các trách nhiệm như xác định phần tử gốc, dòng chữ xuất hiện, cài đặt kiểu chữ và kích thước đường viền. Cuối cùng, định cấu hình ranh giới bằng một loạt gợn sóng và đặt tông màu nền thành màu trắng.

     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) 

Tạo danh sách để xác định tập hợp màu cho bảng màu. Sử dụng phép lặp để tạo nút cho mỗi màu, có tính đến giá trị RGB tương ứng của nó. Chỉ định vùng chứa chính, bóng nền, độ dày đường viền, thuộc tính kiểu và chiều rộng cho mỗi nút. Ngoài ra, hãy thiết lập hành động sẽ được thực hiện khi nhấp vào từng hành động. Sắp xếp tất cả các thành phần bằng cách sử dụng lề phù hợp và sắp xếp màu sắc theo cặp.

         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 

Theo cách tương tự, chúng ta hãy phác họa các nút dùng để tẩy, một nút để làm sạch màn hình và một nút khác để bảo quản hình minh họa.

         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,
        ) 

Để tạo tiện ích tỷ lệ tùy chỉnh có thể điều chỉnh kích thước của cả con trỏ và công cụ xóa trong phạm vi và độ dài pixel được chỉ định, cần phải xác định tiện ích Tỷ lệ. Tiện ích này phải được cung cấp phần tử gốc, hướng và phạm vi tính bằng pixel cũng như độ dài cho thanh trượt. Ngoài ra, sẽ rất hữu ích nếu bao gồm phần tử Canvas có phần tử gốc, màu nền, chiều rộng đường viền và hình phù điêu có rãnh với các kích thước cụ thể.

Định vị khung vẽ ở tọa độ phù hợp và định cấu hình neo của nó ở góc phía tây bắc (cạnh trên cùng bên trái). Sau đó, liên kết trình xử lý sự kiện B1-Motion với chức năng vẽ được chỉ định. Trong ngữ cảnh này, “B1” biểu thị trạng thái nhấn nút chuột trái, trong khi “Chuyển động” biểu thị chuyển động tiếp theo xảy ra từ thao tác nhập của người dùng. Về cơ bản, việc sử dụng thiết lập này cho phép theo dõi chuyển động của chuột khi nhấn nút trái liên tục.

         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) 

Xác định tính năng của ứng dụng Paint

Để thực hiện quy trình vẽ trong ứng dụng của mình, chúng tôi đã triển khai một phương pháp có tên là “paint”. Cách tiếp cận này liên quan đến việc vẽ liên tục các hình elip nhỏ trên màn hình. Để đạt được điều này, chúng tôi tính toán góc trên cùng bên trái của mỗi hình elip bằng cách trừ hai tọa độ từ cả tọa độ X và Y của sự kiện chuột gần đây nhất. Ngược lại, góc dưới cùng bên phải được xác định bằng cách thêm hai giá trị tương ứng của X và Y. Cuối cùng, các ranh giới này xác định hình dạng của hình elip sẽ được tạo cho mọi khung hình tiếp theo cho đến khi có thông báo mới.

Điều chỉnh màu tô, màu đường viền và độ dày đường kẻ theo lựa chọn của người dùng cho con trỏ.

     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 , cục tẩy , và clear\_screen. Mỗi phương thức này phục vụ mục đích riêng trong việc điều chỉnh hình thức và nội dung của khung vẽ. Hàm select\_color chấp nhận một đối số duy nhất biểu thị một giá trị màu cụ thể, sau đó được sử dụng để đặt màu hiện tại được con trỏ vẽ. Điều này cho phép dễ dàng lựa chọn các màu khác nhau nếu cần.pythondef select_color(self, color):self.selected_color=colorTiếp theo, chúng ta có hàm eraser, hàm này cũng chỉ yêu cầu một tham số đầu vào. Nó có nhiệm vụ tạo ra hiệu ứng “tẩy” khi vẽ trên canvas, dẫn đến các đường nét bán trong suốt hòa quyện vào nhau.

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

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

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

Kết hợp chức năng được cung cấp bởi phương thức canvas\_color vào lớp TurtleScreen sao cho nó mở một bộ chọn màu hiển thị nhiều màu sắc khác nhau để người dùng lựa chọn. Sau khi lựa chọn được thực hiện, hãy sử dụng phương pháp configure để thiết lập màu nền của khung vẽ và sau đó áp dụng màu này cho giao diện của cục tẩy.

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

Kết hợp các bước được cung cấp thành một câu trả lời bằng tiếng Anh trang nhã: “Xác định một phương thức có tên là’save\_as’, nhắc người dùng chọn tên tệp và vị trí để lưu ảnh chụp màn hình đã chụp. Sử dụng lớp ImageGrab của Pillow để chụp toàn bộ màn hình bằng cách hiển thị hộp thoại tệp. Sau khi được chọn, hãy sử dụng các kỹ thuật cắt xén bằng cách sử dụng tọa độ đã chỉ định để có được vùng canvas mong muốn. Lặp đi lặp lại điều chỉnh tọa độ khi cần thiết để đạt được khu vực quan tâm cụ thể.

Chắc chắn! Đây là nỗ lực của tôi trong việc diễn giải mã của bạn bằng ngôn ngữ trang trọng hơn:pythondef save_image(filepath):try:p=PILImage.create(filename=filepath)if isinstance(p, ImageGrab.InvalidGrab):raise Exception(“Không thể tải hình ảnh” )# Lưu hình ảnh và hiển thị thông báo xác nhận boxp.save(str(filepath))tkinter.messagebox.showinfo(‘Thành công’,‘Hình ảnh đã được lưu’)ngoại trừ Ngoại lệ như e:# Xử lý các ngoại lệ và hiển thị thông báo lỗi 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}") 

Tận dụng các khả năng của mô-đun Tkinter bằng cách khởi tạo các phiên bản của cả hai lớp Tk và DrawApp, đồng thời tận dụng chức năng được cung cấp bởi phương pháp vòng lặp chính để bắt đầu vòng lặp sự kiện Tkinter và liên tục giám sát các tương tác của người dùng với giao diện đồ họa cho đến khi nó được đóng lại.

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

Kiểm tra các tính năng vẽ khác nhau bằng Python

Khi thực thi ứng dụng Paint, người dùng sẽ thấy giao diện người dùng đồ họa có công cụ chọn màu, bốn phím chức năng, điều khiển trượt và bề mặt canvas trống để tạo tác phẩm nghệ thuật:

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

Chọn một màu bằng cách nhấp vào nó và sau đó sử dụng nút nhấp chuột trái để tạo tác phẩm nghệ thuật trong bóng đã chọn đó trên bề mặt canvas:

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

Khi nhấp vào tùy chọn “Tẩy” và trượt thanh trượt dọc theo hướng lên trên, người ta có thể chọn phóng to công cụ tẩy. Để kiểm tra chức năng của nó, chỉ cần vẽ bằng cọ đã chọn và sau đó sử dụng cục tẩy để xóa các đường kẻ khỏi tác phẩm nghệ thuật của bạn.

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

Khi nhấp vào tùy chọn “Clear Screen”, phần mềm sẽ xóa mọi tác phẩm nghệ thuật đã thực hiện trước đó. Để sửa đổi màu nền, vui lòng nhấn vào tab “Nền”, tab này sẽ hiển thị phổ màu để chọn.

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

Khi chọn tùy chọn “Lưu bản vẽ”, một cửa sổ sẽ xuất hiện cho phép bạn chọn vị trí mong muốn và gán tiêu đề cho tệp đã lưu của mình. Sau đó phần mềm sẽ tự động lưu trữ file vào thư mục được chỉ định.

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

Nâng cao ứng dụng Paint

Để tăng tính linh hoạt của phần mềm vẽ tranh, nên triển khai một tính năng cho phép người dùng kết hợp các dạng hình học trong tác phẩm nghệ thuật của họ. Ngoài ra, việc cung cấp các tùy chọn để chọn kiểu cọ vẽ và cài đặt độ trong suốt sẽ mở rộng hơn nữa khả năng của chương trình. Hơn nữa, việc tích hợp một chức năng cho phép chèn văn bản và nhãn dán đồ họa có thể mang lại lợi ích trong việc mở rộng phạm vi sáng tạo tiềm năng. Cuối cùng, việc kết hợp các tính năng như khả năng hoàn tác, làm lại, chia tỷ lệ hoặc xoay hình ảnh sẽ hợp lý hóa đáng kể quá trình vẽ tổng thể.

Để tạo ra các phần tử trực quan khác nhau, có thể sử dụng nhiều kỹ thuật khác nhau bằng cách sử dụng các phương thức create\_hình chữ nhật, create\_oval, create\_line và create\_polygon. Ngoài ra, để kết hợp nội dung văn bản hoặc hình ảnh, người ta có thể sử dụng các chức năng create\_text và create\_image. Hơn nữa, nếu muốn, chức năng thay đổi kích thước và chuyển đổi của Gối có thể được sử dụng để thay đổi kích thước và hướng của hình ảnh.