رابط گرافیکی با tkinter
تا اینجا همه برنامههای ما در ترمینال زندگی میکردند. از این فصل
بیرون میآییم: پنجره واقعی با دکمه و فیلد و منو. ابزار ما
tkinter است که جزو کتابخانه استاندارد پایتون است و
هیچ نصبی نمیخواهد.
۱. اولین پنجره و حلقه رویداد
'''The smallest possible Tkinter program: one empty window.'''
import tkinter as tk
def main() -> None:
# Tk() creates the main window. There must be exactly one per program.
root = tk.Tk()
root.title('A simple program') # the text of the title bar
root.geometry('400x300') # 'WIDTHxHEIGHT', in pixels
# mainloop() starts the EVENT LOOP: the program now waits for clicks and
# key presses, and it does not return until the window is closed.
# Nothing written after mainloop() runs before that.
root.mainloop()
if __name__ == '__main__':
main()
اولین پنجره: نمونه 01_window/app.py
شرح مثال
tk.Tk()پنجره اصلی را میسازد. در هر برنامه دقیقاً یکی از آن باید وجود داشته باشد.geometry('400x300')اندازه را به پیکسل میگیرد. حرف کوچکxبین دو عدد، ضربدر نیست بلکه جداکننده است.mainloop()مهمترین خط است: حلقه رویداد را شروع میکند.
برنامه ترمینالی از بالا به پایین اجرا میشود و تمام. برنامه گرافیکی
اما بعد از راهاندازی وارد یک حلقه بیپایان میشود و
منتظر میماند: کلیک شد؟ کلیدی فشرده شد؟ پنجره
تغییر اندازه داد؟ برای هر رویداد، تابع مربوطه را صدا میزند و باز
منتظر میماند. به همین دلیل هر چه بعد از mainloop()
بنویسید تا بسته شدن پنجره اجرا نمیشود.
۲. برچسب
برچسب متنی را نشان میدهد که کاربر نمیتواند ویرایشش کند.
def main() -> None:
root = tk.Tk()
root.title('Showing a label')
root.geometry('400x300')
# Every widget receives its PARENT as its first argument.
label = tk.Label(root, text='Welcome to my program')
# Creating a widget is not enough: it must be placed with a geometry
# manager, otherwise it stays invisible.
label.pack()
# A widget takes many options.
tk.Label(
root,
text='Kadoos Institute, Rasht',
font=('Arial', 18, 'bold'),
fg='white', # foreground = the color of the text
bg="#224160", # background
padx=20,
pady=10,
).pack(pady=20)
root.mainloop()
برچسب: نمونه 02_label/app.py
شرح مثال
- هر ویجت، والدش را به عنوان اولین آرگومان میگیرد. اینجا والد، پنجره اصلی است.
- ساختن ویجت کافی نیست. تا وقتی با یک مدیر چیدمان قرار داده نشود، نامرئی میماند. این پرتکرارترین سؤال تازهکارهاست: «چرا چیزی نمیبینم؟»
fgرنگ متن وbgرنگ پسزمینه است. رنگ را میشود با نام ('white') یا با کد شانزدهشانزدهی داد.padxوpadyفاصله داخلی و بیرونی را تنظیم میکنند و بیشترین تأثیر را در زیبایی برنامه دارند.
۳. دکمه و تابع پاسخ
'''A Button runs a function when it is clicked.
Note how the widgets are created inside main() and the callback is a NESTED
function: that way it sees `label` without needing `global`.
'''
def main() -> None:
root = tk.Tk()
root.title('Button and label')
root.geometry('400x300')
label = tk.Label(root, text='I am waiting for a click')
label.pack(pady=20)
def change_text() -> None:
'This function is called by the button.'
print('Clicked!')
# config() changes an option of an existing widget.
label.config(text='The button was clicked')
# command=change_text passes the FUNCTION ITSELF.
# command=change_text() would CALL it immediately and pass its result -
# that is the classic beginner mistake.
button = tk.Button(root, text='Click me', command=change_text)
button.pack()
# A counter, to show that the callback keeps its state between clicks.
clicks = {'count': 0}
def count_click() -> None:
clicks['count'] += 1
counter_label.config(text=f'Clicks: {clicks["count"]}')
counter_label = tk.Label(root, text='Clicks: 0')
counter_label.pack(pady=(20, 0))
tk.Button(root, text='Count', command=count_click).pack()
root.mainloop()
دکمه: نمونه 03_button/app.py
شرح مثال
- بزرگترین نکته این فصل همینجاست:
command=change_textبدون پرانتز. با پرانتز، تابع همان لحظه اجرا میشود و نتیجهاش به دکمه داده میشود، نه خود تابع. config()گزینه یک ویجت موجود را عوض میکند.- توابع پاسخ به شکل تابع تودرتو داخل
mainنوشته شدهاند، پسlabelرا میبینند و هیچ نیازی بهglobalنیست. نسخه اصلی این درس پر ازglobalبود؛ این شکل بسیار تمیزتر است. - شمارنده در یک دیکشنری نگه داشته شده است، چون تابع تودرتو میتواند دیکشنری بیرونی را تغییر دهد ولی نمیتواند به یک عدد بیرونی مقدار تازه بدهد. جایگزین دیگرش
nonlocalاست.
۴. فیلد متنی
'''An Entry is a one-line text field.
entry.get() -> what the user typed (always a str)
entry.delete(0, tk.END) -> empty it
entry.insert(0, 'text') -> write into it
'''
def main() -> None:
root = tk.Tk()
root.title('Text input')
root.geometry('400x300')
entry = tk.Entry(root, width=30)
entry.pack(pady=10)
entry.focus() # the cursor starts in this field
label = tk.Label(root, text='')
label.pack(pady=10)
def show_text() -> None:
user_input = entry.get().strip()
if not user_input:
label.config(text='Please type something first.')
return
label.config(text='You wrote: ' + user_input)
tk.Button(root, text='Show', command=show_text).pack()
tk.Button(root, text='Clear',
command=lambda: entry.delete(0, tk.END)).pack(pady=5)
# bind() connects a keyboard or mouse event to a function.
# '<Return>' is the Enter key.
entry.bind('<Return>', lambda event: show_text())
root.mainloop()
فیلد متنی: نمونه 04_entry/app.py
شرح مثال
entry.get()همیشه رشته میدهد، حتی اگر کاربر عدد تایپ کرده باشد. برای عدد باید خودتان تبدیل کنید و محافظ بگذارید.- ورودی خالی باید همیشه بررسی شود. یک
strip()هم فاصلههای اضافه را برمیدارد. lambdaوقتی به کار میآید که بخواهید تابعی با آرگومان را بهcommandبدهید. به خاطر داشته باشیدcommandتابع بدون آرگومان میخواهد.bindرویداد صفحهکلید یا ماوس را به تابع وصل میکند. تابعی کهbindصدا میزند همیشه یک آرگومان رویداد میگیرد، به همین دلیلlambda event: ...نوشته شده است.
۵. سه مدیر چیدمان
در tkinter سه راه برای قرار دادن ویجتها وجود دارد. انتخاب درست، نصف کار طراحی رابط است.
| مدیر | چه میکند | کی به کار میآید |
|---|---|---|
pack() | ویجتها را پشت سر هم میچیند | چیدمانهای ساده، نوارها، ستون تکی |
grid() | جدولی از سطر و ستون | فرمها، ماشینحساب، هر چیز جدولی |
place() | مختصات دقیق پیکسلی | بهندرت. با تغییر اندازه پنجره خراب میشود |
اگر روی ویجتهایی که والد مشترک دارند هم
pack() و هم grid() به کار ببرید، برنامه
بیهیچ پیامی قفل میشود. نه خطایی میبینید و نه
پنجرهای؛ فقط برنامه هنگ میکند. این یکی از سختترین باگها برای
تازهکارهاست. راه حل: هر قاب، مدیر مخصوص خودش را دارد.
گزینههای پرکاربرد این دو مدیر را در یک جا ببینید:
| گزینه | مال کدام | وظیفه آن |
|---|---|---|
side | pack | جهت چیدن: top، left، right، bottom |
fill | pack | کشیده شدن در عرض یا ارتفاع: x، y، both |
expand | pack | گرفتن فضای اضافه باقیمانده |
row و column | grid | شماره سطر و ستون، از صفر |
columnspan | grid | کشیده شدن روی چند ستون |
sticky | grid | چسبیدن به جهتها: n s e w و ترکیبشان |
padx و pady | هر دو | فاصله افقی و عمودی |
۶. فرم با grid
'''grid() places the widgets in a table of rows and columns.
It is the right manager for a form. Never use pack() and grid() on widgets
that share the same parent: the program then freezes.
'''
def main() -> None:
root = tk.Tk()
root.title('Login form')
root.geometry('400x300')
# sticky='e' pushes the label to the East (the right) of its cell.
tk.Label(root, text='Username:').grid(row=0, column=0,
padx=10, pady=5, sticky='e')
entry_user = tk.Entry(root, width=25)
entry_user.grid(row=0, column=1, padx=10, pady=5)
tk.Label(root, text='Password:').grid(row=1, column=0,
padx=10, pady=5, sticky='e')
# show='*' hides what is typed.
entry_pass = tk.Entry(root, width=25, show='*')
entry_pass.grid(row=1, column=1, padx=10, pady=5)
label_result = tk.Label(root, text='')
label_result.grid(row=3, column=0, columnspan=2)
def login() -> None:
username = entry_user.get().strip()
password = entry_pass.get()
if not username or not password:
label_result.config(text='Both fields are required.', fg='red')
return
if username == 'admin' and password == '1234':
label_result.config(text=f'Welcome, {username}!', fg='green')
else:
label_result.config(text='Wrong username or password.', fg='red')
# columnspan=2 makes the button as wide as the two columns.
tk.Button(root, text='Login', command=login).grid(row=2, column=0,
columnspan=2, pady=10)
root.mainloop()
فرم ورود: نمونه 05_grid_login/app.py
شرح مثال
- ساختار فرم همیشه همین است: ستون صفر برچسبها، ستون یک فیلدها.
sticky='e'برچسب را به سمت شرق خانهاش میچسباند تا برچسبها با هم تراز شوند.show='*'کاراکترهای تایپشده را پنهان میکند. برای رمز عبور لازم است.- نتیجه در یک برچسب داخل پنجره نشان داده میشود، نه با
print. در برنامه گرافیکی، کاربر ترمینال را نمیبیند. - این فقط یک نمونه آموزشی است: رمز عبور را هرگز در کد ننویسید. روش درست را در فصل سی و هشتم با درهمسازی رمز میبینید.
۷. قابها
قاب یک جعبه نامرئی برای گروهبندی ویجتهاست. هر قاب
مدیر چیدمان مخصوص خودش را دارد، پس یک بخش پنجره میتواند
pack باشد و بخش دیگر grid.
def main() -> None:
root = tk.Tk()
root.title('Using frames')
root.geometry('400x300')
# fill='x' -> the frame takes the whole width.
top_frame = tk.Frame(root, bg='lightblue', height=100)
top_frame.pack(fill='x')
tk.Label(top_frame, text='Top section', bg='lightblue').pack(pady=30)
# fill='both' + expand=True -> the frame takes all the remaining space.
bottom_frame = tk.Frame(root, bg='darkred')
bottom_frame.pack(fill='both', expand=True)
# side= decides where pack() puts the widget inside its parent.
tk.Button(bottom_frame, text='Left button').pack(side='left',
padx=10, pady=10)
tk.Button(bottom_frame, text='Right button').pack(side='right',
padx=10, pady=10)
root.mainloop()
قاب: نمونه 06_frame/app.py
قاببندی، کلید ساختن رابطهای بزرگ است. هر بخش منطقی برنامه یک قاب
میشود و بعد قابها کنار هم چیده میشوند. ترکیب
fill='both' با expand=True یعنی «همه فضای
باقیمانده را بگیر» و پرکاربردترین ترکیب pack است.
۸. تیک و دکمه رادیویی
'''Checkbutton (several independent choices) and Radiobutton (one choice).
Both need a CONTROL VARIABLE - IntVar, StringVar, BooleanVar - which holds the
current value and is read with get().
Every radio button of a group shares the SAME variable; what tells them apart
is their `value`.
'''
def main() -> None:
root = tk.Tk()
root.title('Options')
root.geometry('400x300')
label_status = tk.Label(root, text='')
label_color = tk.Label(root, text='')
var_check = tk.IntVar() # 0 or 1
var_radio = tk.StringVar(value='red') # the selected value
def show_selection() -> None:
'Called every time one of the widgets changes.'
if var_check.get():
label_status.config(text='Enabled')
else:
label_status.config(text='Disabled')
label_color.config(text='Selected colour: ' + var_radio.get())
tk.Checkbutton(root, text='Enable', variable=var_check,
command=show_selection).pack(pady=(10, 5))
for colour in ('red', 'blue', 'green'):
tk.Radiobutton(root, text=colour, variable=var_radio, value=colour,
command=show_selection).pack(anchor='w', padx=140)
label_status.pack(pady=(15, 0))
label_color.pack()
show_selection() # show the initial state
root.mainloop()
تیک و رادیویی: نمونه 07_check_radio/app.py
شرح مثال
- تفاوت دو ویجت: تیک چند انتخاب مستقل است (هر کدام متغیر خودش)، رادیویی یک انتخاب از چند تا.
- همه دکمههای رادیویی یک گروه، یک متغیر مشترک دارند. چیزی که از هم جدایشان میکند
valueاست. اگر هر کدام متغیر جدا بگیرند، همه با هم انتخاب میشوند: یک باگ رایج. - دکمههای رادیویی با یک حلقه ساخته شدهاند. سه خط تقریباً یکسان نوشتن کار خوبی نیست.
- در انتها
show_selection()یک بار مستقیم صدا زده میشود تا وضعیت اولیه هم نمایش داده شود. وگرنه کاربر تا اولین کلیک، پنجرهای نیمهخالی میبیند.
۹. فهرست انتخاب
'''A Listbox shows a list the user can choose from.
insert(tk.END, item) -> add at the end
curselection() -> a TUPLE of the selected indexes (empty when none)
get(index) -> the text of one line
delete(index) -> remove a line
'''
def main() -> None:
root = tk.Tk()
root.title('Listbox')
root.geometry('400x350')
listbox = tk.Listbox(root, height=6)
for item in ['Tehran', 'Isfahan', 'Shiraz', 'Tabriz', 'Mashhad', 'Rasht']:
listbox.insert(tk.END, item)
listbox.pack(pady=10)
label = tk.Label(root, text='')
label.pack()
def show_selected() -> None:
selected = listbox.curselection()
# curselection() gives an empty tuple when nothing is selected -
# reading selected[0] without this test raises IndexError.
if selected:
label.config(text='Your choice: ' + listbox.get(selected[0]))
else:
label.config(text='Nothing is selected')
def delete_selected() -> None:
selected = listbox.curselection()
if selected:
listbox.delete(selected[0])
tk.Button(root, text='Show the selection', command=show_selected).pack(pady=5)
tk.Button(root, text='Delete the selection', command=delete_selected).pack()
# A double click also shows the selection.
listbox.bind('<Double-Button-1>', lambda event: show_selected())
root.mainloop()
فهرست: نمونه 08_listbox/app.py
curselection() یک تاپل از شمارههای
انتخابشده میدهد و وقتی چیزی انتخاب نشده، تاپل خالی است. خواندن
selected[0] بدون بررسی، مستقیم به IndexError
میرسد. این دقیقاً همان درس فصل نهم است که حالا در دنیای گرافیکی تکرار
میشود.
۱۰. متغیر کنترلی و شمارنده
تا اینجا هر بار متن برچسب را با config() عوض میکردیم.
راه تمیزتر متغیر کنترلی است: برچسب به متغیر وصل
میشود و هر وقت متغیر عوض شود، برچسب خودش بهروز
میشود.
'''Control variables: the clean way to keep a widget and a value in agreement.
With `textvariable=`, the label updates ITSELF whenever the variable changes:
we never call label.config() again.
'''
def main() -> None:
root = tk.Tk()
root.title('Counter')
root.geometry('400x300')
counter_var = tk.IntVar(value=0)
def increment() -> None:
counter_var.set(counter_var.get() + 1)
def decrement() -> None:
counter_var.set(counter_var.get() - 1)
def reset() -> None:
counter_var.set(0)
tk.Label(root, textvariable=counter_var,
font=('Arial', 24)).pack(pady=20)
button_frame = tk.Frame(root)
button_frame.pack()
tk.Button(button_frame, text='+', command=increment,
width=5).pack(side='left', padx=5)
tk.Button(button_frame, text='-', command=decrement,
width=5).pack(side='left', padx=5)
tk.Button(button_frame, text='Reset', command=reset,
width=6).pack(side='left', padx=5)
root.mainloop()
شمارنده: نمونه 09_counter/app.py
| متغیر کنترلی | برای چه |
|---|---|
tk.StringVar() | متن |
tk.IntVar() | عدد صحیح |
tk.DoubleVar() | عدد اعشاری |
tk.BooleanVar() | درست یا نادرست |
.get() و .set(x) | خواندن و نوشتن مقدار |
textvariable= | گره زدن ویجت به متغیر |
دکمههای + و - داخل یک قاب جداگانه گذاشته
شدهاند تا در یک ردیف افقی بنشینند، در حالی که بقیه پنجره عمودی چیده
شده است. این همان فایده قاب است که در بخش هفتم گفتیم.
۱۱. پنجرههای پیام
'''messagebox: the standard dialog boxes.
showinfo / showwarning / showerror -> just an OK button
askyesno / askokcancel -> return True or False
askquestion -> returns 'yes' or 'no'
'''
import tkinter as tk
from tkinter import messagebox
def main() -> None:
root = tk.Tk()
root.title('Message boxes')
root.geometry('400x300')
def show_info() -> None:
messagebox.showinfo('Information', 'This is an information message')
def ask_question() -> None:
# The answer is used to decide what to do next.
if messagebox.askyesno('Question', 'Do you want to close the program?'):
root.destroy()
tk.Button(root, text='Show information', command=show_info).pack(pady=5)
tk.Button(root, text='Ask and quit', command=ask_question).pack(pady=5)
root.mainloop()
پنجره پیام: نمونه 10_messagebox/app.py
توجه کنید که messagebox باید جداگانه
import شود؛ با import tkinter as tk به تنهایی
در دسترس نیست. پنجرههای پرسشی True یا
False برمیگردانند و همانجا در if به کار
میروند. پیش از هر کار برگشتناپذیر مثل حذف، حتماً یک
askyesno بگذارید.
۱۲. نوار منو
'''A menu bar.
Menu(root) -> the bar itself
root.config(menu=menubar) -> attach it to the window
add_cascade -> a menu that opens a sub-menu
add_command -> an entry that runs a function
tearoff=0 -> remove the old dashed line at the top
'''
def main() -> None:
root = tk.Tk()
root.title('A program with a menu')
root.geometry('400x300')
label = tk.Label(root, text='Use the menu above', font=('Arial', 14))
label.pack(pady=50)
def new_file() -> None:
label.config(text='New file')
def show_about() -> None:
messagebox.showinfo('About', 'This program is a teaching example.')
menubar = tk.Menu(root)
root.config(menu=menubar)
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label='File', menu=file_menu)
file_menu.add_command(label='New', command=new_file)
file_menu.add_separator()
# root.destroy() closes the window properly; root.quit() only stops the loop.
file_menu.add_command(label='Exit', command=root.destroy)
help_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label='Help', menu=help_menu)
help_menu.add_command(label='About', command=show_about)
root.mainloop()
منو: نمونه 11_menu/app.py
شرح مثال
- ساخت منو سه قدم دارد: نوار را بساز، با
root.config(menu=...)به پنجره بچسبان، و بعد زیرمنوها را اضافه کن. tearoff=0آن خطچین قدیمی بالای منو را حذف میکند. تقریباً همیشه لازم است.- تفاوت
destroy()باquit()را بدانید:destroyپنجره را درست میبندد، ولیquitفقط حلقه رویداد را متوقف میکند و گاهی برنامه را نیمهباز رها میکند. همیشهdestroyرا انتخاب کنید.
۱۳. فرم با اعتبارسنجی
مهمترین بخش هر برنامه گرافیکی، رسیدگی به ورودی اشتباه است. هر چیزی که
از Entry بیرون میآید متن است و float()
میتواند شکست بخورد.
def calculate() -> None:
try:
length = float(entry_length.get())
width = float(entry_width.get())
except ValueError:
result.config(text='Please enter two numbers.', fg='red')
return
if length <= 0 or width <= 0:
result.config(text='The values must be positive.', fg='red')
return
area = length * width
perimeter = (length + width) * 2
result.config(text=f'Area: {area:g} Perimeter: {perimeter:g}',
fg='green')
اعتبارسنجی: نمونه 12_rectangle/app.py
شرح مثال
- دو لایه بررسی داریم: اول عدد بودن با
try/except، بعد منطقی بودن مقدار. - الگوی
returnزودهنگام، کد را تخت نگه میدارد و ازifهای تودرتو جلوگیری میکند. - رنگ پیام هم پیام میدهد: قرمز برای خطا، سبز برای موفقیت.
- قالب
:gعدد را بدون صفرهای اضافه نشان میدهد، پس12.0میشود12.
۱۴. ماشینحساب کامل
import tkinter as tk
ALLOWED_CHARACTERS = set('0123456789+-*/(). ')
BUTTONS = [
('7', 1, 0), ('8', 1, 1), ('9', 1, 2), ('/', 1, 3),
('4', 2, 0), ('5', 2, 1), ('6', 2, 2), ('*', 2, 3),
('1', 3, 0), ('2', 3, 1), ('3', 3, 2), ('-', 3, 3),
('0', 4, 0), ('.', 4, 1), ('=', 4, 2), ('+', 4, 3),
]
def main() -> None:
root = tk.Tk()
root.title('Calculator')
root.geometry('300x400')
display = tk.Entry(root, font=('Arial', 18), justify='right')
display.grid(row=0, column=0, columnspan=4, sticky='we', padx=5, pady=5)
def press(key: str) -> None:
'Add one character at the end of the display.'
display.insert(tk.END, str(key))
def calculate() -> None:
expression = display.get()
# Refuse anything that is not a number or an operator.
if not expression or not set(expression) <= ALLOWED_CHARACTERS:
display.delete(0, tk.END)
display.insert(tk.END, 'Error')
return
try:
result = eval(expression)
except (SyntaxError, ZeroDivisionError, ValueError):
display.delete(0, tk.END)
display.insert(tk.END, 'Error')
return
display.delete(0, tk.END)
display.insert(tk.END, str(result))
for text, row, column in BUTTONS:
if text == '=':
button = tk.Button(root, text=text, width=5, height=2,
command=calculate)
else:
# t=text captures the CURRENT value of text.
button = tk.Button(root, text=text, width=5, height=2,
command=lambda t=text: press(t))
button.grid(row=row, column=column, padx=2, pady=2)
# The columns share the extra space when the window is resized.
for column in range(4):
root.grid_columnconfigure(column, weight=1)
root.mainloop()
ماشینحساب: نمونه 13_calculator/app.py
سه درس این برنامه
- دکمهها با حلقه ساخته میشوند. نوشتن شانزده خط تقریباً یکسان اتلاف وقت است و هر تغییری باید شانزده بار تکرار شود.
-
دام اتصال دیرهنگام. در
lambda t=text: press(t)آنt=textحیاتی است. بدون آن، همه لامبداها به یک متغیر مشترک نگاه میکنند و همه دکمهها آخرین کاراکتر حلقه را تایپ میکنند. این باگ در هر زبانی که closure دارد وجود دارد و دیدنش یک بار، برای همیشه یادتان میماند. -
evalخطرناک است. این تابع هر کد پایتونی را اجرا میکند. اینجا پیش از اجرا بررسی میشود که متن فقط رقم و عملگر دارد. مقایسهset(expression) <= ALLOWED_CHARACTERSیعنی «همه کاراکترها در مجموعه مجاز هستند» و از فصل چهاردهم میآید.
grid_columnconfigure(column, weight=1) باعث میشود با
بزرگ شدن پنجره، ستونها فضای اضافه را بین خودشان تقسیم کنند. بدون آن،
دکمهها گوشه بالا چپ جمع میشوند و پنجره زشت میشود.
پوشه S34-tkinter-basics شامل سیزده پوشه از 01_window تا 13_calculator است. در هر پوشه یک app.py هست که با python app.py اجرا میشود. هیچ نصبی ضرورتی ندارد، چون tkinter جزو خود پایتون است.
خلاصه فصل
| ابزار | وظیفه آن |
|---|---|
tk.Tk() | پنجره اصلی، یکی در هر برنامه |
title و geometry | عنوان و اندازه پنجره |
mainloop() | شروع حلقه رویداد |
Label | نمایش متن |
Button | دکمه، با command=func بدون پرانتز |
Entry | فیلد یکخطی. get همیشه رشته میدهد |
Frame | گروهبندی ویجتها |
Checkbutton و Radiobutton | انتخاب چندگانه و انتخاب یگانه |
Listbox | فهرست. curselection ممکن است خالی باشد |
pack و grid و place | سه مدیر چیدمان. در یک ظرف فقط یکی |
IntVar و StringVar | متغیر کنترلی، با textvariable |
config() | تغییر گزینه یک ویجت موجود |
bind('<Return>', f) | اتصال رویداد به تابع |
messagebox | پنجرههای پیام و پرسش |
Menu و add_cascade | نوار منو |
root.destroy() | بستن درست برنامه |
تمرینهای فصل سی و چهار
- پنجرهای بسازید که نام شما در عنوانش باشد و یک برچسب خوشامد داشته باشد.
- فرمی بسازید که نام بپرسد و در یک برچسب بنویسد
Hello <name>!. - مبدل دما از سلسیوس به فارنهایت بسازید، با اعتبارسنجی کامل ورودی.
- پنجرهای با سه دکمه رادیویی بسازید که رنگ پسزمینه را عوض کنند.
- فهرست خرید بسازید: یک
Entry، دکمه افزودن، یکListboxو دکمه حذف. - به یکی از برنامههایتان منوی
File > ExitوHelp > Aboutاضافه کنید. - پیش از بسته شدن برنامه، با
askyesnoاز کاربر تأیید بگیرید. - بازی حدس عدد را با رابط گرافیکی بنویسید.
- به ماشینحساب، دکمه پاک کردن و دکمه حذف آخرین کاراکتر اضافه کنید.