Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
AhmadAlsaadi
GitHub Repository: AhmadAlsaadi/Arabic-python-notebook
Path: blob/master/الفصل التسع-واجهة المستخدم GUI.ipynb
675 views
Kernel: Python 3 (ipykernel)
import style style._set_css_style("custom.css")

الفصل العاشر : واجهة المستخدم GUI


تعتبر واجهة المستخدم من أفضل طرق التفاعل التي يمكن ان يقدمها مطوري البرامج لمستخدمي البرامج. حيث تحتوي واجهة المستخدم على ازرار للضغط عليها وصناديق نصوص لادخال النصوص وقوائم اختيار والكثير الكثير من الأدوات التي تمكن مستخدمي البرامج من التفاعل مع برامجهم وادخال البيانات لها. ويتوفر لمطوري بايثون العديد من المكتبات التي تسهل عمل واجهات مستخدم احترافية والتي من اشهرها:

  1. مكتبة tkinter والتي تأتي مدمجة مع إصدارة بايثون كمكتبة قياسية .

  2. مكتبة PyQt5 وهي مكتبة خارجية ذائعة الصيت متوائمة مع أنطمة التشغيل المشهورة.

  3. مكتبة wxPython وهي ايصاً مكتبة خارجية متوائمة مع أنطمة التشغيل المشهورة.

  4. مكتبة Kivy وهي مكتبة خارجية مفتوحة المصدر متوائمة مع أنطمة التشغيل المشهورة.

أهداف الفصل

عند اتمام هذا الفصل يجب ان يكون لديك المام بالآتي:

  1. التعرف على بناء واجهة مستخدم بسيطة باستخدام مكتبة tkinter
  2. التعرف على بناء واجهة مستخدم بسيطة باستخدام مكتبة PyQt5
  3. التعرف على بناء واجهة مستخدم بسيطة باستخدام مكتبة Kivy

مكتبة tkinter

تمثل مكتبة Tkinter مكتبة الواجهة الرسومية القياسية لبايثون حيث تأتي هذه المكتبة من ضمن المكتبات القياسية التي يتم تنصيبها مع مفسر بايثون. ولعمل واجهه رسوميه اساسية من خلال هذه المكتبة نحتاج لكتابة ثلاثة اسطر قصيرة من الكود البرمجي كما في المثال التالي:
import tkinter
from tkinter import Tk win=Tk() win.mainloop()
فعند تنقيذ المثال السابق سوف تظهر لنا نافذه رسومية اساسية بمقاس افتراضي 200 بكسل عرضا و 200 بكسل طولا تحمل عنوان افتراضي tk وايقونه رسوميه لريشة زقاء وكذلك ثلاثة ازراز لتصغير وتكبير واغلاق النافذة. فالسطر الاول من الكود البرمجي السابق هو مجرد استدعاء للصنف Tk المسؤول عن انشاء نوافذ قياسية من مكتبة tkinter كما تعلمنا سابقا. اما السطر الثاني فهو مجرد عمل نسخة من الصنف Tk واسناده الى المتغير win. في السطر الثالث تم استدعاء الدالة ()mainloop على نسخة النافذه الاساسية التي انشأناها من الصنف Tk. وظيفة هذه الدالة هي عمل حلقة تكرار تبقى النافذه على الشاشة وتجعلها تنتظر اي تفاعل من المستخدم سواء كان بتحريك او تكبير او اتصغير او غير ذلك من الافعال التي سوف يأتي شرحها لاحقا.
لنقم الان تغير عنوان النافذه السابقة الي "اله حاسبة" من خلال استخدام الدالة ()title كما يلي:
from tkinter import Tk win=Tk() win.title("ألة حاسبة") win.mainloop()
قد يبدو ان اسم النافذه غير مكتمل وذلك لان مقاس النافذه الافتراضي غير كافي الاظهار الاسم. لنقم بتغيير مقاس النافذه الرئيسية الى 400 بكسل عرضا و 300 بكسل طولا باستخدام الدالة ()geometry كما يلي:
from tkinter import Tk win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.mainloop()
لاحظ ان القيمة المدخلة للدالة ()geometry هي قيمة نصية تمثل القيمة الاولى من اليسار عرض النافذة والقيمة الثانية تمثل طول او ارتفاع النافذه بحيث تم الفصل بين القيمتين بعلامة الضرب "x".
على الرغم من اننا قمنا باتغيير مقاس النافذه الرئيسية عند بداية تشغيل البرنامج الا ان هذا الامر لن يمنع المستخدم من تغيير مقاسات النافذه متى ما اراد ذلك. فبمجرد الوقوف بمؤشر الفارة عند احد اطراف النافذه فان المؤشر سوف يتغير شكله الى سهمين مزدوجين تعني ان المستخدم عند ضغطه لزر الفأرة في هذا المكان مع مواصلة الضغط والتحرك سوف يقوم بتغيير مقاسات النافذة كيفما شاء. ويمكنك التأكد من ذلك بتشغيل الكود البرمجي السابق ومحاولة تغيير مقاسات النافذة.
ان اعطاء المستخدم صلاحيات تغيير مقاس النافذه الرئيسية قد يشوه شكل الالة الحاسبة عند قيامه بعملية تكبير او تصغير الناقذه لذلك من الافضل ان نقوم بمنع المستخدم من تغيير مقاسات النافذة الرئيسية باستخدام الدالة ()resizable وااعظائها القيم صفر و صفر في كلا المدخلين كما في المثال التالي:
from tkinter import Tk win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) win.mainloop()
لاحظ انه عند تشغيل الكود السابق والوقوف بزر الفأرة على احد اطراف النافذة الرئيسية لا يتغير مؤشر الفأرة الى سهمين مزدوجين مما يعني ان عملية تغيير مقاسات النافذه اصحبت غير ممكنه. كما ان زر التكبير في النافذه الرئيسية اصبح غير نشط ايضاً.
ان ايقونه الريشة الزرقاء لا تتناسب مع الآلة الحاسبة التي ننوي القيام بانشائها. لنقم بتغيير هذه الايقونه الى ايقونه آلة حسابة صغيرة تم تحميلها من الانترنت وحفظها في ملف الصور الخاص بهذا الكتاب تحت اسم calculator.png. ولارفاق الايقونه الى النافذه الاساسية نحتاج الى استدعاء صنف الصور PhotoImage من مكتبة tkinter ومن ثم عمل نسخة من هذا الصنف باستخدام مسار الصورة التي تم تحميلها من الانترنت كمدخل. ثم نقوم باستخدام هذه النسخة والتي اسندناها الى متغير اسمه photo كمدخل ثاني للدالة ()iconphoto كما يلي:
from tkinter import Tk, PhotoImage win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) win.mainloop()
ان تعلم اضافة الادوات الى النافذة الرئيسية من ازرار و خلافه لن يتحقق الا بعد معرفتنا للطريقة التي يتم بها ترتيب هذه الادوات داخل هذه النافذة من اجل عرضها على شاشة المستخدم. وفي مكتبة Tkinter هناك ثلاث طرق تسخدم لترتيب الادوات داخل النوافذ وهي على النحو التالي:
اولاً: طريقة الحشو pack
تعتبر طريقة الحشو من اسهل الطرق التي يتم فيها ترتيب الادوات داخل النوافذ فهي لا تحتاج الى تحديد اماكن الادوات على النافذه وانما تكتفي بمعرفه ترتيب ظهور الادوات عليها فيتم ترتيبها اما عموديا او رأسيا حسب ما يحدده المبرمج. ولكي نتعرف على طريقة الترتبب هذه لنقم بتكوين عدد من ازرار الالة حاسبة التي نود انشائها باستدعاء صنف الازرار Button من مكتبة Tkinter ولنقم بعمل عدة نسخ منه كما في الكود التالي:
from tkinter import Tk, PhotoImage, Button win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) b1=Button(win, text='1') b2=Button(win, text='2') b3=Button(win, text='3') win.mainloop()
كما اشرنا سابقا ان عملية انشاء نسخ من صنف الازرار Button لا تكفي لاظهار هذه الازرار على النافذه الرئيسية على الرغم من اننا قمنا بتحديد المكان الذي نود ان تظهر فيه هذه الازرار وذلك باستخدام متغير النافذه الرئيسية كمتغير اول كما قمنا ايضا بتحديد النص الذي يجب ان يظهر على الزر عند انشاؤه. ان عدم ظهور الازرار في الكود السابق سببه هو اننا لم نقم باستخدام اي دالة تخبر مفسر بايثون بالكيفية التي يتم بها عرض هذه الازرار داخل النافذه الرئيسية. لذلك عند رغبتنا في استخدام طريقة الحشو لترتيب هذه الازرار فانه يتوجب علينا استخدام الدالة ()pack والتي تعمل على ترتيب الازرار بشكل عامودي في النافذة الرئيسية على نحو افتراضي بحسب ترتيب هذه الادوات في الكود البرمجي كما يلي:
from tkinter import Tk, PhotoImage, Button win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) b1=Button(win, text='1').pack(side='bottom') b2=Button(win, text='2').pack(side='bottom') b3=Button(win, text='3').pack(side='bottom') win.mainloop()
لكي نقوم بتغيير ترتيب الازرار بشكل افقي نحتاج ان نغير القيمة الافتراضية للمدخل side في دالة ()pack من top الى left او right كما في الكود التالي:
from tkinter import Tk, PhotoImage, Button win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) b1=Button(win, text='1').pack(side='left') b2=Button(win, text='2').pack(side='left') b3=Button(win, text='3').pack(side='left') win.mainloop()
from tkinter import Tk, PhotoImage, Button win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) b1=Button(win, text='1').pack(side='right') b2=Button(win, text='2').pack(side='right') b3=Button(win, text='3').pack(side='right') win.mainloop()
لاحظ ان استخدام القيمة النصية right للمدخل side جعل بداية ترتيب الازرار تبدأ من يمين النافذة والقيمة left بدأت الترتيب من يسار النافذة الرئيسية.
ان حجم الازرار في الكود السابق كان يتغير بطول النص الموجود على كل زر فلو قمنا بتغيير القيم النصية على كل زر لتغير حجم الزر بتغير القيمة النصية كما يلي:
from tkinter import Tk, PhotoImage, Button win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) b1=Button(win, text='1').pack(side='right') b2=Button(win, text='But 2').pack(side='right') b3=Button(win, text='Button 3').pack(side='right') win.mainloop()
لتوحيد احجام الازرار والتحكم في ابعادها نقوم بتغيير قيم المدخل width والمدخل height عند عمل نسخة لكل زر كما يلي:
from tkinter import Tk, PhotoImage, Button win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) b1=Button(win, text='1',width=10,height=2).pack(side='right') b2=Button(win, text='2',width=10, height=2).pack(side='right') b3=Button(win, text='3',width=10,height=2).pack(side='right') win.mainloop()
للتحكم في المسافات الافقية بين الازرار نستخدم قيم اكبر من الصفر للمدخل xpad في الدالة ()pack كما يلي:
from tkinter import Tk, PhotoImage, Button win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) b1=Button(win, text='1',width=10,height=2).pack(side='right',padx=6) b2=Button(win, text='2',width=10, height=2).pack(side='right',padx=3) b3=Button(win, text='3',width=10,height=2).pack(side='right',padx=3) win.mainloop()
عندما نقوم بزيادة عدد الازرار الى 6 مثلا فان خاصية الحشو pack لا تقوم بالنزول الى صف ثاني لاستيعاب عدد الازرار الذي يزيد عن عرض النافذة الرئيسية ويصبح عدد من الازرار غير ظاهر للمستخدم كما يلي:
from tkinter import Tk, PhotoImage, Button win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) b1=Button(win, text='1',width=10,height=2).pack(side='right',padx=6) b2=Button(win, text='2',width=10, height=2).pack(side='right',padx=3) b3=Button(win, text='3',width=10,height=2).pack(side='right',padx=3) b4=Button(win, text='4',width=10,height=2).pack(side='right',padx=3) b5=Button(win, text='5',width=10, height=2).pack(side='right',padx=3) b6=Button(win, text='6',width=10,height=2).pack(side='right',padx=3) win.mainloop()
ولتغلب على هذه المشكلة نحتاج الى عمل حيلة تمكننا من ترتيب الازرار في صفوف. ويمكن عمل هذه الحيلة باستدعاء الصنف اطار Frame من المكتبة Tkinter بحيث نعمل إطار لكل صف ونرتب الإطارات في النافذة بشكل عمودي ونرتب الأزرار داخل الإطارات بشكل افقي كما يلي:
from tkinter import Tk, PhotoImage, Button, Frame win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) row1=Frame(win) row1.pack(pady=3) b1=Button(row1, text='1',width=10,height=2).pack(side='right',padx=3) b2=Button(row1, text='2',width=10, height=2).pack(side='right',padx=3) b3=Button(row1, text='3',width=10,height=2).pack(side='right',padx=3) row2=Frame(win) row2.pack(pady=3) b4=Button(row2, text='4',width=10,height=2).pack(side='right',padx=3) b5=Button(row2, text='5',width=10, height=2).pack(side='right',padx=3) b6=Button(row2, text='6',width=10,height=2).pack(side='right',padx=3) win.mainloop()
لنقم الآن بإضافة كل ما نحتاجه من أزار الى النافذة الرئيسية باستخدام الحيلة السابقة ليصبح الكود البرمجي بالشكل التالي:
from tkinter import Tk, PhotoImage, Button, Frame win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) row1=Frame(win) row1.pack(pady=3) b_mult=Button(row1, text='x',width=4,height=2).pack(side='right',padx=3) b9=Button(row1, text='9',width=10,height=2).pack(side='right',padx=3) b8=Button(row1, text='8',width=10,height=2).pack(side='right',padx=3) b7=Button(row1, text='7',width=10,height=2).pack(side='right',padx=3) row2=Frame(win) row2.pack(pady=3) b_minus=Button(row2, text='-',width=4,height=2).pack(side='right',padx=3) b6=Button(row2, text='6',width=10, height=2).pack(side='right',padx=3) b5=Button(row2, text='5',width=10,height=2).pack(side='right',padx=3) b5=Button(row2, text='4',width=10,height=2).pack(side='right',padx=3) row3=Frame(win) row3.pack(pady=3) b_plus=Button(row3, text='+',width=4,height=2).pack(side='right',padx=3) b3=Button(row3, text='6',width=10, height=2).pack(side='right',padx=3) b2=Button(row3, text='5',width=10,height=2).pack(side='right',padx=3) b1=Button(row3, text='4',width=10,height=2).pack(side='right',padx=3) row4=Frame(win) row4.pack(pady=3) b_equal=Button(row4, text='=',width=4,height=2).pack(side='right',padx=3) b_dot=Button(row4, text='.',width=10, height=2).pack(side='right',padx=3) b0=Button(row4, text='0',width=10,height=2).pack(side='right',padx=3) b_sign=Button(row4, text='+/-',width=10,height=2).pack(side='right',padx=3) win.mainloop()
لو أردنا أن نقوم بإجراء أي تعديل على أحد خصائص الأزرار في الكود السابق فإننا سوف نجد أنفسنا مضطرىن الى إجراء هذا التغيير على كافة الأزرار الموجودة فتصبح العملية مرهقة للغاية. لذلك يكون من الأنسب أن نعمل صنف معدل للأزرار بحيث يصبح هذا الصتف هو الصنف الأساسي الذي تنسخ منه بقية الأزرار وعندها يصبح التعديل على الصنف يكفي لإجراء التعديل على كافة الأزرار الموجودة كما في الكود التالي:
from tkinter import Tk, PhotoImage, Button, Frame win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) class Cal_Button(Button): def __init__(self,*args,**kwargs): Button.__init__(self,*args,**kwargs) self["width"]=8 self["height"]=2 self["font"]=12 for arg in kwargs.items(): self[arg[0]]=arg[1] row1=Frame(win) row1.pack(pady=3) b_mult=Cal_Button(row1, text='x',width=3).pack(side='right',padx=3) b9=Cal_Button(row1, text='9').pack(side='right',padx=3) b8=Cal_Button(row1, text='8').pack(side='right',padx=3) b7=Cal_Button(row1, text='7').pack(side='right',padx=3) row2=Frame(win) row2.pack(pady=3) b_minus=Cal_Button(row2, text='-',width=3).pack(side='right',padx=3) b6=Cal_Button(row2, text='6').pack(side='right',padx=3) b5=Cal_Button(row2, text='5').pack(side='right',padx=3) b5=Cal_Button(row2, text='4').pack(side='right',padx=3) row3=Frame(win) row3.pack(pady=3) b_plus=Cal_Button(row3, text='+',width=3).pack(side='right',padx=3) b3=Cal_Button(row3, text='6').pack(side='right',padx=3) b2=Cal_Button(row3, text='5').pack(side='right',padx=3) b1=Cal_Button(row3, text='4').pack(side='right',padx=3) row4=Frame(win) row4.pack(pady=3) b_equal=Cal_Button(row4, text='=',width=3).pack(side='right',padx=3) b_dot=Cal_Button(row4, text='.').pack(side='right',padx=3) b0=Cal_Button(row4, text='0').pack(side='right',padx=3) b_sign=Cal_Button(row4, text='+/-').pack(side='right',padx=3) win.mainloop()
لنقم الان باضافة المكان الذي سوف تظهر فيه العمليات الحسابية ونتائجها. سوف نحتاج لاستدعاء الصنف Label من مكتبة tkinter وعمل نسخة من هذا الصنف واسنادها للمتغير display كما في المثال التالي:
from tkinter import Tk, PhotoImage, Label, Button, Frame class Cal_Button(Button): def __init__(self,*args,**kwargs): Button.__init__(self,*args,**kwargs) self["width"]=8 self["height"]=2 self["font"]=12 for arg in kwargs.items(): self[arg[0]]=arg[1] win=Tk() win.title("ألة حاسبة") win.geometry("400x300") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) display=Label(win,text="0.0",height=3,bg='white',width=38,font=12) display.pack(pady=3) row1=Frame(win) row1.pack(pady=3) b_mult=Cal_Button(row1, text='x',width=3).pack(side='right',padx=3) b9=Cal_Button(row1, text='9').pack(side='right',padx=3) b8=Cal_Button(row1, text='8').pack(side='right',padx=3) b7=Cal_Button(row1, text='7').pack(side='right',padx=3) row2=Frame(win) row2.pack(pady=3) b_minus=Cal_Button(row2, text='-',width=3).pack(side='right',padx=3) b6=Cal_Button(row2, text='6').pack(side='right',padx=3) b5=Cal_Button(row2, text='5').pack(side='right',padx=3) b5=Cal_Button(row2, text='4').pack(side='right',padx=3) row3=Frame(win) row3.pack(pady=3) b_plus=Cal_Button(row3, text='+',width=3).pack(side='right',padx=3) b3=Cal_Button(row3, text='6').pack(side='right',padx=3) b2=Cal_Button(row3, text='5').pack(side='right',padx=3) b1=Cal_Button(row3, text='4').pack(side='right',padx=3) row4=Frame(win) row4.pack(pady=3) b_equal=Cal_Button(row4, text='=',width=3).pack(side='right',padx=3) b_dot=Cal_Button(row4, text='.').pack(side='right',padx=3) b0=Cal_Button(row4, text='0').pack(side='right',padx=3) b_sign=Cal_Button(row4, text='+/-').pack(side='right',padx=3) win.mainloop()
--------------------------------------------------------------------------- TclError Traceback (most recent call last) /tmp/ipykernel_3640/42548479.py in <module> 13 win.resizable(0,0) 14 photo = PhotoImage(file = "img/calculator.png") ---> 15 win.iconphoto(False,photo) 16 display=Label(win,text="0.0",height=3,bg='white',width=38,font=12) 17 display.pack(pady=3,anchor="w") /usr/lib/python3.8/tkinter/__init__.py in wm_iconphoto(self, default, *args) 2125 self.tk.call('wm', 'iconphoto', self._w, "-default", *args) 2126 else: -> 2127 self.tk.call('wm', 'iconphoto', self._w, *args) 2128 2129 iconphoto = wm_iconphoto TclError: can't use "pyimage2" as iconphoto: not a photo image

لنقم الآن بإضافة وظائف لأزار الآلة الحاسبة وذلك بكتابة دوال تقوم بمهام ادخال الارقام واجراء العمليات الحسابية عند الضغط على هذه الأزرار.

from tkinter import Tk, PhotoImage, Label, Button, Frame def text(txt): op=["/","x","+","-"] if txt=="c": display["text"]="0.0" elif txt in op and display["text"][-1] in op: display["text"]=display["text"][:-1]+txt elif display["text"]=="0.0": display["text"]=txt else: display["text"]+=txt if display["text"][-1]=="=": cal=display["text"].replace("x","*") display["text"]+="\n"+"\t"*3+str(eval(cal[:-1])) class Cal_Button(Button): def __init__(self,*args,**kwargs): Button.__init__(self,*args,**kwargs) self["width"]=8 self["height"]=2 self["font"]=12 for arg in kwargs.items(): self[arg[0]]=arg[1] self["command"]=lambda:text(self["text"]) win=Tk() win.title("ألة حاسبة") win.geometry("400x350") win.resizable(0,0) photo = PhotoImage(file = "img/calculator.png") win.iconphoto(False,photo) display=Label(win,text="0.0",height=3,bg='white',width=38,font=12,anchor="w",justify="left") display.pack(pady=3) row0=Frame(win) row0.pack(pady=3) b_mult=Cal_Button(row0, text='/',width=3).pack(side='right',padx=3) bbl=Cal_Button(row0, text='c').pack(side='right',padx=3) bbr=Cal_Button(row0, text=')').pack(side='right',padx=3) bc=Cal_Button(row0, text='(').pack(side='right',padx=3) row1=Frame(win) row1.pack(pady=3) b_mult=Cal_Button(row1, text='x',width=3).pack(side='right',padx=3) b9=Cal_Button(row1, text='9').pack(side='right',padx=3) b8=Cal_Button(row1, text='8').pack(side='right',padx=3) b7=Cal_Button(row1, text='7').pack(side='right',padx=3) row2=Frame(win) row2.pack(pady=3) b_minus=Cal_Button(row2, text='-',width=3).pack(side='right',padx=3) b6=Cal_Button(row2, text='6').pack(side='right',padx=3) b5=Cal_Button(row2, text='5').pack(side='right',padx=3) b5=Cal_Button(row2, text='4').pack(side='right',padx=3) row3=Frame(win) row3.pack(pady=3) b_plus=Cal_Button(row3, text='+',width=3).pack(side='right',padx=3) b3=Cal_Button(row3, text='3').pack(side='right',padx=3) b2=Cal_Button(row3, text='2').pack(side='right',padx=3) b1=Cal_Button(row3, text='1').pack(side='right',padx=3) row4=Frame(win) row4.pack(pady=3) b_equal=Cal_Button(row4, text='=',width=3).pack(side='right',padx=3) b_dot=Cal_Button(row4, text='.').pack(side='right',padx=3) b0=Cal_Button(row4, text='0').pack(side='right',padx=3) b_sign=Cal_Button(row4, text='+/-').pack(side='right',padx=3) win.mainloop()
ثانياً: طريقة تحديد المحاور place
ثالثاً: طريقة الجدول grid

مكتبة PyQt5

eval("3+5")
8

مكتبة Kivy

pip install kivy
Collecting kivy Downloading Kivy-2.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (31.3 MB) |████████████████████████████████| 31.3 MB 4.0 MB/s eta 0:00:011 |███████████▎ | 11.1 MB 907 kB/s eta 0:00:23 Collecting Kivy-Garden>=0.1.4 Downloading Kivy_Garden-0.1.5-py3-none-any.whl (4.6 kB) Requirement already satisfied: pygments in /home/alhakeeeem/.local/lib/python3.8/site-packages (from kivy) (2.9.0) Requirement already satisfied: docutils in /home/alhakeeeem/.local/lib/python3.8/site-packages (from kivy) (0.19) Requirement already satisfied: requests in /usr/lib/python3/dist-packages (from Kivy-Garden>=0.1.4->kivy) (2.22.0) Installing collected packages: Kivy-Garden, kivy Successfully installed Kivy-Garden-0.1.5 kivy-2.1.0 Note: you may need to restart the kernel to use updated packages.
from kivy.app import App from kivy.uix.button import Button class LanguageLearnerApp(App): def build(self): return Button(text="Hello World!", size=(100,100), pos=(100,100)) LanguageLearnerApp().run()
[INFO ] [Logger ] Record log in /home/alhakeeeem/.kivy/logs/kivy_23-01-07_2.txt [INFO ] [Kivy ] v2.1.0 [INFO ] [Kivy ] Installed at "/home/alhakeeeem/.local/lib/python3.8/site-packages/kivy/__init__.py" [INFO ] [Python ] v3.8.10 (default, Nov 14 2022, 12:59:47) [GCC 9.4.0] [INFO ] [Python ] Interpreter at "/usr/bin/python3" [INFO ] [Logger ] Purge log fired. Processing... [INFO ] [Logger ] Purge finished! [INFO ] [Factory ] 189 symbols loaded [INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil (img_ffpyplayer ignored) [INFO ] [Text ] Provider: sdl2 [INFO ] [Window ] Provider: sdl2 [INFO ] [GL ] Using the "OpenGL" graphics system [INFO ] [GL ] Backend used <sdl2> [INFO ] [GL ] OpenGL version <b'1.4 (4.6.0 NVIDIA 456.71)'> [INFO ] [GL ] OpenGL vendor <b'NVIDIA Corporation'> [INFO ] [GL ] OpenGL renderer <b'GeForce GT 730/PCIe/SSE2'> [INFO ] [GL ] OpenGL parsed version: 1, 4

مكتبة pyGUI