Tkinter详解和爱心跳动示例(Python)

@TOC

Tkinter简要介绍

Tkinter 是 Python 的标准 GUI(图形用户界面)库。它提供了创建窗口和对话框的基本工具,可以用来构建各种复杂的用户界面。

1.基本概念

  • Tk: Tk 是 Tkinter 的底层实现,最初是为 Tcl 语言设计的。Tkinter 是 Tk 的 Python 接口。
  • Widget: Tkinter 中的控件,如按钮、标签、文本框等。
  • Event: 用户与界面的交互,如点击按钮、键盘输入等。
  • Callback: 事件触发后执行的函数。

1.1Tk

在 Tkinter 中,Tk 是一个类,用于创建主窗口。以下是关于 Tk 类的一些关键点:

  • 创建主窗口:通过实例化 Tk 类来创建应用程序的主窗口。
  • 初始化方法:通常使用 __init__ 方法进行初始化,但大多数情况下直接调用 Tk() 即可。
  • 进入事件循环:使用 mainloop() 方法启动事件循环,使窗口保持打开状态并响应用户操作。
  • 窗口标题:可以使用 title() 方法设置窗口的标题。
  • 窗口大小:可以通过 geometry() 方法设置窗口的初始大小和位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
import tkinter as tk

# 创建主窗口
root = tk.Tk()

# 设置窗口标题
root.title("我的应用")

# 设置窗口大小
root.geometry("400x300")

# 进入事件循环
root.mainloop()

1.2 Canvas

在 Tkinter 中,Canvas 是一个非常强大的小部件,用于绘制图形、文本、图像等。

创建 Canvas:通过实例化 Canvas 类来创建一个画布。

常用方法

  • create_line(x1, y1, x2, y2, …):绘制线条。
  • create_rectangle(x1, y1, x2, y2, …):绘制矩形。
  • create_oval(x1, y1, x2, y2, …):绘制椭圆。
  • create_polygon(x1, y1, x2, y2, …, xn, yn, …):绘制多边形。
  • create_text(x, y, text=””):绘制文本。
  • create_image(x, y, image=image_object, anchor=NW):绘制图像。

配置选项:

  • width 和 height:设置画布的宽度和高度。
  • bg:设置背景颜色。

绑定事件:可以使用 bind 方法为画布上的对象绑定事件。

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

# 创建主窗口
root = tk.Tk()
root.title("Canvas 示例")

# 创建 Canvas 小部件
canvas = tk.Canvas(root, width=400, height=300, bg='white')
canvas.pack()

# 绘制线条
canvas.create_line(50, 50, 350, 50, fill='blue')

# 绘制矩形
canvas.create_rectangle(50, 100, 150, 200, fill='green')

# 绘制椭圆
canvas.create_oval(200, 100, 300, 200, fill='red')

# 绘制文本
canvas.create_text(200, 250, text="Hello, Tkinter!", fill='black')

# 进入事件循环
root.mainloop()

在 Tkinter 的 Canvas 小部件中,delete 方法用于删除画布上的特定项目或所有项目。

  • 删除特定项目:通过传递项目的标识符(ID)来删除特定的项目。
  • 删除所有项目:通过传递特殊标签 ALL 来删除画布上的所有项目。
  • 项目标识符:每个项目在创建时都会返回一个唯一的标识符,可以用来引用该项目。

常用方法

  • canvas.delete(item_id):删除指定标识符的项目。
  • canvas.delete(tk.ALL):删除画布上的所有项目。
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
import tkinter as tk

# 创建主窗口
root = tk.Tk()
root.title("Canvas 删除示例")

# 创建 Canvas 小部件
canvas = tk.Canvas(root, width=400, height=300, bg='white')
canvas.pack()

# 绘制一些项目
line_id = canvas.create_line(50, 50, 350, 50, fill='blue')
rect_id = canvas.create_rectangle(50, 100, 150, 200, fill='green')
oval_id = canvas.create_oval(200, 100, 300, 200, fill='red')

# 删除特定项目
def delete_specific_item():
canvas.delete(line_id) # 删除线条

# 删除所有项目
def delete_all_items():
canvas.delete(tk.ALL) # 删除所有项目

# 创建按钮
btn_delete_specific = tk.Button(root, text="删除线条", command=delete_specific_item)
btn_delete_specific.pack()

btn_delete_all = tk.Button(root, text="删除所有项目", command=delete_all_items)
btn_delete_all.pack()

# 进入事件循环
root.mainloop()

1.3 pack

在 Tkinter 中,pack 是一种几何管理器(geometry manager),用于将小部件(widgets)放置到其父容器中。pack 管理器通过将小部件“打包”到父容器的边缘来自动排列它们。

基本用法:通过调用小部件的 pack() 方法将其添加到父容器中。

常用选项

  • side:指定小部件在父容器中的对齐方式,可选值有 TOP(默认)、BOTTOM、LEFT 和 RIGHT。
  • fill:指定小部件是否填充父容器的剩余空间,可选值有 NONE(默认)、X、Y 和 BOTH。
  • expand:指定小部件是否扩展以填充父容器的额外空间,布尔值 True 或 False。
  • padx 和 pady:指定小部件与父容器之间的外部填充(外边距)。
  • ipadx 和 ipady:指定小部件内部的填充(内边距)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import tkinter as tk

# 创建主窗口
root = tk.Tk()
root.title("Pack 示例")

# 创建多个小部件
button1 = tk.Button(root, text="按钮1")
button2 = tk.Button(root, text="按钮2")
button3 = tk.Button(root, text="按钮3")

# 使用 pack 方法布局小部件
button1.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
button2.pack(side=tk.LEFT, fill=tk.Y, ipadx=10, ipady=5)
button3.pack(side=tk.RIGHT, fill=tk.Y, ipadx=10, ipady=5)

# 进入事件循环
root.mainloop()

1.4 main.after

在 Tkinter 中,main.after 是一个非常有用的方法,用于在指定的时间间隔后执行某个函数或方法。它常用于实现定时任务、动画效果或延迟操作。

基本用法:main.after(ms, function, *args),其中 ms 是时间间隔(毫秒),

  • function 是要执行的函数,*args 是传递给函数的参数。
  • 递归调用:可以通过在函数内部再次调用 after 方法来实现周期性的任务。\
  • 取消任务:可以使用 after_cancel 方法取消尚未执行的任务。

常用方法

  • main.after(ms, function, *args):在 ms 毫秒后调用 function 函数,并传递 *args 参数。
  • main.after_cancel(id):取消由 after 方法返回的任务标识符 id 所表示的任务。

2.常用控件

2.1 Label

在 Tkinter 中,Label 是一个用于显示文本或图像的小部件。它通常用于在界面上显示静态信息。

创建 Label:通过实例化 Label 类来创建一个标签。

常用选项

  • text:设置标签显示的文本。
  • image:设置标签显示的图像。
  • font:设置文本的字体样式。
  • fg 或 foreground:设置文本的颜色。
  • bg 或 background:设置背景颜色。
  • width 和 height:设置标签的宽度和高度(单位为字符或像素)。
  • anchor:设置文本在标签中的对齐方式(例如 N、S、E、W、CENTER 等)。
  • justify:设置多行文本的对齐方式(例如 LEFT、CENTER、RIGHT)。

方法

  • config():用于修改标签的属性。
  • pack(), grid(), place():用于布局标签。

显示文本

1
2
3
4
5
6
7
8
9
10
11
12
import tkinter as tk

# 创建主窗口
root = tk.Tk()
root.title("Label 示例")

# 创建一个 Label 小部件
label = tk.Label(root, text="欢迎使用 Tkinter!", font=("Arial", 16), fg="blue", bg="white")
label.pack(pady=20)

# 进入事件循环
root.mainloop()

显示图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import tkinter as tk
from PIL import Image, ImageTk

# 创建主窗口
root = tk.Tk()
root.title("Label 图像示例")

# 加载图像
image = Image.open("path/to/your/image.png")
photo = ImageTk.PhotoImage(image)

# 创建一个 Label 小部件显示图像
label = tk.Label(root, image=photo)
label.pack(pady=20)

# 进入事件循环
root.mainloop()

修改标签属性

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

# 创建主窗口
root = tk.Tk()
root.title("Label 属性修改示例")

# 创建一个 Label 小部件
label = tk.Label(root, text="初始文本", font=("Arial", 16), fg="blue", bg="white")
label.pack(pady=20)

# 修改标签的文本
def change_text():
label.config(text="文本已更改", fg="red")

# 创建一个按钮,点击时修改标签的文本
button = tk.Button(root, text="更改文本", command=change_text)
button.pack(pady=10)

# 进入事件循环
root.mainloop()

2.2 Text

Text 小部件是一个多行文本编辑器,可以用来显示和编辑多行文本。它支持插入、删除和格式化文本,还可以插入图像和嵌入其他小部件。

常用方法和属性

1.创建 Text 小部件:

1
text_box = Text(root, wrap=WORD, bg='black', fg='white', font=('Arial', 12), height=5, width=20)
  1. 放置 Text 小部件:
1
text_box.place(x=10, y=10)
  1. 插入文本:
1
text_box.insert(END, "Your text here\n")
  1. 删除文本:
1
2
text_box.delete('1.0', END)  # 删除所有文本
text_box.delete('1.0', '1.5') # 删除从第1行第1个字符到第1行第5个字符之间的文本
  1. 获取文本:
1
content = text_box.get('1.0', END)  # 获取所有文本
  1. 配置属性:
1
2
text_box.config(state=DISABLED)  # 禁用文本编辑
text_box.config(state=NORMAL) # 启用文本编辑

跳动的爱心

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
import random
from math import sin, cos, pi, log
from tkinter import *

CANVAS_WIDTH = 640 # 画布的宽
CANVAS_HEIGHT = 480 # 画布的高
CANVAS_CENTER_X = CANVAS_WIDTH / 2 # 画布中心的X轴坐标
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2 # 画布中心的Y轴坐标
IMAGE_ENLARGE = 11 # 放大比例
HEART_COLOR = "#FF69B4" # 心的颜色
STAR_COLOR = "white" # 星星的颜色


# 生成随机星星的位置和大小
def generate_stars(num_stars):
stars = []
for _ in range(num_stars):
x = random.randint(0, CANVAS_WIDTH)
y = random.randint(0, CANVAS_HEIGHT)
size = random.randint(1, 3)
stars.append((x, y, size))
return stars


def heart_function(t, shrink_ratio: float = IMAGE_ENLARGE):
"""
“爱心函数生成器”
:param shrink_ratio: 放大比例
:param t: 参数
:return: 坐标
"""
# 基础函数
x = 16 * (sin(t) ** 3)
y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))

# 放大
x *= shrink_ratio
y *= shrink_ratio

# 移到画布中央
x += CANVAS_CENTER_X
y += CANVAS_CENTER_Y

return int(x), int(y)


def scatter_inside(x, y, beta=0.15):
"""
随机内部扩散
:param x: 原x
:param y: 原y
:param beta: 强度
:return: 新坐标
"""
ratio_x = - beta * log(random.random())
ratio_y = - beta * log(random.random())

dx = ratio_x * (x - CANVAS_CENTER_X)
dy = ratio_y * (y - CANVAS_CENTER_Y)

return x - dx, y - dy


def shrink(x, y, ratio):
"""
抖动
:param x: 原x
:param y: 原y
:param ratio: 比例
:return: 新坐标
"""
force = -1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.6) # 这个参数...
dx = ratio * force * (x - CANVAS_CENTER_X)
dy = ratio * force * (y - CANVAS_CENTER_Y)
return x - dx, y - dy


def curve(p):
"""
自定义曲线函数,调整跳动周期
:param p: 参数
:return: 正弦
"""
# 可以尝试换其他的动态函数,达到更有力量的效果(贝塞尔?)
return 2 * (2 * sin(4 * p)) / (2 * pi)


class Heart:
"""
爱心类
"""

def __init__(self, generate_frame=20):
self._points = set() # 原始爱心坐标集合
self._edge_diffusion_points = set() # 边缘扩散效果点坐标集合
self._center_diffusion_points = set() # 中心扩散效果点坐标集合
self.all_points = {} # 每帧动态点坐标
self.build(2000)

self.random_halo = 1000

self.generate_frame = generate_frame
for frame in range(generate_frame):
self.calc(frame)

def build(self, number):
# 爱心
for _ in range(number):
t = random.uniform(0, 2 * pi) # 随机不到的地方造成爱心有缺口
x, y = heart_function(t)
self._points.add((x, y))

# 爱心内扩散
for _x, _y in list(self._points):
for _ in range(3):
x, y = scatter_inside(_x, _y, 0.05)
self._edge_diffusion_points.add((x, y))

# 爱心内再次扩散
point_list = list(self._points)
for _ in range(6000):
x, y = random.choice(point_list)
x, y = scatter_inside(x, y, 0.17)
self._center_diffusion_points.add((x, y))

@staticmethod
def calc_position(x, y, ratio):
# 调整缩放比例
force = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520) # 魔法参数

dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1)
dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1)

return x - dx, y - dy

def calc(self, generate_frame):
ratio = 10 * curve(generate_frame / 10 * pi) # 圆滑的周期的缩放比例

halo_radius = int(4 + 6 * (1 + curve(generate_frame / 10 * pi)))
halo_number = int(3000 + 4000 * abs(curve(generate_frame / 10 * pi) ** 2))

all_points = []

# 光环
heart_halo_point = set() # 光环的点坐标集合
for _ in range(halo_number):
t = random.uniform(0, 4 * pi) # 随机不到的地方造成爱心有缺口
x, y = heart_function(t, shrink_ratio=11.5) # 魔法参数
x, y = shrink(x, y, halo_radius)
if (x, y) not in heart_halo_point:
# 处理新的点
heart_halo_point.add((x, y))
x += random.randint(-14, 14)
y += random.randint(-14, 14)
size = random.choice((1, 2, 2))
all_points.append((x, y, size))

# 轮廓
for x, y in self._points:
x, y = self.calc_position(x, y, ratio)
size = random.randint(1, 3)
all_points.append((x, y, size))

# 内容
for x, y in self._edge_diffusion_points:
x, y = self.calc_position(x, y, ratio)
size = random.randint(1, 2)
all_points.append((x, y, size))

for x, y in self._center_diffusion_points:
x, y = self.calc_position(x, y, ratio)
size = random.randint(1, 2)
all_points.append((x, y, size))

self.all_points[generate_frame] = all_points

def render(self, render_canvas, render_frame):
for x, y, size in self.all_points[render_frame % self.generate_frame]:
render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=HEART_COLOR)


def draw(main: Tk, render_canvas: Canvas, render_heart: Heart, render_frame=0):
render_canvas.delete('all')

# 绘制星星
stars = generate_stars(100) # 生成100颗星星
for x, y, size in stars:
render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=STAR_COLOR)

render_heart.render(render_canvas, render_frame)
main.after(160, draw, main, render_canvas, render_heart, render_frame + 1)


def change_label_color(label, colors, index=0):
label.config(fg=colors[index])
index = (index + 1) % len(colors)
label.after(500, change_label_color, label, colors, index)


if __name__ == '__main__':
root = Tk()
root.title('Beating_heart')

# 创建画布
canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
canvas.pack()

# 创建左上角的文本框
# text_box = Text(root, wrap=WORD, bg='black', fg='white', font=('Arial', 12), height=5, width=20)
# text_box.place(x=10, y=10)

# 插入社交网址
# social_urls = [
# "ZhiHu: https://www.zhihu.com/people/qin-zheng-kai-89",
# "Csdn: https://blog.csdn.net/qq_45832050?type=blog",
# "GitHub: https://github.com/QInzhengk",
# ]
# for url in social_urls:
# text_box.insert(END, url + '\n')

heart = Heart()
draw(root, canvas, heart)

# 创建Label并设置初始颜色
colors = ["#FF69B4", "#FFD700", "#00FF00", "#00BFFF", "#FF1493"]
label = Label(root, text="peace and love", bg="black")
label.place(relx=.5, rely=.5, anchor=CENTER)

# 启动颜色变化
change_label_color(label, colors)

root.mainloop()

在这里插入图片描述

参考

1.Graphical User Interfaces with Tk — Python 3.13.0 documentation

2.Python - GUI 编程 (tutorialspoint.com)

3.https://github.com/star-start/Beating_heart


Tkinter详解和爱心跳动示例(Python)
https://qzkq.github.io/2026/01/03/Tkinter详解和爱心跳动示例(Python)/
作者
Qin Zk
发布于
2026年1月3日
许可协议