tkinter ۲: جدول، قاب و رویداد
- جدول (
Treeview) با ستونهای دلخواه بسازی - ردیف اضافه کنی، همه را پاک کنی و ردیف انتخابشده را بخوانی
- با
bindبه انتخاب ردیف واکنش نشان دهی - دکمهها را در یک
Frameبا حلقه بسازی و پنجره را قابل کشیدن کنی
tkinter داخل مرورگر اجرا نمیشود، چون پنجرهی واقعی ویندوز میسازد. کدهای این درس را در VS Code کپی کن و اجرا کن (دکمهی «کپی» گوشهی هر کد). بعد از هر اجرا، تیک کارهایی را که انجام دادی بزن.
ساختن جدول
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')
columns: شناسهی ستونها (برای خود برنامه، دیده نمیشوند).show='headings': ستون درختی پیشفرض (#0) را پنهان میکند.headingعنوان قابلدیدن ستون وcolumnعرض و چینش آن است.
پر کردن و خالی کردن جدول
# پاک کردن همهی ردیفها
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 میشود.
دیدن راهحل (اول خودت تلاش کن)
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
رویداد: وقتی روی ردیف کلیک میشود
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)
bindیک تابع را به یک رویداد وصل میکند.<<TreeviewSelect>>یعنی «انتخاب جدول عوض شد».- tkinter به تابع یک شیء رویداد میدهد؛ برای همین پارامتر
eventلازم است حتی اگر استفاده نشود. selection()شناسهی ردیفهای انتخابشده را میدهد وitem(id, 'values')مقدارهایشان را (بهصورت متن).
خط ۱۲۰ پروژه تا خط ۱۲۷ پروژه و اتصال در خط ۱۴۲ پروژه.
دکمهها در قاب، با حلقه
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 یک ظرف است که شبکهی خودش را دارد؛ دکمهها داخل آن ۴ تا ۴ تا چیده میشوند.
کشیده شدن با پنجره
root.grid_rowconfigure(5, weight=1) # ردیف جدول بلند شود
root.grid_columnconfigure(3, weight=1) # ستون ۳ پهن شود
تمرین بزرگ: لیست اسمها
در VS Code برنامهای بساز با یک جعبه، دکمهی «اضافه کن» و یک جدول یکستونه. هر اسمی که اضافه میشود در یک لیست پایتون ذخیره شود و جدول با یک تابع refresh از روی لیست دوباره پر شود. با کلیک روی ردیف، اسم در جعبه بیاید.
خطها را مرتب کن
تابع refresh را مرتب کن:
table.delete(item)def refresh(query=''):for item in table.get_children():table.insert('', 'end', values=(name, p['buy'], p['sell'], p['qty']))for name, p in shop.products.items():if query in name.lower():
آزمون این درس
برای گذراندن این درس حداقل ۸۰٪ جواب درست لازم است. هر چند بار خواستی میتوانی دوباره امتحان بدهی.