Python Learningاز صفر تا نوشتن پروژه از حفظ
درس ۱۲ · ابزارهای پروژه

tkinter ۲: جدول، قاب و رویداد

حدود ۶۰ دقیقه۲ تمرین۶ سؤال آزمون
بعد از این درس می‌توانی:
  • جدول (Treeview) با ستون‌های دلخواه بسازی
  • ردیف اضافه کنی، همه را پاک کنی و ردیف انتخاب‌شده را بخوانی
  • با bind به انتخاب ردیف واکنش نشان دهی
  • دکمه‌ها را در یک Frame با حلقه بسازی و پنجره را قابل کشیدن کنی
حواست باشد

tkinter داخل مرورگر اجرا نمی‌شود، چون پنجره‌ی واقعی ویندوز می‌سازد. کدهای این درس را در VS Code کپی کن و اجرا کن (دکمه‌ی «کپی» گوشه‌ی هر کد). بعد از هر اجرا، تیک کارهایی را که انجام دادی بزن.

ساختن جدول

Python
columns = ('name', 'buy', 'sell', 'qty')
table = ttk.Treeview(root, columns=columns, show='headings', height=13)
for key, label in [('name', 'نام کالا'), ('buy', 'قیمت خرید'), ('sell', 'قیمت فروش'), ('qty', 'موجودی')]:
    table.heading(key, text=label)
    table.column(key, width=150, anchor='center')
table.grid(row=5, column=0, columnspan=4, padx=10, pady=10, sticky='nsew')
در پروژه‌ی فروشگاه

خط ۱۳۶ پروژه تا خط ۱۴۱ پروژه.

پر کردن و خالی کردن جدول

Python
# پاک کردن همه‌ی ردیف‌ها
for item in table.get_children():
    table.delete(item)

# اضافه کردن ردیف
table.insert('', 'end', values=('pen', 10, 15, 3))

'' یعنی ردیف در سطح اصلی است و 'end' یعنی ته جدول. table.delete فقط ردیف نمایشی را پاک می‌کند، نه داده را.

در پروژه‌ی فروشگاه

تابع refresh در خط ۱۱۳ پروژه تا خط ۱۱۸ پروژه: اول همه‌ی ردیف‌ها را پاک می‌کند، بعد برای هر کالا که با جست‌وجو جور است یک ردیف می‌گذارد.

تمرین

منطق refresh (بدون پنجره)

تابع rows_for(products, query='') بنویس که لیستی از تاپل‌های (name, buy, sell, qty) برگرداند، فقط برای کالاهایی که query در نامشان (با حروف کوچک) هست. این همان چیزی است که در جدول insert می‌شود.

Ctrl + Enter
دیدن راه‌حل (اول خودت تلاش کن)
def rows_for(products, query=''):
    rows = []
    for name, p in products.items():
        if query in name.lower():
            rows.append((name, p['buy'], p['sell'], p['qty']))
    return rows

رویداد: وقتی روی ردیف کلیک می‌شود

Python
def choose(event):
    selection = table.selection()
    if not selection:
        return
    name, buy, sell_price, qty = table.item(selection[0], 'values')
    for key, value in [('name', name), ('buy', buy), ('sell', sell_price), ('qty', qty)]:
        fields[key].delete(0, tk.END)
        fields[key].insert(0, value)

table.bind('<<TreeviewSelect>>', choose)
در پروژه‌ی فروشگاه

خط ۱۲۰ پروژه تا خط ۱۲۷ پروژه و اتصال در خط ۱۴۲ پروژه.

دکمه‌ها در قاب، با حلقه

Python
buttons = [('افزودن کالا', add), ('ویرایش کالا', edit), ('حذف کالا', delete),
           ('ثبت فروش', sell), ('جست‌وجو', search), ('نمایش همه', refresh), ('گزارش فروش', report)]
frame = ttk.Frame(root)
frame.grid(row=4, column=0, columnspan=4, padx=10, pady=12)
for i, (label, action) in enumerate(buttons):
    ttk.Button(frame, text=label, command=lambda a=action: run(a)).grid(row=i // 4, column=i % 4, padx=4, pady=4)

Frame یک ظرف است که شبکه‌ی خودش را دارد؛ دکمه‌ها داخل آن ۴ تا ۴ تا چیده می‌شوند.

کشیده شدن با پنجره

Python
root.grid_rowconfigure(5, weight=1)     # ردیف جدول بلند شود
root.grid_columnconfigure(3, weight=1)  # ستون ۳ پهن شود
در پروژه‌ی فروشگاه

خط ۱۲۹ پروژه تا خط ۱۴۴ پروژه.

تمرین بزرگ: لیست اسم‌ها

در VS Code برنامه‌ای بساز با یک جعبه، دکمه‌ی «اضافه کن» و یک جدول یک‌ستونه. هر اسمی که اضافه می‌شود در یک لیست پایتون ذخیره شود و جدول با یک تابع refresh از روی لیست دوباره پر شود. با کلیک روی ردیف، اسم در جعبه بیاید.

مرتب کن

خط‌ها را مرتب کن

تابع refresh را مرتب کن:

  1. table.delete(item)
  2. def refresh(query=''):
  3. for item in table.get_children():
  4. table.insert('', 'end', values=(name, p['buy'], p['sell'], p['qty']))
  5. for name, p in shop.products.items():
  6. if query in name.lower():

آزمون این درس

برای گذراندن این درس حداقل ۸۰٪ جواب درست لازم است. هر چند بار خواستی می‌توانی دوباره امتحان بدهی.

۱. show='headings' چه می‌کند؟
۲. table.insert('', 'end', values=(...)) ردیف را کجا می‌گذارد؟
۳. table.delete(item) داده‌ی فروشگاه را هم پاک می‌کند؟
۴. چرا choose(event) پارامتر event دارد؟
۵. دکمه‌ی شماره‌ی ۵ با row=i // 4, column=i % 4 کجا می‌رود؟
۶. grid_rowconfigure(5, weight=1) برای چیست؟