一、Tkinter 简单介绍

Tkinter 是使用 python 进行窗口视窗设计的模块。tkinter是python 自带的,可以编辑的GUI界面,我们可以用GUI 实现很多直观的功能。

 Tkinter 模块元素简要说明

Tkinter支持16个核心的窗口部件,这个16个核心窗口部件类简要描述如下:

  • Button: 一个简单的按钮,用来执行一个命令或别的操作。

  • Canvas: 组织图形。这个部件可以用来绘制图表和图,创建图形编辑器,实现定制窗口部件。

  • Checkbutton: 代表一个变量,它有两个不同的值。点击这个按钮将会在这两个值间切换。

  • Entry: 文本输入域。

  • Frame: 一个容器窗口部件。帧可以有边框和背景,当创建一个应用程序或dialog(对话)版面时,帧被用来组织其它的窗口部件。

  • Label: 显示一个文本或图象。

  • Listbox: 显示供选方案的一个列表。listbox能够被配置来得到radiobutton或checklist的行为。

  • Menu: 菜单条。用来实现下拉和弹出式菜单。

  • Menubutton: 菜单按钮。用来实现下拉式菜单。

  • Message: 显示一文本。类似label窗口部件,但是能够自动地调整文本到给定的宽度或比率。

  • Radiobutton: 代表一个变量,它可以有多个值中的一个。点击它将为这个变量设置值,并且清除与这同一变量相关的其它radiobutton。

  • Scale: 允许你通过滑块来设置一数字值。

  • Scrollbar: 为配合使用canvas, entry, listbox, and text窗口部件的标准滚动条。

  • Text: 格式化文本显示。允许你用不同的样式和属性来显示和编辑文本。同时支持内嵌图象和窗口。

  • Toplevel: 一个容器窗口部件,作为一个单独的、最上面的窗口显示。

  • messageBox:消息框,用于显示你应用程序的消息框。(Python2中为tkMessagebox)

注意在Tkinter中窗口部件类没有分级;所有的窗口部件类在树中都是兄弟关系。

所有这些窗口部件提供了Misc和几何管理方法、配置管理方法和部件自己定义的另外的方法。此外,Toplevel类也提供窗口管理接口。这意味一个典型的窗口部件类提供了大约150种方法。

二、代码实践

1. Label

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

# 第1步,实例化object,建立窗口window
window = tk.Tk()
# 第2步,给窗口的可视化起名字
window.title('hello world')
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('400x200')
# 第4步,在图形界面上设定标签
l = tk.Label(window, text='你好,世界', bg='#97FFFF', font=('Microsoft YaHei', 13), width=20, height=2)
# 第5步,放置标签
l.pack()
# 第6步,主窗口循环显示
window.mainloop()

2.Button

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
import tkinter as tk  


# 定义一个函数功能
def hit_me():
global on_hit
if not on_hit:
on_hit = True
var.set('你好,世界!')
else:
on_hit = False
var.set('')


on_hit = False
# 第1步,实例化object,建立窗口window
window = tk.Tk()
# 第2步,给窗口的可视化起名字
window.title('hello world')
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('400x200')
# 第4步,在图形界面上设定标签
var = tk.StringVar() # 将label标签的内容设置为字符类型,用var来接收hit_me函数的传出内容用以显示在标签上
# 说明: bg为背景,fg为字体颜色,font为字体,width为长,height为高,这里的长和高是字符的长和高,比如height=2,就是标签有2个字符这么高
l = tk.Label(window, textvariable=var, bg='#97FFFF', font=('Microsoft YaHei', 12), width=30, height=2)
l.pack()
# 第5步,在窗口界面设置放置Button按键
b = tk.Button(window, text='点我', font=('Microsoft YaHei', 12), width=10, height=1, command=hit_me)
b.pack()
# 第6步,主窗口循环显示
window.mainloop()

3.Entry

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

# 第1步,实例化object,建立窗口window
window = tk.Tk()
# 第2步,给窗口的可视化起名字
window.title('hello world')
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('400x200')
# 第4步,在图形界面上设定输入框控件entry并放置控件
e1 = tk.Entry(window, show='*', font=('Microsoft YaHei', 14)) # 显示成密文形式
e2 = tk.Entry(window, font=('Microsoft YaHei', 14)) # 显示成明文形式
e1.pack()
e2.pack()
# 第5步,主窗口循环显示
window.mainloop()

4.Text

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
import tkinter as tk  


# 第7步,创建并放置两个按钮分别触发两种情况
def insert_point():
var = e.get()
t.insert('insert', var)


def insert_end():
var = e.get()
t.insert('end', var)


# 第1步,实例化object,建立窗口window
window = tk.Tk()
# 第2步,给窗口的可视化起名字
window.title('hello world')
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('400x200')
# 第4步,在图形界面上设定输入框控件entry框并放置
e = tk.Entry(window, font=('Microsoft YaHei', 14))
e.pack()
# 第5步,创建并放置两个按钮分别触发两种情况
b1 = tk.Button(window, text='insert point', font=('Microsoft YaHei', 12), width=10, height=2, command=insert_point)
b1.pack()
b2 = tk.Button(window, text='insert end', font=('Microsoft YaHei', 12), width=10, height=2, command=insert_point)
b2.pack()
# 第6步,创建并放置一个多行文本框text用以显示,指定height=3为文本框是三个字符高度
t = tk.Text(window, height=3)
t.pack()
# 第8步,主窗口循环显示
window.mainloop()
image.png

5.Listbox

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
import tkinter as tk  


def print_selection():
value = lb.get(lb.curselection())
var1.set(value)


window = tk.Tk()
window.title('hello world')
window.geometry('400x200')
var1 = tk.StringVar()
l = tk.Label(window, bg='green', fg='yellow', font=('Arial', 12), width=10, textvariable=var1)
l.pack()
b1 = tk.Button(window, text='print selection', width=15, height=2, command=print_selection)
b1.pack()
# 方法1:创建Listbox并为其添加内容
var2 = tk.StringVar()
var2.set((1, 2, 3, 4))
lb = tk.Listbox(window, listvariable=var2)
# 方法2:创建一个list并将值循环添加到Listbox控件中
list_items = [11, 22, 33, 44]
for item in list_items:
lb.insert('end', item)
# 方法3:
lb.insert(1, 'first')
lb.insert(2, 'second')
lb.delete(2)
lb.pack()
window.mainloop()

6.Radiobutton

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


def print_selection():
l.config(text='you have selected ' + var.get())


window = tk.Tk()
window.title('hello world')
window.geometry('400x200')

var = tk.StringVar() # 定义var为字符串类型变量用来存放返回值
l = tk.Label(window, bg='#76EEC6', width=20, text='empty')
l.pack()
# 创建三个radiobutton选项,其中variable=var, value='A'的意思就是,当我们鼠标选中了其中一个选项,把value的值A放到变量var中,然后赋值给variable
r1 = tk.Radiobutton(window, text='Option A', variable=var, value='A', command=print_selection)
r1.pack()
r2 = tk.Radiobutton(window, text='Option B', variable=var, value='B', command=print_selection)
r2.pack()
r3 = tk.Radiobutton(window, text='Option C', variable=var, value='C', command=print_selection)
r3.pack()
window.mainloop()
print(var.get())
image.png

7.Checkbutton

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
import tkinter as tk  


def print_selection():
if (var1.get() == 1) & (var2.get() == 0):
l.config(text='I love only Python')
elif (var1.get() == 0) & (var2.get() == 0):
l.config(text='I love only C++')
elif (var1.get() == 0) & (var2.get() == 0):
l.config(text='I do not love either')
else:
l.config(text='I love both')


window = tk.Tk()
window.title('hello world')
window.geometry('400x200')

l = tk.Label(window, bg='#76EEC6', width=20, text='empty')
l.pack()

# 定义两个Checkbutton选项并放置
var1 = tk.IntVar() # 定义var1和var2整型变量用来存放选择行为返回值
var2 = tk.IntVar()
c1 = tk.Checkbutton(window, text='python', variable=var1, onvalue=1, offvalue=0, command=print_selection)
c2 = tk.Checkbutton(window, text='C++', variable=var2, onvalue=1, offvalue=0, command=print_selection)
c1.pack()
c2.pack()
window.mainloop()

8.Scale

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
import tkinter as tk  


def print_selection(v):
l.config(text='you have selected ' + v)


window = tk.Tk()
window.title('hello world')
window.geometry('400x200')
l = tk.Label(window, bg='#76EEC6', width=20, text='empty')
l.pack()

# 创建一个尺度滑条,长度200字符,从0开始10结束,以2为刻度,精度为0.01,触发调用print_selection函数
# orient=tk.HORIZONTAL:表示滑块是水平放置的,从左到右滑动。
# orient=tk.VERTICAL:表示滑块是垂直放置的,从上到下滑动。
s = tk.Scale(
window,
# label='try me',
from_=0,
to=100,
orient=tk.HORIZONTAL,
length=200,
showvalue=True, # 是否显示当前滑块的值
tickinterval=20,
resolution=1,
command=print_selection)
s.set(85)
s.pack()
window.mainloop()

9.Canvas

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


def moveit():
canvas.move(rect, 2, 2)


window = tk.Tk()
window.title('hello world')
window.geometry('400x300')

# 创建画布
canvas = tk.Canvas(window, bg='#76EEC6', width=400, height=200)
image = Image.open(r'D:\图片\头像\thumbnail.jpg')
image_file = ImageTk.PhotoImage(image)
image = canvas.create_image(200, 20, anchor='n', image=image_file)
rect = canvas.create_rectangle(330, 30, 330+20, 30+20)
canvas.pack()
b = tk.Button(window, text='move item', command=moveit)
b.pack()
window.mainloop()

10.Frame

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
import tkinter as tk  


window = tk.Tk()
window.title('hello world')
window.geometry('400x300')

l = tk.Label(window, bg='#76EEC6', width=20, text='on the window')
l.pack()

# 创建一个主frame,长在主window窗口上
frame = tk.Frame(window)
frame.pack()
# 创建一个主frame,长在主window窗口上
frame_l = tk.Frame(frame) # 第二层frame,左frame,长在主frame上
frame_r = tk.Frame(frame) # 第二层frame,右frame,长在主frame上
frame_l.pack(side='left')
frame_r.pack(side='right')

tk.Label(frame_l, text='on the frame_l1', bg='#FFBBFF').pack()
tk.Label(frame_l, text='on the frame_l2', bg='#FFBBFF').pack()
tk.Label(frame_l, text='on the frame_l3', bg='#FFBBFF').pack()
tk.Label(frame_r, text='on the frame_r1', bg='#FFE1FF').pack()
tk.Label(frame_r, text='on the frame_r2', bg='#FFE1FF').pack()
tk.Label(frame_r, text='on the frame_r3', bg='#FFE1FF').pack()
window.mainloop()

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
import tkinter as tk  


def do_job():
global counter
l.config(text='do ' + str(counter))
counter += 1


counter = 0
window = tk.Tk()
window.title('hello world')
window.geometry('400x300')

l = tk.Label(window, bg='#76EEC6', width=20, text=' ')
l.pack()

# 创建一个菜单栏,这里我们可以把他理解成一个容器,在窗口的上方
menubar = tk.Menu(window)
# 创建一个File菜单项(默认不下拉,下拉内容包括New,Open,Save,Exit功能项)
file_menu = tk.Menu(menubar, tearoff=0)
# 将上面定义的空菜单命名为File,放在菜单栏中,就是装入那个容器中
menubar.add_cascade(label='File', menu=file_menu)
# 在File中加入New、Open、Save等小菜单,即我们平时看到的下拉菜单,每一个小菜单对应命令操作。
file_menu.add_command(label='New', command=do_job)
file_menu.add_command(label='Open', command=do_job)
file_menu.add_command(label='Save', command=do_job)
file_menu.add_separator() # 添加一条分隔线
file_menu.add_command(label='Exit', command=window.quit)

edit_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label='Edit', menu=edit_menu)
edit_menu.add_command(label='Cut', command=do_job)
edit_menu.add_command(label='Cope', command=do_job)
edit_menu.add_command(label='Paste', command=do_job)

# 创建第二级菜单,即菜单项里面的菜单
sub_menu = tk.Menu(file_menu)
sub_menu.add_command(label='Sub menu 1', command=do_job)
# 在菜单项里面的菜单项里面的菜单命令
file_menu.add_cascade(label='Import', menu=sub_menu, underline=0)
# 配置让菜单栏menubar显示出来
menubar.add_command(label='Exit', command=window.quit)
window.config(menu=menubar)
window.mainloop()

12.MessageBox

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
import tkinter as tk  
import tkinter.messagebox as tm


def hit_me():
global v
v += 1
if v > 6:
v = 0
show(v)


def show(a):
match a:
case 1:
tm.showinfo(title='Hi', message='你好!')
case 2:
tm.showwarning(title='Hi', message='有警告')
case 3:
tm.showerror(title='Hi', message='出错了')
case 4:
print(tm.askquestion(title='Hi', message='你好!'))
case 5:
print(tm.askyesno(title='Hi', message='你好!'))
case 6:
print(tm.askokcancel(title='Hi', message='你好!'))


v = 0
window = tk.Tk()
window.title('hello world')
window.geometry('400x300')
tk.Button(window, text='hit me', bg='#76EEC6', command=hit_me).pack()
window.mainloop()

13.Pack

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


window = tk.Tk()
window.title('hello world')
window.geometry('400x300')

tk.Label(window, text='P', fg='red').pack(side='top')
tk.Label(window, text='P', fg='red').pack(side='bottom')
tk.Label(window, text='P', fg='red').pack(side='left')
tk.Label(window, text='P', fg='red').pack(side='right')

window.mainloop()

14.Place

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


window = tk.Tk()
window.title('hello world')
window.geometry('400x300')

tk.Label(window, text='P', fg='red').place(x=100, y=100, anchor='nw')

window.mainloop()

15.Grid

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


window = tk.Tk()
window.title('hello world')
window.geometry('400x300')

for i in range(3):
for j in range(3):
tk.Label(window, text=f'{i}_{j}', bg='#76EEC6').grid(row=i, column=j, padx=10, pady=10, ipadx=10, ipady=10)

window.mainloop()

三、项目实践

利用 Tkinter 做了一个图片处理的小工具,主要功能有两个:1. 在保证图片分辨率不变的情况下进行图片压缩,使图片占用空间变小。2. 对图片的的分辨率进行调整,对图片的高和宽的进行等比例的缩放。3. 打开默认输出文件夹位置与对输出的文件夹进行清理。界面如下:

使用说明: - 图片压缩: 需要事先调整图片的压缩率(默认是 85)再点击运行。每次运行前都会清空一次默认输出文件夹,自己选择的保存路径则不会清空。 - 图片缩小: 先点击一下文件,选择单张图片,会自动显示图片的分辨率,与按照比例缩放进行后的图片的分辨率(默认50%缩放),选择好缩放比例后点击运行,会自动打开文件所在文件夹。

项目具体的代码可在 Github 仓库 uek2233/Image-Processing-Toolbox (github.com) 下载。