本文主要介绍几个比较实用的例子。先载入一些包:
from tkinter import Tk, ttk, PhotoImage
from tkinter import Menu, StringVar, filedialog, , Listbox
1 可绑定“动作”的按钮#
绑定按钮,令其输出欢迎信息:
class App(Tk):
def __init__(self):
super().__init__()
# 创建带命令的按钮
self.btn = ttk.Button(self, text="点我!",
command=self.say_hello)
# 布局按钮
self.btn.grid(padx=120, pady=30)
def say_hello(self):
print("欢迎进入 tkinter 世界!")
if __name__ == "__main__":
app = App()
app.title("tkinter 的应用")
app.mainloop()
效果图:
2 带图片的按钮#
RELIEFS = ['sunken', 'raised', 'groove', 'ridge', 'flat']
class ButtonsApp(Tk):
def __init__(self):
super().__init__()
self.img = PhotoImage(file="python.gif")
self.btn = ttk.Button(self, text="带图片的按钮",
image=self.img, compound='left',
command=self.disable_btn)
self.btn.grid(row=0, column=2)
for i, RELIEF in enumerate(RELIEFS):
temp = ttk.Frame(self, relief=RELIEF,
borderwidth=5, width=50, height=50)
label = ttk.Label(temp, text=RELIEF)
label.grid(row=0, column=0)
temp.grid(row=1, column=i, padx=10, pady=10)
def disable_btn(self):
self.btn.config(state='disabled')
if __name__ == "__main__":
app = ButtonsApp()
app.mainloop()
显示效果:
该例子将图片放置在文字的左侧,且绑定了一个命令,该命令实现按钮的失活操作。第二行显示了不同的 relief 的 ttk.Frame。
3 可跟踪 ttk.Entry 的“变量”#
class App(Tk):
def __init__(self):
super().__init__()
self.var = StringVar()
self.var.trace("w", self.show_message)
self.entry = ttk.Entry(textvariable=self.var)
self.btn = ttk.Button(text="清除",
command=lambda: self.var.set(""))
self.label = ttk.Label()
self.entry.grid()
self.btn.grid()
self.label.grid()
def show_message(self, *args):
value = self.var.get()
text = f"你好, {value}!" if value else ''
self.label.config(text=text)
if __name__ == "__main__":
app = App()
app.mainloop()
效果图:
该例子实时跟踪文本框的输入,并显示在第 3 行。
4 验证 ttk.Entry#
import re
class App(Tk):
def __init__(self):
super().__init__()
self.pattern = re.compile("^\w{0,10}$")
self.label = ttk.Label(text="输入您的用户名")
vcmd = (self.register(self.validate_username), "%i", "%P")
self.entry = ttk.Entry(validate="key",
validatecommand=vcmd,
invalidcommand=self.print_error)
self.label.pack()
self.entry.pack(anchor='w', padx=10, pady=10)
def validate_username(self, index, username):
print("修改 " + index)
return self.pattern.match(username) is not None
def print_error(self):
print("无效的用户名")
if __name__ == "__main__":
app = App()
app.mainloop()
验证输入的字符是否满足条件。
5 Listbox(列表框)#
该组件有一个比较重要的选项 selectmode
用来确定可以选择多少项,以及鼠标拖动的影响选择:
'browse'
:通常,只能从列表框中选择一行。如果单击一个项目,然后拖动到不同的行,选择将会跟随鼠标,是默认的。'single'
:你只能选择一行,不能拖动。'multiple'
:您可以同时选择任意数量的行。点击在任意直线上,无论它是否被选中。不能拖动。'extended'
: 您可以一次选择任何相邻的多个选项。能拖动。支持Shift和Control(如Windows下的快捷键)。
示例:
DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"]
MODES = ['single', 'browse', 'multiple', 'extended']
class ListApp(Tk):
def __init__(self):
super().__init__()
self.list = Listbox()
self.list.insert(0, *DAYS)
self.print_btn = ttk.Button(self, text="Print selection",
command=self.print_selection)
self.btns = [self.create_btn(m) for m in MODES]
self.list.pack()
self.print_btn.pack(fill='both')
for btn in self.btns:
btn.pack(side='left')
def create_btn(self, mode):
def cmd(): return self.list.config(selectmode=mode)
return ttk.Button(self, command=cmd,
text=mode.capitalize())
def print_selection(self):
selection = self.list.curselection()
print([self.list.get(i) for i in selection])
if __name__ == "__main__":
app = ListApp()
app.mainloop()
效果图见:
6 鼠标触发的事件#
class App(ttk.Frame):
def __init__(self, master=None, **kw):
super().__init__(master, **kw)
style = ttk.Style()
style.configure("BG.TFrame", foreground="black", background="green")
self.configure(style="BG.TFrame", height=100, width=100)
self.bind_mul()
self.grid(padx=50, pady=50)
def bind_mul(self):
event_names = ("<Button-1>", "<Double-Button-1>",
"<ButtonRelease-1>", "<B1-Motion>",
"<Enter>", "<Leave>")
[self.bind(event_name, self.print_event) for event_name in event_names]
def print_event(self, event):
position = f"(x={event.x}, y={event.y})"
print(event.type, "event", position)
if __name__ == "__main__":
root = Tk()
app = App(root)
root.mainloop()
7 键盘触发的事件#
class App(Tk):
def __init__(self):
super().__init__()
entry = ttk.Entry(self)
entry.bind("<FocusIn>", self.print_type)
entry.bind("<Key>", self.print_key)
entry.grid(padx=20, pady=20)
def print_type(self, event):
print(event.type)
def print_key(self, event):
print(
f"Symbol: {event.keysym},Code: {event.keycode}, Char: {event.char}")
if __name__ == "__main__":
app = App()
app.mainloop()
效果图:
8 自定义标题栏图标#
class App(Tk):
def __init__(self):
super().__init__()
self.title("自定义标题栏图标")
self.iconbitmap("python.ico")
# width x height ±x±y
self.geometry("400x200+50+50")
if __name__ == "__main__":
app = App()
app.mainloop()
width 和 height(通常以像素为单位)非常不言自明。 “±x”(水平位置)用正负号指定,因此“+25”表示窗口的左边缘应距屏幕左边缘25个像素,而“-50”表示右边缘窗口的宽度应距屏幕右边缘50像素。 同样,“y”(垂直)位置为“+10”表示窗口的上边缘应比屏幕顶部低10个像素,而“-100”表示窗口的底部边缘应比屏幕顶部高100像素屏幕底部。
9 自定义列表框#
class ListFrame(ttk.Frame):
def __init__(self, master, items=[]):
super().__init__(master)
self.list = Listbox(self)
self.scroll = ttk.Scrollbar(self, orient='vertical',
command=self.list.yview)
self.list.config(yscrollcommand=self.scroll.set)
self.list.insert(0, *items)
self.list.pack(side='left')
self.scroll.pack(side='left', fill='y')
def pop_selection(self):
index = self.list.curselection()
if index:
value = self.list.get(index)
self.list.delete(index)
return value
def insert_item(self, item):
self.list.insert('end', item)
class App(Tk):
def __init__(self):
super().__init__()
months = ["January", "February", "March", "April",
"May", "June", "July", "August", "September",
"October", "November", "December"]
self.frame_a = ListFrame(self, months)
self.frame_b = ListFrame(self)
self.btn_right = ttk.Button(self, text=">",
command=self.move_right)
self.btn_left = ttk.Button(self, text="<",
command=self.move_left)
self.frame_a.pack(side='left', padx=10, pady=10)
self.frame_b.pack(side='right', padx=10, pady=10)
self.btn_right.pack(expand=True, ipadx=5)
self.btn_left.pack(expand=True, ipadx=5)
def move_right(self):
self.move(self.frame_a, self.frame_b)
def move_left(self):
self.move(self.frame_b, self.frame_a)
def move(self, frame_from, frame_to):
value = frame_from.pop_selection()
if value:
frame_to.insert_item(value)
if __name__ == "__main__":
app = App()
app.mainloop()
10 不同颜色的标签#
class App(Tk):
def __init__(self):
super().__init__()
colors = ("yellow", "orange", "red", "green", "blue")
labels = [ttk.Label(text=f'label_{color}', background=color)
for color in colors]
opts = {'ipadx': 20, 'ipady': 10, 'fill': 'both'}
labels[0].pack(side='top', **opts)
labels[1].pack(side='top', **opts)
labels[2].pack(side='left', **opts)
labels[3].pack(side='left', **opts)
labels[4].pack(side='left', **opts)
if __name__ == "__main__":
app = App()
app.mainloop()
效果图:
Grid 布局:
class App(Tk):
def __init__(self):
super().__init__()
colors = ("yellow", "orange", "red", "green", "blue")
labels = [ttk.Label(text=color, background=color)
for color in colors]
opts = {'ipadx': 10, 'ipady': 10, 'sticky': 'nswe'}
for k, lb in enumerate(labels):
lb.grid(row=self.set_row(k),
column=self.set_column(k),
rowspan=2 if k in (2, 3) else None,
columnspan=3 if k == 4 else None,
**opts)
def set_row(self, k):
if k == 1:
return 1
elif k == 4:
return 2
else:
return 0
def set_column(self, k):
if k == 2:
return 1
elif k == 3:
return 2
else:
return 0
if __name__ == "__main__":
app = App()
app.mainloop()
class App(Tk):
def __init__(self):
super().__init__()
colors = ("yellow", "orange", "red", "green", "blue")
labels = [ttk.Label(text=color, background=color)
for color in colors]
labels[0].place(relwidth=0.25, relheight=0.25)
labels[1].place(x=100, anchor='n',
width=100, height=50)
labels[2].place(relx=0.5, rely=0.5, anchor='center',
relwidth=0.5, relheight=0.5)
labels[3].place(in_=labels[2], anchor='nw',
x=2, y=2, relx=0.5, rely=0.5,
relwidth=0.5, relheight=0.5)
labels[4].place(x=200, y=200, anchor='se',
relwidth=0.25, relheight=0.25)
if __name__ == "__main__":
app = App()
app.mainloop()
11 创建个人信息记录表单#
class App(Tk):
def __init__(self):
super().__init__()
style = ttk.Style()
style.configure("W.TFrame", background="white")
group_1 = ttk.LabelFrame(self, text="个人信息", style="W.TFrame")
group_1.pack(padx=10, pady=5)
ttk.Label(group_1, text="性别").grid(row=0)
ttk.Label(group_1, text="姓名").grid(row=1)
ttk.Entry(group_1).grid(row=0, column=1, sticky='w')
ttk.Entry(group_1).grid(row=1, column=1, sticky='w')
group_2 = ttk.LabelFrame(self, text="地址", style="W.TFrame")
group_2.pack(padx=10, pady=5)
ttk.Label(group_2, text="国籍").grid(row=0)
ttk.Label(group_2, text="省市").grid(row=1)
ttk.Label(group_2, text="邮编").grid(row=2)
ttk.Entry(group_2).grid(row=0, column=1, sticky='w')
ttk.Entry(group_2).grid(row=1, column=1, sticky='w')
ttk.Entry(group_2, width=8).grid(row=2, column=1,
sticky='w')
self.btn_submit = ttk.Button(self, text="提交")
self.btn_submit.pack(padx=10, pady=10, side='right')
if __name__ == "__main__":
app = App()
app.mainloop()
12 可切换背景和前景的颜色选择器#
from functools import partial
from tkinter.colorchooser import askcolor
class App(Tk):
def __init__(self):
super().__init__()
self.title("Colors demo")
text = "The quick brown fox jumps over the lazy dog"
self.label = ttk.Label(self, text=text)
self.fg_btn = ttk.Button(self, text="Set foreground color",
command=partial(self.set_color, "fg"))
self.bg_btn = ttk.Button(self, text="Set background color",
command=partial(self.set_color, "bg"))
self.label.pack(padx=20, pady=20)
self.fg_btn.pack(side='left', fill='both', expand=True)
self.bg_btn.pack(side='left', fill='both', expand=True)
def set_color(self, option):
color = askcolor()[1]
print("Chosen color:", color)
self.label.config(**{option: color})
if __name__ == "__main__":
app = App()
app.mainloop()
13 变换字体#
class App(Tk):
def __init__(self):
super().__init__()
self.title("Fonts demo")
text = "The quick brown fox jumps over the lazy dog"
self.label = ttk.Label(text=text)
self.family = StringVar()
families = ("Times", "Courier", "Helvetica")
self.option = ttk.OptionMenu(self, self.family, *families)
self.size = StringVar()
self.size.trace("w", self.set_font)
self.spinbox = ttk.Spinbox(from_=8, to=18,
textvariable=self.size)
self.family.set(families[0])
self.size.set("10")
self.label.pack(padx=20, pady=20)
self.option.pack(side='left', fill='both', expand=True)
self.spinbox.pack(side='left', fill='both', expand=True)
self.family.trace("w", self.set_font)
def set_font(self, *args):
family = self.family.get()
size = self.size.get()
self.label.config(font=(family, size))
if __name__ == "__main__":
app = App()
app.mainloop()
from tkinter.font import Font
class App(Tk):
def __init__(self):
super().__init__()
header = Font(family='Helvetica', size=18, weight='bold')
subtitle = Font(family="Helvetica 14 italic")
style = ttk.Style()
style.map("C.TButton",
foreground=[('pressed', 'red'), ('active', 'blue')],
background=[('pressed', '!disabled', 'black'), ('active', 'white')])
self.create_label(font=header, text="This is the header")
self.create_label(font=subtitle, text="This is the subtitle")
self.create_label(text="This is a paragraph")
self.create_label(text="This is another paragraph")
self.create_button("C.TButton", text="See more")
def create_label(self, **options):
return ttk.Label(**options).pack(padx=20, pady=5, anchor='w')
def create_button(self, style, **options):
return ttk.Button(style=style, **options).pack(padx=5, pady=5, anchor='e')
if __name__ == "__main__":
app = App()
app.mainloop()
14 设置鼠标光标#
class App(Tk):
def __init__(self):
super().__init__()
self.title("Cursors demo")
self.resizable(0, 0)
self.label = ttk.Label(self, text="Click the button to start")
self.btn_launch = ttk.Button(self, text="Start!",
command=self.perform_action)
self.btn_help = ttk.Button(self, text="Help",
cursor="question_arrow")
btn_opts = {"side": 'left', "expand": True, "fill": 'x',
"ipadx": 30, "padx": 20, "pady": 5}
self.label.pack(pady=10)
self.btn_launch.pack(**btn_opts)
self.btn_help.pack(**btn_opts)
def perform_action(self):
self.btn_launch.config(state='disabled')
self.btn_help.config(state='disabled')
self.label.config(text="Working...")
self.after(3000, self.end_action)
self.config(cursor="watch")
def end_action(self):
self.btn_launch.config(state='normal')
self.btn_help.config(state='normal')
self.label.config(text="Done!")
self.config(cursor="arrow")
def set_watch_cursor(self, widget):
widget._old_cursor = widget.cget("cursor")
widget.config(cursor="watch")
for w in widget.winfo_children():
self.set_watch_cursor(w)
def restore_cursor(self, widget):
widget.config(cursor=widget.old_cursor)
for w in widget.winfo_children():
self.restore_cursor(w)
if __name__ == "__main__":
app = App()
app.mainloop()
15 tkinter.Text#
from tkinter import Text
class App(Tk):
def __init__(self):
super().__init__()
self.title("Text demo")
self.resizable(0, 0)
self.text = Text(width=50, height=10)
self.btn_clear = ttk.Button(text="Clear text",
command=self.clear_text)
self.btn_insert = ttk.Button(text="Insert text",
command=self.insert_text)
self.btn_print = ttk.Button(text="Print selection",
command=self.print_selection)
self.text.pack()
self.btn_clear.pack(side='left', expand=True, pady=10)
self.btn_insert.pack(side='left', expand=True, pady=10)
self.btn_print.pack(side='left', expand=True, pady=10)
def clear_text(self):
self.text.delete("1.0", 'end')
def insert_text(self):
self.text.insert('insert', "Hello, world")
def print_selection(self):
selection = self.text.tag_ranges('sel')
if selection:
content = self.text.get(*selection)
print(content)
if __name__ == "__main__":
app = App()
app.mainloop()
设定超链接:
import webbrowser
from tkinter import Text
class App(Tk):
def __init__(self):
super().__init__()
self.title("Text tags demo")
self.text = Text(self, width=50, height=10)
self.btn_link = ttk.Button(self, text="Add hyperlink",
command=self.add_hyperlink)
self.text.tag_config("link", foreground="blue", underline=1)
self.text.tag_bind("link", "<Button-1>", self.open_link)
self.text.tag_bind("link", "<Enter>",
lambda _: self.text.config(cursor="hand2"))
self.text.tag_bind("link", "<Leave>",
lambda e: self.text.config(cursor=""))
self.text.pack()
self.btn_link.pack(expand=True)
def add_hyperlink(self):
selection = self.text.tag_ranges('sel')
if selection:
self.text.tag_add("link", *selection)
def open_link(self, event):
position = f"@{event.x},{event.y} + 1c"
index = self.text.index(position)
prevrange = self.text.tag_prevrange("link", index)
url = self.text.get(*prevrange)
webbrowser.open(url)
if __name__ == "__main__":
app = App()
app.mainloop()