۵. ساخت پنجره و فرم ورودی

خط ۶۵ تا ۷۵

از اینجا کد از کلاس بیرون می‌آید و رابط کاربری را می‌سازد. اول شیء فروشگاه و پنجره‌ی اصلی ساخته می‌شوند، بعد با یک حلقه چهار ردیف «برچسب + جعبه‌ی ورودی» برای نام، قیمت خرید، قیمت فروش و تعداد ساخته می‌شود.

کد این بخش

shop_manager.py, lines 65–75
65shop = Shop()66root = tk.Tk()67root.title('مدیریت فروشگاه - Python')68root.geometry('760x560')69 70fields = {}71for row, (key, label) in enumerate([('name', 'نام کالا'), ('buy', 'قیمت خرید'), ('sell', 'قیمت فروش'), ('qty', 'تعداد')]):72    ttk.Label(root, text=label).grid(row=row, column=0, padx=8, pady=5, sticky='e')73    entry = ttk.Entry(root, width=28)74    entry.grid(row=row, column=1, padx=8, pady=5)75    fields[key] = entry

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

توضیح خط به خط

خط ۶۵shop = Shop()
یک شیء از کلاس Shop می‌سازد. همین‌جا __init__ (خط ۹) اجرا و داده‌ها از فایل خوانده می‌شوند. shop یک متغیر سراسری است و همه‌ی توابع پایین فایل از آن استفاده می‌کنند.
خط ۶۶root = tk.Tk()
پنجره‌ی اصلی برنامه را می‌سازد. هر برنامه‌ی tkinter دقیقاً یک Tk() دارد و بقیه‌ی ویجت‌ها داخل آن قرار می‌گیرند.
خط ۶۷root.title('مدیریت فروشگاه - Python')
عنوانی که در نوار بالای پنجره نوشته می‌شود.
خط ۶۸root.geometry('760x560')
اندازه‌ی اولیه‌ی پنجره: ۷۶۰ پیکسل عرض و ۵۶۰ پیکسل ارتفاع. قالب رشته 'عرضxارتفاع' است.
خط ۶۹
خط خالی.
خط ۷۰fields = {}
دیکشنری خالی برای نگه‌داری جعبه‌های ورودی. کلیدها name، buy، sell و qty خواهند بود تا بعداً با fields['name'] به جعبه‌ی نام برسیم.
خط ۷۱for row, (key, label) in enumerate([('name', 'نام کالا'), ('buy', 'قیمت خرید'), ('sell', 'قیمت فروش'), ('qty', 'تعداد')]):
حلقه روی لیستی از چهار تاپل (کلید، برچسب فارسی). enumerate به هر عضو یک شماره از ۰ تا ۳ می‌دهد که در row می‌رود، و (key, label) تاپل را باز می‌کند. پس در دور اول row=0، key='name' و label='نام کالا' است.
خط ۷۲ttk.Label(root, text=label).grid(row=row, column=0, padx=8, pady=5, sticky='e')
یک برچسب متنی می‌سازد و همان‌جا با grid در ردیف row و ستون ۰ می‌گذارد. padx و pady فاصله‌ی دور ویجت‌اند و sticky='e' آن را به سمت شرق (راست) خانه می‌چسباند. چون بعداً به برچسب کاری نداریم، آن را در متغیری نگه نمی‌داریم.
خط ۷۳entry = ttk.Entry(root, width=28)
یک جعبه‌ی ورودی با عرض ۲۸ کاراکتر می‌سازد و در entry نگه می‌دارد.
خط ۷۴entry.grid(row=row, column=1, padx=8, pady=5)
جعبه را در ستون ۱ همان ردیف قرار می‌دهد. این کار عمداً در خط جدا انجام شده، چون grid مقدار None برمی‌گرداند. اگر entry = ttk.Entry(...).grid(...) نوشته می‌شد، entry برابر None می‌شد و دیگر نمی‌شد متن آن را خواند.
خط ۷۵fields[key] = entry
جعبه را با کلیدش در دیکشنری fields ذخیره می‌کند.

یادداشت

ردیف‌های ۰ تا ۳ شبکه‌ی پنجره با این فرم پر می‌شوند. ردیف ۴ مال دکمه‌هاست (خط ۱۳۲) و ردیف ۵ مال جدول (خط ۱۴۱).

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

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

shop
در توابع add خط ۹۴، edit خط ۹۷، delete خط ۱۰۰، sell خط ۱۰۳، report خط ۱۱۰ و در refresh خط ۱۱۶.
root
والد همه‌ی ویجت‌هاست: برچسب‌ها خط ۷۲، جعبه‌ها خط ۷۳، قاب دکمه‌ها خط ۱۳۱، جدول خط ۱۳۷. تنظیم کشیدگی در خط ۱۴۳ و خط ۱۴۴ و حلقه‌ی اصلی در خط ۱۴۶.
fields
خواندن متن در values خط ۷۸–خط ۸۱، delete خط ۱۰۰، sell خط ۱۰۳ و search خط ۱۰۶؛ نوشتن متن در choose خط ۱۲۶ و خط ۱۲۷.

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

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

  1. چرا خط ۷۳ و خط ۷۴ دو خط جدا هستند و entry = ttk.Entry(...).grid(...) نوشته نشده؟

    نمایش جواب

    چون grid مقدار None برمی‌گرداند و entry برابر None می‌شد.

  2. متغیر row در حلقه‌ی خط ۷۱ چه مقدارهایی می‌گیرد؟

    نمایش جواب

    ۰، ۱، ۲ و ۳ — برای هر جعبه‌ی فرم یکی، از enumerate.

  3. sticky='e' در خط ۷۲ چه کار می‌کند؟

    نمایش جواب

    برچسب را به سمت شرق (راست) خانه‌ی شبکه می‌چسباند.

  4. متد Shop.__init__ کی اجرا می‌شود؟

    نمایش جواب

    یک بار، در خط ۶۵، وقتی shop = Shop() شیء را می‌سازد.