۶. خواندن فرم، run و توابع دکمهها¶
خط ۷۷ تا ۱۱۱
این بخش پل بین پنجره و کلاس Shop است. values متن جعبهها را به عدد تبدیل میکند، run هر کاری را امن اجرا میکند و خطاها را نشان میدهد، و شش تابع کوتاه هر کدام کار یک دکمه را انجام میدهند.
کد این بخش¶
77def values():78 name = fields['name'].get().strip()79 buy = float(fields['buy'].get())80 sell = float(fields['sell'].get())81 qty = int(fields['qty'].get())82 return name, buy, sell, qty83 84def run(action):85 try:86 action()87 if action is not search: refresh()88 except (ValueError, TypeError) as exc:89 messagebox.showerror('خطا', str(exc))90 except OSError as exc:91 messagebox.showerror('خطای فایل', str(exc))92 93def add():94 shop.add(*values())95 96def edit():97 shop.edit(*values())98 99def delete():100 shop.delete(fields['name'].get().strip())101 102def sell():103 shop.sell(fields['name'].get().strip(), int(fields['qty'].get()))104 105def search():106 name = fields['name'].get().strip().lower()107 refresh(name)108 109def report():110 count, income = shop.report()111 messagebox.showinfo('گزارش فروش', f'تعداد فروختهشده: {count}\nدرآمد کل فروش: {income:,.0f}')
روی شمارهی هر خط بزن تا به توضیحش بروی؛ روی «خط …» در توضیح بزن تا همان خط در کد روشن شود.
توضیح خط به خط¶
- خط ۷۸
name = fields['name'].get().strip()¶ get()متن جعبهی نام را میدهد وstrip()فاصلههای اول و آخر را حذف میکند تا «مداد » و «مداد» یکی حساب شوند.- خط ۷۹
buy = float(fields['buy'].get())¶ - متن قیمت خرید را با
floatبه عدد اعشاری تبدیل میکند. اگر متن عدد نباشد (یا خالی باشد)ValueErrorرخ میدهد که درrun(خط ۸۸) گرفته میشود. - خط ۸۲
return name, buy, sell, qty¶ - چهار مقدار را بهشکل یک تاپل برمیگرداند. ترتیب دقیقاً با پارامترهای
Shop.add(خط ۲۸) وShop.edit(خط ۳۶) یکی است. - خط ۸۴
def run(action):¶ - تابع مرکزی
run. ورودیاشactionخودش یک تابع است؛ در پایتون میشود تابع را مثل هر مقدار دیگری به تابع دیگر داد. همهی دکمهها از طریقrunکار میکنند (خط ۱۳۴). - خط ۸۷
if action is not search: refresh()¶ - اگر کار بدون خطا تمام شد، جدول را با دادهی تازه پر میکند (خط ۱۱۳). اگر خطا رخ دهد این خط اجرا نمیشود.
is notبررسی میکند کهactionهمان تابعsearch(خط ۱۰۵) نباشد؛ چونsearchخودش جدول را فیلترشده پر کرده، اگر اینجا دوبارهrefresh()بدون فیلتر اجرا شود نتیجهی جستوجو پاک میشود. نوشتنifو دستورش در یک خط مجاز است وقتی بدنه فقط یک دستور باشد. - خط ۸۸
except (ValueError, TypeError) as exc:¶ - خطاهای ورودی و منطقی را میگیرد: همهی
raise ValueErrorهای کلاس و خطای تبدیل در خط ۷۹–خط ۸۱.as excخود شیء خطا را درexcمیگذارد. - خط ۸۹
messagebox.showerror('خطا', str(exc))¶ - پنجرهی خطا با عنوان «خطا» و متن پیام خطا را نشان میدهد.
str(exc)همان پیام فارسی داخلraiseاست. - خط ۹۳
def add():¶ - تابع دکمهی «افزودن کالا». همنام متد
Shop.addاست ولی تداخلی ندارند: یکی تابع سراسری است و دیگری ویژگی شیءshop. - خط ۹۴
shop.add(*values())¶ values()تاپل چهارتایی میدهد و ستاره*آن را باز میکند تا چهار آرگومان جدا بهshop.addبرسد. یعنی همانshop.add(name, buy, sell, qty).- خط ۱۰۰
shop.delete(fields['name'].get().strip())¶ - برای حذف فقط نام لازم است، پس بهجای
values()مستقیم متن جعبهی نام خوانده میشود. به همین دلیل خالی بودن قیمتها اینجا خطا نمیدهد. - خط ۱۰۳
shop.sell(fields['name'].get().strip(), int(fields['qty'].get()))¶ - نام و تعداد را میخواند و به
shop.sellمیدهد. توجه کن که جعبهی «تعداد» هم برای موجودی کالا و هم برای تعداد فروش استفاده میشود. - خط ۱۰۶
name = fields['name'].get().strip().lower()¶ - متن جعبهی نام را میخواند و با
lower()کوچک میکند تا جستوجوی نامهای انگلیسی به بزرگی و کوچکی حروف حساس نباشد. حروف فارسی بزرگ و کوچک ندارند.
یادداشت
در نسخهی قبلی، خط ۸۷ فقط refresh() بود و دکمهی «جستوجو» کار نمیکرد: search() جدول را فیلتر میکرد (خط ۱۰۷) ولی بلافاصله refresh() بدون فیلتر همهی کالاها را برمیگرداند. شرط if action is not search این مشکل را حل کرده است. شرط در همان یک خط نوشته شده تا شمارهی خطهای بعدی تغییر نکند.
ارتباط با بقیهی کد¶
همچنین ببینید
values()- در
addخط ۹۴ وeditخط ۹۷. run(action)- در خط ۱۳۴ برای هر هفت دکمه. خودش
refreshرا در خط ۸۷ صدا میزند، بهجز برای دکمهی جستوجو. add,edit,delete,sell,search,report- در لیست
buttons(خط ۱۲۹ و خط ۱۳۰) کنار متن دکمهها قرار میگیرند. - توابع کلاس
add←Shop.addخط ۲۸،edit←Shop.editخط ۳۶،delete←Shop.deleteخط ۴۴،sell←Shop.sellخط ۵۰،report←Shop.reportخط ۶۲.messagebox- در خط ۴ وارد شده است.
سؤالهای تمرینی¶
اول خودت جواب بده، بعد جواب را باز کن.
ستارهی
*درshop.add(*values())چه کار میکند؟نمایش جواب
تاپل چهارتایی را به چهار آرگومان جدا باز میکند:
shop.add(name, buy, sell, qty).کاربر در قیمت
abcمینویسد و «افزودن» را میزند. مسیر اجرا را دنبال کن.چرا
deleteازvalues()استفاده نمیکند؟نمایش جواب
برای حذف فقط نام لازم است و
values()با خالی بودن قیمتها خطا میداد.بدون شرط خط ۸۷، دکمهی جستوجو چه میکرد؟
نمایش جواب
عملاً هیچ:
searchجدول را فیلتر میکند و بلافاصلهrefresh()همهی کالاها را دوباره نشان میدهد.{income:,.0f}برای1234567.8چه چاپ میکند؟نمایش جواب
1,234,568— با جداکنندهی هزارگان و گرد شده بدون اعشار.