tkinter使用指南

Tkinter模块元素简要说明

tkinter类 元素
Button 按钮
Canvas 画布
Checkbutton 复选框
Entry 单行文本框
Frame 框架
Label 标签
LabelFrame 容器控件
Listbox 列表框
Menu 菜单
Menubutton 菜单按钮
Message 消息框
OptionMenu 选择菜单
PanedWindow 窗口布局管理
Radiobutton 单选框
Scale 进度条
Scrollbar 滚动条
Spinbox 输入控件
Text 多行文本框
Toplevel 顶层
messageBox 消息框

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种方法。

动手实践学习

创建主窗口及Label部件的创建和使用

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上设定标签
l = tk.Label(window, text='你好!this is Tkinter', bg='green', font=('Arial', 12), width=30, height=2)
# 说明: bg为背景,font为字体,width为长,height为高,这里的长和高是字符的长和高,比如height=2,就是标签有2个字符这么高

# 第5步,放置标签
l.pack() # Label内容content区域放置位置,自动调节尺寸
# 放置lable的方法有:1)l.pack(); 2)l.place();

# 第6步,主窗口循环显示
window.mainloop()
# 注意,loop因为是循环的意思,window.mainloop就会让window不断的刷新,如果没有mainloop,就是一个静态的window,传入进去的值就不会有循环,mainloop就相当于一个很大的while循环,有个while,每点击一次就会更新一次,所以我们必须要有循环

测试效果
图片

Button窗口部件

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上设定标签
var = tk.StringVar() # 将label标签的内容设置为字符类型,用var来接收hit_me函数的传出内容用以显示在标签上
l = tk.Label(window, textvariable=var, bg='green', fg='white', font=('Arial', 12), width=30, height=2)
# 说明: bg为背景,fg为字体颜色,font为字体,width为长,height为高,这里的长和高是字符的长和高,比如height=2,就是标签有2个字符这么高
l.pack()

# 定义一个函数功能(内容自己自由编写),供点击Button按键时调用,调用命令参数command=函数名
on_hit = False
def hit_me():
global on_hit
if on_hit == False:
on_hit = True
var.set('you hit me')
else:
on_hit = False
var.set('')

# 第5步,在窗口界面设置放置Button按键
b = tk.Button(window, text='hit me', font=('Arial', 12), width=10, height=1, command=hit_me)
b.pack()

# 第6步,主窗口循环显示
window.mainloop()

测试效果
图片
图片

Entry窗口部件

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上设定输入框控件entry并放置控件
e1 = tk.Entry(window, show='*', font=('Arial', 14)) # 显示成密文形式
e2 = tk.Entry(window, show=None, font=('Arial', 14)) # 显示成明文形式
e1.pack()
e2.pack()

# 第5步,主窗口循环显示
window.mainloop()

测试效果
图片

Text窗口部件

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上设定输入框控件entry框并放置
e = tk.Entry(window, show = None)#显示成明文形式
e.pack()

# 第5步,定义两个触发事件时的函数insert_point和insert_end(注意:因为Python的执行顺序是从上往下,所以函数一定要放在按钮的上面)
def insert_point(): # 在鼠标焦点处插入输入内容
var = e.get()
t.insert('insert', var)
def insert_end(): # 在文本框内容最后接着插入输入内容
var = e.get()
t.insert('end', var)

# 第6步,创建并放置两个按钮分别触发两种情况
b1 = tk.Button(window, text='insert point', width=10,
height=2, command=insert_point)
b1.pack()
b2 = tk.Button(window, text='insert end', width=10,
height=2, command=insert_end)
b2.pack()

# 第7步,创建并放置一个多行文本框text用以显示,指定height=3为文本框是三个字符高度
t = tk.Text(window, height=3)
t.pack()

# 第8步,主窗口循环显示
window.mainloop()

测试效果
图片

Listbox窗口部件

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上创建一个标签label用以显示并放置
var1 = tk.StringVar() # 创建变量,用var1用来接收鼠标点击具体选项的内容
l = tk.Label(window, bg='green', fg='yellow',font=('Arial', 12), width=10, textvariable=var1)
l.pack()

# 第6步,创建一个方法用于按钮的点击事件
def print_selection():
value = lb.get(lb.curselection()) # 获取当前选中的文本
var1.set(value) # 为label设置值

# 第5步,创建一个按钮并放置,点击按钮调用print_selection函数
b1 = tk.Button(window, text='print selection', width=15, height=2, command=print_selection)
b1.pack()

# 第7步,创建Listbox并为其添加内容
var2 = tk.StringVar()
var2.set((1,2,3,4)) # 为变量var2设置值
# 创建Listbox
lb = tk.Listbox(window, listvariable=var2) #将var2的值赋给Listbox
# 创建一个list并将值循环添加到Listbox控件中
list_items = [11,22,33,44]
for item in list_items:
lb.insert('end', item) # 从最后一个位置开始加入值
lb.insert(1, 'first') # 在第一个位置加入'first'字符
lb.insert(2, 'second') # 在第二个位置加入'second'字符
lb.delete(2) # 删除第二个位置的字符
lb.pack()

# 第8步,主窗口循环显示
window.mainloop()

测试效果
图片

Radiobutton窗口控件

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上创建一个标签label用以显示并放置
var = tk.StringVar() # 定义一个var用来将radiobutton的值和Label的值联系在一起.
l = tk.Label(window, bg='yellow', width=20, text='empty')
l.pack()

# 第6步,定义选项触发函数功能
def print_selection():
l.config(text='you have selected ' + var.get())

# 第5步,创建三个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()

# 第7步,主窗口循环显示
window.mainloop()

测试效果
图片

Checkbutton窗口部件

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上创建一个标签label用以显示并放置
l = tk.Label(window, bg='yellow', width=20, text='empty')
l.pack()

# 第6步,定义触发函数功能
def print_selection():
if (var1.get() == 1) & (var2.get() == 0): # 如果选中第一个选项,未选中第二个选项
l.config(text='I love only Python ')
elif (var1.get() == 0) & (var2.get() == 1): # 如果选中第二个选项,未选中第一个选项
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') # 如果两个选项都选中

# 第5步,定义两个Checkbutton选项并放置
var1 = tk.IntVar() # 定义var1和var2整型变量用来存放选择行为返回值
var2 = tk.IntVar()
c1 = tk.Checkbutton(window, text='Python',variable=var1, onvalue=1, offvalue=0, command=print_selection) # 传值原理类似于radiobutton部件
c1.pack()
c2 = tk.Checkbutton(window, text='C++',variable=var2, onvalue=1, offvalue=0, command=print_selection)
c2.pack()

# 第7步,主窗口循环显示
window.mainloop()

测试效果
图片

Scale窗口部件

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上创建一个标签label用以显示并放置
l = tk.Label(window, bg='green', fg='white', width=20, text='empty')
l.pack()

# 第6步,定义一个触发函数功能
def print_selection(v):
l.config(text='you have selected ' + v)

# 第5步,创建一个尺度滑条,长度200字符,从0开始10结束,以2为刻度,精度为0.01,触发调用print_selection函数
s = tk.Scale(window, label='try me', from_=0, to=10, orient=tk.HORIZONTAL, length=200, showvalue=0,tickinterval=2, resolution=0.01, command=print_selection)
s.pack()

# 第7步,主窗口循环显示
window.mainloop()

测试效果
图片

Canvas窗口部件

示例代码

from PIL import Image
from PIL import ImageTk

import tkinter as tk # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上创建 500 * 200 大小的画布并放置各种元素
canvas = tk.Canvas(window, bg='green', height=200, width=500)
# 说明图片位置,并导入图片到画布上
image_file = Image.open("/home/ltb/timg.jpeg").resize((500, 300))

image_file = ImageTk.PhotoImage(image_file)

# image_file = tk.PhotoImage(file='/home/ltb/timg.gif') # 图片位置(相对路径,与.py文件同一文件夹下,也可以用绝对路径,需要给定图片具体绝对路径)
image = canvas.create_image(250, 0, anchor='n', image=image_file) # 图片锚定点(n图片顶端的中间点位置)放在画布(250,0)坐标处
# 定义多边形参数,然后在画布上画出指定图形
x0, y0, x1, y1 = 100, 100, 150, 150
line = canvas.create_line(x0 - 50, y0 - 50, x1 - 50, y1 - 50) # 画直线
oval = canvas.create_oval(x0 + 120, y0 + 50, x1 + 120, y1 + 50, fill='white') # 画圆 用黄色填充
arc = canvas.create_arc(x0, y0 + 50, x1, y1 + 50, start=0, extent=180) # 画扇形 从0度打开收到180度结束
rect = canvas.create_rectangle(330, 30, 330 + 20, 30 + 20) # 画矩形正方形
canvas.pack()


# 第6步,触发函数,用来一定指定图形
def moveit():
canvas.move(rect, 2, 2) # 移动正方形rect(也可以改成其他图形名字用以移动一起图形、元素),按每次(x=2, y=2)步长进行移动


# 第5步,定义一个按钮用来移动指定图形的在画布上的位置
b = tk.Button(window, text='move item', command=moveit).pack()

# 第7步,主窗口循环显示
window.mainloop()

# 在一个类中创建Canvas需要把要显示再画布上的图片声明为全局变量,不然画布无法显示图片。

图像锚定点位置参数图
图片
测试效果
图片

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,在图形界面上创建一个标签用以显示内容并放置
l = tk.Label(window, text=' ', bg='green')
l.pack()

# 第10步,定义一个函数功能,用来代表菜单选项的功能,这里为了操作简单,定义的功能比较简单
counter = 0


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


# 第5步,创建一个菜单栏,这里我们可以把他理解成一个容器,在窗口的上方
menubar = tk.Menu(window)

# 第6步,创建一个File菜单项(默认不下拉,下拉内容包括New,Open,Save,Exit功能项)
filemenu = tk.Menu(menubar, tearoff=0)
# 将上面定义的空菜单命名为File,放在菜单栏中,就是装入那个容器中
menubar.add_cascade(label='File', menu=filemenu)

# 在File中加入New、Open、Save等小菜单,即我们平时看到的下拉菜单,每一个小菜单对应命令操作。
filemenu.add_command(label='New', command=do_job)
filemenu.add_command(label='Open', command=do_job)
filemenu.add_command(label='Save', command=do_job)
filemenu.add_separator() # 添加一条分隔线
filemenu.add_command(label='Exit', command=window.quit) # 用tkinter里面自带的quit()函数

# 第7步,创建一个Edit菜单项(默认不下拉,下拉内容包括Cut,Copy,Paste功能项)
editmenu = tk.Menu(menubar, tearoff=0)
# 将上面定义的空菜单命名为 Edit,放在菜单栏中,就是装入那个容器中
menubar.add_cascade(label='Edit', menu=editmenu)

# 同样的在 Edit 中加入Cut、Copy、Paste等小命令功能单元,如果点击这些单元, 就会触发do_job的功能
editmenu.add_command(label='Cut', command=do_job)
editmenu.add_command(label='Copy', command=do_job)
editmenu.add_command(label='Paste', command=do_job)

# 第8步,创建第二级菜单,即菜单项里面的菜单
submenu = tk.Menu(filemenu) # 和上面定义菜单一样,不过此处实在File上创建一个空的菜单
filemenu.add_cascade(label='Import', menu=submenu, underline=0) # 给放入的菜单submenu命名为Import

# 第9步,创建第三级菜单命令,即菜单项里面的菜单项里面的菜单命令(有点拗口,笑~~~)
submenu.add_command(label='Submenu_1', command=do_job) # 这里和上面创建原理也一样,在Import菜单项中加入一个小菜单命令Submenu_1

# 第11步,创建菜单栏完成后,配置让菜单栏menubar显示出来
window.config(menu=menubar)

# 第12步,主窗口循环显示
window.mainloop()

测试效果
图片

Frame窗口部件

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x
 
# 第4步,在图形界面上创建一个标签用以显示内容并放置
tk.Label(window, text='on the window', bg='red', font=('Arial', 16)).pack()   # 和前面部件分开创建和放置不同,其实可以创建和放置一步完成
 
# 第5步,创建一个主frame,长在主window窗口上
frame = tk.Frame(window)
frame.pack()
 
# 第6步,创建第二层框架frame,长在主框架frame上面
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')
 
# 第7步,创建三组标签,为第二层frame上面的内容,分为左区域和右区域,用不同颜色标识
tk.Label(frame_l, text='on the frame_l1', bg='green').pack()
tk.Label(frame_l, text='on the frame_l2', bg='green').pack()
tk.Label(frame_l, text='on the frame_l3', bg='green').pack()
tk.Label(frame_r, text='on the frame_r1', bg='yellow').pack()
tk.Label(frame_r, text='on the frame_r2', bg='yellow').pack()
tk.Label(frame_r, text='on the frame_r3', bg='yellow').pack()
 
# 第8步,主窗口循环显示
window.mainloop()

测试效果
图片

messageBox窗口部件

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入
import tkinter.messagebox  # 要使用messagebox先要导入模块
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x
 
# 第5步,定义触发函数功能
def hit_me():
    tkinter.messagebox.showinfo(title='Hi', message='你好!')              # 提示信息对话窗
    # tkinter.messagebox.showwarning(title='Hi', message='有警告!')       # 提出警告对话窗
    # tkinter.messagebox.showerror(title='Hi', message='出错了!')         # 提出错误对话窗
    # print(tkinter.messagebox.askquestion(title='Hi', message='你好!'))  # 询问选择对话窗return 'yes', 'no'
    # print(tkinter.messagebox.askyesno(title='Hi', message='你好!'))     # return 'True', 'False'
    # print(tkinter.messagebox.askokcancel(title='Hi', message='你好!'))  # return 'True', 'False'
 
# 第4步,在图形界面上创建一个标签用以显示内容并放置
tk.Button(window, text='hit me', bg='green', font=('Arial', 14), command=hit_me).pack()
 
# 第6步,主窗口循环显示
window.mainloop()

测试效果
图片

窗口部件三种放置方式 pack/grid/place

pack

按上下左右的方式排列

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,pack 放置方法
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') # 右

# 第5步,主窗口循环显示
window.mainloop()

测试效果
图片

grid

所有的内容会被放在这些规律的方格中

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x

# 第4步,grid 放置方法
for i in range(3):
for j in range(3):
tk.Label(window, text=1).grid(row=i, column=j, padx=10, pady=10, ipadx=10, ipady=10)

# 第5步,主窗口循环显示
window.mainloop()

测试效果
图片

place

给精确的坐标来定位

示例代码

import tkinter as tk  # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x
 
# 第4步,place 放置方法(精准的放置到指定坐标点的位置上)
tk.Label(window, text='Pl', font=('Arial', 20), ).place(x=50, y=100, anchor='nw')
 
# 第5步,主窗口循环显示
window.mainloop()

测试效果
图片

Tkinter布局之pack

我们使用pack函数的时候,默认先使用的放在上面,然后依次向下排,它会给我们的部件一个自认为合适的位置和大小,这是默认方式。

side 按钮停靠的位置

left:左
top:上
right:右
bottom:下

fill 填充

x:水平方向填充
y:竖直方向填充
both:水平和竖直方向填充
none:不填充

expand 扩展

yes:扩展整个空白区
no:不扩展

部件消除

示例代码

# 销毁上一个布局的frame及其部件
# 先销毁frame下的部件,再销毁frame
for widget in self.last_frame.winfo_children():
widget.destroy()
self.last_frame.destroy()

多线程按钮部件

示例代码

# 打开摄像头
button_open_camera = tk.Button(self.frame_3, text="打开摄像头", height=3, command=self.camera_threading)
button_open_camera.pack(side="top", fill="x")

# 关闭摄像头
button_close_camera = tk.Button(self.frame_3, text="关闭摄像头", height=3, command=self.close_camera)
button_close_camera.pack(side="top", fill="x")

# 线程函数
def camera_threading(self):
self.thread = threading.Thread(target=self.open_camera)
self.thread.setDaemon(True)
self.thread.start()

# 打开摄像头函数,被线程函数调用
def open_camera(self):
try:
cap = cv2.VideoCapture(0)
self.thread_flag = True
while(self.thread_flag):

ret, frame = cap.read()
cv2.imshow("video", frame)
cv2.imwrite(self.temporary_path, frame)

if ret != True:
break

c = cv2.waitKey(60)
if c == 27:
break

cv2.destroyAllWindows()
cap.release()
except:
messagebox.showerror(title="读取视频出错", message="读取出错或未检测到usb摄像头")

# 关闭摄像头函数,用全局变量控制
def close_camera(self):
self.thread_flag = False
os._exit(0)

第一个Tkinter程序

from PIL import Image
from PIL import ImageTk

import tkinter as tk
from tkinter import filedialog, messagebox

import threading

import cv2

import os
import shutil
from datetime import datetime


class AppUI():

def __init__(self):
# 全局变量
self.first = True
self.last_frame = None
self.thread_flag = False
self.temporary_path = "/mnt/tkinter_pj1/temporary_picture.jpg"
self.database = "/mnt/tkinter_pj1/Images/all"

# 存线程实例
self.thread_obj = []

# 创建窗口
self.window = tk.Tk()
self.window.title("手术器械自动识别系统")
self.window.geometry("500x200") # 参数
self.main_menu()
self.main_layout()

self.window.mainloop()


# 主菜单
def main_menu(self):
self.menu_bar = tk.Menu(self.window)
self.start_menu = tk.Menu(self.menu_bar, tearoff=0)
self.menu_bar.add_cascade(label="开始", menu=self.start_menu)

self.start_menu.add_command(label="首页", command=self.main_layout)
self.start_menu.add_command(label="单张图像预测", command=self.layout_2)
self.start_menu.add_command(label="实时图像检测", command=self.layout_3)
self.start_menu.add_command(label="图像采集", command=self.layout_4)

self.window.config(menu=self.menu_bar)

def main_layout(self):

if self.first == False:
# 销毁上一个layout的frame及其控件
for widget in self.last_frame.winfo_children():
widget.destroy()
self.last_frame.destroy()
self.window.geometry("500x200")

self.first = False
self.main_frame = tk.Frame(self.window)
self.main_frame.pack(expand="yes", fill="both")
self.last_frame = self.main_frame

label_main_frame_title = tk.Label(self.main_frame, text='欢迎来到手术器械自动识别系统', font=('Arial', 17), height=3)
label_main_frame_title.pack(side="top", fill="both")

# 三个button
button_single_predict = tk.Button(self.main_frame, text='单张图像识别', font=('Arial', 15), width=10, height=3, command=self.layout_2)
button_single_predict.pack(side="left", expand="yes", fill="both")
button_realtime_predict = tk.Button(self.main_frame, text="实时图像识别", font=('Arial', 15), width=10, height=3, command=self.layout_3)
button_realtime_predict.pack(side="left", expand="yes", fill="both")
button_catch_picture = tk.Button(self.main_frame, text="图像采集", font=('Arial', 15), width=10, height=3, command=self.layout_4)
button_catch_picture.pack(side="left", expand="yes", fill="both")

def layout_2(self):

# 销毁上一个layout的frame及其控件
for widget in self.last_frame.winfo_children():
widget.destroy()
self.last_frame.destroy()
self.window.geometry("800x555")

# 创建frame_2
self.frame_2 = tk.Frame(self.window)
self.frame_2.pack(expand="yes", fill="both")
self.last_frame = self.frame_2

label_frame_2_title = tk.Label(self.frame_2, text='单张图像识别', font=('Arial', 15), height=3, width=30)
label_frame_2_title.pack(side="top")

# 显示图片
self.canvas = tk.Canvas(self.frame_2, height=480, width=640)
self.canvas.pack(side="left")

# 选择路径
button_picture_path = tk.Button(self.frame_2, text="选择路径", height=3, command=self.select_picture_path)
button_picture_path.pack(side="top", fill="x")

# 路径
label_picture_path = tk.Label(self.frame_2, text="图片路径", height=3)
label_picture_path.pack(side="top", fill="x")

self.entry_picture_path = tk.Entry(self.frame_2, show=None)
self.entry_picture_path.pack(side="top", fill="x")

self.entry_predict_result = tk.Entry(self.frame_2, show=None)
self.entry_predict_result.pack(side="bottom", fill="x")

button_predict_picture = tk.Button(self.frame_2, text="图片预测", height=3, command=self.predict_picture)
button_predict_picture.pack(side="bottom", fill="x")

def layout_3(self):

# 销毁上一个layout的frame及其控件
for widget in self.last_frame.winfo_children():
widget.destroy()
self.last_frame.destroy()
self.window.geometry("800x555")

self.frame_3 = tk.Frame(self.window)
self.frame_3.pack(expand="yes", fill="both")
self.last_frame = self.frame_3

label_frame_3_title = tk.Label(self.frame_3, text='实时图像识别', font=('Arial', 15), height=3, width=30)
label_frame_3_title.pack(side="top")

# 显示图片
self.canvas = tk.Canvas(self.frame_3, height=480, width=640)
self.canvas.pack(side="left")

# 打开摄像头
button_open_camera = tk.Button(self.frame_3, text="打开摄像头", height=3, command=self.camera_threading)
button_open_camera.pack(side="top", fill="x")

# 关闭摄像头
button_close_camera = tk.Button(self.frame_3, text="关闭摄像头", height=3, command=self.close_camera)
button_close_camera.pack(side="top", fill="x")

self.entry_realtime_result = tk.Entry(self.frame_3, show=None)
self.entry_realtime_result.pack(side="bottom", fill="x")

button_realtime_prediction = tk.Button(self.frame_3, text="实时检测", height=3, command=self.realtime_prediction)
button_realtime_prediction.pack(side="bottom", fill="x")


def layout_4(self):

# 销毁上一个layout的frame及其控件
for widget in self.last_frame.winfo_children():
widget.destroy()
self.last_frame.destroy()
self.window.geometry("800x555")

self.frame_4 = tk.Frame(self.window)
self.frame_4.pack(expand="yes", fill="both")
self.last_frame = self.frame_4

label = tk.Label(self.frame_4, text='图像采集', font=('Arial', 15), width=30, height=3)
label.pack(side="top")

# 显示图片
self.canvas = tk.Canvas(self.frame_4, height=480, width=640)
self.canvas.pack(side="left")

# 打开摄像头
button_open_camera = tk.Button(self.frame_4, text="打开摄像头", height=3, command=self.camera_threading)
button_open_camera.pack(side="top", fill="x")

# 关闭摄像头
button_close_camera = tk.Button(self.frame_4, text="关闭摄像头", height=3, command=self.close_camera)
button_close_camera.pack(side="top", fill="x")

button_picture_capture = tk.Button(self.frame_4, text="图片采集", height=3, command=self.picture_capture)
button_picture_capture.pack(side="bottom", fill="x")

self.entry_input_label = tk.Entry(self.frame_4, show=None, text="")
self.entry_input_label.pack(side="bottom", fill="x")

label_input_label = tk.Label(self.frame_4, text="输入类别")
label_input_label.pack(side="bottom", fill="x")

def select_picture_path(self):
self.pic_path = filedialog.askopenfilename()

self.entry_picture_path.delete(0, "end")
self.entry_picture_path.insert(0, self.pic_path)

self.show_picture(self.pic_path)


def show_picture(self, path):
try:
self.picture = Image.open(path).resize((640, 480))
self.picture = ImageTk.PhotoImage(self.picture)
self.canvas.create_image(0, 0, anchor="nw", image=self.picture)
except:
messagebox.showerror(title="路径错误", message="路径输入错误或选中文件不是图片")

def open_camera(self):
try:
cap = cv2.VideoCapture(0)
self.thread_flag = True
while(self.thread_flag):

ret, frame = cap.read()
cv2.imshow("video", frame)
cv2.imwrite(self.temporary_path, frame)

if ret != True:
break

c = cv2.waitKey(60)
if c == 27:
break

cv2.destroyAllWindows()
cap.release()
except:
messagebox.showerror(title="读取视频出错", message="读取出错或未检测到usb摄像头")

def close_camera(self):
self.thread_flag = False
os._exit(0)

def realtime_prediction(self):
self.show_picture(self.temporary_path)
pass

def predict_picture(self):
self.entry_predict_result.delete(0, "end")
self.entry_predict_result.insert(0, 0)
pass

def picture_capture(self):
content = self.entry_input_label.get()
if len(content) > 0:
time_stamp = '{:%Y-%m-%d-%H-%M-%S}'.format(datetime.now())
sub_class_folder = os.path.join(self.database, str(self.entry_input_label.get()))
if not os.path.exists(sub_class_folder):
os.mkdir(sub_class_folder)
image_store_path = os.path.join(sub_class_folder,
'{}_{}.jpg'.format(str(self.entry_input_label.get()), time_stamp))
if self.thread_flag:
self.show_picture(self.temporary_path)
shutil.copy(self.temporary_path, image_store_path)
messagebox.showinfo(title="成功", message="成功保存图片")
else:
messagebox.showwarning(title="警告", message="未打开摄像头")
else:
messagebox.showwarning(title="警告", message="请输入类别号")

def camera_threading(self):
self.thread = threading.Thread(target=self.open_camera)
self.thread.setDaemon(True)
self.thread.start()

if __name__ == "__main__":

app = AppUI()

pyinstaller 打包

# 安装pyinstall
sudo pip3 install pyinstaller

# 切换到需要打包的目录,执行
pyinstaller -F -W GUI.py
# -F: 只生成耦合可执行的文件
# -W: 表示窗口,无控制台
# 生成的可执行文件就在目录dist中

# 修改图标
-i icon.ico 或者 --icon.ico
# 图片放在需要打包的文件同目录中

参考

本文参考以下网站、博客
http://www.cnblogs.com/shwee/p/9427975.html
https://blog.csdn.net/yingshukun/article/details/78838395
http://www.cnblogs.com/kongzhagen/p/6144588.html

Author: pangzibo243
Link: https://litianbo243.github.io/2019/08/05/Tkinter使用指南/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
支付宝打赏
微信打赏