เหตุใดจึงต้องใช้คลาสเมื่อตั้งโปรแกรม tkinter gui ใน python


19

ฉันเขียนโปรแกรมใน python เป็นหลักและตั้งโปรแกรม GUI สองตัวด้วย Tkinter การสอนทุกครั้งที่ฉันเคยเห็นได้แนะนำให้กำหนดและใช้คลาสสำหรับ GUI แต่ GUI ของฉันทำงานได้อย่างไร้ที่ติโดยใช้เพียงโพรซีเดอร์เท่านั้น

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

คำตอบ:


19

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

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

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

ตัวอย่างเช่นลองพิจารณาตัวอย่างง่าย ๆ (สมมติว่า tkinter มีการนำเข้าเช่นimport tkinter as tk(python3) หรือimport Tkinter as tk(python2):

def quit(event=None):
    sys.exit()
root = tk.Tk()
label = tk.Label(root, text="Hello, world")
label.pack()
label.bind("<1>", quit)
root.mainloop()

สำหรับฉันแล้วการไหลของรหัสนั้นผิดทั้งหมด ฉันต้องกำหนดวิธีการเลิกก่อนที่ฉันจะอ้างอิงและการสร้างหน้าต่างรูตและการเรียกไปยังการฉีดจะถูกคั่นด้วยรหัสอื่นทั้งหมด

โดยใช้คลาสอย่างไรก็ตามฉันสามารถเขียนรหัสในลำดับที่เป็นธรรมชาติมากขึ้น:

class MyWindow(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Hello, world")
        label.pack()
        label.bind("<1>", self.quit)
    def quit(self, event=None):
        sys.exit()

root = tk.Tk()
MyWindow(root).pack()
root.mainloop()

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

ข้อดีอีกอย่างคือตอนนี้ฉันสามารถเปลี่ยนหน้าต่างที่มีได้อย่างง่ายดายโดยไม่ต้องเปลี่ยนอะไรเกี่ยวกับหน้าต่าง "หลัก" (และในทางกลับกัน) นั่นคือฉันสามารถเพิ่มเส้นขอบหรือส่วนใหม่ที่สมบูรณ์ไปยัง GUI หลัก แต่ฉันไม่ต้องแตะโค้ดบรรทัดเดียวภายใน MyWindow ตรงกันข้ามกับรหัสขั้นตอนที่คุณอาจต้องเปลี่ยนlabel.pack()คำสั่งและคำสั่ง pack (หรือกริด) ของวิดเจ็ตอื่น ๆ ทั้งหมดใน UI

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


ทำไมคุณถึงใช้ Frame ในตัวอย่างที่สอง? คุณไม่สามารถหลีกเลี่ยงได้เหมือนอย่างที่คุณทำในตัวอย่างแรก? มีความลับเบื้องหลังการใช้ Frame กับคลาสหรือไม่?
multigoodverse

2
เฟรมเป็นเพียงเพื่อความสะดวก ไม่มีความลับในการสืบทอดจาก Frame ฉันสามารถสืบทอดจากobjectหรือคลาสอื่น ๆ ได้ แต่โดยทั่วไปแล้วฉันจะสร้างเฟรมต่อไป ถ้าฉันใส่ทุกอย่างไว้ในกรอบมันทำให้รู้สึกถึงการทำให้คลาสเป็นเฟรม .
ไบรอัน Oakley

1
ทำให้รู้สึกขอบคุณ! คนอื่น ๆ นอกจากนี้ผมได้เห็นตัวเองก่อนที่จะใช้ตัวแปร แต่ฉันเห็นคุณกำลังใช้สิ่งที่ชอบ แทนlabel=tk.Label() self.tk.Label()นั่นเป็นตัวเลือกสไตล์หรือไม่? นี่คือตัวอย่างการใช้ตัวเอง: python-textbok.readthedocs.org/en/1.0/…
multigoodverse

1
@BryanOakley ฉันเดาว่าคุณตั้งใจจะใช้พาเรนต์แทนที่จะเป็นรูทในบรรทัดต่อไปของ MyWindow .__ init__: "label = tk.Label (root, text =" Hello, world ")"
user3885927

1
@ user3885927: ใช่! ว้าวใช้เวลาเกือบสามปีกว่าที่บางคนจะสังเกตเห็นว่า แม้ว่าจะไม่ใช่parentแต่เป็นselfเพราะคลาสนั้นเป็น Frame ขอบคุณ!
ไบรอัน Oakley
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.