۷. به‌روزرسانی جدول و انتخاب ردیف

خط ۱۱۳ تا ۱۲۷

دو تابع این بخش جدول را با فرم هماهنگ نگه می‌دارند. refresh جدول را خالی و از نو پر می‌کند، و choose وقتی روی یک ردیف کلیک شود اطلاعات آن را در جعبه‌های فرم می‌نویسد.

کد این بخش

shop_manager.py, lines 113–127
113def refresh(query=''):114    for item in table.get_children():115        table.delete(item)116    for name, p in shop.products.items():117        if query in name.lower():118            table.insert('', 'end', values=(name, p['buy'], p['sell'], p['qty']))119 120def choose(event):121    selection = table.selection()122    if not selection:123        return124    name, buy, sell_price, qty = table.item(selection[0], 'values')125    for key, value in [('name', name), ('buy', buy), ('sell', sell_price), ('qty', qty)]:126        fields[key].delete(0, tk.END)127        fields[key].insert(0, value)

روی شماره‌ی هر خط بزن تا به توضیحش بروی؛ روی «خط …» در توضیح بزن تا همان خط در کد روشن شود.

توضیح خط به خط

خط ۱۱۳def refresh(query=''):
تابع refresh با یک پارامتر اختیاری. اگر چیزی داده نشود query رشته‌ی خالی است و همه‌ی کالاها نمایش داده می‌شوند. این تابع از table استفاده می‌کند که تازه در خط ۱۳۷ ساخته می‌شود؛ مشکلی پیش نمی‌آید چون بدنه‌ی تابع تا وقتی صدا زده نشود اجرا نمی‌شود و اولین صدا زدن در خط ۱۴۵ است.
خط ۱۱۴for item in table.get_children():
get_children() شناسه‌ی همه‌ی ردیف‌های فعلی جدول را می‌دهد.
خط ۱۱۵table.delete(item)
هر ردیف را از جدول پاک می‌کند. این فقط ردیف نمایشی است و کالا از فروشگاه حذف نمی‌شود (برخلاف Shop.delete در خط ۴۴).
خط ۱۱۶for name, p in shop.products.items():
روی همه‌ی کالاها حلقه می‌زند. items() جفت‌های (کلید، مقدار) را می‌دهد: name نام کالا و p دیکشنری قیمت‌ها و موجودی.
خط ۱۱۷if query in name.lower():
فقط کالاهایی را نشان می‌دهد که متن جست‌وجو در نامشان باشد. رشته‌ی خالی در هر رشته‌ای «وجود دارد»، پس '' in name همیشه True است و همه نمایش داده می‌شوند.
خط ۱۱۸table.insert('', 'end', values=(name, p['buy'], p['sell'], p['qty']))
یک ردیف به جدول اضافه می‌کند. '' یعنی ردیف در سطح اصلی است (زیرمجموعه‌ی ردیف دیگری نیست)، 'end' یعنی ته جدول، و values مقدار چهار ستون به ترتیب خط ۱۳۶ است.
خط ۱۱۹
خط خالی.
خط ۱۲۰def choose(event):
تابع choose برای رویداد انتخاب ردیف. tkinter هنگام صدا زدن یک شیء رویداد به آن می‌دهد، پس پارامتر event لازم است حتی اگر استفاده نشود. در خط ۱۴۲ به جدول وصل می‌شود.
خط ۱۲۱selection = table.selection()
selection() تاپلی از شناسه‌ی ردیف‌های انتخاب‌شده برمی‌گرداند.
خط ۱۲۲if not selection:
اگر چیزی انتخاب نشده باشد... این حالت مثلاً وقتی پیش می‌آید که refresh ردیف انتخاب‌شده را پاک کند و رویداد با انتخاب خالی اجرا شود.
خط ۱۲۳return
...از تابع خارج شو و کاری نکن.
خط ۱۲۴name, buy, sell_price, qty = table.item(selection[0], 'values')
مقدارهای اولین ردیف انتخاب‌شده را می‌گیرد و در چهار متغیر باز می‌کند. نام sell_price (به‌جای sell) انتخاب شده تا با تابع sell (خط ۱۰۲) اشتباه نشود. این مقدارها از جدول به‌شکل رشته برمی‌گردند، مثلاً '242400.0'.
خط ۱۲۵for key, value in [('name', name), ('buy', buy), ('sell', sell_price), ('qty', qty)]:
حلقه روی چهار جفت (کلید جعبه، مقدار).
خط ۱۲۶fields[key].delete(0, tk.END)
متن فعلی جعبه را از اندیس ۰ تا انتها (tk.END) پاک می‌کند.
خط ۱۲۷fields[key].insert(0, value)
مقدار جدید را از ابتدای جعبه می‌نویسد.

یادداشت

بعد از کلیک روی یک ردیف، جعبه‌ی «تعداد» موجودی کالا را نشان می‌دهد. برای ثبت فروش باید آن را به تعداد فروش تغییر دهی، وگرنه کل موجودی فروخته می‌شود.

ارتباط با بقیه‌ی کد

همچنین ببینید

refresh(query='')
صدا زده‌شدن در run خط ۸۷، search خط ۱۰۷، دکمه‌ی «نمایش همه» خط ۱۳۰ و پر کردن اولیه‌ی جدول خط ۱۴۵.
choose(event)
در خط ۱۴۲ به رویداد <<TreeviewSelect>> جدول وصل می‌شود.
table
در خط ۱۳۷ ساخته می‌شود.
fields
در خط ۷۰ ساخته و در خط ۷۵ پر می‌شود.
shop.products
داده‌ای که در خط ۳۳، خط ۴۱، خط ۴۷ و خط ۵۸ تغییر می‌کند.

سؤال‌های تمرینی

اول خودت جواب بده، بعد جواب را باز کن.

  1. چرا refresh() بدون ورودی همه‌ی کالاها را نشان می‌دهد؟

    نمایش جواب

    query برابر '' است و رشته‌ی خالی در هر رشته‌ای هست، پس شرط خط ۱۱۷ همیشه درست است.

  2. آیا table.delete(item) در خط ۱۱۵ کالا را از فروشگاه حذف می‌کند؟

    نمایش جواب

    نه. فقط ردیف جدول را پاک می‌کند و داده‌ی shop.products دست نمی‌خورد.

  3. choose از event استفاده نمی‌کند. پس چرا این پارامتر هست؟

    نمایش جواب

    tkinter همیشه یک شیء رویداد به تابع وصل‌شده (خط ۱۴۲) می‌دهد؛ بدون این پارامتر صدا زدن تابع خطای TypeError می‌داد.

  4. مقدارهایی که table.item(...) در خط ۱۲۴ برمی‌گرداند چه نوعی دارند؟

    نمایش جواب

    رشته، مثلاً '242400.0'.