Contents

วิธีสร้างแอปพลิเคชัน Paint โดยใช้ Python

เครื่องมือระบายสีแบบง่ายๆ เป็นหนึ่งในแอพทั่วไปที่คุณพบได้ในคอมพิวเตอร์ส่วนใหญ่ ช่วยให้ศิลปินทำผิดพลาดโดยไม่ต้องกลัว เลือกสีใดก็ได้ด้วยการคลิกปุ่ม และเปลี่ยนขนาดฝีแปรงได้ทันที คุณสามารถใช้มันเพื่อสร้างโลโก้แบรนด์ สร้างแนวคิดให้กับอินเทอร์เฟซผู้ใช้ และใส่คำอธิบายประกอบไดอะแกรม

เราสามารถสร้างโปรแกรมซอฟต์แวร์วาดภาพในลักษณะใดได้บ้าง?

โมดูล Tkinter และหมอน

ในการพัฒนาแอพพลิเคชั่นการลงสีโดยใช้ Python จำเป็นต้องติดตั้งทั้งโมดูล Tkinter และ Pillow ในระบบ เฟรมเวิร์ก Tkinter เป็นหนึ่งในตัวเลือกยอดนิยมเมื่อพูดถึงการออกแบบอินเทอร์เฟซผู้ใช้แบบกราฟิก (GUI) สำหรับแอปพลิเคชันเดสก์ท็อปที่ใช้ Python เฟรมเวิร์กนี้มีวิดเจ็ตในตัวที่หลากหลาย เช่น ป้ายกำกับ กล่องข้อความ แคนวาส และปุ่มที่ช่วยให้นักพัฒนาสามารถสร้างอินเทอร์เฟซแบบโต้ตอบที่ดึงดูดสายตาได้อย่างรวดเร็วและง่ายดาย

Pillow ซึ่งเป็นอนุพันธ์ของ Python Imaging Library (PIL) ที่มีชื่อเสียง ทำหน้าที่เป็นชุดเครื่องมือประมวลผลภาพอเนกประสงค์สำหรับแอปพลิเคชัน Python ด้วยการใช้ประโยชน์จากความสามารถ ผู้ใช้จึงสามารถดำเนินการต่างๆ บนสื่อภาพดิจิทัล เช่น การเปิด การปรับขนาด การหมุน และการครอบตัดรูปภาพได้อย่างง่ายดาย นอกจากนี้ ไลบรารีนี้ยังอำนวยความสะดวกในการแปลงรูปแบบ ช่วยให้สามารถพัฒนาอัลกอริธึมที่ซับซ้อน เช่น ระบบแนะนำสูตรอาหาร และมอบฟังก์ชันในการดึงรูปภาพจากฐานข้อมูลแบบสุ่ม

หากต้องการติดตั้งโมดูลเหล่านี้ ให้รัน:

 pip install tk pillow 

กำหนดโครงสร้างของแอปพลิเคชัน Paint

ซอร์สโค้ดที่สมบูรณ์สำหรับโปรเจ็กต์นี้มีอยู่ในพื้นที่เก็บข้อมูล GitHub ของเรา ซึ่งคุณสามารถเข้าถึงได้โดยไปที่ URL ดังกล่าว

ในการเริ่มต้น เราจะนำเข้าโมดูลที่จำเป็น ต่อจากนั้น เราจะสร้างอินสแตนซ์ของคลาส DrawApp ตั้งค่าคุณสมบัติ เช่น ชื่อเรื่องของหน้าต่าง สีตัวชี้ และสีของยางลบ นอกจากนี้ เรายังจะตรวจสอบให้แน่ใจด้วยว่าแอปพลิเคชันเปิดในโหมดเต็มหน้าจอโดยเรียกใช้เมธอด 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()

ในการสร้างอินเทอร์เฟซกับวิดเจ็ต ให้สร้างฟังก์ชันชื่อ setup\_widgets ภายในฟังก์ชันนี้ ให้สร้างส่วนประกอบที่มีป้ายกำกับซึ่งแสดงชื่อเรื่องโดยระบุความสัมพันธ์ระหว่างผู้ปกครอง ข้อความที่จะแสดง การกำหนดค่าแบบอักษร สีฉากหลัง และเฉดสีของเนื้อหาที่เป็นข้อความ นอกจากนี้ สร้างกรอบงานรอบๆ แผงการเลือกสีโดยมอบหมายความรับผิดชอบ เช่น การกำหนดองค์ประกอบหลัก คำจารึกที่จะแสดง การตั้งค่าแบบอักษร และขนาดเส้นขอบ สุดท้าย กำหนดค่าขอบเขตด้วยชุดลูกคลื่นและตั้งค่าโทนสีพื้นหลังให้เป็นสีขาว

     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) 

สร้างรายการเพื่อกำหนดชุดสีสำหรับชุดสี ใช้การวนซ้ำเพื่อสร้างปุ่มสำหรับแต่ละสี โดยคำนึงถึงค่า RGB ที่สอดคล้องกัน ระบุคอนเทนเนอร์หลัก สีพื้นหลัง ความหนาของเส้นขอบ คุณสมบัติรูปแบบ และความกว้างสำหรับทุกปุ่ม นอกจากนี้ ให้สร้างการดำเนินการที่จะดำเนินการเมื่อคลิกที่แต่ละรายการ จัดเรียงส่วนประกอบทั้งหมดโดยใช้ระยะขอบที่เหมาะสมและจัดระเบียบสีเป็นคู่

         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 

ในทำนองเดียวกัน ให้เราแยกแยะปุ่มต่างๆ สำหรับยางลบ ปุ่มหนึ่งสำหรับทำความสะอาดจอแสดงผล และอีกปุ่มหนึ่งเพื่อรักษาภาพประกอบไว้

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

ในการสร้างวิดเจ็ตมาตราส่วนที่กำหนดเองซึ่งสามารถปรับขนาดของทั้งตัวชี้และยางลบภายในช่วงและความยาวพิกเซลที่ระบุได้ จำเป็นต้องกำหนดวิดเจ็ตมาตราส่วน วิดเจ็ตนี้ควรได้รับองค์ประกอบหลัก การวางแนว และช่วงเป็นพิกเซล รวมถึงความยาวของแถบเลื่อน นอกจากนี้ การรวมองค์ประกอบ Canvas เข้ากับพาเรนต์ สีพื้นหลัง ความกว้างของเส้นขอบ และการนูนร่องที่มีขนาดเฉพาะจะเป็นประโยชน์

วางตำแหน่งผืนผ้าใบในพิกัดที่เหมาะสมและกำหนดค่าการยึดไว้ที่มุมตะวันตกเฉียงเหนือ (ขอบซ้ายบน) จากนั้น เชื่อมโยงตัวจัดการเหตุการณ์ B1-Motion กับฟังก์ชันการทาสีที่กำหนด ในบริบทนี้ “B1” หมายถึงสถานะการกดของปุ่มซ้ายของเมาส์ ในขณะที่ “การเคลื่อนไหว” หมายถึงการเคลื่อนไหวที่ตามมาซึ่งเกิดจากการป้อนข้อมูลของผู้ใช้ โดยพื้นฐานแล้ว การใช้การตั้งค่านี้ทำให้สามารถติดตามการเคลื่อนไหวของเมาส์ได้ในขณะที่กดปุ่มซ้ายอย่างต่อเนื่อง

         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) 

กำหนดคุณสมบัติของแอพพลิเคชั่น Paint

เพื่อดำเนินการกระบวนการพ่นสีภายในแอปพลิเคชันของเรา เราได้นำวิธีการที่เรียกว่า"สี"มาใช้ วิธีการนี้เกี่ยวข้องกับการวาดรูปวงรีเล็กๆ บนหน้าจออย่างต่อเนื่อง เพื่อให้บรรลุเป้าหมายนี้ เราคำนวณมุมซ้ายบนของแต่ละวงรีโดยการลบสองออกจากพิกัด X และ Y ของเหตุการณ์เมาส์ล่าสุด ในทางกลับกัน มุมขวาล่างถูกกำหนดโดยการเพิ่มสองค่าตามลำดับของ X และ Y ท้ายที่สุด ขอบเขตเหล่านี้จะกำหนดรูปร่างของวงรีที่จะถูกสร้างขึ้นสำหรับทุกเฟรมที่ตามมาจนกว่าจะมีประกาศเพิ่มเติม

ปรับสีเติม สีเค้าร่าง และความหนาของเส้นตามที่ผู้ใช้เลือกสำหรับเคอร์เซอร์

     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 , ยางลบ และ clear\_screen แต่ละวิธีมีจุดประสงค์เฉพาะของตนเองในการจัดการลักษณะที่ปรากฏและเนื้อหาของผืนผ้าใบ ฟังก์ชัน select\_color ยอมรับอาร์กิวเมนต์เดียวที่แสดงถึงค่าสีเฉพาะ ซึ่งจากนั้นจะใช้เพื่อตั้งค่าสีปัจจุบันที่วาดโดยตัวชี้ ช่วยให้สามารถเลือกสีต่างๆ ได้ง่ายตามต้องการ.pythondef select_color(self, color):self.selected_color=colorถัดไป เรามีฟังก์ชัน ยางลบ ซึ่งต้องการพารามิเตอร์อินพุตเพียงตัวเดียวด้วย มีหน้าที่สร้างเอฟเฟกต์ “ยางลบ” เมื่อวาดภาพบนผืนผ้าใบ ส่งผลให้ได้เส้นกึ่งโปร่งใสที่ผสมผสานกัน

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

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

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

รวมฟังก์ชันการทำงานที่ได้รับจากเมธอด canvas\_color เข้ากับคลาส TurtleScreen โดยจะเปิดตัวเลือกสีที่แสดงเฉดสีต่างๆ เพื่อให้ผู้ใช้เลือก เมื่อเลือกตัวเลือกแล้ว ให้ใช้วิธีการ กำหนดค่า เพื่อสร้างสีพื้นหลังของผืนผ้าใบ จากนั้นจึงใช้สีนี้กับลักษณะของยางลบ

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

รวมขั้นตอนที่ให้ไว้ในการตอบกลับภาษาอังกฤษที่สวยงาม: “กำหนดวิธีการที่เรียกว่า’บันทึก\_as’ซึ่งจะแจ้งให้ผู้ใช้เลือกชื่อไฟล์และตำแหน่งสำหรับบันทึกภาพหน้าจอที่บันทึกไว้ ใช้คลาส ImageGrab ของ Pillow เพื่อยึดทั้งหน้าจอโดยการนำเสนอกล่องโต้ตอบไฟล์ เมื่อเลือกแล้ว ให้ใช้เทคนิคการครอบตัดโดยใช้พิกัดที่ระบุเพื่อให้ได้ขอบเขตผืนผ้าใบที่ต้องการ ปรับพิกัดซ้ำๆ ตามความจำเป็นเพื่อให้ได้พื้นที่เฉพาะที่สนใจ

แน่นอน! นี่คือความพยายามของฉันในการถอดความโค้ดของคุณในภาษาที่เป็นทางการมากขึ้น: pythondef save_image(filepath):try:p=PILImage.create(filename=filepath)if isinstance(p, ImageGrab.InvalidGrab):raise Exception(“Failed to load the image” )# บันทึกรูปภาพและแสดงข้อความยืนยัน boxp.save(str(filepath))tkinter.messagebox.showinfo(‘Success’,‘The image has been Saved’)ยกเว้นข้อยกเว้นเป็น e:# จัดการข้อยกเว้นและแสดงข้อความแสดงข้อผิดพลาด boxtkinter.messagebox.showerror(‘ข้อผิดพลาด’, 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}") 

ใช้ความสามารถของโมดูล Tkinter โดยการสร้างอินสแตนซ์ของทั้งคลาส Tk และ DrawApp ในขณะที่ใช้ประโยชน์จากฟังก์ชันการทำงานที่ได้รับจากวิธี mainloop เพื่อเริ่มต้นลูปเหตุการณ์ Tkinter และตรวจสอบการโต้ตอบของผู้ใช้กับอินเทอร์เฟซแบบกราฟิกอย่างต่อเนื่องจนกว่าจะปิด

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

การทดสอบคุณสมบัติการวาดภาพที่แตกต่างกันโดยใช้ Python

เมื่อเรียกใช้แอปพลิเคชัน Paint ผู้ใช้จะเห็นอินเทอร์เฟซผู้ใช้แบบกราฟิกที่มีเครื่องมือเลือกสี ปุ่มฟังก์ชันสี่ปุ่ม ตัวควบคุมการปรับแบบเลื่อน และพื้นผิวผ้าใบเปล่าสำหรับสร้างงานศิลปะ:

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

เลือกเฉดสีโดยคลิกที่สี จากนั้นใช้ปุ่มคลิกซ้ายของเมาส์เพื่อสร้างงานศิลปะภายในเฉดสีที่เลือกไว้บนพื้นผิวผ้าใบ:

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

เมื่อคลิกที่ตัวเลือก"ยางลบ"และเลื่อนแถบเลื่อนแนวตั้งไปในทิศทางขึ้น คุณสามารถเลือกที่จะขยายเครื่องมือยางลบได้ หากต้องการทดสอบฟังก์ชันการทำงาน เพียงวาดด้วยแปรงที่เลือก จากนั้นใช้ยางลบเพื่อลบเส้นออกจากงานศิลปะของคุณ

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

เมื่อคลิกที่ตัวเลือก"ล้างหน้าจอ"ซอฟต์แวร์จะลบอาร์ตเวิร์คที่ดำเนินการก่อนหน้านี้ทั้งหมด หากต้องการปรับเปลี่ยนเฉดสีฉากหลัง โปรดแตะที่แท็บ"พื้นหลัง"ซึ่งจะแสดงสเปกตรัมของสีให้เลือก

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

เมื่อเลือกตัวเลือก"บันทึกภาพวาด"หน้าต่างจะปรากฏขึ้นเพื่อให้คุณสามารถเลือกตำแหน่งที่ต้องการและกำหนดชื่อเรื่องให้กับไฟล์ที่คุณบันทึกไว้ ซอฟต์แวร์จะจัดเก็บไฟล์ไว้ในไดเร็กทอรีที่ระบุโดยอัตโนมัติ

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

การปรับปรุงแอปพลิเคชั่น Paint

เพื่อเพิ่มความอเนกประสงค์ของซอฟต์แวร์การลงสี ขอแนะนำให้นำคุณสมบัติมาใช้ซึ่งจะช่วยให้ผู้ใช้รวมรูปทรงเรขาคณิตไว้ในอาร์ตเวิร์คของตนได้ นอกจากนี้ การให้ตัวเลือกสำหรับการเลือกสไตล์แปรงและการตั้งค่าความโปร่งใสจะช่วยเพิ่มขีดความสามารถของโปรแกรมให้ดียิ่งขึ้น นอกจากนี้ การรวมฟังก์ชันที่ทำให้สามารถแทรกข้อความและสติ๊กเกอร์กราฟิกอาจเป็นประโยชน์ในการขยายขอบเขตของการสร้างสรรค์ที่เป็นไปได้ สุดท้ายนี้ การรวมคุณสมบัติต่างๆ เช่น ความสามารถในการเลิกทำ ทำซ้ำ ปรับขนาด หรือหมุนภาพ จะช่วยปรับปรุงกระบวนการวาดโดยรวมได้อย่างมาก

เพื่อสร้างองค์ประกอบภาพต่างๆ เป็นไปได้ที่จะใช้เทคนิคต่างๆ โดยใช้วิธี create\_rectangle, create\_oval, create\_line และ create\_polygon นอกจากนี้ สำหรับการรวมเนื้อหาหรือรูปภาพที่เป็นลายลักษณ์อักษร เราอาจใช้ฟังก์ชัน create\_text และ create\_image นอกจากนี้ หากต้องการ คุณสามารถใช้ฟังก์ชันการปรับขนาดและการย้ายตำแหน่งของ Pillow เพื่อเปลี่ยนขนาดและการวางแนวของรูปภาพได้