ראשי » פיתוח ממשק משתמש בשפת Python

    מלאו פרטים לקבלת ייעוץ





    אני מאשר קבלת מבצעים ועדכונים מחברת RT-GROUP בכפוף לprivacy

    [honeypot Email id:email class:email]

    מדריך פייתון לכתיבת GUI למחשבון – הקדמה

    פייטון היא שפה מאוד פופולרית בתעשיית ההייטק בימים אלו, יש לה קהילה מאוד מפותחת של מפתחי פייתון והיא ממציאה את עצמה בכל פעם מחדש עם שימושים נוספים ע"י חברות ההייטק וסטארטאפים
    הסיבה לפופולריות של השפה טמונה במספר סיבות ויתרונות כגון:

    הצוות המנצח של Real Time College הכין במיוחד עבורכם מדריך מפורט לפיתוח GUI – ממשק משתמש בשפת פייתון.
    לטובת פיתוח זה השתמשנו ב API של ספריית tkinter.

    מומלץ לכתוב את המדריך בעצמכם על מנת לתרגל את כתיבת הקוד ואת העבודה עם API, אתם כמובן מוזמנים להוסיף פונקציות נוספות וכמובן כמו תמיד ליצור איתנו קשר במידה ויש שאלות או נושאים לא ברורים.
    לאחר התרגול תוכלו להמשיך ולקרוא על השפה באתר שלנו, ולהמשיך להתמקצע וללמוד בקורס פייתון אשר יפתח עבורכם הרבה דלתות לקריירה.
    בהצלחה?

    בואו ונראה כיצד נוכל ליצור מחשבון פשוט באמצעות ה – API של TkInter ב- Python.

    python

    !Let's Learn Python

    ראשית נתכונן לפרוייקט ונכין את תכנית הפיתוח, נתאר כיצד נרצה שהמחשבון יראה – כדי שנוכל להחליט באילו בקרים להשתמש ואיך למקם אותם בתוך החלון. נסתכל בדיאגרמה הבאה:

    תמונת אווירה

    בדיאגרמה מופיעה תיבת טקסט שבה יופיע מה שהמשתמש יֶקליד וכן התוצאה שתוצג לאחר לחיצה על "=". בנוסף ישנם 15 כפתורים שמשנים את הקלט, כפתור "C" שמוחק את הקלט, וכפתור "=" שמחשב את התוצאה.

    אנחנו יכולים לראות שיש למחשבון מבנה טבלאי, כאשר חלק מהבקרים תופסים יותר מ"תא" אחד. לכן לצורך סידור הבקרים נוכל להיעזר בגיאומטריית Grid.
    נוכל להתחיל לגשת בכתיבת הקוד. נתחיל עם קוד קצר יחסית כדי לקבל את ההרגשה של מה שאנחנו הולכים ליצור. ניצור חלון עם תיבת טקסט וכפתור בודד שמדפיס "1" בתוך תיבת הטקסט:

    
    
    
    import tkinter as tk
    root = tk.Tk()
    
    txt_display = tk.Entry(root)
    txt_display.pack()
    
    btn_1 = tk.Button(
        root,
        text="1",
        command=lambda: txt_display.insert(tk.END, "1"))
    btn_1.pack()
    
    
    
    
    
    root.mainloop()
    
    

    התוצאה שנקבל תראה כך:

    תמונת אווירה

    אמנם זה לא נראה מרשים, אך זו התחלה לקראת התוצר הסופי. לחיצה על הכפתור תשרשר את התו "1" לתוך תיבת הטקסט. נסביר את החלקים השונים של הקוד:

    
    import tkinter as tk
    

    שורה זו טוענת את המודול של TkInter בזיכרון, המודול מכיל את הקוד הפונקציות והמידע הדרוש ליצירת חלונות. כיוון שאנחנו הולכים להשתמש במודול זה בהרבה מקומות בקוד, אנחנו מקצרים את שמו ל-tk.

    
    root = tk.Tk()
    

    שורה זו מייצרת אובייקט חלון ראשי

    
    txt_display = tk.Entry(root)
    txt_display.pack()
    

    שורות אלו מייצרות תיבת טקסט (Entry), בעת היצירה של בקר של TkInter, ניתן לציין כפרמטרים את המאפיינים של הבקר. הפרמטר הראשון הינו המאסטר (master) של הבקר שמחליט למי שייך הבקר. במקרה שלנו אנו אומרים שהבקר שייך לחלון הראשי שיצרנו.

    לאחר יצירת הבקר אנו מחליטים כיצד הוא יופיע בחלון. בתור התחלה אנחנו מציגים אותו באמצעות pack שממקמת את הבקרים לפי סדר ברשימה, מלמעלה למטה. בהמשך נשנה זאת באמצעות grid (סידור טבלאי) כפי שתכננו במקור.

    
    btn_1 = tk.Button(
        root,
        text="1",
        command=lambda: txt_display.insert(tk.END, "1"))
    
    btn_1.pack()
    

    כאן אנו מייצרים כפתור. תהליך היצירה זהה לזה של תיבת הטקסט שיצרנו לעיל, אך, לכפתור פרמטרים נוספים. פרמטר text מגדיר את הטקסט שיופיע על גבי החלון. פרמטר command מגדיר איזו פונקציה תתבצע בעת לחיצה על הכפתור. בד"כ אנחנו אמורים ליצור את הפונקציה לפני-כן ואז לכתוב את שמה כפרמטר ל-command. אבל בגלל שהפונקציה של ביטוי בודד, נוכל לכתוב אותה באמצעות ביטוי lambda שמייצר לנו פונקציה אנונימית.

    מה שפונקציית ה-Lambda מבצעת זה לגשת לתיבת הטקסט שיצרנו ולבצע לתוכו הכנסת טקסט. דבר זה נעשה באמצעות מתודת insert שמקבלת שני פרמטרים. הראשון הוא המיקום בו נרצה שהטקסט יתווסף והשני הוא הטקסט שיש להוסיף. המיקום יכול להיות מספר מ-0 ומעלה שמציין את המקום, או לחילופין הוא יכול להיות הערך הקבוע END, ערך זה מציין את המקום שאחרי התו האחרון בתיבת הטקסט ולכן זה הערך שנשתמש בו.

    גם את הכפתור נמקם בינתיים על-פי גיאומטריית pack.

    על בסיס הקוד שלעיל נוכל ליצור את כל הכפתורים האחרים עם שינוי ה-text למה שהכפתור מציג. ושינוי ה-command כך שיוסיף את הטקסט הזה. יש לשים לב, שלצורך דוגמה זו הכפתור "X" יזין את הטקסט "*" היות וזה מה שפייתון מזהה בתור כפל. בנוסף, הכפתורים של מחיקה ("C") ושל חישוב התוצאה ("=") יכתבו באופן שונה כיוון שאלו יצטרכו פונקציות אחרות ב-command שלהם.

    
    root.mainloop()
    

    פקודה זו מריצה את הקוד שמנהל את התצוגה וההפעלה של החלון עד לסגירתו ריצה את החלון. בלי פקודה זו החלון לא יתפקד. פקודה זו צריכה להופיע בסוף הקוד לאחר יצירת הבקרים והגדרתם.

    עבור כפתור המחיקה ("C") נוסיף את הקוד הבא (לפני קריאה ל-mainloop):

    
    
    btn_clear = tk.Button(
        root,
        text="C",
        command=lambda: txt_display.delete(0, tk.END))
    
    btn_clear.pack()
    
    
    
    

    המתודה delete מקבלת בפרמטר ראשון את המיקום שממנו יש למחוק, כולל. אנו בוחרים ב-0 שמייצג את התו הראשון. והפרמטר השני הוא המיקום שעד אליו יש למחוק, אבל לא כולל, אנחנו בוחרים ב-END שמייצג את המקום אחרי התו האחרון (ולכן ימחוק את התו האחרון).

    עבור כפתור התוצאה נוסיף את הקוד הבא:

    
    def display_result():
        string = txt_display.get()
        try:
            result = eval(string)
        except:
            result = "ERROR"
    
        txt_display.delete(0, tk.END)
        txt_display.insert(0, str(result))
    
    btn_equal = tk.Button(
        root,
        text="=",
        command=display_result)
    
    btn_equal.pack()
    
    
    
    

    היות והקוד של ההשוואה יותר מורכב אנו יוצרים פונקציה עבורו בשם "dsiplay_result" באמצעות def במקום להשתמש ב-lambda. הפונקציה שולפת את המחרוזת שבתוך תיבת הטקסט באמצעות מתודת get. ולאחר מכן היא מנסה לבצע פונקציית eval את המחרוזת הזו. פונקציית eval היא פונקציה מובנית בפייתון שמאפשרת לתרגם מחרוזת לביטוי בפייתון. כך למשל אם המחרוזת מכילה "2+3" תוחזר התוצאה 5.

    הקוד של eval מופיע תחת הכותרת try שמאפשרת לקוד להחליט מה לבצע במידה ונזרקת שגיאה (למשל אם המשתמש מזין משהו לא חוקי כגון "12…334++" ). אם נזרקת שגיאה, הקוד שבכותרת except יתבצע ויקבע את התוצאה ל-error.

    לאחר חישוב התוצאה נעדכן את תיבת הטקסט כך שתכיל אותה, לשם כך נצטרך לבצע שתי פעולות. פעולת delete כדי למחוק את כל הטקסט הישן. ופעולת insert כדי להכניס את result. כיוון ש-result עלול להיות מספר ולא מחרוזת אנחנו ממירים אותו למחרוזת באמצעות פונקציית str.

    לאחר מכן הגדרת הכפתור היא כפי שיצרנו את הכפתורים האחרים רק שה-command מקושר לפונקציה שיצרנו.

    התוצר הסופי נראה כך:

    תמונת אווירה

    לחיצה על הכפתורים מראה שהקוד עובד. כדי לבדוק את פקודת ההשוואה נוכל להזין טקסט של פעולה חשבונית ואז ללחוץ על הכפתור כדי לקבל את התוצאה.

    כעת נוכל להוסיף את שאר הכפתורים ובהזדמנות זו לעבור לגיאומטריה בשיטה grid. נסתכל שוב במודל שיצרנו ונחלק אותו לעמודות ושורות:

    תמונת אווירה

    אנחנו יכולים לזהות איך כל בקר צריך להיות ממוקם בטבלה:

    תיבת הטקסט צריכה להתחיל בשורה 0 עמודה 0 ולתפוס 5 עמודות (מ-0 עד 4)
    הכפתור "1" צריך להיות ממוקם בשורה 1 עמודה 0
    הכפתור "2" צריך להיות ממוקם בשורה 1 עמודה 1
    וכולי לגבי שאר הכפתורים שתופסים תא בודד.

    הכפתור "0" ימוקם בשורה 4 עמודה 0 ויתפוס 2 שורות.
    הכפתור "=" ימוקם בשורה 2 עמודה 4 ויתפוס 3 עמודות.

    כדי למקם את הכפתורים, נחליף בקוד את הקריאה למתודה pack בקריאה למתודה grid. מתודה יכולה לקבל את הפרמטרים הבאים:

    ● column – עמודת התחלה
    ● row – שורת התחלה
    ● columnspan – כמה עמודות לתפוס
    ● rowspan – כמה שורות לתפוס
    ● sticky – קובע כיצד על הבקר שבתוך הטבלה "להיצמד" לגבולות שלה. אנחנו נשתמש בערך "NESW" שמשמעותו צפון-דרום-מזרח-מערב כדי לומר לבקר לתפוס את המקום המרבי שהוא יכול בטבלה.

    הקוד שנקבל יראה כך:

    
    
    
    import tkinter as tk
    
    def display_result():
        string = txt_display.get()
        try:
            result = eval(string)
        except:
            result = "ERROR"
    
        txt_display.delete(0, tk.END)
        txt_display.insert(0, str(result))
    
    root = tk.Tk()
    
    txt_display = tk.Entry(root)
    txt_display.grid(row=0, column=0, columnspan=5, sticky='NESW')
    
    
    btn_1 = tk.Button(root, text="1",
        command=lambda: txt_display.insert(tk.END, "1"))
    btn_1.grid(row=1, column=0, sticky='NESW')
    
    btn_2 = tk.Button(root, text="2",
        command=lambda: txt_display.insert(tk.END, "2"))
    btn_2.grid(row=1, column=1, sticky='NESW')
    
    btn_3 = tk.Button(root, text="3",
        command=lambda: txt_display.insert(tk.END, "3"))
    btn_3.grid(row=1, column=2, sticky='NESW')
    
    btn_4 = tk.Button(root, text="4",
        command=lambda: txt_display.insert(tk.END, "4"))
    btn_4.grid(row=2, column=0, sticky='NESW')
    
    btn_5 = tk.Button(root, text="5",
        command=lambda: txt_display.insert(tk.END, "5"))
    btn_5.grid(row=2, column=1, sticky='NESW')
    
    btn_6 = tk.Button(root, text="6",
        command=lambda: txt_display.insert(tk.END, "6"))
    btn_6.grid(row=2, column=2, sticky='NESW')
    
    btn_7 = tk.Button(root, text="7",
        command=lambda: txt_display.insert(tk.END, "7"))
    btn_7.grid(row=3, column=0, sticky='NESW')
    
    btn_8 = tk.Button(root, text="8",
        command=lambda: txt_display.insert(tk.END, "8"))
    btn_8.grid(row=3, column=1, sticky='NESW')
    
    btn_9 = tk.Button(root, text="9",
        command=lambda: txt_display.insert(tk.END, "9"))
    btn_9.grid(row=3, column=2, sticky='NESW')
    
    
    btn_0 = tk.Button(root, text="0",
        command=lambda: txt_display.insert(tk.END, "0"))
    btn_0.grid(row=4, column=0, columnspan=2, sticky='NESW')
    
    btn_dot = tk.Button(root, text=".",
        command=lambda: txt_display.insert(tk.END, "."))
    
    btn_dot.grid(row=4, column=2, sticky='NESW')
    
    btn_plus = tk.Button(root, text="+",
        command=lambda: txt_display.insert(tk.END, "+"))
    
    btn_plus.grid(row=1, column=3, sticky='NESW')
    
    btn_minus = tk.Button(root, text="-",
        command=lambda: txt_display.insert(tk.END, "-"))
    btn_minus.grid(row=2, column=3, sticky='NESW')
    
    btn_mul = tk.Button(root, text="*",
        command=lambda: txt_display.insert(tk.END, "*"))
    btn_mul.grid(row=3, column=3, sticky='NESW')
    
    btn_div = tk.Button(root, text="/",
        command=lambda: txt_display.insert(tk.END, "/"))
    btn_div.grid(row=4, column=3, sticky='NESW')
    
    btn_back = tk.Button(root, text="C", command=lambda: txt_display.delete(0, tk.END))
    btn_back.grid(row=1,column=4, sticky='NESW')
    
    btn_equal = tk.Button(root, text="=", command=display_result)
    btn_equal.grid(row=2,column=4, rowspan=3, sticky='NESW')
    
    root.mainloop()
    
    

    והתוצר שנקבל אם נריץ את הקוד יראה כך:

    תמונת אווירה בדיקות תוכנה

    נוכל לחסוך בקוד ולשפר את התחזוקה שלו ע"י שימוש בלולאה שתיצור את הכפתורים מ-1 עד 9 ושתמקם אותם בטבלה. ע"י חלוקת שלמים (//) וחלוקת מודולו (% שארית) נוכל גם לחשב את המיקום של כל כפתור לפי ערכו.

    ● כדי לחשב את מספר העמודה ניקח את ערך הכפתור, נחסר 1, נחלק ב-3 ונשמור את השארית

    ● כדי לחשב את מספר השורה נחלק את ערך הכפתור, נחסר 1, נחלק ב-3 (חלוקת שלמים) ולתוצאה נוסיף 1 (ההוספה של 1 היא בגלל הכפתורים מתחילים שורה אחת מתחת לשורה הראשונה).

    ז"א שאת הקוד שאחראי על יצירת הכפתורים מ-1 עד 9 נוכל להחליף בקוד הלולאה הבא:

    
    for num in range(1,10):
        btn = tk.Button(
            root,
            text=str(num),
            command = lambda x=num: txt_display.insert(tk.END, str(x)))
    
        btn.grid(column=(num-1)%3, row=(num-1)//3+1, sticky = 'NESW')
    
    
    

    הלולאה תעבור על כל ערך מ-1 עד 10 לא כולל (ז"א עד 9) ותשמור ב-num. ועבוד ערך זה ניצור את כפתור במקום המתאים. המשמעות של x=num בקוד היא ליצור משתנה לוקלי x ש"ילכוד" את ערכו של num בכל סיבוב. בלעדיו, כשהפונקציה תרוץ היא תמיד תקרא את ערכו האחרון של num (שהוא 0)

    בזאת למעשה סיימנו את היצירה של המחשבון שלנו. בהמשך נציג שינויים נוספים לשיפור המראה של החלון.

    נוסיף אובייקט פונט שייצג את הפונט שנשתמש בו עבור הכפתורים:

    
    
    import tkinter.font
    
    # ...
    
    font_buttons=tkinter.font.Font(root, family='Arial', size=20,
                                   weight='bold')
    
    
    

    נגדיר את הכותרת שתופיע בראש החלון ע"י root.title:

    
    root.title("Calculator")
    

    ונעדכן כל חלק בקוד שמייצר כפתור כך שיכלול פרמטר נוסף font ונקבע אותו לאובייקט שיצרנו. כך למשל עבור כפתור "+":

    
    btn_plus = tk.Button(root, text="+", font = font_buttons
        command=lambda: txt_display.insert(tk.END, "+"))
    

    עבור תיבת הטקסט נגדיר פונט משלו, לא חייבים ליצור אובייקט פונט לשם כך. נוכל להזין מחרוזת עם פרטי הפונט. בנוסף נרצה להגדיר שהטקסט ייושר מימין לשמאל במקום משמאל לימין. אז הקוד לתיבת הטקסט שלנו יעודכן כלהלן:

    
    txt_display = tk.Entry(root, font="Courier 40 bold", justify='right')
    txt_display.grid(row=0, column=0, columnspan=5, sticky='NESW')
    
    

    בנוסף, ע"י הפונקצייה root.rowconfigure והמתודה root.columnconfigure נוכל לתת "משקל" לשורות ולעמודות של הטבלה. המשקל הוא ערך שקובע כמה חלק מהחלון יש לתת לשורה או עמודה ביחס לשאר השורות והעמודות. כך למשל משקל 2 יתפוס פי שניים יותר מקום ממשקל 1.

    כברירת מחדל, המשקל הוא 0 כך שהתאים יקבלו גודל מינימלי ולא ישנו את גודלם אם נשנה את גודל החלון. אם נשנה את משקלם ל-1 הם ישנו את גודלם. נוכל לעשות זאת בלולאה של 5 סיבובים מ-0 עד 4 בה נגדיר את המשקל לשורות ולעמודות:

    
    
    for i in range(5):
        root.rowconfigure(i, weight=1)
        root.columnconfigure(i, weight=1)
    
    

    עם שינויים אלו המחשבון שלנו יראה כך:

    תמונת אווירה בדיקות תוכנה

    ולהלן הקוד הסופי:

    
    
    import tkinter as tk
    import tkinter.font
    
    def display_result():
        string = txt_display.get()
        try:
            result = eval(string)
        except:
            result = "ERROR"
    
        txt_display.delete(0, tk.END)
        txt_display.insert(0, str(result))
    
    root = tk.Tk()
    root.title("Basic Calculator")
    
    font_buttons = tkinter.font.Font(root, family='Arial', size=20, weight='bold')
    
    for i in range(5):
        root.rowconfigure(i, weight=1)
        root.columnconfigure(i, weight=1)
    
    txt_display = tk.Entry(root, font="Courier 40 bold", justify='right')
    txt_display.grid(row=0, column=0, columnspan=5, sticky='NESW')
    for num in range(1,10):
        btn = tk.Button(
            root,
    
            text=str(num),
            font=font_buttons,
            command=lambda x=num: txt_display.insert(tk.END, str(x)))
    
        btn.grid(column=(num-1)%3, row=(num-1)//3+1, sticky = 'NESW')
    
    btn_0 = tk.Button(root, text="0", font=font_buttons,
        command=lambda: txt_display.insert(tk.END, "0"))
    btn_0.grid(row=4, column=0, columnspan=2, sticky='NESW')
    
    btn_dot = tk.Button(root, text=".", font=font_buttons,
        command=lambda: txt_display.insert(tk.END, "."))
    btn_dot.grid(row=4, column=2, sticky='NESW')
    
    btn_plus = tk.Button(root, text="+", font=font_buttons,
        command=lambda: txt_display.insert(tk.END, "+"))
    btn_plus.grid(row=1, column=3, sticky='NESW')
    
    btn_minus = tk.Button(root, text="-", font=font_buttons,
        command=lambda: txt_display.insert(tk.END, "-"))
    btn_minus.grid(row=2, column=3, sticky='NESW')
    
    btn_mul = tk.Button(root, text="*", font=font_buttons,
        command=lambda: txt_display.insert(tk.END, "*"))
    btn_mul.grid(row=3, column=3, sticky='NESW')
    
    btn_div = tk.Button(root, text="/", font=font_buttons,
        command=lambda: txt_display.insert(tk.END, "/"))
    btn_div.grid(row=4, column=3, sticky='NESW')
    
    btn_back = tk.Button(root, text="C", font=font_buttons,
        command=lambda: txt_display.delete(0, tk.END))
    btn_back.grid(row=1,column=4, sticky='NESW')
    
    btn_equal = tk.Button(root, text="=", font=font_buttons,
        command=display_result)
    btn_equal.grid(row=2,column=4, rowspan=3, sticky='NESW')
    
    
    root.mainloop()
    
    
    
    
    

    כל הכבוד! סיימתם את המדריך לכתיבת מחשבון TkInter בפייתון! פיייתון היא שפת תכנות יחסית קלה וידידותית ללימוד והיא נמצאת בשימוש בתחומים רבים בתעשיית ההייטק, כעת ראיתם דוגמא לפיתוח פרוייקט יחסית פשוט בשפת פייתון אך ישנם עוד שימושים רבים עבור השפה.
    חברות הייטק מחפשות באופן תדיר אחר מפתחי פייתון מנוסים אשר יוכלו להשתלב בתחומים רבים בתעשייה.

    כעת אתם מוזמנים להמשיך ולקרוא בנושא באתר שלנו ולבצע תרגילים בפייטון, ניתן במכללת רילטיים ללמוד את קורס פייתון כקורס לימוד פרטני או כחלק ממסלול הכשרה למסלולים נוספים כגון בדיקות תוכנה, דבאופס, בינה מלאכותית ועוד. בעזרת פייתון ניתן לפתוח דלתות רבות לכיוונים נוספים לפיתוח קריירה בהייטק
    לנוחיותכם להלן מאמרים נוספים ומידע נוסף מבית Real Time College