از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
توسعه رابط کاربری گرافیکی پایتون با Tkinter: قسمت 2
سرفصلهای مطلب
این دومین قسمت از مجموعه چند قسمتی ما است روی توسعه رابط کاربری گرافیکی در پایتون با استفاده از Tkinter برای مشاهده سایر قسمت های این مجموعه به لینک های زیر مراجعه کنید:
معرفی
در قسمت اول از سری آموزش های rasanegar Tkinter، یاد گرفتیم که چگونه به سرعت رابط های گرافیکی ساده با استفاده از پایتون بسازیم. در این مقاله روش ایجاد چندین ویجت مختلف و قرار دادن آنها توضیح داده شده است روی صفحه نمایش با استفاده از دو روش مختلف ارائه شده توسط Tkinter – اما با این حال، ما به سختی سطح قابلیت های ماژول را خراشیده ایم.
برای قسمت دوم آموزش ما آماده شوید، جایی که ما می آموزیم که چگونه ظاهر رابط گرافیکی خود را در طول زمان اجرای برنامه خود تغییر دهیم، چگونه به طور هوشمندانه رابط را با بقیه کد خود متصل کنیم، و چگونه به راحتی ورودی متن را دریافت کنیم. کاربران ما
گزینه های شبکه پیشرفته
در آخرین مقاله با آن آشنا شدیم grid()
روشی که به ما امکان میدهد ویجتها را در ردیفها و ستونها جهتدهی کنیم، که اجازه میدهد نتایج بسیار مرتبتری نسبت به استفاده از pack()
روش. گریدهای سنتی دارای معایبی هستند که با مثال زیر قابل توضیح است:
import tkinter
root = tkinter.Tk()
frame1 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame2 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame3 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame1.grid(column=0, row=0, sticky="nsew")
frame2.grid(column=1, row=0, sticky="nsew")
frame3.grid(column=0, row=1, sticky="nsew")
label1 = tkinter.Label(frame1, text="Simple label")
button1 = tkinter.Button(frame2, text="Simple button")
button2 = tkinter.Button(frame3, text="Apply and close", command=root.destroy)
label1.pack(fill='x')
button1.pack(fill='x')
button2.pack(fill='x')
root.mainloop()
خروجی:
اگر قسمت اول آموزش Tkinter ما را گذرانده اید، کد بالا باید به راحتی برای شما قابل درک باشد، اما به هر حال بیایید یک جمع بندی سریع انجام دهیم. در خط 3، ما اصلی خود را ایجاد می کنیم root
پنجره در خطوط 5-7 ما سه فریم ایجاد می کنیم: تعریف می کنیم که the root ویجت والد آنها است و به لبه های آنها یک جلوه سه بعدی ظریف داده می شود. در خطوط 9-11 قاب ها در داخل پنجره با استفاده از توزیع توزیع می شوند grid()
روش. سلول های شبکه ای را که قرار است توسط هر ویجت اشغال شود نشان می دهیم و از آن استفاده می کنیم sticky
گزینه ای برای کشش آنها به صورت افقی و عمودی.
در خطوط 13-15 ما سه ویجت ساده ایجاد می کنیم: یک برچسب، یک دکمه که هیچ کاری انجام نمی دهد، و دکمه دیگری که پنجره اصلی را می بندد (از بین می برد) – یک ویجت در هر فریم. سپس در سطرهای 17-19 از عبارت استفاده می کنیم pack()
روشی برای قرار دادن ویجت ها در فریم های والد مربوطه خود.
همانطور که می بینید، سه ویجت که در دو ردیف و دو ستون توزیع شده اند، نتیجه زیبایی را ایجاد نمی کنند. بااینکه frame3
تمام ردیف خود را برای خود دارد و sticky
این گزینه باعث می شود آن را به صورت افقی کشیده شود، فقط می تواند در داخل مرزهای سلول شبکه فردی خود کشیده شود. لحظه ای که به پنجره نگاه می کنیم به طور غریزی می دانیم که قاب حاوی button2
باید شامل دو ستون باشد – به خصوص با توجه به عملکرد مهمی که دکمه اجرا می کند.
خب، خوشبختانه، سازندگان grid()
متد این نوع سناریو را پیشبینی کرد و یک گزینه span ستون را ارائه داد. پس از اعمال یک اصلاح کوچک در خط 11:
import tkinter
root = tkinter.Tk()
frame1 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame2 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame3 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame1.grid(column=0, row=0, sticky="nsew")
frame2.grid(column=1, row=0, sticky="nsew")
frame3.grid(column=0, row=1, sticky="nsew", columnspan=2)
label1 = tkinter.Label(frame1, text="Simple label")
button1 = tkinter.Button(frame2, text="Simple button")
button2 = tkinter.Button(frame3, text="Apply and close", command=root.destroy)
label1.pack(fill='x')
button1.pack(fill='x')
button2.pack(fill='x')
root.mainloop()
ما می توانیم خودمان را بسازیم frame3
تمام طول پنجره ما را دراز کنید.
خروجی:
روش مکان ()
معمولاً هنگام ساخت رابط های زیبا و سفارشی مبتنی بر Tkinter، place()
و grid()
روش ها باید تمام نیازهای شما را برآورده کنند. با این حال، بسته یک مورد دیگر را ارائه می دهد مدیر هندسه – place()
روش.
را place()
روش مبتنی است روی ساده ترین اصول از هر سه مدیر هندسه Tkinter. استفاده کردن place()
شما می توانید به صراحت موقعیت ویجت خود را در داخل پنجره مشخص کنید، یا با ارائه مستقیم مختصات دقیق آن، یا تعیین موقعیت آن نسبت به اندازه پنجره. به مثال زیر دقت کنید:
import tkinter
root = tkinter.Tk()
root.minsize(width=300, height=300)
root.maxsize(width=300, height=300)
button1 = tkinter.Button(root, text="B")
button1.place(x=30, y=30, anchor="center")
root.mainloop()
خروجی:
در خطوط 5 و 6 مشخص می کنیم که می خواهیم ابعاد پنجره ما دقیقا 300 در 300 پیکسل باشد. در خط 8 یک دکمه ایجاد می کنیم. در نهایت در خط 9 از عبارت استفاده می کنیم place()
روش قرار دادن دکمه در داخل ما root پنجره
ما سه مقدار ارائه می دهیم. با استفاده از x
و y
پارامترها، مختصات دقیق دکمه را در داخل پنجره تعریف می کنیم. گزینه سوم، anchor
، به ما اجازه می دهد تعریف کنیم که کدام قسمت از ویجت به نقطه (x,y) ختم می شود. در این مورد، ما می خواهیم که پیکسل مرکزی ویجت ما باشد. به طور مشابه به sticky
گزینه از grid()
، می توانیم از ترکیب های مختلف استفاده کنیم n
، s
، e
و w
برای لنگر انداختن ویجت توسط لبه ها یا گوشه های آن.
را place()
روش مهم نیست اگر ما در اینجا اشتباه کنیم. اگر مختصات به مکانی خارج از مرزهای پنجره ما اشاره کند، دکمه نمایش داده نخواهد شد. یک راه امن تر برای استفاده از این مدیر هندسه استفاده از مختصات نسبت به اندازه پنجره است.
import tkinter
root = tkinter.Tk()
root.minsize(width=300, height=300)
root.maxsize(width=300, height=300)
button1 = tkinter.Button(root, text="B")
button1.place(relx=0.5, rely=0.5, anchor="center")
root.mainloop()
خروجی
در مثال بالا، ما خط 9 را اصلاح کردیم. به جای مختصات x و y مطلق، اکنون از مختصات نسبی استفاده می کنیم. با تنظیم relx
و rely
به 0.5، مطمئن می شویم که بدون توجه به اندازه پنجره، دکمه ما در مرکز آن قرار می گیرد.
خوب، یک چیز دیگر در مورد وجود دارد place()
روشی که احتمالا برای شما جالب خواهد بود. حالا بیایید مثال های 2 و 4 از این آموزش را با هم ترکیب کنیم:
import tkinter
root = tkinter.Tk()
frame1 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame2 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame3 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame1.grid(column=0, row=0, sticky="nsew")
frame2.grid(column=1, row=0, sticky="nsew")
frame3.grid(column=0, row=1, sticky="nsew", columnspan=2)
label1 = tkinter.Label(frame1, text="Simple label")
button1 = tkinter.Button(frame2, text="Simple button")
button2 = tkinter.Button(frame3, text="Apply and close", command=root.destroy)
label1.pack(fill='x')
button1.pack(fill='x')
button2.pack(fill='x')
button1 = tkinter.Button(root, text="B")
button1.place(relx=0.5, rely=0.5, anchor="center")
root.mainloop()
خروجی:
در مثال بالا فقط کد را از مثال 2 گرفتیم و سپس در خطوط 21 و 22 دکمه کوچک خود را از مثال 4 در همان پنجره ایجاد و قرار دادیم. ممکن است تعجب کنید که این کد استثنایی ایجاد نمی کند، حتی اگر به وضوح ترکیب کنیم grid()
و place()
روش ها در root پنجره خوب، به دلیل ماهیت ساده و مطلق place()
، در واقع می توانید آن را با آن مخلوط کنید pack()
و grid()
. اما فقط در صورتی که واقعا مجبور باشید.
نتیجه، در این مورد، بدیهی است که بسیار زشت است. اگر دکمه مرکزی بزرگتر بود، بر قابلیت استفاده رابط تأثیر می گذاشت. اوه، و به عنوان یک تمرین، می توانید حرکت خطوط 21 و 22 را در بالای تعاریف فریم ها امتحان کنید و ببینید چه اتفاقی می افتد.
معمولا استفاده از آن ایده خوبی نیست place()
در رابط های شما مخصوصاً در رابطهای کاربری گرافیکی بزرگتر، تنظیم مختصات (حتی نسبی) برای هر ویجت تنها کار بسیار زیادی است و پنجره شما میتواند خیلی سریع به هم ریخته شود – چه اگر کاربر شما تصمیم به تغییر اندازه پنجره داشته باشد یا به خصوص اگر تصمیم دارید محتوای بیشتری به آن اضافه کنید. آی تی.
ظاهر ویجت های ما در حین اجرای برنامه قابل تغییر است. بسیاری از جنبه های آرایشی عناصر پنجره ما را می توان در کد ما با کمک configure
گزینه. بیایید به مثال زیر نگاهی بیندازیم:
import tkinter
root = tkinter.Tk()
def color_label():
label1.configure(text="Changed label", bg="green", fg="white")
frame1 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame2 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame3 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame1.grid(column=0, row=0, sticky="nsew")
frame2.grid(column=1, row=0, sticky="nsew")
frame3.grid(column=0, row=1, sticky="nsew", columnspan=2)
label1 = tkinter.Label(frame1, text="Simple label")
button1 = tkinter.Button(frame2, text="Configure button", command=color_label)
button2 = tkinter.Button(frame3, text="Apply and close", command=root.destroy)
label1.pack(fill='x')
button1.pack(fill='x')
button2.pack(fill='x')
root.mainloop()
خروجی:
در خطوط 5 و 6 ما یک تعریف ساده از یک تابع جدید اضافه کردیم. جدید ما color_label()
تابع وضعیت را پیکربندی می کند label1
. گزینه هایی که configure()
روش برداشت همان گزینه هایی است که هنگام ایجاد اشیاء ویجت جدید و تعریف جنبه های بصری اولیه ظاهر آنها استفاده می کنیم.
در این مورد، با فشار دادن دکمه “پیکربندی” که به تازگی تغییر نام داده است، متن، رنگ پسزمینه (bg) و رنگ پیشزمینه (fg – در این مورد رنگ متن است) متن موجود تغییر میکند. label1
.
حال، فرض کنید دکمه دیگری را به رابط خود اضافه می کنیم که می خواهیم از آن برای رنگ آمیزی سایر ویجت ها به روشی مشابه استفاده کنیم. در این مرحله، color_label()
تابع قادر است فقط یک ویجت خاص نمایش داده شده در رابط ما را تغییر دهد. به منظور اصلاح چندین ویجت، این راه حل از ما می خواهد که به اندازه تعداد کل ویجت هایی که می خواهیم تغییر دهیم، عملکردهای یکسانی را تعریف کنیم. این ممکن است، اما بدیهی است که راه حل بسیار ضعیفی است. البته راه هایی برای رسیدن به آن هدف به شیوه ای زیباتر وجود دارد. بیایید مثال خود را کمی گسترش دهیم.
import tkinter
root = tkinter.Tk()
def color_label():
label1.configure(text="Changed label", bg="green", fg="white")
frame1 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame2 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame3 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame4 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame5 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame1.grid(column=0, row=0, sticky="nsew")
frame2.grid(column=0, row=1, sticky="nsew")
frame3.grid(column=1, row=0, sticky="nsew")
frame4.grid(column=1, row=1, sticky="nsew")
frame5.grid(column=0, row=2, sticky="nsew", columnspan=2)
label1 = tkinter.Label(frame1, text="Simple label 1")
label2 = tkinter.Label(frame2, text="Simple label 2")
button1 = tkinter.Button(frame3, text="Configure button 1", command=color_label)
button2 = tkinter.Button(frame4, text="Configure button 2", command=color_label)
button3 = tkinter.Button(frame5, text="Apply and close", command=root.destroy)
label1.pack(fill='x')
label2.pack(fill='x')
button1.pack(fill='x')
button2.pack(fill='x')
button3.pack(fill='x')
root.mainloop()
خروجی:
خوب، حالا دو برچسب و سه دکمه داریم. فرض کنید میخواهیم «تنظیم دکمه 1» «برچسب ساده 1» و «پیکربندی دکمه 2» را دقیقاً به همان روش پیکربندی «برچسب ساده 2» را پیکربندی کند. البته، کد بالا به این صورت کار نمی کند – هر دو دکمه این را اجرا می کنند color_label()
تابع، که هنوز هم فقط یکی از برچسب ها را تغییر می دهد.
احتمالاً اولین راه حلی که به ذهن شما می رسد اصلاح آن است color_label()
تابع به طوری که یک شی ویجت را به عنوان یک می گیرد بحث و جدل و آن را پیکربندی کنید. سپس میتوانیم تعریف دکمهها را طوری تغییر دهیم که هر کدام از آنها برچسب جداگانه خود را در گزینه فرمان بفرستند:
def color_label(any_label):
any_label.configure(text="Changed label", bg="green", fg="white")
button1 = tkinter.Button(frame3, text="Configure button 1", command=color_label(label1))
button2 = tkinter.Button(frame4, text="Configure button 2", command=color_label(label2))
متأسفانه وقتی این کد را اجرا می کنیم، color_label()
عملکرد در لحظه ایجاد دکمه ها اجرا می شود که نتیجه مطلوبی نیست.
پس چگونه آن را به درستی کار کنیم؟
عبور آرگومان ها از طریق عبارات لامبدا
عبارات لامبدا یک نحو خاص برای ایجاد به اصطلاح ارائه می دهند توابع ناشناس، در یک خط تعریف شده است. پرداختن به جزئیات در مورد روش عملکرد لامبداها و زمان استفاده از آنها معمولاً هدف این آموزش نیست، بنابراین بیایید تمرکز کنیم روی مورد ما، که در آن عبارات لامبدا قطعاً مفید است.
import tkinter
root = tkinter.Tk()
def color_label(any_label):
any_label.configure(text="Changed label", bg="green", fg="white")
frame1 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame2 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame3 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame4 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame5 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame1.grid(column=0, row=0, sticky="nsew")
frame2.grid(column=0, row=1, sticky="nsew")
frame3.grid(column=1, row=0, sticky="nsew")
frame4.grid(column=1, row=1, sticky="nsew")
frame5.grid(column=0, row=2, sticky="nsew", columnspan=2)
label1 = tkinter.Label(frame1, text="Simple label 1")
label2 = tkinter.Label(frame2, text="Simple label 2")
button1 = tkinter.Button(frame3, text="Configure button 1", command=lambda: color_label(label1))
button2 = tkinter.Button(frame4, text="Configure button 2", command=lambda: color_label(label2))
button3 = tkinter.Button(frame5, text="Apply and close", command=root.destroy)
label1.pack(fill='x')
label2.pack(fill='x')
button1.pack(fill='x')
button2.pack(fill='x')
button3.pack(fill='x')
root.mainloop()
خروجی:
ما اصلاح کردیم color_label()
عملکرد مشابهی را که در مثال کوتاه قبلی انجام دادیم انجام می دهد. ما آن را به یک آرگومان پذیرفتیم، که در این مورد میتواند هر برچسبی باشد (ویجتهای متنی دیگر نیز کار میکنند) و با تغییر متن، رنگ متن و رنگ پسزمینه آن را پیکربندی کردیم.
بخش جالب، خطوط 22 و 23 است. در اینجا، ما در واقع دو تابع جدید لامبدا را تعریف می کنیم که آرگومان های مختلفی را به تابع ارسال می کنند. color_label()
عملکرد و اجرا کنید. به این ترتیب، می توانیم از فراخوانی آن اجتناب کنیم color_label()
در لحظه ای که دکمه ها مقداردهی اولیه می شوند عمل کنند.
دریافت ورودی کاربر
ما به پایان دومین مقاله از سری آموزش های Tkinter خود نزدیک می شویم، بنابراین در این مرحله، خوب است راهی برای دریافت ورودی از کاربر برنامه خود به شما نشان دهیم. برای انجام این کار، Entry
ویجت می تواند مفید باشد. به اسکریپت زیر نگاه کنید:
import tkinter
root = tkinter.Tk()
def color_label(any_label, user_input):
any_label.configure(text=user_input, bg="green", fg="white")
frame1 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame2 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame3 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame4 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame5 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame6 = tkinter.Frame(root, borderwidth=2, relief='ridge')
frame1.grid(column=0, row=0, sticky="nsew")
frame2.grid(column=0, row=1, sticky="nsew")
frame3.grid(column=1, row=0, sticky="nsew")
frame4.grid(column=1, row=1, sticky="nsew")
frame5.grid(column=0, row=2, sticky="nsew", columnspan=2)
frame6.grid(column=0, row=3, sticky="nsew", columnspan=2)
label1 = tkinter.Label(frame1, text="Simple label 1")
label2 = tkinter.Label(frame2, text="Simple label 2")
button1 = tkinter.Button(frame3, text="Configure button 1", command=lambda: color_label(label1, entry.get()))
button2 = tkinter.Button(frame4, text="Configure button 2", command=lambda: color_label(label2, entry.get()))
button3 = tkinter.Button(frame5, text="Apply and close", command=root.destroy)
entry = tkinter.Entry(frame6)
label1.pack(fill='x')
label2.pack(fill='x')
button1.pack(fill='x')
button2.pack(fill='x')
button3.pack(fill='x')
entry.pack(fill='x')
root.mainloop()
خروجی:
به خطوط 5 و 6 نگاهی بیندازید. همانطور که می بینید، color_label()
متد اکنون یک آرگومان جدید را می پذیرد. این آرگومان – یک رشته – سپس برای اصلاح برچسب های پیکربندی شده استفاده می شود text
پارامتر. علاوه بر این، در خط 29 ما یک جدید ایجاد می کنیم Entry
ویجت (و در خط 36 آن را در یک قاب جدید ایجاد شده در خط 13 بسته بندی می کنیم).
در خطوط 24 و 25، می بینیم که هر یک از توابع لامبدا یک آرگومان اضافی را نیز ارسال می کند. را get()
روش از Entry
class رشته ای را برمی گرداند که همان چیزی است که کاربر در فیلد ورودی تایپ کرده است. بنابراین، همانطور که احتمالاً قبلاً گمان میکنید، پس از کلیک کردن روی دکمههای “پیکربندی”، متن برچسبهایی که به آنها اختصاص داده شده است به هر متنی که کاربر در قسمت ورودی جدید ما تایپ کرده است تغییر میکند.
نتیجه
امیدوارم این بخش از آموزش بتواند برخی از شکاف ها را در درک شما از ماژول Tkinter پر کند. اگرچه برخی از ویژگی های پیشرفته Tkinter ممکن است در ابتدا کمی دشوار به نظر برسند، فلسفه کلی ساخت رابط ها با استفاده از محبوب ترین بسته رابط کاربری گرافیکی برای پایتون بسیار ساده و شهودی است.
منتظر آخرین بخش از آموزش اصول Tkinter ما باشید، جایی که ما چند میانبر بسیار هوشمندانه را کشف خواهیم کرد که به ما اجازه می دهد رابط های کاربری پیچیده با کد بسیار محدود ایجاد کنیم.
(برچسبها به ترجمه)# python
منتشر شده در 1403-01-26 14:11:05