Python Tkinter(二)

🍦 Tkinter能创造各种有趣的小工具,例如计算器、文本编辑器,甚至是一些小游戏,可将其视为Python通往图形化世界的钥匙。

1 文本控件

  • 文本控件
    • 文本控件(Text)用于显示和编辑多行文本,而Entry控件则适合处理单行文本。
    • 控件类似于HTML的<textarea>标签,允许以不同样式和属性显示并编辑文本。

1-1 基本属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个文本控件
text = Text(
# 部分属性需要配合方法使用才能生效
window, width=30, height=5,

# 是否可撤销文本编辑,默认False
undo=False,

# 执行撤销操作时是否自动插入一个分隔符,默认True
autoseparators=True,

# 被选中文本是否可复制到剪切板,默认True
exportselection=True,

# 插入光标的颜色,默认black
insertbackground="red",

# 插入光标的边框宽度,默认0
insertborderwidth=0,

# 控制光标的闪烁频频率的灭状态,默认300毫秒
insertofftime=300,

# 控制光标的闪烁频频率的亮状态,默认100毫秒
insertontime=100,

# 被选中文本的背景颜色,默认由系统决定
selectbackground="yellow green",

# 被选中文本的边框宽度,默认0
selectborderwidth=0,

# 被选中文本的字体颜色,默认由系统指定
selectforeground="blue",

# 是否启用网格控制,默认False
setgrid=False,

# 指定文本块中每一行与上方空白的间隔,忽略自动换行,默认0
spacing1=10,

# 指定文本块中自动换行的各行之间空白间隔,忽略换行符,默认0
spacing2=10,

# 指定文本块中每一行与下方空白的间隔,忽略自动换行,默认0
spacing3=10,

# 设定Tag所描述的文本块中Tab按键的功能,默认定义8个字符位置
# 如tabs=("1c", "8c")会在当前位置和第8个字符位置插入制表符
tabs="1c",

# 设置当一行文本的长度超过width选项设置的宽度时,是否自动换行
# 参数值:none(不自动换行)、char(按字符换行)、word(按单词换行)
wrap="none",

# 需要创建一个Scrollbar控件,并将其与Text控件关联
# 与Scrollbar关联,表示沿水平方向上下滑动
# xscrollcommand="",
# 与Scrollbar关联,表示沿垂直方向左右滑动
# yscrollcommand=""
)
text.pack()

# INSERT光标处插入,END末尾处插入
text.insert(INSERT, "https://stitch-top.github.io/")

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

1-2 基本方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个文本控件
text = Text(window, width=30, height=1)
text.pack()


def show_position():
# 当按钮被点击时,这个函数将用于确保"2.0"的文本可见
text.see("2.0")


# 添加文本示例
for i in range(1, 6):
text.insert(END, f"Line {i}: This is some text.\n")

# 添加一个按钮,点击时确保"2.0"这个索引位置可见
button = Button(window, text="Show Line 2", command=show_position)
button.pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(1) Scrollbar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个文本控件
text = Text(window, width=30, height=5)

# nsew:指组件将被拉伸以填满整个网格单元格的四个方向
text.grid(row=0, column=0, sticky="nsew")

# INSERT光标处插入,END末尾处插入
text.insert(INSERT, "https://stitch-top.github.io/")


# 创建水平滚动条
x_scrollbar = Scrollbar(
window, orient="horizontal", command=text.xview
)
x_scrollbar.grid(row=1, column=0, sticky="ew")

# 创建垂直滚动条
y_scrollbar = Scrollbar(
window, orient="vertical", command=text.yview
)
y_scrollbar.grid(row=0, column=1, sticky="ns")

# 将滚动条与文本控件关联
text.configure(
xscrollcommand=x_scrollbar.set,
yscrollcommand=y_scrollbar.set
)

# 配置行和列的权重,使文本框能够自动调整大小
window.rowconfigure(0, weight=1)
window.columnconfigure(0, weight=1)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(2) 文本可见

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个文本控件
text = Text(window, width=30, height=5)
text.pack()

# INSERT光标处插入,END末尾处插入
text.insert(INSERT, "https://stitch-top.github.io/")


# 定义一个函数来检查特定位置的文本是否可见
def text_visibility(index):
# 获取文本可见区域的起始(左上角)和结束(右下角)索引
start_index = text.index("@0,0")
end_index = text.index("@0," + str(text.winfo_height()))

checkbox_start = text.index(index)

# 检查索引是否在可见范围内
if start_index <= checkbox_start <= end_index:
print(f"位置{index}:可见")
else:
print(f"位置{index}:不可见")


# 定义一个函数来检查多个位置的文本是否可见
def check_visibility():
# END指文本末尾,1.0指第1行第0个字符,1.1指第1行第1个字符
# 1.3指第1行第3个字符,超出范围指向空格,INSERT指当前光标位置
positions = ["1.0", "1.1", "1.3", END, INSERT]
for pos in positions:
text_visibility(pos)


# 检查多个位置的文本是否可见
check_visibility()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(3) 获取文本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个文本控件
text = Text(window, width=30, height=5)
text.pack()

# INSERT光标处插入,END末尾处插入
text.insert(INSERT, "https://stitch-top.github.io/")


# 定义一个函数来获取并打印特定位置的文本
def get_text(index1, index2):
# 返回特定位置的字符,或一个范围内的文字
text_content = text.get(index1, index2)
print(f"返回{index1}{index2}的字符:{text_content}")


# 获取从第1行第2列到第1行第3列的字符
get_text("1.2", "1.3")

# 获取从光标位置到末尾的文本内容
get_text(INSERT, END)

# 获取从第1行第1列到第3行第1列的文本
get_text("1.0", "3.0")

# 获取从文本开始到光标位置的文本内容
get_text("1.0", INSERT)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(4) 获取边界框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个文本控件
text = Text(window, width=30, height=5)
text.pack()

# INSERT光标处插入,END末尾处插入
text.insert(INSERT, "https://stitch-top.github.io/")


# 定义一个函数来获取特定位置的边界框
def get_bbox(index):
# 返回指定索引的四元组(x, y, width, height)字符边界框
bbox = text.bbox(index)
if bbox:
print(f"返回指定索引字符边界框:{index}---{bbox}")
else:
print(f"返回指定索引字符边界框:{index}")


# 获取选择范围第一个字符的边界框
if "sel.first" in text.tag_names():
get_bbox("sel.first")
else:
print("当前没有选择任何文本!")

# 获取末尾位置的边界框
get_bbox(END)

# 获取第一行第一列的边界框
get_bbox("1.0")

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(5) 撤销与恢复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个框架来放置标签和文本框
frame = Frame(window)
frame.pack(expand=True)

# 创建标签用于显示居中链接
url_label = Label(frame)
url_label.pack()

# 创建一个文本控件
text = Text(
frame, width=30, height=5,

# 是否可撤销文本编辑,默认False
undo=True,

# 执行撤销操作时是否自动插入一个分隔符,默认True
autoseparators=False,
)
text.pack()

# INSERT光标处插入,END末尾处插入
text.insert(INSERT, "https://stitch-top.github.io/")


# 定义撤销方法,调用edit_undo()
def back_out():
text.edit_undo()


# 定义恢复方法,调用edit_redo(),结合undo属性使用
def restore():
text.edit_redo()


# 定义撤销按钮
Button(
frame, text="撤销", command=back_out
).pack(side="left", padx=10, pady=5)

# 定义恢复按钮
Button(
frame, text="恢复", command=restore
).pack(side="right", padx=10, pady=5)


# 定义一个函数,当文本被修改时调用
def text_modified(*args):
# edit_modified():用于查询和设置modified标志
if text.edit_modified():
print("已修改文本!")

# 重置edit_modified标志
text.edit_modified(False)


# 将text_modified函数绑定到Text控件的modify事件
# 插入文本、撤销和恢复操作都会触发<<Modified>>事件
text.bind("<<Modified>>", text_modified)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(6) 模拟复杂编辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个框架来放置标签和文本框
frame = Frame(window)
frame.pack(expand=True)

# 创建标签用于显示居中链接
url_label = Label(frame)
url_label.pack()

# 创建一个文本控件
text = Text(
frame, width=30, height=5,

# 是否可撤销文本编辑,默认False
undo=True,

# 执行撤销操作时是否自动插入一个分隔符,默认True
autoseparators=True,
)
text.pack()

# INSERT光标处插入,END末尾处插入
text.insert(INSERT, "https://stitch-top.github.io/")


# 定义一个函数,模拟复杂的文本编辑操作
def perform_complex_editing():
# 插入文本1
text.insert(END, "复杂编辑1\n")

# 插入文本2
text.insert(END, "复杂编辑2\n")

# 插入文本3
text.insert(END, "复杂编辑3\n")

# 在撤销历史记录中插入一个分隔符
# 指已完成一次完整操作,undo属性为False则无效
text.edit_separator()

# 插入更多文本
text.insert(END, "更多复杂编辑1\n")
text.insert(END, "更多复杂编辑2\n")


# 定义一个按钮,点击时执行复杂的编辑操作
PerformButton = Button(
frame, text="执行复杂编辑",
command=perform_complex_editing
)
PerformButton.pack(
side="left", padx=10, pady=5
)

# 定义一个按钮,点击时撤销所有操作
BackOutButton = Button(
frame, text="撤销所有",
command=lambda: text.edit_undo()
)
BackOutButton.pack(
side="left", padx=10, pady=5
)

# 定义一个按钮,点击时恢复所有操作
ReStoreButton = Button(
frame, text="恢复所有",
command=lambda: text.edit_redo()
)
ReStoreButton.pack(
side="right", padx=10, pady=5
)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(7) 删除特定字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个框架来放置标签和文本框
frame = Frame(window)
frame.pack(expand=True)

# 创建标签用于显示居中链接
url_label = Label(frame)
url_label.pack()

# 创建一个文本控件
text = Text(
frame, width=30, height=5,

# 是否可撤销文本编辑,默认False
undo=True
)
text.pack()

# 插入初始文本
initial_text = "https://stitch-top.github.io/"
text.insert(INSERT, initial_text)

# 用于存储每次删除的文本
deleted_texts = []


# 定义一个函数来删除指定范围内的文本
def delete_text(start_index, end_index):
try:
# 获取要删除的文本
to_delete = text.get(start_index, end_index)

# 删除文本
text.delete(start_index, end_index)

# 将删除的文本存储到列表中
deleted_texts.append(to_delete)

except Exception as e:
print(f"删除过程中出现错误: {e}")


# 定义恢复功能,恢复到初始文本
def restore_initial_text():
# 清空当前文本框
text.delete("1.0", END)

# 插入初始文本
text.insert(INSERT, initial_text)

# 清空删除的文本记录
deleted_texts.clear()

# 恢复后启用所有操作按钮
enable_buttons()


# 禁用所有按钮
def disable_buttons():
for button in buttons:
button.config(state=DISABLED)


# 启用所有按钮
def enable_buttons():
for button in buttons:
button.config(state=NORMAL)


# 创建删除按钮的框架
delete_frame = Frame(frame)
delete_frame.pack(side="left", padx=20)

# 创建恢复/打印按钮的框架
restore_frame = Frame(frame)
restore_frame.pack(side="right", padx=20)

# 创建按钮列表
buttons = []

# 添加恢复按钮
Button(
restore_frame, text="恢复最近删除",
command=restore_initial_text
).pack(pady=5)

# 定义一个按钮,点击时删除从"1.00"到"1.8"的文本
button1 = Button(
delete_frame, text="删除1.00到1.08",
# 设置成1.08会报错:bad text index "1.08"
command=lambda: delete_text("1.00", "1.8")
)
button1.pack(pady=5)
buttons.append(button1)

# 定义一个按钮,点击时删除从"1.14"到"1.18"的文本
button2 = Button(
delete_frame, text="删除1.14到1.18",
command=lambda: delete_text("1.14", "1.18")
)
button2.pack(pady=5)
buttons.append(button2)

# 定义一个按钮,点击时删除从"1.00"到"END"的文本
button3 = Button(
delete_frame, text="删除1.00到END",
command=lambda: delete_text("1.00", END)
)
button3.pack(pady=5)
buttons.append(button3)


# 定义一个函数,获取并打印当前文本内容
def print_text():
print("当前文本内容:", text.get("1.0", END))


# 定义一个按钮,点击时打印当前文本内容
print_button = Button(
restore_frame, text="打印当前文本",
command=print_text
)
print_button.pack(pady=5)

# 将打印按钮也添加到按钮列表中以便于禁用
buttons.append(print_button)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(8) 获取图像属性*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个框架来放置标签和文本框
frame = Frame(window)
frame.pack(expand=True)

# 创建标签用于显示居中链接
url_label = Label(frame)
url_label.pack()

# 创建一个文本控件
text = Text(frame, width=30, height=10)
text.pack(side="top", pady=10)

# INSERT光标处插入,END末尾处插入
text.insert(INSERT, "https://stitch-top.github.io/")

# 创建一个图像
img = PhotoImage(file=r"./file/text.jpg")

# 保存引用,防止图像被垃圾回收
text.image = img

# 在末尾换行插入图像
text.insert(END, "\n")
text.image_create(END, image=img)

# 记录图像标签名称
tag_name = f"img_{len(text.tag_names())}"

# 确保正确插入图像标签
text.tag_add(tag_name, "end-1c", "end-1c")

# 获取图像插入的具体索引位置(最后一个图像的索引位置)
image_index = text.index(f"end-1c-1c")


# 定义一个函数来获取特定位置的图像属性
def get_image_properties(index):
# 获取图像标签的索引
index = image_index

# 获取图像属性
try:
image_info = text.image_cget(index, "image")
print(f"索引{index}的图像属性:{image_info}")
except TclError as e:
print(f"报错:{e}")


# 定义一个按钮,点击时获取图像属性
GetImagePropertiesButton = Button(
frame, text="获取图像属性",
command=lambda: get_image_properties(image_index)
)
GetImagePropertiesButton.pack(side="top", pady=10)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

1-3 文本索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个文本控件
text = Text(window, width=30, height=5)
text.pack()

# 插入文本
text.insert(END, "https://stitch-top.github.io/")

# INSERT:插入光标的位置
insert_pos = text.index(INSERT)
print(f"对应插入光标的位置:{insert_pos}")

# CURRENT:与鼠标最接近的位置
current_pos = text.index("1.5")
print(f"与鼠标最接近的位置:{current_pos}")

# line.column:某一行某一列的一个位置
line_column_pos = text.index("1.2")
print(f"第一行第二列的位置:{line_column_pos}")

# line.end:某一行到末尾的最后一个位置
line_end_pos = text.index("1.end")
print(f"第一行到末尾的最后一个位置: {line_end_pos}")

# SEL:一种针对于Tag的特殊索引用法
text.tag_add("sel", "1.5", "1.end")
sel_first = text.index("sel.first")
sel_last = text.index("sel.last")

# (sel_first, sel_last)表示当前被选中的范围
print(f"当前被选中的范围位置: ({sel_first}, {sel_last})")

# 显示文本控件中最后一个字符的下一个位置
text.insert(
END, f"\n\n最后字符的下个位置({sel_first}, {sel_last})"
)
print("控件最后一个字符的下一个位置:", text.index("1.end"))

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

1-4 文本标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个文本控件
text = Text(window, width=30, height=5)
text.pack()

# 插入文本
text.insert(END, "https://stitch-top.github.io/")

# tag_add(tagName, index1, index2)
# 为指定索引范围内的内容添加一个标签名tagName
text.tag_add("address", "1.8", "1.28")
print(text.get("1.8", "1.28"))


def on_click(event):
print("鼠标点击了Tag标签!")


# tag_bind(tagName, sequence, func, add=None)
# 为tagName标签绑定鼠标点击事件
text.tag_bind("address", "<Button>", on_click)

# tag_configure(tagName, cnf=None, **kw)
# 配置tagName标签的选项
text.tag_configure(
"address", foreground="red", background="yellow"
)

# tag_cget(tagName, option)
# 获取tagName指定的option选项值
# 文本颜色foreground、背景色background、字体font等
background = text.tag_cget("address", "background")
print(f"获取标签指定的背景色:{background}")

# tag_delete(tagNames)
# 删除单个或多个tagNames指定的标签
text.tag_add("protocol", "1.0", "1.5")
text.tag_delete("protocol")

# tag_lower(tagName, belowThis=None)
# 降低某个标签的优先级
# belowThis可以是已定义的标签名
# 或范围表示,如:sel_start、sel_end
# 或范围,如:1.6到1.10
# belowThis不为空则tagName需比指定的Tag优先级低
text.tag_lower("address", "sel")

# tag_raise(tagName, aboveThis=None)
# 提高某个标签的优先级
# aboveThis不为空则tagName需比指定的Tag优先级高
text.tag_raise("address", "sel")

# tag_names(index=None)
# 不带参数则获取所有标签名,否则返回对应位置的标签名
print(f"获取所有标签名:{text.tag_names()}")

# tag_nextrange(tagName, index1, index2=None)
# 在index1到index2范围内查找tagName标签的位置
next_range = text.tag_nextrange(
"address", "1.0", "1.end"
)
print(f"范围内查找标签的位置:{next_range}")

# tag_ranges(tagName)
# 获取所有标签指定的文本,并将其范围以列表形式返回
ranges = text.tag_ranges("address")
print(f"{ranges}")

# tag_remove(tagName, index1, index2=None)
# 删除index1到index2之间的所有tagName标签
# 如果忽略index2参数,则只删除index1指定字符的标签
text.tag_remove("address", "1.8", "1.19")

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

1-5 文本标记

  • 文本标记
    • 文本标记(Mark)通常被用作书签,帮助快速获取内容的指定位置。
    • 两种类型的标记
      • INSERT:指定当前插入的光标位置,闪烁光标。
      • CURRENT:指定当前光标所处坐标最邻近位置。
    • 如果在Mark标记的位置前插入或删除文本,那么Mark标记会跟着一起移动。
    • 删除Mark需用mark_unset(),但只会删除周围的文本,不会删除标记本身。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")

# 创建一个文本控件
text = Text(window, width=30, height=5)
text.pack()

# 插入文本
text.insert(INSERT, "https://stitch-top.github.io/")

# mark_set(markName, index)
# 移动Mark到index参数指定的位置
# 如果markName参数指定的Mark不存在,则创建一个新的Mark
text.mark_set("start", "1.0")

# mark_gravity(markName, direction=None)
# 设置Mark的移动方向,默认right,也可以是left
text.mark_gravity("start", "left")

# mark_previous(index)获取上一个Mark的位置
previous_mark = text.mark_previous("1.5")
print("获取上个Mark位置:", previous_mark)

# mark_next(index)获取下一个Mark的位置
next_mark = text.mark_next("1.5")
print("获取下个Mark位置:", next_mark)

# mark_names()获取所有Mark名字
marks = text.mark_names()
print("获取所有Mark名字:", marks)

# mark_unset(MarkName)删除指定的Mark
text.mark_unset("start")

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

2 列表控件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建一个Listbox控件
listbox = Listbox(window, width=25, height=6)
listbox.pack()

# 添加示例选项
options = [
"Option 1", "Option 2", "Option 3",
"Option 4", "Option 5", "Option 6"
]
for option in options:
listbox.insert(END, option)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

2-1 常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
from tkinter import *
from tkinter import messagebox

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建框架1来放置Text控件和Listbox控件
frame1 = Frame(window)
frame1.grid(row=0, column=0, sticky="nsew", padx=25)

# 创建框架2来放置按钮
frame2 = Frame(window)
frame2.grid(row=0, column=1, sticky="nsew", padx=5, pady=50)

# 创建框架3来放置按钮
frame3 = Frame(window)
frame3.grid(row=0, column=2, sticky="nsew", padx=5, pady=50)

# 创建框架4来放置按钮
frame4 = Frame(window)
frame4.grid(row=0, column=3, sticky="nsew", padx=5, pady=50)

# 创建一个Text控件
text = Text(frame1, width=25, height=6)
text.grid(row=0, column=0, padx=10, pady=10)

# 创建一个Listbox控件
listbox = Listbox(frame1, width=25, height=6)
listbox.grid(row=1, column=0, padx=10, pady=10)

# 添加示例选项
options = [
"Option 1", "Option 2", "Option 3",
"Option 4", "Option 5", "Option 6",
"Option 7", "Option 8", "Option 9"
]
for option in options:
listbox.insert(END, option)


# 清除Text控件中的内容
def clear_text():
if text.get("1.0", END).strip() == "":
messagebox.showinfo("提示", "文本区域为空!")
else:
text.delete("1.0", END)


# 定义一个函数来激活选项,激活时会在文本下方画下划线
def activate(index):
listbox.activate(index)
listbox.selection_set(index)
text.insert(INSERT, f"激活选项:{index + 1}\n")


# 定义一个函数来返回某个选项的边框
# 四元组:(xoffset, yoffset, width, height)
# xoffset和yoffset:表示距离左上角的偏移位置
def bbox(index):
bbox_info = listbox.bbox(index)
if bbox_info:
text.insert(INSERT, f"选项{index + 1}的边框:{bbox_info}\n")
else:
text.insert(INSERT, f"选项{index + 1}无边框!\n")


# 定义一个函数来获取当前选中的选项,从0开始
def get_curselection():
selection = listbox.curselection()
text.insert(INSERT, f"当前选项:{selection}\n")


# 定义一个函数来获取Listbox组件中选项的数量
def size():
size = listbox.size()
text.insert(INSERT, f"选项总数:{size}\n")


# 定义一个函数来删除某些选项(只删一个)
def delete_options(index):
listbox.delete(index, index + 1)
text.insert(INSERT, f"删除选项:{index + 1}\n")


# 定义一个函数来获取某个范围内的选项文本(只获取一个)
def get_options_text(index):
options = listbox.get(index, index + 1)
if options:
text.insert(
INSERT,
f"选项{index + 1}{index + 2}的文本:\n{options}\n"
)
else:
text.insert(INSERT, "没有找到范围内的文本!\n")


# 定义一个函数来返回某个选项的序号
def get_index(index):
idx = listbox.index(index + 1)
text.insert(INSERT, f"返回选项{index + 1}的序号:{idx}\n")


# 定义一个函数来获取某个项目的属性
def itemcget(index, option):
value = listbox.itemcget(index, option)
text.insert(
INSERT, f"选项{index + 1}{option}属性值:{value}\n"
)


# 定义一个函数来设置某个项目的属性,由可变参数**options指定
def itemconfig(index, **options):
listbox.itemconfig(index, **options)
text.insert(INSERT, f"选项{index + 1}标记为红色!\n")


# 定义一个函数来获取最接近给定Y坐标的选项
def nearest_y(y):
index = listbox.nearest(y)
text.insert(INSERT, f"给定最近Y坐标{y}的选项:{index + 1}\n")


# 定义一个函数来设置选中状态(只选中一个)
def selection_set(index):
listbox.selection_set(index, index + 1)
text.insert(INSERT, f"选中{index + 1}{index + 2}\n")


# 定义一个函数来滚动Listbox组件
def xview(command, *args):
if command == "moveto":
listbox.xview(*args)
elif command == "scroll":
listbox.xview(*args[0], *args[1:])
text.insert(INSERT, f"Xview command: {command} {args}\n")


def yview(command, *args):
if command == "moveto":
listbox.yview(*args)
elif command == "scroll":
listbox.yview(*args[0], *args[1:])
text.insert(INSERT, f"Yview command: {command} {args}\n")


def perform_action(action_type, index):
if action_type == "activate":
activate(listbox.curselection()[0])
elif action_type == "bbox":
bbox(listbox.curselection()[0])
elif action_type == "get_curselection":
get_curselection()
elif action_type == "delete_options":
delete_options(listbox.curselection()[0])
elif action_type == "get_options_text":
get_options_text(listbox.curselection()[0])
elif action_type == "get_index":
get_index(listbox.curselection()[0])
elif action_type == "itemcget":
itemcget(listbox.curselection()[0], "background")
elif action_type == "itemconfig":
itemconfig(listbox.curselection()[0], background="red")
elif action_type == "selection_set":
selection_set(listbox.curselection()[0])


# 定义用于选择选项的命令
def on_button_click(action_type):
selection = listbox.curselection()
if selection:
# 调用通用函数并传递操作类型
perform_action(action_type, selection[0])
else:
# 提示用户未选择选项
messagebox.showwarning("提示", "请先选择一个选项!")


# 创建按钮
Button(
frame2, text="清空内容",
command=clear_text
).grid()
Button(
frame2, text="激活选项",
command=lambda: on_button_click("activate")
).grid()

Button(
frame2, text="获取边框",
command=lambda: on_button_click("bbox")
).grid()

Button(
frame2, text="当前选项",
command=lambda: on_button_click("get_curselection")
).grid()

Button(
frame3, text="选项总数", command=size
).grid()

Button(
frame3, text="删除选项",
command=lambda: on_button_click("delete_options")
).grid()

Button(
frame3, text="获取文本",
command=lambda: on_button_click("get_options_text")
).grid()

Button(
frame3, text="选项序号",
command=lambda: on_button_click("get_index")
).grid()

Button(
# 需要itemconfig()先标记,才能显示属性
frame4, text="选项属性",
command=lambda: on_button_click("itemcget")
).grid()

Button(
frame4, text="选项标记",
command=lambda: on_button_click("itemconfig")
).grid()

Button(
frame4, text="最近项目",
command=lambda: nearest_y(10)
).grid()

Button(
frame4, text="选择项目",
command=lambda: on_button_click("selection_set")
).grid()

# 绑定滚动条到Listbox的xview和yview
scrollbar = Scrollbar(frame1)
scrollbar.grid(row=1, column=1, sticky="ns")
listbox.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

2-2 常用属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 初始值,StringVar类型变量中,用空格分隔每个项目
var = StringVar(value="选项1 选项2 选项3")

# 创建一个Listbox控件
listbox = Listbox(
window, width=15, height=6,

# 指向一个StringVar类型的变量
listvariable=var,

# 控制选中项目的显示外观,自定义背景色
selectbackground="green",

# 边框宽度,默认由selectbackground指定的颜色填充,没有边框
# 如果设置,Listbox的每一项会相应变大,被选中项为raised样式
selectborderwidth=3,

# 自定义文本颜色,默认值由系统指定
selectforeground="yellow",

# 在列表框中添加网格线,窗口会撑得很大
setgrid=False,

# 控制列表框是否可以接收键盘焦点,默认True
takefocus=False
)

# 垂直滚动条
scrollbar_y = Scrollbar(
window, orient=VERTICAL, command=listbox.yview
)

# 水平滚动条(Listbox不太常用)
scrollbar_x = Scrollbar(
window, orient=HORIZONTAL, command=listbox.xview
)

# 连接到Listbox
listbox.config(yscrollcommand=scrollbar_y.set)
listbox.config(xscrollcommand=scrollbar_x.set)

# 布局管理器控制参数,NSEW:扩展到填充整个单元格
listbox.grid(row=0, column=0, padx=10, sticky=NSEW)

# 垂直滚动条在右侧, 占据整列高度
scrollbar_y.grid(row=0, column=1, padx=5, sticky=NS)

# 水平滚动条在底部, 占据整行宽度
scrollbar_x.grid(row=1, column=0, sticky=EW)

# 调整列和行的权重,允许Listbox和滚动条根据内容大小调整
# window.columnconfigure(0, weight=1)
# window.rowconfigure(0, weight=1)

# var的变化会更新Listbox
var.set(
"""
新选项1 新选项2 新选项3
新选项4 新选项5 新选项6
新选项7 新选项8 新选项9
"""
)

# 单选模式
# 默认browse,也是单选,但允许通过方向键或鼠标改变选择
listbox_single = Listbox(
window, width=15, height=8, selectmode="single"
)
listbox_single.grid(row=0, column=2)

# 多选模式
listbox_multiple = Listbox(
window, width=15, height=8, selectmode="multiple"
)
listbox_multiple.grid(row=0, column=3)

# 扩展选择模式(需按住Shift或Ctrl键)
listbox_extended = Listbox(
window, width=15, height=8, selectmode="extended"
)
listbox_extended.grid(row=0, column=4)

for i in range(7):
listbox_single.insert(END, f"单选{i+1}")
listbox_multiple.insert(END, f"多选{i+1}")
listbox_extended.insert(END, f"扩展选择{i+1}")

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

2-3 删除功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 初始值,StringVar类型变量中,用空格分隔每个项目
var = StringVar(value="选项1 选项2 选项3 选项4 选项5")

# 创建一个Listbox控件
listbox = Listbox(
window, width=25, height=6,

# 指向一个StringVar类型的变量
listvariable=var,
)
listbox.pack()

# 使用匿名函数,创建删除按钮
Button(
window, text="删除",
command=lambda x = listbox:x.delete(ACTIVE)
).pack(side="bottom")

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

2-4 添加选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from tkinter import *
from tkinter import messagebox

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建变量,用来接收鼠标点击的具体选项内容
var = StringVar()
label = Label(
window, bg="#B0B0B0", font=("微软雅黑", 12),
width=20, textvariable=var
)
label.pack()


# 创建一个按钮点击事件
def click_button():
# 使用curselection来选中文本
try:
selection_index = listbox.curselection()
if selection_index:
index = selection_index[0]
val = listbox.get(index)
var.set(val)
else:
messagebox.showwarning("错误", "没有选择任何条目!")
except IndexError:
messagebox.showwarning("错误", "没有选择任何条目!")


# 创建一个按钮
button = Button(
window, text="获取当前选项", command=click_button
)
button.pack()

# 创建一个Listbox控件
str = StringVar()
str.set(("C", "C++", "Java", "Python", "Golang"))
listbox = Listbox(
window, listvariable=str
)
listbox.pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

3 下拉菜单

  • 下拉菜单
    • 下拉菜单控件,又叫复合框(Combobox),该控件是列表控件的改进版。
    • Combobox控件不包含在Tkinter模块中,而是包含在tkinter.ttk子模块中。
    • Combobox形式上虽与列表控件存在不同,但本质相同,属性和方法通用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from tkinter import *
from tkinter import ttk

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建下拉菜单
cbox = ttk.Combobox(window)
cbox.grid(row=1, sticky=NW)

# 设置下拉菜单中的值
cbox["value"] = (
"C", "C++", "Java", "Python", "Golang"
)

# 设置下拉菜单选项的默认值
cbox.current(3)


# 回调函数,绑定执行事件,向文本插入选中文本
def func(event):
# get():获取当前选中选项的内容
text.insert(INSERT, cbox.get() + "\n")


# 绑定下拉菜单事件
cbox.bind("<<ComboboxSelected>>", func)

# 创建文本框
text = Text(window)
text.grid()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

4 单选控件

  • 单选控件
    • 单选框按钮控件(Radiobutton),同样允许用户选择具体的选项值。
    • 不过仅允许用户选择单一的选项值,各个选项值之间是互斥的关系。
    • Radiobutton控件通常都是成组出现的,所有控件都使用相同的变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# IntVar():用于处理整数类型的变量
var = IntVar()

# 根据单选按钮的value值选择相应的选项
var.set(0)

# 创建单选按钮
Radiobutton(
window, text="苹果", fg="green",
font=("微软雅黑", 11, "bold"),
variable=var, value=0
).pack()

Radiobutton(
window, text="西瓜", fg="green",
font=("微软雅黑", 11, "bold"),
variable=var, value=1
).pack()

Radiobutton(
window, text="香蕉", fg="green",
font=("微软雅黑", 11, "bold"),
variable=var, value=2
).pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

4-1 代码重构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

site = [
("苹果", 0), ("西瓜", 1), ("香蕉", 2),
("樱桃", 3), ("柑橘", 4), ("蜜柚", 5)
]

# IntVar():用于处理整数类型的变量
var = IntVar()

# 重构代码
for fruit, num in site:
Radiobutton(
window, text=fruit,
variable=var, value=num
).pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

4-2 常用属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

site = [
("苹果", "苹果"), ("西瓜", "西瓜"), ("香蕉", "香蕉"),
("樱桃", "樱桃"), ("柑橘", "柑橘"), ("蜜柚", "蜜柚")
]

# 定义选中变量
var = StringVar(value="苹果")

# 重构代码
for fruit, num in site:
Radiobutton(
window, text=fruit, value=num,

# 与Radiobutton控件关联的变量
variable=var,

# 背景色,默认值由系统指定
activebackground="lightblue",

# 前景色,默认值由系统指定
activeforeground="green",

# Radiobutton不可用时的前景色,默认系统指定
disabledforeground="red",

# 默认值none,有指定位图或图片,则不显示文本
# 设置成center,文本显示在图像上(重叠)
# 其他值:bottom、left、right、top
compound="left",

# 选项前的小圆圈是否被绘制,默认True
indicatoron=True,

# Radiobutton为选中状态时显示的图
# indicatoron=True时才生效
selectcolor="lightgreen",

# 接受输入焦点,默认False
takefocus=True
).pack()


# 定义显示选中选项的函数
def show_selection():
selection = var.get()
print(f"请选择:{selection}")


# 创建一个按钮以显示选中的选项
Button(
window, text="打印选择", command=show_selection
).pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

4-3 常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

site = [
("苹果", "苹果"), ("香蕉", "香蕉"),
("樱桃", "樱桃"), ("蜜柚", "蜜柚")
]

# 定义选中变量
var = StringVar(value="苹果")

# 创建Radiobutton控件
radiobuttons = []
for fruit, num in site:
rb = Radiobutton(
window, text=fruit, value=num,

# 与Radiobutton控件关联的变量
variable=var,

# 选项前的小圆圈是否被绘制,默认True
indicatoron=True,

# Radiobutton为选中状态时显示的图
# indicatoron=True时才生效
selectcolor="lightgreen",
)
rb.pack()

# 记录每个Radiobutton,以便后续操作
radiobuttons.append(rb)


# 定义显示选中选项的函数
def show_selection():
selection = var.get()
print(f"请选择:{selection}")


# 定义取消选择的函数
def deselect_selected():
# 取消每个Radiobutton的选中状态
for rb in radiobuttons:
# 取消按钮的选中状态
rb.deselect()

# 清空StringVar的值
var.set(None)
print("您已取消选择!")


# 定义刷新控件的函数
def flash_selected():
# 获取当前选中的Radiobutton
current_selected = var.get()
for rb in radiobuttons:
if rb.cget("value") == current_selected:
# 刷新当前选中的Radiobutton
rb.flash()
break


# 定义调用选中命令的函数
def invoke_selected():
current_selected = var.get()
for rb in radiobuttons:
if rb.cget("value") == current_selected:
# 调用当前选中的Radiobutton命令,并返回函数返回值
# 若控件状态是disabled或未指定command,则方法无效
rb.invoke()
break


# 创建按钮以显示选中的选项
Button(
window, text="打印选择", command=show_selection
).pack()

# 创建按钮以取消选择
Button(
window, text="取消选择", command=deselect_selected
).pack()

# 创建按钮以刷新选中的Radiobutton
Button(
window, text="刷新选项", command=flash_selected
).pack()

# 创建按钮以调用选中项目的命令
# Radiobutton未设置command,触发该按钮无效
Button(
window, text="调用选项", command=invoke_selected
).pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

4-4 实例运用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)
label = Label(
window, font=("微软雅黑", "11", "bold"), fg="#43CD80"
)
label.pack(side="bottom")


def select():
dict = {
0: "苹果", 1: "西瓜", 2: "香蕉",
3: "樱桃", 4: "柑橘", 5: "蜜柚"
}
str = "您选择了" + dict.get(var.get()) + "!"
label.config(text=str)


site = [
("苹果", 0), ("西瓜", 1), ("香蕉", 2),
("樱桃", 3), ("柑橘", 4), ("蜜柚", 5)
]

# IntVar():用于处理整数类型的变量
var = IntVar()

# 重构代码
for fruit, num in site:
Radiobutton(
window, text=fruit, variable=var, value=num,
command=select, indicatoron=False
).pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

5 复选控件

  • 复选控件
    • 复选框控件(Checkbutton)允许用户同时选择多项,各选项之间属于并列关系。
    • Checkbutton同样有许多适用场景,如选择兴趣爱好、选修课、购买多物品等。

5-1 常用属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建Label控件
label1 = Label(
window, fg="#43CD80",
font=("微软雅黑", 11, "bold")
)
label1.pack()

label2 = Label(
window, fg="#43CD80",
font=("微软雅黑", 11, "bold")
)
label2.pack()

# 创建整型变量
var1 = IntVar()
var2 = IntVar()
var3 = IntVar()

# 设置复选框控件,使用variable参数来接收变量
check1 = Checkbutton(
window, text="苹果",

# 和复选框按钮关联的变量,值会随用户选择行为改变
variable=var1,
font=("微软雅黑", 11, "bold"),

# 自定义选中状态的值
onvalue=1,

# 自定义未选中状态的值
offvalue=0,

# 默认True,是否绘制用来选择选项的小方块
# False时会改变原有按钮的样式,与单选按钮相同
indicatoron=True,

# 选择框的颜色,默认由系统指定
selectcolor="lightgreen",

# Checkbutton为选中状态时显示的图
# 若没有指定image选项,该选项会被忽略
# selectimage="",

# Checkbutton显示StringVar变量
# textvariable="",

# 复选框文本应被分成的行数
# 指定每行的长度,单位是屏幕单元,默认值0
wraplength=0
)

check2 = Checkbutton(
window, text="西瓜", variable=var2,
font=("微软雅黑", 11, "bold"),
onvalue=1, offvalue=0
)

check3 = Checkbutton(
window, text="樱桃", variable=var3,
font=("微软雅黑", 11, "bold"),
onvalue=1, offvalue=0
)

check1.pack()
check2.pack()
check3.pack()


# 定义执行函数
def fruits():
# 不选情况下
if var1.get() == 0 and var2.get() == 0 and var3.get() == 0:
content = "您还未进行选择!"
else:
c1 = "苹果" if var1.get() == 1 else ""
c2 = "西瓜" if var2.get() == 1 else ""
c3 = "樱桃" if var3.get() == 1 else ""
content = "您选择了:%s %s %s!" % (c1, c2, c3)

# 设置标签字体
label2.config(text=content)


Button(
window, text="我选好啦!",
bg="#BEBEBE", command=fruits
).pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

5-2 常用方法

  • 常用方法
    • flash():刷新Checkbutton,对其进行重绘操作(同单选控件)。
    • invoke():调用Checkbutton中command选项指定的函数或方法。
    • desellect():取消Checkbutton的选中状态,即设置variable为offvalue。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建整型变量
var1 = IntVar()
var2 = IntVar()

# 设置复选框控件,使用variable参数来接收变量
check1 = Checkbutton(
window, text="苹果",

# 和复选框按钮关联的变量,值会随用户选择行为改变
variable=var1,
font=("微软雅黑", 11, "bold"),

# 自定义选中状态的值
onvalue=1,

# 自定义未选中状态的值
offvalue=0,
)

check2 = Checkbutton(
window, text="西瓜", variable=var2,
font=("微软雅黑", 11, "bold"),
onvalue=1, offvalue=0,
)

# 设置复选框按钮的onvalue为1,表示选中状态
check1.select()

# 选中后取消
check2.select()
check2.toggle()

check1.pack()
check2.pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

6 滑块控件

  • 滑块控件
    • 滑块控件,即标尺控件(Scale),该控件同样拥有许多应用场景。
    • 可创建类似于标尺式的滑动条对象,通过滑动来设置值(刻度值)。

6-1 基本属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建Scale控件
Scale(
window,

# 当鼠标在上方飘过时滑块的背景色
activebackground="lightgreen",

# 设置增长量的大小,默认0,增长量范围1~10
bigincrement=0,

# 指定边框宽度,默认2
borderwidth=2,

# 设置数字的最多位数,默认0
# 例如设置0~20,digits为5,则范围在0.000~20.000滑动
digits=0,

# 设置滑块最顶(左)端的位置,默认0
from_=0,

# 设置滑块最底(右)端的位置,默认100
to=100,

# 滑块左侧Label和刻度的文字字体,默认值由系统指定
font=("微软雅黑", 9, "bold"),

# 当Scale获得焦点时高亮边框的颜色,默认值由系统指定
highlightcolor="blue",

# 垂直的顶端右侧、水平的左端上方显示文本标签,默认不显示
label="音量控制",

# Scale控件的长度,默认100像素
length=300,

# Scale控件的宽度,默认15像素
width=15,

# 设置Scale控件是水平或垂直放置,默认垂直VERTICAL
orient=HORIZONTAL,

# 指定鼠标左键点击滚动条凹槽时的响应时间,默认300毫秒
repeatdelay=300,

# 指定鼠标左键紧按滚动条凹槽时的响应间隔,默认100毫秒
repeatinterval=100,

# 指定Scale控件的分辨率,即每点击一下移动的步长,默认1
resolution=20,

# 设置是否显示滑块旁边的数字,默认True
showvalue=True,

# 设置滑块的长度,默认30像素
sliderlength=30,

# 默认NORMAL,是否支持鼠标事件和键盘事件
# 设为DISABLED,则不能移动滑块
state=NORMAL,

# 指定使用Tab键是否可以将焦点移动到该Scale控件上
# 默认开启,可通过设置为False避免焦点落在此控件上
takefocus=True,

# 设置显示的刻度,默认不显示刻度
# 如果设置一个值,那么就会按照该值的倍数显示刻度
tickinterval=5,

# 设置凹槽的颜色,默认值由系统指定
troughcolor="orange",

# 指定一个与Scale控件相关联的变量,该变量存放滑块最新的位置
# variable="",

# 指定一个函数,当滑块发生改变时自动调用
# command=""
).pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

6-2 基本方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建文本标签
label = Label(
window, bg="#9FB6CD", justify="left"
)
label.pack(side="bottom")

# 定义一个回调函数,处理滑块变化
def on_scale_change(value):
# 打印当前滑块的位置
print("滑块当前位置:", value)

# 获取当前滑块的位置
current_value = s.get()
print("当前滑块位置:", current_value)

# 获取当前滑块位置的相对坐标
coords = s.coords()
print("滑块相对坐标:", coords)

# 获得鼠标位置相对于Scale控件左上角位置的相对坐标
x, y = window.winfo_pointerxy()

# 计算相对于Scale的坐标,绝对坐标转换为相对窗口坐标
widget_x = x - window.winfo_rootx()
widget_y = y - window.winfo_rooty()

# 返回一个字符串表示指定位置下的Scale控件
widget = s.identify(
widget_x - s.winfo_x(),
widget_y - s.winfo_y()
)
print("鼠标位置对应的控件:", widget)
print("--------------------------")

label.config(
text=f"当前滑块位置:{value}\n"
f"滑块相对坐标:{coords}\n"
f"鼠标位置对应的控件:{widget}"
)

# 创建Scale控件
s = Scale(
window,

# 当鼠标在上方飘过时滑块的背景色
activebackground="lightgreen",

# 设置增长量的大小,默认0,增长量范围1~10
bigincrement=0,

# 指定边框宽度,默认2
borderwidth=2,

# 设置数字的最多位数,默认0
# 例如设置0~20,digits为5,则范围在0.000~20.000滑动
digits=0,

# 设置滑块最顶(左)端的位置,默认0
from_=0,

# 设置滑块最底(右)端的位置,默认100
to=100,

# 滑块左侧Label和刻度的文字字体,默认值由系统指定
font=("微软雅黑", 9, "bold"),

# 当Scale获得焦点时高亮边框的颜色,默认值由系统指定
highlightcolor="blue",

# 垂直的顶端右侧、水平的左端上方显示文本标签,默认不显示
label="音量控制",

# Scale控件的长度,默认100像素
length=300,

# Scale控件的宽度,默认15像素
width=15,

# 设置Scale控件是水平或垂直放置,默认垂直VERTICAL
orient=HORIZONTAL,

# 指定鼠标左键点击滚动条凹槽时的响应时间,默认300毫秒
repeatdelay=300,

# 指定鼠标左键紧按滚动条凹槽时的响应间隔,默认100毫秒
repeatinterval=100,

# 指定Scale控件的分辨率,即每点击一下移动的步长,默认1
resolution=20,

# 设置是否显示滑块旁边的数字,默认True
showvalue=True,

# 设置滑块的长度,默认30像素
sliderlength=30,

# 设置凹槽的颜色,默认值由系统指定
troughcolor="orange",

# 将回调函数绑定到Scale控件上
command=on_scale_change
)
s.pack()

# 设置滑块的初始位置为20
s.set(value=20)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

7 画布控件

  • 画布控件
    • 画布控件(Canvas)有两个功能,可绘制图形,可展示图片,包括位图。
    • 每个画布对象都有个唯一的身份ID,方便Tkinter控制和操作画布对象。

7-1 基本属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)


def update_scroll_region(event=None):
# 更新滚动区域,以确保所有绘图对象都在滚动范围内
canvas.configure(scrollregion=canvas.bbox("all"))


# 创建一个框架用于包含画布和滚动条
frame = Frame(window)
frame.pack(expand=True)

# 创建画布
canvas = Canvas(
frame,

# 画布高、宽,单位像素
height=100, width=150,

# Canvas控件的背景色,background(bg)
bg="lightgrey",

# Canvas控件的边框宽度,borderwidth(bd)
bd=3,

# 画布状态:normal(默认值)、disabled
# 该值不会影响画布对象的状态
state="normal",

# 指定一个距离,当鼠标与画布对象的距离小于该值时
# 认为鼠标位于画布对象上,是一个浮点类型的值,单位像素
closeenough="10.0",

# 是否允许滚动超出scrollregion设置的滚动范围,默认True
confine=True,

# 画布对象被选中时的前景色
selectforeground="lightblue",

# 画布对象被选中时的背景色
selectbackground="lightgreen",

# 画布对象被选中时的边框宽度
selectborderwidth=3,

# 使用Tab键将焦点移动到输入框中,默认开启
# 设置为False时,避免焦点在输入框中
takefocus=True,

# 3c表示每次滚动3厘米,单位还有i英寸、m毫米、p像素
# 默认0,表示可以水平滚动到任意位置
xscrollincrement="3c",
yscrollincrement="3c"
)

# 创建水平滚动条
h_scroll = Scrollbar(
frame, orient=HORIZONTAL, command=canvas.xview
)
h_scroll.pack(side=BOTTOM, fill=X)

# 创建垂直滚动条
v_scroll = Scrollbar(
frame, orient=VERTICAL, command=canvas.yview
)
v_scroll.pack(side=RIGHT, fill=Y)

# 配置Canvas和滚动条链接
canvas.configure(
xscrollcommand=h_scroll.set,
yscrollcommand=v_scroll.set
)

# 在Canvas上绘制一些矩形
for i in range(7):
canvas.create_rectangle(
10 + i * 30, 10,
30 + i * 30, 30, fill="lightblue"
)

for j in range(10):
canvas.create_rectangle(
10, 10 + j * 30,
30, 30 + j * 30, fill="white"
)

# 更新滚动区域以包含所有绘制的对象
update_scroll_region()

# 画布在框架中填满可用空间
canvas.pack(side=TOP, fill=BOTH, expand=True)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

7-2 绘图方法

  • 绘图方法
    • Canvas控件采用了坐标系的方式来确定画布中的每一点。
    • 默认主窗口左上角为坐标原点,这种坐标系叫窗口坐标系。
    • 当画布大于主窗口大小时,可采用带滚动条的Canvas控件。
    • 此时会以画布左上角为坐标原点,这种坐标系叫画布坐标系。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建画布
canvas = Canvas(
window, bg="lightgrey", width=350, height=200
)
canvas.pack()

# 设置坐标点,此处可用元组形式设置
point=[(100, 100), (250, 100)]

# 创建画布,添加线条
line = canvas.create_line(
point, fill="purple", dash=(1, 1),
arrow=LAST, width=5
)

# 移动其中一条线段,只需使用coords()移动曲线更改坐标
canvas.coords(line, 175, 30, 175, 170)

# 绘制圆形或椭圆
canvas.create_oval(30, 30, 50, 70)

# 绘制至少三个点的多边形
canvas.create_polygon(70, 30, 100, 30, 100, 70)

# 绘制一个矩形
# 前两参数决定矩形的左上角坐标,后两参数决定右下角坐标
canvas.create_rectangle(120, 30, 150, 70)

# 绘制一个文字字符串
canvas.create_text(90, 100, text="文字字符串")

# 创建一个图片
img = PhotoImage(file=r"./file/canvas.jpg")
canvas.create_image(260, 95, image=img)

# 创建一个位图,参数值:gray12、gray25、gray50、gray75
# hourglass、error、questhead、info、warning、question
canvas.create_bitmap(40, 160, bitmap="hourglass")

# 绘制一个弧形
canvas.create_arc(
90, 140, 150, 210,
start=0, extent=180,
fill="lightgreen"
)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(1) 直线属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建画布
canvas = Canvas(
window, bg="lightgrey", width=350, height=200
)
canvas.pack()

# 创建画布,添加线条
line = canvas.create_line(
# 坐标参数,定义线条的起始点和结束点
[50, 100, 300, 100, 125, 50],

# 边框宽度【基础外观属性】
width=5,

# 填充颜色,空字符串表示透明
fill="purple",

# 指定一个位图进行填充,默认空字符串,表示实心
stipple="gray50",

# 绘制虚线,值是一个整数元组,元组元素分别代表短线的长度和间隔【虚线属性】
# 5像素的虚线和1像素的间隔,2像素的虚线和1像素的间隔,交替绘制
dash=(5, 1, 2, 1),
# dash=(5, 2),

# 虚线开始的偏移位置(从虚线的第3个像素的位置开始绘制)
dashoffset=3,

# 画布对象为active时,绘制虚线【活动状态属性为active】
activedash=(4, 2),

# 画布对象为active时,填充颜色
activefill="blue",

# 画布对象为active时,指定填充的位图
# 参数值:gray12、gray25、gray50、gray75、error
# hourglass、questhead、info、warning、question
activestipple="gray75",

# 画布对象为active时,指定边框的宽度
activewidth=3,

# 画布对象的状态,默认normal,还包括disabled和hidden
state="normal",

# 画布对象为disabled时,绘制虚线【禁用状态属性disabled】
disableddash=(5, 5),

# 画布对象为disabled时,填充颜色
disabledfill="orange",

# 画布对象为disabled时,指定填充的位图
disabledstipple="warning",

# 画布对象为disabled时,指定边框的宽度
disabledwidth=10,

# 默认线段不带箭头,通过设置该项添加箭头【箭头属性】
# first添加箭头到开始位置
# last添加箭头到结束的位置
# both两端都添加箭头
arrow="both",

# 用一个三元组指定箭头的形状,默认(8, 10, 3)
# 元组中的数值分别代表箭头中三条边的长度
arrowshape=(16, 20, 10),

# 线段两端的样式,默认butt:两端平切于起始点【线段端点和连接属性】
# projecting:两端在起始位置将width设置的长度延长一半
# round:两端在起始位置将width设置的长度延长一半,并以圆角绘制
capstyle="round",

# 绘制两个相邻线段之间的接口样式,默认round
# round:以连接点为圆心,1/2的width长度为半径来绘制圆角
# bevel:在连接点处将两线段的夹角做平切操作
# miter:沿着两线段的夹角延伸至一个点
joinstyle="bevel",

# 以曲线的样式代替所绘线段,默认False【曲线属性】
smooth=True,

# 绘制曲线时,该选项指定由多少条折线来构成曲线
# 默认12,只有当smooth选项为True时该选项才生效
splinesteps=12,

# 添加标签【其他属性】
tags="直线属性",

# 当点画模式时填充位图的偏移,使用stipple设定图形的点画模式
offset=5
)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

(2) 扇形属性

  • 对于扇形、矩形、三角形、圆形等封闭式图形,主要由轮廓线和填充颜色两部分组成。
  • 在绘制这些图形时,相关函数的可选参数存在略微差异,具体参考:Python TKinter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建画布
canvas = Canvas(
window, bg="lightgrey", width=350, height=200
)
canvas.pack()

# 绘制扇形
arc = canvas.create_arc(
# 【几何属性】
50, 50, 225, 225,

# 指定起始位置的偏移角度
start=0,

# 指定跨度,默认90°
extent=90,

# 边框宽度【通用的视觉样式属性】
width=3,

# 填充颜色,空字符串表示透明
fill="lavender",

# 指定轮廓的颜色
outline="purple",

# 绘制虚线,值是一个整数元组,元组元素分别代表短线的长度和间隔
# 5像素的虚线和1像素的间隔,2像素的虚线和1像素的间隔,交替绘制
dash=(5, 1, 2, 1),

# 虚线开始的偏移位置(从虚线的第3个像素的位置开始绘制)
dashoffset=3,

# 默认创建扇形pieslice,弓形chord,弧形arc
style="chord",

# 画布对象为active时,绘制虚线【活动状态属性为active】
activedash=(4, 2),

# 画布对象为active时,填充颜色
activefill="light blue",

# 画布对象为active时,绘制轮廓线
activeoutline="green",

# 画布对象为active时,指定填充轮廓的位图
# 参数值:gray12、gray25、gray50、gray75、error
# hourglass、questhead、info、warning、question
activeoutlinestipple="error",

# 画布对象为active时,指定填充的位图
# 参数值:gray12、gray25、gray50、gray75、error
# hourglass、questhead、info、warning、question
activestipple="gray75",

# 画布对象为active时,指定边框的宽度
activewidth=5,

# 画布对象的状态,默认normal,还包括disabled和hidden
state="normal",

# 画布对象为disabled时,绘制虚线【禁用状态属性disabled】
disableddash=(5, 5),

# 画布对象为disabled时,填充颜色
disabledfill="orange",

# 画布对象为disabled时,绘制轮廓线
disabledoutline="dark green",

# 画布对象为disabled时,指定填充轮廓的位图
disabledoutlinestipple="hourglass",

# 画布对象为disabled时,指定填充的位图
disabledstipple="hourglass",

# 画布对象为disabled时,指定边框的宽度
disabledwidth=10,

# 【点画模式下的位图/偏移属性】
# 当点画模式时填充位图的偏移,参数值x, y坐标偏移和位置偏移
offset=NE,

# 指定当点画模式绘制轮廓时位图的偏移
outlineoffset=NE,

# 指定一个位图来填充边框,默认值是空字符串,表示黑色
outlinestipple="",

# 添加标签【其他属性】
tags="扇形属性"
)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

7-3 遍历位图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建画布
canvas = Canvas(
window, bg="lightgrey", width=350, height=200
)
canvas.pack()

# 内置位图名称
bitmaps = [
"gray75", "gray50", "gray25", "gray12",
"error", "hourglass", "info", "questhead",
"question", "warning"
]

# 列出所有的位图样式
for i in range(len(bitmaps)):
# 前两个参数指定一个位图的位置,后续依次排列
# (i+1)*32:控制位图水平位置,且每个位图之间水平间隔32像素
# 控制所有位图的垂直位置30像素,bitmap选择要绘制的位图图案
canvas.create_bitmap((i+1)*32, 30, bitmap=bitmaps[i])

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

7-4 对象操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from tkinter import *

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)

# 创建画布
canvas = Canvas(
window, bg="lightgrey", width=350, height=200
)


# 定义移动函数
def move_img():
# 定义移动坐标
canvas.move(image, 50, 0)


img = PhotoImage(file=r"./file/canvas.jpg")
image = canvas.create_image(10, 90, image=img, anchor=W)

# 将按钮放置在画布中
btn=Button(
canvas, text="点击移动画布", bg="#8A8A8A",
activebackground="#7CCD7C", command=move_img
)

# 在指定位置创建一个窗口控件,tags来添加标签
canvas.create_window(
175, 185, height=30, width=100, window=btn
)

# 删除画布对象,若传入ALL,则删除所有的画布对象
# canvas.delete(image)
canvas.pack()

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

8 菜单控件

  • 菜单控件
    • 使用菜单控件(Menu)可充分节省有限的窗口区域,让界面更加简洁优雅,避免臃肿、混乱。
    • 提供了三种类型的菜单:topleve(主目录)、pull-down(下拉式)、pop-up(快捷键或弹出式)。

8-1 主目录菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from tkinter import *
import tkinter . messagebox

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)


# 绑定一个执行函数,点击菜单项时,显示一个消息对话框
def menu_command():
tkinter.messagebox.showinfo(
"主菜单栏", "您正在使用主菜单栏!"
)


# 创建一个主目录菜单,也叫顶级菜单
main_menu = Menu(window)

# 新增命令菜单项
main_menu.add_command(label="文件", command=menu_command)
main_menu.add_command(label="编辑", command=menu_command)
main_menu.add_command(label="格式", command=menu_command)
main_menu.add_command(label="查看", command=menu_command)
main_menu.add_command(label="帮助", command=menu_command)

# 显示菜单
window.config(menu=main_menu)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

8-2 下拉式菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from tkinter import *
import tkinter . messagebox

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)


# 绑定一个执行函数,点击菜单项时显示一个消息对话框
# 添加event=None后,函数能够接受一个可选的事件参数
def menu_command(event=None):
tkinter.messagebox.showinfo(
"下拉菜单", "您正在使用下拉菜单!"
)


# 创建一个主目录菜单,也叫顶级菜单
main_menu = Menu(window)

# 在顶级菜单上新增"文件"菜单的子菜单,同时不添加分割线
file_menu = Menu(main_menu, tearoff=False)

# 新增"文件"菜单的菜单项,并使用accelerator设置菜单项的快捷键
file_menu.add_command(
label="新建", command=menu_command, accelerator="Ctrl+N"
)
file_menu.add_command(
label="打开", command=menu_command, accelerator="Ctrl+O"
)
file_menu.add_command(
label="保存", command=menu_command, accelerator="Ctrl+S"
)

# 添加一条分割线
file_menu.add_separator()
file_menu.add_command(label="退出", command=window.quit)

# 新增命令菜单项
# 添加一个父菜单:add_cascade(**options)
# 将指定的子菜单,通过menu参数与父菜单连接,从而创建一个下拉菜单
# 添加一个多选按钮的菜单项:add_checkbutton(**options)
# 添加一个单选按钮的菜单项:add_radiobutton(**options)
# 添加一条分割线:add_separator(**options)
main_menu.add_cascade(label="文件", menu=file_menu)
main_menu.add_command(label="编辑", command=menu_command)
main_menu.add_command(label="格式", command=menu_command)
main_menu.add_command(label="查看", command=menu_command)
main_menu.add_command(label="帮助", command=menu_command)

# 显示菜单
window.config(menu=main_menu)

# 绑定键盘事件,按下键盘按键时触发执行函数
window.bind("<Control-n>", menu_command)
window.bind("<Control-N>", menu_command)
window.bind("<Control-o>", menu_command)
window.bind("<Control-O>", menu_command)
window.bind("<Control-s>", menu_command)
window.bind("<Control-S>", menu_command)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

8-3 弹出式菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from tkinter import *
import tkinter . messagebox

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)


def func():
tkinter.messagebox.showinfo(
"弹出菜单", "您正在使用弹出菜单!"
)


# 定义事件函数
def menu_command(event):
# 在指定的位置显示弹出菜单
main_menu.post(event.x_root, event.y_root)


# 创建一个弹出菜单
main_menu = Menu(window, tearoff=False)
main_menu.add_command(label="新建", command=func)
main_menu.add_command(label="复制", command=func)
main_menu.add_command(label="粘贴", command=func)
main_menu.add_command(label="剪切", command=func)

# 绑定键盘右键<Button-3>,1左键,2中间的滑轮
window.bind("<Button-3>", menu_command)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

8-4 菜单按钮控件

  • 菜单按钮控件
    • 菜单按钮控件(Menubutton)是一个与Menu控件相关联的按钮。
    • 通过Menubutton创建的菜单按钮可自由地放置在窗口任意位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from tkinter import *
import tkinter . messagebox

# 调用Tk()创建主窗口
window = Tk()
window.geometry("500x250")
window.resizable(0, 0)


def func():
tkinter.messagebox.showinfo(
"菜单按钮", "您正在使用菜单按钮!"
)


# 创建一个菜单按钮
menu_btn = Menubutton(
window, text="点击进行操作", relief="solid"
)

# 设置布局
menu_btn.grid(padx=200, pady=80)

# 添加菜单,使用tearoff参数不显示分割线
file_menu=Menu(menu_btn, tearoff=False)
file_menu.add_command(label="新建", command=func)
file_menu.add_command(label="复制", command=func)
file_menu.add_command(label="粘贴", command=func)
file_menu.add_command(label="剪切", command=func)

# 显示菜单,将菜单命令绑定在菜单按钮对象上
menu_btn.config(menu=file_menu)

# 设置窗口主循环,一直显示,直到窗口被关闭
window.mainloop()

Python Tkinter(二)
https://stitch-top.github.io/2025/02/07/python/python15-python-tkinter-er/
作者
Dr.626
发布于
2025年2月7日 00:30:00
许可协议