ساخت ماشین حساب با پایتون + [ آموزش گام به گام ]
.
.
در این مقاله قصد داریم با استفاده از پایتون یک ماشین حساب گرافیکی شیک بسازیم. با افراز ادیو همراه باشید تا مرحله به مرحله ساخت ماشین حساب با پایتون را با هم یاد بگیریم.
ساخت ماشین حساب با پایتون به صورت گرافیگی
عرض و سلام و احترام خدمت تک تک همراهان افراز ادیو. ما برگشتیم با یک مقاله جدید. در این مقاله قصد داریم تا با استفاده از کتابخانه tkinter یک ماشین حساب گرافیکی مثل تصویر زیر را از صفرِ صفر بسازیم.
این آموزش را به چند بخش تقسیم میکنیم. در بخش اول میاییم با استفاده از پایتون ظاهر ماشین حساب خودمون رو طراحی میکنیم. یعنی بعد از این که بخش اول رو تموم کردیم، هیچ کدوم از دکمهها کار نمیکنه. در بخش بعدی هم میریم سراغ اصل کار، یعنی وقتی روی هر دکمهای کلیک شد، کار مخصوص خودش رو انجام بده.
پس بدون فوت وقت بریم تا شروع کنیم.
ساخت ظاهر ماشین حساب با پایتون
ساخت پنجره ماشین حساب
همانطور که در ابتدای این مقاله هم گفتیم، میخواهیم از کتابخانه tkinter پایتون برای ساخت این ماشین حساب، استفاده کنیم. پس اول باید اون رو به برنامه import کنیم. خیلی خیلی مرسوم هست که کتابخانه tkinter را با نام مستعار tk به برنامه import میکنند.
راستی تا یادم نرفته بگم که شما هم همراه ما، حتماً حتماً کدها را بنویسید. یکی از دلایلی که خود کد رو نمیذاریم این هست که شما کد رو تایپ کنید، این کار خودش باعث یادگیری و به خاطر سپردن دستورات میشه.
حالا میتونیم از تمام امکانات کتابخانه tkinter استفاده کنیم. در ابتدا بیایید تا پنجره اولیه خودمون رو بسازیم. برای این منظور باید از کلاس Tk موجود در tkinter یک شی بسازیم و درون یک متغیر ذخیره کنیم. (این قراره همون پنجره ما باشه). کد زیر رو ببینیم.
توجه کنید که نام متغیر دلخواه است (یعنی لزومی نداره که حتماً window انتخاب شود و شما هر نامی رو که دوست داشتید میتونید انتخاب کنید به شرطی که قواعد نامگذاری رو رعایت کنید).
الان انتظار داریم تا با اجرای برنامه یک صفحه برای ما باز شود. پس بیایید تا برنامه را اجرا بگیریم. من اجرا گرفتم شما هم گرفتید؟ خُب من که چیزی ندیدم و به احتمال زیاد برای شما هم چیزی نیامد. دلیلش چیست؟ میدانیم که پایتون برنامه را از بالا به پایین خط به خط میخونه و اجرا میکنه و اگر به انتهای کد برسه برنامه رو میبنده. اینجا هم دقیقاً همین اتفاق افتاد، در واقع میشه گفت که پایتون یک لحظه برنامه رو اجرا کرد و سریع بست. برای این که برنامه رو در حال اجرا نگه داریم باید کد زیر رو به برنامه اضافه کنیم.
حالا برنامه رو اجرا کنیم. من که دیدم، شما هم دیدید؟ بله، بالاخره موفق شدیم تا پنجره گرافیکی رو ببینیم. تصویر زیر:
توجه: دلیل اینکه یک خط بین خط 2 و 4 فاصله انداختیم، این بود که با اینکار خواستیم بگیم که تمام دستوراتی که در ادامه میخواهیم بنویسیم، بالای windows.mainloop() نوشته میشود.
در واقع این پنجره پیشفرضی است که tkinter برای ما میسازد. در پنجره پیشفرض عنوان همیشه tk نوشته میشود. منظورم کادر نارنجی در تصویر زیر است.
و همیشه آیکون برنامه یک پر است منظور کادر سبز در تصویر زیر است.
اندازه پنجره نیز 200 در 200 پیکسل است یعنی:
همین جا بگم که تمام این موارد توسط ما قابل تغییر است. پس بیایید تا با توجه به عکس ماشین حساب گرافیکی خود، موارد بالا را تنظیم کنیم. اول از همه سایز پنجره را تنظیم کنیم برای این منظور از دستوز .geometry() به صورت زیر استفاده میکنیم:
در واقع سایز مورد نظر را به صورت ارتفاع×عرض در قالب یک رشته در ورودی دستور .geometry() مینویسیم.
حال بیایید تا عنوان برنامه خود را از tk به عنوان دلخواه خود تغییر دهیم. برای این منظور از دستور .title() به صورت زیر استفاده میکنیم.
در ادامه لوگو برنامه را از پَر به لوگو دلخواه خود تغییر میدهیم. برای این منظور از دستور .iconbitmap() به صورت زیر استفاده میکنیم. فقط باید توجه کنیم که برای استفاده از این دستور به یک آیکون با پسوند .ico نیاز داریم.
ما یک آیکون ماشین حساب با پسوند .ico از اینترنت پیدا کردیم و آن را کنار فایل پایتونی خود گذاشتیم و سپس با استفاده از دستور .iconbitmap() آن را برای ماشین حساب خود قرار دادیم.
در ادامه میخواهیم کاری کنیم تا اندازه برنامه قابل تغییر نباشد. برای این منظور از دستور .resizeable() به صورت زیر استفاده میکنیم.
ورودی متد resizable دو نوع Boolean است. یعنی نوعی که میتواند False یا True باشد. اولین ورودی مربوط به width عرض پنجره است و دومین ورودی مربوط به height ارتفاع پنجره است. که ما تغییر اندازه هر دو مورد را False کردهایم. پس یعنی در هیچ جهتی نمیتوان اندازه پنجره را تغییر داد.
به نظرم خوبه که بیاییم و تا اینجای کار یک خروجی از برنامه بگیریم.
بله میبینیم که تمام موارد مورد انتظار، انجام شده است. بسیار عالی، حالا اگه گفتید نوبت چیه؟ بله دقیقاً الان نوبت قرار دادن دکمهها و بقیه موارد در پنجره ساخته شده است. پس همچنان با ما همراه باشید.
ایجاد المانها (ویجتها) در ماشین حساب گرافیکی با پایتون
یکبار دیگر نگاهی به ماشین حساب گرافیکی خود داشته باشیم.
به طور کلی ما در این ماشین حساب گرافیکی، از دو ویجت استفاده کردهایم، یکی دکمه (همان Button) و یکی هم ورودی (همان Entry). در واقع ما 16 دکمه داریم و یک ورودی. حال بیایید تا این اِلِمانها را تک به تک بسازیم.
برای این که ورودی (Entry) را بسازیم از کلاس Entry موجود در tkinter به صورت زیر استفاده میکنیم.
حالا هر مورد رو توضیح میدیم.
1) میتونم بگم که اولین ورودی تمام اِلِمانها، مشخص کردن این است که این اِلِمان قرار است در کدام پنجره قرار بگیرد. یعنی در یک برنامه گرافیکی ممکن است ما چندین پنجره به طور همزمان داشته باشیم. مثلاً window و window1 و … . بنابراین باید مشخص کنیم که اِلِمانی که میخواهیم بسازیم قرار است در کدام پنجره قرار بگیرد.
2) مورد بعدی border (یا همان حاشیه) است. Border میتواند یک مقدار عددی بگیرد. کار border ایجاد یک حاشیه اطراف اِلِمان Entry است. هر چه مقدار آن بیشتر باشد، حاشیه ما بیشتر است و هر چه کمتر باشد حاشیه نیز کمتر است. اما شاید بپرسید که حاشیه چیست؟ بذارید تو شکل ماشین حساب به شما نشان دهیم.
3) پارامتر بعدی font است. با استفاده از این پارامتر میتونیم نوع فونت و اندازه نوشته را تعیین کنیم. برای مقدار دهی نیز ابتدا باید نام فونت دلخواه خود و سپس اندازه فونت را درون یک تاپل بنویسیم. همانند تصویر15. توجه کنید که شما تنها میتوانید از نام فونتهایی استفاده کنید که در سیستم شما نصب شده باشد.
4) مورد بعدی پارامتر justify است. این پارامتر، تراز متن را مشخص میکند که وسط چین باشد، راست چین باشد یا چپ چین. همانطور که در تصویر15 مشاهده میکنیم، مقدار justify را right قرار دادهایم. به این معنا که متن از راست نوشته شود.
شاید برای شما سوالی پیش آمده باشد که مگر در Entry متنی وجود دارد که بخواهیم برای آن فونت یا تراز مشخص کنیم؟ در جواب باید بگویم زمانی که ما روی دکمهها کلیک میکنیم درون ویجت Entry تایپ میشود. (در ادامه میبینیم)
در آخر هم اشاره کنم که این ویجت را درون متغیر display ذخیره کردهایم. در تصویر15 با کادر سفید مشخص شده است. فکر کنم دیگه بدونیم که نام متغیر دلخواه است.
حال نوبت دکمهها است. برای این که بتوانیم یک دکمه در پنجره داشته باشیم، از کلاس Button موجود در tkinter به صورت زیر استفاده میکنیم.
به همین راحتی یک دکمه ساختیم. اگر به ورودیهای کلاس Button نگاه کنید میبینید که خیلی شبیه Entry است. اما باز یک توضیح مختصری برای هر یک میدهیم.
1) مورد 1 همانند قبل پنجرهای است که قرار است این ویجت درون آن قرار بگیرد.
2) پارامتر text برای ما جدید است. با این پارامتر مشخص میکنیم که متن نوشته شده در دکمه چه چیزی باشد. منظور ما از متن همان نوشتهای است که روی دکمهها وجود دارد به تصویر زیر توجه کنید:
پس ما با توجه به دکمه مورد نظر باید متن مناسب را داخل آن قرار دهیم. در تصویر 17 از آنجایی که ما میخواستیم دکمه 1 را بسازیم پس برای text رشته 1 را مشخص کردیم.
3) مورد font نیز برای شما آشنا است. دقیقاً مثل کلاس Entry است.
دکمه ساخته شده را درون متغیر number1 ریختهایم. (باز هم بگم که اسمش را هر چیزی دوست دارید میتونید بذارید)
اما ما تا الان فقط یک دکمه ساختیم هنوز باید 15 دکمه دیگر بسازیم. پس بریم تا این 15 دکمه را نیز تک به تک بسازیم. من برم کدشو بزنم.
خب این هم کُدش. حالا بیایید تا برنامه رو اجرا بگیریم تا تمام اِلِمانهایی که ساختیم ببینیم. من اجرا گرفتم. اما پنجره همچنان خالی بود. خودتون ببینید.
پس این همه کُد زدیم، الکی بود. در جواب باید بگم که نه، اصلاً الکی نبود. در واقع شما با این کار صرفاً مواد اولیه رو تهیه کردید. یعنی فرض کنید شما رو مسئول تزئین خانه بابت تولد یکی از فامیلها کردن. شما تا الان فقط رفتید و وسایل رو خریدید مثل بادکنک، ریسه و … اما هنوز روی دیوار قرار ندادید. در واقع اگر بخوام پایتونی صحبت کنم، ما تمام ویجتها را ساختیم و گفتیم که قراره در کدام پنجره باشه، اما هنوز نحوه چیدمان را مشخص نکردیم.
به طور کلی ما دو نوع چیدمان داریم یکی pack که چیدمان پُشتهای است (زیر هم) و دیگری چیدمان grid که چیدمان شبکهای (جدولی) است. خٌب به نظر شما در این ماشین حساب گرافیکی کدام چیدمان استفاده شده است؟ بله، بدون شک چیدمان grid در واقع ویجتهای ما به صورت سطری و ستونی (جدولی) در پنجره قرار گرفته است. یکبار دیگر به تصویر ماشین حساب گرافیکی خود نگاه کنیم.
مشاهده میکنیم که چیدمان ویجتهای ما به صورت 5 سطر (شروع شماره گذاری از 0) و 4 ستون (شروع شماره گذاری از 0) است.
برای قرار دادن هر یک از ویجتها کافیست تا موقعیت سطر و ستون جایگاه آن ویجت را در دستور grid مشخص کنیم. نحوه استفاده از دستور grid به صورت زیر است:
حال هر مورد را توضیح میدهیم:
1) مورد اول متغیری است که میخواهیم موقعیت چیدمان آن را مشخص کنیم. متغیر display همان ورودی برنامه بود.
2) اولین پارامتر در دستور grid، مشخص کردن موقعیت سطر (row) ویجتِ ما است. اگر به تصویر ماشین حساب گرافیکی خود نگاه کنیم میبینیم که ویجت display در سطر شماره 0 قرار گرفته است.
3) پارامتر بعدی در دستور grid، مشخص کردن موقعیت ستون (column) ویجتِ ما است. شما میبینید که ما در تصویر بالا مقدار column را 0 قرار دادهایم. اما اگر به تصویر ماشین حساب نگاه کنیم، میبینیم که ویجت display ما در 4 ستون قرار گرفته است. پس شاید انتظار داشتید برای پارامتر column مقدار 0 و 1 و 2 و 3 بدهیم. اما این طور نیست.
در واقع اگر ما اِلِمانی (ویجتی) داشته باشیم که بخواهد چند ستون را اِشغال کند، موقعیت آن را در ستون ابتدایی تنظیم میکنیم و سپس با پارامتر columnspan (که در مورد بعد توضیح میدهیم) میگوییم که چند ستون را اِشغال کند.
4) پارامتر آخر ما columnspan است. توسط این پارامتر میگوییم که ویجت ما از ستونی که در آن قرار گرفته است تا چند ستون را اِشغال کند. مثلاً در تصویر بالا ویجت display در ستون 0 با مقدار columnspan 4 تنظیم شده است. که به این معناست، display در ستون 0 قرار بگیرد اما باید به طور کلی 4 ستون را اِشغال کند. پس به طور خلاصه موقعیت متغیر display سطر 0 و ستون 0 و 1و 2و 3و شد.
حال که با نحوه کار دستور grid آشنا شدیم وقت آن است که بقیه ویجتها را نیز بچینیم. بیایید تا دکمه 7 را که در سطر 1 و ستون 0 است بچینیم.
همانطور که میبینیم تمام کار انجام شده مثل قبلی بود. فقط مقادیر پارامترها عوض شد. (چون موقعیت این ویجت در جای دیگری بود) فقط باید به یک نکته توجه کنیم. اگر به تصویر ماشین حساب نگاه کنیم دکمه عدد 7 در سطر 1 و ستون 0 قرار گرفته و تنها یک ستون را اِشغال کرده است. پس columnspan آن را 1 قرار دادیم. یک نکته بگم که اگر تعداد ستون اِشغالی 1 باشد دیگر نیازی به نوشتن columnspan نیست.
در واقع مقدار پیشفرش columnspan 1 است. حالا بیایید تک به تک ویجتها را در سر جای خودشان بچینیم. من برم کد رو بزنم بیام. (فقط جاهایی که تعداد ستون اِشغالی 1 است دیگر colmnspan را نمینویسیم).
خب از این جا به بعد از اونجایی که کد داره طولانی میشه دیگه نمیشه عکس کل کد رو فرستاد و فقط بخشهای جدیدی که نوشتیم رو میفرستیم.
الان دیگه زمانش رسیده تا از کد یک اجرا بگیریم. بریم تا داشته باشیم.
خُب مثل این که چیزی نشد که میخواستیم. اما صبر کنید، با یکم کد نوشتن حلش میکنیم.
اگر به دکمهها نگاه کنید، میبینید که موقعیت قرار گیری دکمهها درست است. اما سایز هر دکمه فقط به اندازه کاراکتر درونش است. ما میتوانیم به راحتی این موضوع را حل کنیم. فقط کافیست بگوییم که هر ویجت در موقعیت خودش تا جایی که میتواند به 4 طرفش بچسبد. (خودمونی اگر بخوام بگم، یعنی انقدر کِش بیاد تا 4 طرفش را پر کند) برای درک بهتر به تصویر زیر نگاه کنید:
فکر کنم با دیدن تصویر بالا موضوع جا افتاده باشه. اما هنوز این سوال که چطوری اینکار را انجام دهیم بی پاسخ مانده است. ما در توضیحات خود از لفظ “چسبیدن” استفاده کردیم. برچسب به انگلیسی sticker میشود پس فقط کافیست که در دستورات grid پارامتری که هم معنای sticker باشد مقدار دهی کنیم این پارامتر چیزی نیست جز sticky به معنای “چسبنده”. اما چه مقداری باید بدهیم؟؟ اگر به تصویر بالا نگاه کنید میبینید که 4 جهت بالا و پایین و راست و چپ مشخص شده است. این 4 جهت به انگلیسی چه میشود؟ شکل زیر را ببینیم.
حال بیایید اول حرف هر یک از این 4 جهت را به هم بچسبانیم، پس داریم: news – بنابراین فقط کافیست تا پارامتر sticky را news بدهیم تا هر اِلِمان به 4 طرفش بچسبد. پس بریم تا کدش رو بزنیم:
حال کد را اجرا کنیم:
خُب الان یکمی بهتر شد. اما هنوز باب دلمون نشده. در واقع الان مشکلی که داریم اینه که اول از همه یکسری از اِلِمانها از پنجره جلو زدن (مثل دکمههای + و – و * و / و هم چنین خود display) و مورد دوم اینکه پنجره ما پر نشده است. پس بریم تا این دو مشکل را حل کنیم.
برای حل این دو مشکل فقط کافیست تا کاری کنیم که تمام ویجتها به نحوی کنارهم بشینن تا کل فضای پنجره (هم در راستای عرض و هم در راستای ارتفاع) را پُر کنند. در واقع باید بگوییم که از مقدار عرض (300 پیکسل) سهم هر ویجت چقدر باشد تا کل عرض پر شود و هم چنین از مقدار ارتفاع (450 پیکسل) سهم هر ویجت چقدر باشد تا کل ارتفاع پر شود. برای این منظور از دستور rowconfigure برای سطر و columnconfigure برای ستون به صورت زیر استفاده میکنیم. ابتدا بیایید سهم موقعیت سطر 0 و ستون 0 را مشخص کنیم. یعنی خانه row=0 و column=0 چقدر سهم از کل عرض و ارتفاع باید بگیرد، کد زیر را ببینیم:
1) مورد اول نام متغیر پنجره ما است.
همان طور که در متن بالا بیان شد ما یک دستور برای سهم سطر دارم و یک دستور برای سهم ستون. بنابراین برای هر موقعیت نیاز به نوشتن دو خط کد داریم. در خط 48 ، مورد 2 کد مربوط به سطر است. همانطور که میبینید در ورودی این دستور یک عدد نوشته شده است که بیان کننده شماره است و ورودی دوم weight است که سهم این ویجت از سطر را بیان میکند که مقدار آن 1 داده شده است. شاید بپرسید که این 1 از کجا آمده و اصلاً چرا 1، چرا عدد دیگری نوشته نشود؟ جلوتر توضیح میدهیم.
خط 51، مورد 5 همانند مورد 1 است و نام متغیر پنجره قرار داده شده است. مورد 6 کد مربوط به ستون است. همانطور که میبینید نحوه کار با این متد همانند سطر است. در ورودی اول شماره ستون را مشخص میکنیم و در ورودی بعدی سهم این ستون را مشخص میکنیم.
توجه: فاصله بین خط 48 و 51 صرفاً برای نوشتن توضیحات بود و دلیل خاصی نداشت.
حال برویم 3 موقعیت بعدی دیگر. یعنی سطر 0 و ستون 1، سطر 0 و ستون 2، سطر 0 و ستون 3.
کار سطر 0 تمام شد. مشاهده میکنیم که برای هر موقعیت دو خط کد نوشته شده است. یکی برای سطر و یکی برای ستون. الان میتونیم در مورد weight توضیح بدیم. ببینید دوستان عدد نوشته شده برای weight مشخص میکند که نسبت سهم هر موقعیت به موقعیت دیگر چقدر باشد.
همانطور که مشاهده میکنید برای هر 4 موقعیت بالا (چه ستون و چه سطر) مقدار weight را 1 قرار دادیم. که به این معناست، در راستای ستون، سهم هر موقعیت یکسان است. یعنی مثلا اگر 400 پیکسل داشته باشیم، به هر موقعیت 100 پیکسل برسد. در واقع آن چیزی که مهم است یکسان بودن مقدار weight است. مثلاً اگر یکی را 1 و دیگری را 2 قرار دهیم به این معناست که یکی دو برابر سهم میگرد.
حال باید برای تمام موقعیتها این دو خط کد را بنویسیم. ماشین حساب ما 5 سطر در 4 ستون است. که میشود 20 خانه. برای هر خانه هم دو خط کد پس میشود 40 خط کد. اما ما چنین کاری نمیکنیم چرا که for بلدیم. پس کافیست تا با یک حلقه تو در تو مشکل را حل کنیم. به صورت زیر:
کدهای نوشته شده در خط 48 تا 58 را پاک کردیم و به جای آن کد بالا را نوشتیم. در حلقه تو در تو بالا، حلقه بیرون در بازه 0 تا 4 پیمایش میکند (که مربوط به سطرها میشود) و حلقه درونی در بازه 0 تا 3 حرکت میکند (که مربوط به ستونها میشود). درون حلقه نیز از دو دستور rowconfigure و columnconfigure استفاده کردیم و به هر کدام ورودی مناسب را دادیم.
خُب بریم تا اجرا بگیریم.
بله، میبینیم که ماشین حساب ما دقیقاً چیزی شد که میخواستیم. اما تا الان فقط ظاهر ماشین حساب رو ساختیم. اگه الان شما روی دکمهها کلیک کنید هیچ کاری انجام نمیشود. از اینجا به بعد مقاله میریم تا بخش عملیاتی ماشین حساب گرافیکی رو بزنیم. قبل از آن بیایید یک دورنمایی از کد رو ببینیم.
خُب به پایان بخش اول مقاله رسیدیم. یعنی بخش ظاهر ماشین حساب رو زدیم. به نظرم یک استراحتی داشته باشید و بعد با انرژی بالا مطالب رو ادامه بدید.
نوشتن کد برای دکمههای ماشین حساب گرافیکی
نوشتن کد برای دکمههای اعداد ماشین حساب:
برای این که با کلیک روی دکمهها کاری انجام شود باید یک تابع تعریف کنیم و سپس نام تابع را دورن آن دکمه مورد نظر جلوی پارامتر command بنویسیم. به نظرم بریم کد بزنیم تا مفهوم جمله بالا رو بهتر متوجه بشیم:
من میخوام وقتی دکمه 1 روش کلیک شد عدد 1 در display چاپ شود. برای این منظور یک تابع مینویسم تا این کار را انجام دهد. بریم که داشته باشیم.
در تصویر بالا در خط 8 تابعی تعریف کردیم به نام click1 (فقط حواسمون باشه که تابع در ادامه کد، نوشته نشده و ما اومدیم به خط 8 و تابع را در آن جا تعریف کردیم) در تابع یک دستور نوشتیم که الان باید در مورد آن صحبت کنیم:
مورد1): مورد اول همان نام متغیر display ما است.
مورد2): از متد insert استفاده کردهایم. در واقع برای درج اعداد درون ویجت Entry باید از این متد استفاده کنیم. این متد دو ورودی میگیرد که مورد 3 و 4 میشود که در ادامه هر یک را توضیح میدهیم.
مورد 3): با این ورودی مشخص میکنیم که عدد درج شده در چه موقعیت (اندیسی) درون Entry تایپ شود. وقتی این اندیس را tk.END میگذاریم به این معناست که هر سری عدد تایپ شده به انتهای متن نوشته شده اضافه (درج) شود.
توجه: از آنجایی که به پارامتر justify درون ویجت Entry مقدار center را دادهایم تایپ اعداد از سمت راست انجام میشود همانند ماشین حساب ویندوز. تصویر زیر را ببینید:
اما بریم سراغ جواب آن سوال که چرا tk.END ؟خوب ببینید فرض کنید مثلاً عدد زیر در display باشد.
در تصویر بالا عدد 4365 در display وجود دارد. اعداد بالایی نوشته شده شماره خانه هر عدد است. حالا فرض کنید روی دکمه 1 کلیک کنیم شما انتظار دارید بعد از کلیک، عدد شما 43651 باشد یا 14365؟ بله بدون شک انتظار داریم عدد 43651 باشد. پس یعنی عدد نوشته باید در خانه آخر درج شود. پس دلیل tk.END را متوجه شدیم. اما شاید بپرسید که خانه آخر 3 است پس باید مقدار 3 را مینوشتیم. در جواب باید بگویم نوشتن مقدار tk.END خودش خانه آخر را به دست میآورد. حال بریم و مورد 4 را بررسی کنیم.
مورد 4): در مورد 4 عددی که قرار است درج شود (تایپ شود) را مشخص میکنیم. از آنجایی که داریم برای دکمه 1 مینویسیم پس باید عدد 1 تایپ شود.
بعد از اینکه تابع را نوشتیم، باید آن را به دکمه وصل کنیم. برای این منظور سراغ خط تعریف دکمه 1 (number1) میرویم. و پارامتر command را به تعریف دکمه اضافه میکنیم. به صورت زیر:
در خط 12 مشاهده میکنیم که پارامتر command اضافه شده است و جلوی آن نام تابعی که نوشتیم را قرار دادیم. حال اگر برنامه را اجرا کنیم و روی دکمه 1 کلیک کنیم، عدد 1 در display تایپ میشود.
خُب خیلی عالی شد.
اما یک سوال، آیا باید برای تک به تک دکمهها یک تابع جدا بنویسیم؟ در جواب میگوییم خیر. ما میتوانیم به تابعی که تعریف کردهایم یک ورودی بدهیم که این ورودی عدد مورد نظر ما است. سپس میگوییم با هر بار کلیک عددی که به عنوان ورودی برایت ارسال کردهایم را تایپ کن. پس داریم:
در تصویر بالا نام تابع را به click تغییر دادیم تا یک نام جامع تری نسبت به click1 باشد. (توجه کنید که نام تابع اختیاری است و ما صرفاً برای خوانایی برنامه این کار را کردهایم چرا که از نام click1 خواننده برداشت میکند که این تابع مخصوص دکمه 1 نوشته شده است، اما نام click حالت کلی و جامعتری دارد). در دستور تابع هم دقیقاً همان چیزی نوشتیم که در متن بالا توضیح داده بودیم. در واقع یک ورودی دادیم که همان عدد مورد نظر برای تایپ است و همان را در متد insert نوشتیم.
حال باید برویم و به تک تک دکمهها این تابع را وصل کنیم. اما باید حواسمان باشد که هر دکمه باید عدد مربوط به خودش را به تابع ارسال کند. برای این که بتوانیم کاری کنیم تا هر دکمه، عدد خود را به تابع ارسال کند باید از دستور lambda به صورت زیر استفاده کنیم:
اما بیایید یکی از لامبداهای نوشته شده را توضیح دهیم. میدانیم که لامبدا یک تابع تک خطی است.
1): مورد اول که کلید واژه دستور lambda است.
2): گفتیم که لامبدا یک تابع تک خطی است. میدانیم که توابع میتوانند ورودی داشته باشند. اگر بخواهیم لامبدا ورودی داشته باشد بعد از نوشتن کلید واژه آن میتوانیم ورودیها را مشخص کنیم، که ما نام این ورودی را c قرار دادیم و باز یادآوری کنم که نام اختیاری است.
3): مقدار پیش فرض این ورودی را مشخص کردهایم. این مقدار با توجه به هر دکمه تعیین میشود. اگر برای دکمه 1 بخواهیم بنویسیم پس باید این مقدار 1 باشد.
4): بعد از نوشتن کلید واژه lambda و مشخص کردن ورودیها یک : میزنیم و سپس کاری که لامبدا قرار است انجام دهد را مشخص میکنیم. در این جا کار مورد نظر ما صدا زدن تابع click و ارسال عدد مناسب (یعنی همان c) است.
حال برنامه را اجرا میگیریم.
میبینیم که با فشردن دکمههای 1 و 2 و 6 و 5 به درستی عدد 1265 چاپ شده است.
نوشتن کد برای دکمههای عملگرهای ماشین حساب با پایتون
حالا وقت آن است که برای دکمههای + و – و / و * نیز تابع مناسب را بنویسیم. با فشردن این دکمهها نیز قرار است تا آن علامت در صفحه چاپ شود و سپس با زدن دکمه = جواب نشان داده شود. یعنی فرض کنید چنین چیزی روی display باشد.
حال اگر کاربر روی دکمه = کلیک کند باید جواب 22 در display نشان داده شود. پس فعلاً بیایید تا برای 4 عمل اصلی تابع مناسب بنویسیم. نوشتن این تابع بسیار مشابه تابع click است.
حال اگر برنامه را اجرا کنیم و چند دکمه عدد و عملگر را بزنیم، میبینیم که برنامه به درستی کار میکند.
مشاهده میکنیم که با فشردن دکمههای اعداد و عملگرها برنامه به خوبی کار میکند.
نوشتن کد برای دکمه مساوی در ماشین حساب با پایتون
حال زمان آن رسیده که دکمه مساوی را تکمیل کنیم. برای این منظور کافیست تا عبارت نوشته شده در display را بگیریم و سپس آن را به دستور eval بدهیم تا جواب را محاسبه کند و در نهایت جواب به دست آمده را درون display نشان دهیم. برای این منظور یک تابع تعریف میکنیم به نام equal و سپس درون آن ابتدا عبارت نوشته شده در display را میگیریم و سپس آن را به دستور eval میدهیم تا نتیجه به دست آید. حال باید ابتدا محتویات display را پاک کنیم (از ابتدا تا انتها) و سپس نتیجه به دست آمده را درون display درج کنیم. به تصویر زیر نگاه کنید.
بیشتر بخشهای کد بالا در خود تصویر47 توضیح داده شد. اما یکسری از خطوط که به توضیح بیشتری نیاز دارد را در این قسمت توضیح میدهیم.
خط 15): اگر بخواهیم محتویات یک ویجت Entry را بگیریم از متد get باید استفاده کنیم.
خط 16): عبارت نوشته شده در display را به دستور eval میدهیم تا نتیجه را به دست آورد.
خط17): برای این که محتویات نوشته شده در display را پاک کنیم از دستور delete استفاده میکنیم. نحوه استفاده از این دستور به این صورت است که باید شماره خانه ابتدایی و شماره خانه انتهایی که میخواهیم پاک شود را به آن بدهیم. اگر به کد توجه کنید میبینیدکه ابتدا را 0 گذاشتیم و انتها را tk.END به این معنا که از اول تا آخر را پاک کن.
خط 18): سپس با استفاده از دستور insert جواب به دست آمده را درون display درج میکنیم. با دستور insert نیز قبلاً آشنا شدیم.
شاید برای شما سوالی پیش آمده باشد که چرا تابع ورودی ندارد؟ در جواب باید بگویم که برای این بخش نیازی به ورودی نداشتیم.
فقط باید حواسمان باشد که بعد از تعریف تابع حتماً حتماً آن را به دکمه متصل کنیم. در خط 35 این کار را کردیم.
شاید برای شما سوالی پیش آمده باشد که قبلیها با لامبدا بود اما چرا این لامبدا نداره؟ در جواب باید بگوییم که زمانی از لامبدا استفاده میکنیم که بخواهیم به تابع تعریف شده، ورودی بدهیم. از آنجایی که تابع equal ورودی ندارد پس از لامبدا استفاده نمیکنیم.
حال از برنامه اجرا میگیریم.
میبینیم که با فشردن دکمه مساوی جواب ما به دست آمد.
اما سوال بسیار مهمی اینجا مطرح میشود و آن هم این است که اگر ما یک عبارت نادرست وارد کنیم و روی مساوی بزنیم چه جوابی میگیریم مثلا تصویر زیر یک عبارت نادرست است.
خُب مشاهده میکنیم که با وارد کردن عبارت بالا در برنامه ارور SyntaxError دریافت میکنیم. برای رفع این مشکل باید از مدیریت خطا استفاده کنیم. در واقع باید در تابع equal یک بلوک try except قرار دهیم. پس بریم تا کدش رو بزنیم.
در کد بالا با نوشتن خطوط 17 و 18 و 19 را درون بخش try قرار دادیم و برای بخش except نیز ارور SyntaxError را معرفی کردیم. با این کار برنامه ابتدا سعی میکند تا بخش try را اجرا کند اگر موفق شد که هیچ اما اگر با ارور SyntaxError مواجه شد به بخش except میرود و کدهای آن بخش را اجرا میکند. در بخش except نیز ابتدا با استفاده از متد delete محتویات display را پاک کرده و سپس کلمه Error را در display قرار میدهیم. حالا بیایید تست کنیم.
برنامه خیلی عالی کار میکنه.
اما باز هم یک مشکل دیگه، اگر ما خودمان درون ویجت display یک عبارت نامعتبر بنویسیم (از طریق کیبورد تایپ کنیم) چه رخ میدهد مثل تصویر زیر:
بله باز هم ارور میگیریم. اینبار ارور ما از نوع NameError است. پس باز باید با مدیریت خطا آن را مدیریت کنیم. فقط کافیست تا یک except دیگر به بلوک try except نوشته شده اضافه کنیم. داریم:
و اما یک ارور دیگر اگر کاربر تقسیم بر صفر انجام داد چطور؟ بله باز هم ارور داریم، ببینیم:
اینبار ارور ZeroDivisionError گرفتیم. فکر کنم دیگه بلد باشید باید چی کار کنیم. پس بزن بریم:
و اینم نتیجه:
نوشتن کد برای دکمه C – ماشین حساب گرافیکی
خب زمان آن رسیده تا دکمه C رو بنویسیم. دکمه C هم بسیار آسونه. فقط کافیه بگیم زمانی که روی این دکمه کلیک شد، کل محتویات display پاک شود. پس داریم.
کد نوشته شده در تابع clear_button رو میشناسیم. همان متد delete است که در تابع equal نیز داشتیم.
خب دوستان به پایان این مقاله طولانی رسیدیم. جا داره یک خسته نباشید جانانه خدمت تک تک عزیزانی که تا اینجا مقاله رو خوندند، بگیم. امیدوارم که تونسته باشیم با این مقاله نیز مطالب جدیدی را به شما یاد بدهیم. تیم افراز ادیو خیلی خوشحال میشه اگه نظری، پیشنهادی و… داشتید در بخش نظرات برای ما بنویسید. ما تک به تک شون رو میخونیم. پس تا مقاله بعدی خدا نگهدار.