【Tkinter 入门教程】
1. Tkinter库的简介:
Tkinter是Tk GUI工具包的Python绑定包。它是Tk GUI工具包的标准Python接口,并且是Python的业界标准GUI工具包。Tkinter同时也包含在Python的Linux、Microsoft Windows和Mac OS X标准库中。Tkinter的名字来自Tk interface。
- 若在命令行执行
python -m tkinter
,应会弹出一个简单的 Tk 界面窗口, 表明 tkinter 包已安装完成,还会显示当前安装的 Tcl/Tk 版本,以便阅读对应版本的 Tcl/Tk 文档。Python=3.8.10
- Tkinter 支持众多的 Tcl/Tk 版本,带或不带多线程版本均可。官方的 Python 二进制版本捆绑了 Tcl/Tk 8.6多线程版本。关于可支持版本的更多信息,请参阅 _tkinter 模块的源代码。
- Tkinter 并不只是做了简单的封装,而是增加了相当多的代码逻辑,让使用体验更具 Python 风格(pythonic)。本文将集中介绍这些增加和变化部分,关于未改动部分的细节,请参考 Tcl/Tk 官方文档。
tkinter 的介绍 : http://en.wikipedia.org/wiki/tkinter
TkDocs:TkDocs Home
tkinter命令:https://www.tcl.tk/man/tcl8.6/TkCmd/contents.html
1.1 GUI编程
- 如果有过 C 或者 Python等语⾔的编程经验,开发GUI界面手到擒来,在 Python ⾥⾯这种⼯具并不多,这也是和 Python 是⼀个脚本语⾔有关。
- 要说 tkinter,先说 tk,它原本是 Tcl 编程语⾔的界⾯库, 后来开发出了Python 接⼝,Tkinter 在 Python2 和 Python3 中的变化较⼤,在 Python2 中叫做 Tkinter,在 Python3 中叫做 tkinter,⽽且在导⼊类库的时候也有些许的变化,请读者稍加注意。
1.2 Tkinter的定位
- 掌握⼀⻔ Python 的界 ⾯编程也很有意思。有时候我们需要⼀些界⾯程序,但是⼜不想⽤那些庞⼤ ⽽繁杂的类库的时候,tkinter 的优势就显现出来了,那就是简洁简单。💕💕💕
- 我感觉 tkinter 是⼀个还不错的界⾯库,但是我感觉 Python 并不是特别擅⻓复杂的应⽤(🐧🐧🐧🐧麻雀虽小五脏俱全🐧🐧🐧),⽽且我感觉⽐如 wxPython 或者 pyQt 等更胜⼀筹,但是不管怎么样,我们可以通过Python⾃带的tkinter,进⼊GUI编程的世界。🎉🎉🎉
- 鹏鹏只用两周就完成项目啦!相信接下来可以帮助你😘😘😘
2. Hello word! 程序起飞
2.1 第⼀个程序
我们新建⼀个⽆格式的⽂本⽂件,通常是.txt ⽂件,然后修改名称为 Hello_World.py
,然
后⽤⽂本编辑器打开,然后写三⾏代码。
#导入Tkinter模块,并用别名tk引用它。
import tkinter as tk
#定义一个函数say_hello,当按钮被点击时,这个函数会被调用。 这个函数会更新标签(label)的文本为"Hello World!"。
def say_hello():
label.config(text="Hello World!")
#创建一个顶级窗口(root window),这是整个GUI程序的基础。
root = tk.Tk()
#创建一个标签(Label),设置其初始文本为"Click the button to say hello!",并将其添加到根窗口中。
label = tk.Label(root, text="Click the button to say hello!")
label.pack()
#pack()方法用于将控件放置在父容器中,并自动调整它们的大小和位置。
#创建一个按钮(Button),设置其文本为"SAY Hello",并将其命令属性设置为say_hello函数。这意味着当用户点击此按钮时,say_hello函数将被调用。
button = tk.Button(root, text="Say Hello", command=say_hello)
button.pack()
#最后,进入主循环。在此过程中,程序会持续监听用户的操作,如点击按钮等,并作出相应的响应。
root.mainloop()
总结起来,这个程序会在屏幕上显示一个窗口,其中包含一个标签和一个按钮。当用户点击Say Hello
按钮时,标签上的文本会变为"Hello World!"。
2.2 字体颜色主题
要设置不同的字体颜色主题,可以使用font属性为标签和按钮设置自定义的字体颜色。下面是一个示例,演示如何将文本颜色设置为红色:
import tkinter as tk
def say_hello():
label.config(text="Hello World!")
root = tk.Tk()
# 创建一个自定义的字体对象,设置其大小
custom_font = ('Arial', 14, 'bold')
#设置背景填充颜色
label = tk.Label(root, text="Click the button to say hello!", font=custom_font, bg = 'red')
label.pack()
button = tk.Button(root, text="Say Hello", command=say_hello, font=custom_font, bg = 'red')
button.pack()
root.mainloop()
在这个例子中,我们创建了一个名为custom_font的自定义字体对象,设置了字体名称(‘Arial’)、大小(14)、粗体样式(‘bold’)和背景颜色(‘red’)。然后,我们将这个自定义字体应用到标签和按钮上。
字体名称 | 大小 | 粗体样式 | 颜色 |
---|---|---|---|
Arial 、 宋体 | 1~100 | bold | red 、green 、blue |
您也可以根据需要更改字体颜色和其他属性。例如,您可以创建多个不同的自定义字体对象,用于表示不同的颜色主题,并在程序运行时动态地切换它们。
3. 组件讲解
3.1 tkinter 的核⼼组件
- 在 tkinter 中,有 21 个核⼼组件,它们提供 了GUI开发的完整功能,因为使⽤频率较⾼。
- 这 21 个核⼼组件是 : Label、Button、Entry、Menu、 Radiobutton 、Checkbutton、Text、Image、Canvas、Frame、LabelFrame、Toplevel、 Listbox、Menubutton、Message、OptionMenu、PaneWindow 、 Scale 、Scrollbar 、Spinbox、Bitmap。
3.2 组件的使⽤
- 各个组件都有相应的类,我们可以通过⾯向对象的⽅式 去使⽤它们。
- 这些组件的使⽤也很相似,在实例化这些组件的时候, 第⼀个参数都是⽗窗⼝或者⽗组件,后⾯跟着的就是该组 件的⼀些属性,⽐如上⾯我们学到的 Label 的 text属性和 background 属性。
- 多个组件的位置控制⽅式也很相似,我们可以⽤ pack ⽅法来进⾏简单的布局,具体的个例我们后⾯再说。
- 组件也会有些⽅法是共⽤的,⽐如 configure ⽅法来设置属性等等。
3.3 标签Label
标签就是输出显示信息可动态也可静态✨✨✨
3.3.1 标签显示内容
- 所谓 标签 ,就是贴在物品前⾯的⼀个简短的说明, 它⽤于说明⼀些⽂字信息。
- 标签可以说是最简单的窗⼝组件了,它不需要执⾏任何功能,只是⽤来显示信息。
- 下⾯是代码示例:
from tkinter import *
root = Tk()
root.wm_title("这是⼀个Tkinter程序窗⼝标题")
wl= Label(root, text = "欢迎来到tkinter")
wl.pack()
root.mainloop()
代码分析
- 这⾥的 Label 是⼀个类,可以在 init.py ⽂件⾥查看 相应的源代码。
- wl 是⼀个 Label 的实例,它有⼀个 text 属性 ,⽤来指定 它的⽂本内容。
- ⼤家可以看到它的标准属性,⽐如有 background , font , bitmap , padx ,relief 等等, 还有 underline 等等。
- 该类有个 pack ⽅法,没错,这个 pack ⽅法我们后⾯会 讲,⼤家可以理解为它的作⽤就是找个合适的位置进⾏放置即可,即 pack() 之后就选定位置放上去了。
- 这⾥的初始化的时候,需要先指定 root,是说 wl 这个组 件是在 root 这个窗⼝的,不是属于别的窗⼝的,以后我们 有了多窗⼝的应⽤程序,不会混淆。
Widget 类
-
我们上⾯发现,Label 类是继承⾃ Widget 类的,并且⾃ ⼰只有⼀个⽅法,就是⽤来
初始化⾃身的,那么要想彻底 理解 Label,就必须彻底理解 Widget。 -
我们找到了 Widget 的代码,发现它更加短⼩,甚⾄连个 ⽅法都没有,下⾯是
Widget 的截图:
-
通过这个注释,我们可以理解如下:它是⼀个可以指定 位置并且可以使⽤
pack , place 和 grid 来布局管理的窗⼝ 组件。 -
然后我们找到 BaseWidget ,发现它的代码也很短⼩,代 码截图如下:
-
该类继承⾃ Misc ,包含了四个函数,函数的功能通过名 字就可以知道了。⾄于Misc类,我们后⾯会讲解的。Misc其实是英⽂ Miscellaneous 的前四个字⺟,杂项、混合体、⼤杂烩的意思。在软件⾥经常可以看到与misc相关的⽂件或函数名,使⽤misc来命名主要是表示该⽂件⽬前还没归类好,不知道将它归到哪个⽅⾯或者放置在哪个地⽅⽐较好,所以暂时⽤misc。
3.3.2 多标签的应⽤程序
- 如果我们想要多个标签,该怎么办呢?
- 很简单,只需要声明多个标签的实例,然后分别 pack 到 窗⼝上即可。
from tkinter import *
root = Tk()
root.wm_title("这是⼀个Tkinter程序窗⼝标题")
w1 = Label(root, text = "欢迎来到tkinter教程!", background = "white")
w2 = Label(root, text = "好好学习,天天向上!", background = "green")
w3 = Label(root, text = "轻松愉快,就选Python!", background = "red")
w1.pack()
w2.pack()
w3.pack()
root.mainloop()
3.3.3 总结
- 我们这⼀节学习了 Label 这个组件,它的创建使⽤ Label 这个类,实例化的时候⾸
先要指定它的⽗窗⼝,然后就是 ⽤字典的⽅式设置⾃⼰的⼀些特征,这些特征上⾯
都列出 了,但是没有实例演示。 - 然后使⽤ pack() ⽅法布局上去,关于布局,我们后⾯会详 细讲,这⾥我们统⼀使⽤
pack() 就可以了。
3.4 按钮Button
- 按钮也是⾮常重要的组件, 按钮的重要性在于它可以执⾏相应 的功能。
- 按钮的英⽂表述是 button ,它随处可⻅,当我们单 击的时候,它可以执⾏相应的功能。
- 按钮在 tkinter 中有⼀个类专⻔负责它,叫做 Button ,该类也⾮常简短。
3.4.1 按钮与功能的绑定
- 上⽂说到,按钮可以执⾏相应的功能,这⾥的功能我们 可以理解为⼀个函数,或者这些功能通过相应的函数去实 现。
- 绑定⽅式通常有如下⼏种:第⼀种,在按钮组件被声明 的时候⽤ command 属性声明, command 属性接受⼀个函数名, 注意函数名不要加双引号。第⼆种,使⽤ bind⽅法,该⽅ 法是 Misc 这个类的⼀个⽅法,下⾯我们仔细讲解。
3.4.2 第⼀种⽅法绑定事件
我们要完成的功能是我们按下这个按钮的时候,就会在 窗⼝上增加⼀个 Label,它显示“我爱 python”。
from tkinter import *
def myLabel():
global py, i
s = Label(py, text = "轻松愉快,就选Python! 重要的事情说 %d 遍!" % i)
s.pack()
i+=1 # 每次点击后,i的值会⾃增1
py = Tk()
i = 1 # 全局变量i 初始化为 1
b = Button(py, text = "Python", command = myLabel)
b.pack()
py.mainloop()
运⾏结果:(⼀开始是只有⼀个按钮的,点击⼀下,就会在这个窗⼝上多⼀个标签,下⾯是我点击了三次之后的截图):
代码解读
- 其实很简单,这⾥只需要注意 command 属性后⾯不要加任何的标点符号。
- 这⾥的 myLabel 函数中,使⽤了全局的 py 和 i 变量,需要注意。
3.4.3 第⼆种⽅式绑定事件
下⾯使⽤第⼆种⽅式来绑定事件,这个事件完成同样的功能。
from tkinter import *
# method 1
# def myLabel():
# method 2
def myLabel(event):
global py, i
s = Label(py, text = "轻松愉快,就选Python! 重要的事情说 %d 遍!" % i)
s.pack()
i+=1 # 每次点击后,i的值会⾃增1
py = Tk()
i = 1 # 全局变量i 初始化为 1
# method 1
# b = Button(py, text = "Python", command = myLabel)
# method 2
b = Button(py, text = "Python") # command = myLabel ⽊有了
b.bind("<Button-1>", myLabel) # 多了这⼀句
b.pack()
py.mainloop()
和第⼀种⽅法的结果⼀样
代码解读:
- bind这个⽅法是在 Misc 类中的,可以接受三个参数,但是本例中我们只传递了两个参数。
- 第⼀个参数可能对刚使⽤它的⼈来说有点复杂,常⻅的⿏标左键单击如下: <Button1> (也就是上⾯的代码⽤到的),或者 等。
- 第⼆个参数可以是⼀个函数名,记住,不要加任何的标 点符号,否则运⾏时会报错的。
- 使⽤ bind 函数的时候,第⼆个参数是⼀个函数名,该函数必须接受⼀个参数,即表示该事件。 这个参数通常⽤ event 来表示,如果我们调⽤的函数不接 受任何参数,则会报错如下 : TypeError: myLabel() takes no arguments
(1 given)
bind的第⼀个参数是⽤字符串包含的事件类型,它采⽤的描述⽅式是: <MODIFIER-MODIFIER-TYPE-DETAIL>
- 这⾥的 MODIFIER 即键盘或者⿏标修饰符,它的全部取值如下: Control, Mod2,M2, Shift, Mod3, M3, Lock, Mod4, M4, Button1, B1, Mod5, M5, Button2, B2, Meta, M, Button3,B3, Alt, Button4, B4, Double,Button5, B5 Triple , Mod1, M1
- TYPE 表示类型,它的全部取值如下: Activate, Enter, Map, ButtonPress,Button, Expose, Motion, ButtonRelease, FocusIn, MouseWheel,Circulate, FocusOut, Property, Colormap, Gravity Reparent, Configure,KeyPress, Key, Unmap, Deactivate, KeyRelease Visibility, Destroy,Leave
- DETAIL 表示细节,其实也就是对第⼆个参数的⼀些辅助说明。
3.4.4 设置属性
下⾯我们可以设置⼀些属性,这些东⻄随着⼤量的代码示例,⼤家会接触不少的。
⽐如我们可以设置背景⾊,这⾥直接设置属性,代码截 图:
from tkinter import *
py = Tk()
b1 = Button(py, text = "tkinter教程")
b1["width"] = 20
b1["height"] = 6
b1.pack()
b2 = Button(py, text = "Python学院")
b2["width"] = 40
b2["background"] = "white"
b2.pack()
py.mainloop()
3.4.5 总结
- 关于按钮,我们重点理解的就是它如何和事件进⾏绑定的。
- 当然,使⽤⼀些其他属性来美化按钮也很重要。
- 下⾯要讲⼀讲布局⽅⾯的东⻄了。
3.5 输⼊框Entry
3.5.1 输⼊框的重要性
应⽤程序要取得⽤户的信息,输⼊框是必不可少的,虽然执⾏命令可以使⽤按钮,但是总不能让⽤户⼀直点击按钮吧。
- 输⼊框是 Entry,可以阅读它的源代码。
- 源代码截图:
- ⽐较重要的也就是get 函数,get 函数使⽤的时候不需要任何参数,它的返回值就是该输⼊框的内容。
3.5.2 密码框
代码:
from tkinter import *
def reg():
myAccount = a_entry.get() # 获取⽤户输⼊的⽤户名
myPassword = p_entry.get() # 获取⽤户输⼊的密码
a_len = len(myAccount) # 获取输⼊的⽤户名⻓度
p_len = len(myPassword) # 获取输⼊的密码⻓度
if myAccount == "qq_group" and myPassword == "945348278":
msg_label["text"] = "登录成功" # ⽤户名和密码全部正确
elif myAccount == "qq_group" and myPassword != "945348278":
msg_label["text"] = "密码错误" # ⽤户名正确密码错误
p_entry.delete(0, p_len)
else:
msg_label["text"] = "⽤户名错误" # ⽤户名错误
a_entry.delete(0, a_len)
p_entry.delete(0, p_len)
root = Tk()
# ⽤户名
a_label = Label(root, text = "⽤户名:")
a_label.grid(row = 0, column = 0, sticky = W)
a_entry = Entry(root)
a_entry.grid(row = 0, column = 1, sticky = E)
# 密码
p_label = Label(root, text = "密码:")
p_label.grid(row = 1, column = 0, sticky = W)
p_entry = Entry(root)
p_entry["show"] = "*" # 密码显示为 *
p_entry.grid(row = 1, column = 1, sticky = E)
# 登录按钮
btn = Button(root, text = "登录", command = reg)
btn.grid(row = 2, column = 1, sticky = E)
# 提示信息
msg_label = Label(root, text = "")
msg_label.grid(row = 3)
root.mainloop()
-
其实密码框和输⼊框基本是⼀样的,都是向⾥⾯输⼊信 息⽤的。
-
如果要说不⼀样,也就⼀个地⽅不⼀样:密码框需要输 ⼊的信息的显示字符⽐较单⼀。
-
⽐如 e 是⼀个输⼊框,我们可以设置它的 show 属性让它 变成⼀个密码框,即 e[‘show’] = ‘*’ 就可以了。
-
下⾯是⼀个⼩型登录程序,它的⽤户名是
qq_group
,密码是945348278
,如果输⼊正确,那么点击“登录”按钮之后,就会显 示“登录成功”,如果输⼊不符合,那么就会显示“⽤户 名或者密码错误”,并且清空两个输⼊框。 -
运⾏结果:
-
输⼊正确的⽤户名和密码,显示
登录成功
:
-
输⼊错误的⽤户名或密码,显示
⽤户名错误
或密码错误
:
3.6 菜单Menu
- 菜单的信息量是⾮常⼤的,给用户提供导航使用,由于菜单⼜可以有⼦菜单,因此菜单的信息量⾮常⼤。
- 菜单的分类也较多,通常可以分为下拉菜单、弹出菜单 等等。
3.6.1 添加顶层菜单
- 我们可以使⽤ Menu 类来新建⼀个菜单, Menu 和其他的组件⼀样,第⼀个是parent ,这⾥通常可以为窗⼝。
- 然后我们可以⽤ add_commmand ⽅法来为它添加菜单项, 如果该菜单是顶层菜单,则添加的菜单项依次向右添加。 如果该菜单时顶层菜单的⼀个菜单项,则它添加的是
下拉 菜单的菜单项。 - add_command 中的参数常⽤的有 label 属性,⽤来指定的 是菜单项的名称, command属性⽤来指定被点击的时候调⽤ 的⽅法, acceletor 属性指定的是快捷键, underline 属性 是是否拥有下划线。
- 最后可以⽤窗⼝的 menu 属性指定我们使⽤哪⼀个作为它 的顶层菜单。
3.6.2 代码演练
- 这⾥只是做出了顶级菜单,它们四个是并列的⼀⾏,并 没有实现什么功能,效果图如下:
- 下⾯是代码演示:
from tkinter import *
root = Tk()
menuBar = Menu(root)
for item in ["⽂件", "编辑", "视图", "关于"]:
menuBar.add_command(label = item)
root["menu"] = menuBar
root.mainloop()
- 可以看到,⾮常简单的⽅式,我们使⽤ add_command 来 添加菜单项即可。
3.6.3 有⼦菜单的情况
- 如果有⼦菜单,则情况稍微复杂点,这个时候,我们需 要使⽤ add_cascade ,cascade 可以理解为“级联”,即它 的作⽤只是为了引出后⾯的菜单。
- add_cascade 的⼀个很重要的属性就是 menu 属性,它指 明了要把那个菜单级联到该
菜单项上,当然,还必不可少 的就是 label 属性,⽤于指定该菜单项的名称。 - 我们先新建⼀个 Menu 的实例,然后使⽤ add_command 来 添加菜单项,这样等该菜单
建⽴完毕,我们要把它作为另 ⼀个菜单项的⼦菜单,就需要使⽤ add_cascade ⽅法。
3.6.4 代码演练
- 下⾯我们使⽤了下拉菜单,这也是我们通常使⽤的菜单 形式,即⼀⾏菜单项,点击之后会产⽣⼀个下拉菜单。
- 效果
- 代码演示:
from tkinter import *
root = Tk()
menuBar = Menu(root)
fMenu = Menu(menuBar) # ⽂件
for item in ["新建", "打开", "保存", "另存为", "退出"]:
fMenu.add_command(label = item)
eMenu = Menu(menuBar) # 编辑
for item in ["复制", "粘贴", "剪切", "撤销"]:
eMenu.add_command(label = item)
vMenu = Menu(menuBar) # 视图
for item in ["默认视图", "全屏模式", "显示/隐藏菜单"]:
vMenu.add_command(label = item)
aMenu = Menu(menuBar) # 关于
for item in ["版权信息", "帮助⽂档"]:
aMenu.add_command(label = item)
menuBar.add_cascade(label = "⽂件", menu = fMenu)
menuBar.add_cascade(label = "编辑", menu = eMenu)
menuBar.add_cascade(label = "视图", menu = vMenu)
menuBar.add_cascade(label = "关于", menu = aMenu)
root["menu"] = menuBar
root.mainloop()
这⾥要注意的是我们可以先把⼦菜单做好,然后再做上层菜单。
3.6.5 弹出菜单
- 弹出菜单⼜叫“上下⽂菜单”,也叫“右键菜单”,它 通常是⿏标单击右键产⽣的菜单,因此会有“右键菜单” 的说法。
- 其实很多界⾯库⾥⾯都是给出了弹出菜单的简单的制作 ⽅法的,但是 tkinter ⾥⾯我们却只能使⽤⽐较原始的事 件绑定的⽅式去做。
- ⼤体思路就是:我们先新建⼀个菜单,然后向菜单项中 添加各种功能,最后我们监听⿏标右键消息,如果是⿏标 右键被单击,此时可以根据需要判断下⿏标位置来确定是 哪个弹出菜单被弹出,然后使⽤ Menu 类的 pop ⽅法来弹出 菜单。
- ⼤体思路就是如此,⾄于具体的细节,让我们到代码实 战中⼀探究竟。
- Menu 类⾥⾯有⼀个 post ⽅法,它接收两个参数,即 x 和 y 坐标,它会在相应的位置弹出菜单。
- 还记得⽤ bind ⽅法来绑定事件吗?⽽且要记得⿏标右键 是⽤的
3.6.6 代码演练
-
界⾯效果(该右键菜单中如果点击 python 选项,则会新 建⼀个标签,标签内容是“我的Python课程”):
-
代码演示
from tkinter import *
def myLabel():
global root
Label(root, text = "我的Python课程").pack() # 点击Python后添加这个标签
root = Tk()
menuBar = Menu(root)
for each in ["C/C++", "JavaEE", "Android", "PHP", "UI设计", "iOS", "前端与移动开发", "⽹络营销", "云计算"]:
menuBar.add_command(label = each)
menuBar.add_command(label = "Python", command = myLabel)
def pop(event):
menuBar.post(event.x_root, event.y_root)
root.bind("<Button-3>", pop) # ⿏标右击绑定
root.mainloop()
此处利⽤了 Menu 的 post ⽅法,还有 bind ⽅法,⼀定要 记住⿏标右键的事件名称,这些⽤多了之后⾃然能记住。
3.7 复选Checkbutton与单选Radiobutton
3.7.1 复选按钮
- 复选按钮就是 Checkbutton 类,它的实例化和 Button 很 相似。
- 既然是按钮,那就可以有 command 属性,该属性可以对 应到⼀个函数上去来执⾏某些功能。
- 复选框通常是⽤来选择信息的时候的⼀种选择,它前⾯ 有个⼩正⽅形的⽅块,如果选中则有⼀个对号,也可以再 次点击以取消该对号来取消选中。
3.7.2 复选框代码实例
-
该实例,使⽤了两个复选框,点击那个复选框,如果处 于选中状态,则在下⾯的标签中显示被选中的字样,如果 没有被选中,则显示未被选中的字样。
-
效果截图:
-
代码:
from tkinter import *
timeA = 0
timeB = 0
def funcA():
global lab, btnA, timeA
if timeA % 2 == 0:
timeA += 1
lab["text"] = "Python学科被选中"
else:
timeA += 1
lab["text"] = "Python学科被取消"
def funcB():
global lab, btnB, timeB
if timeB % 2 == 0:
timeB += 1
lab["text"] = "C++学科被选中"
else:
timeB += 1
lab["text"] = "C++学科被取消"
root = Tk()
btnA = Checkbutton(root, text = "Python学科", command = funcA)
btnA.pack()
btnB = Checkbutton(root, text = "C++学科", command = funcB)
btnB.pack()
lab = Label(root, text = " ")
lab.pack()
root.mainloop()
代码也很简单,⽤于控制次数的 timeA 和 timeB
3.7.2 单选框
- 单选框和复选框⾮常相似,只是把 Checkbutton 换成 Radiobutton。
- 我就不代码示例了,因为实在是太相似且简单了。
- 可以参考单选框类源代码。
3.8 文本Text
- 所谓⽂本域,也就是⽂本,其实它可以看做⼀个⼤型的⽂本框,它的属性也更多⼀些。
在Tkinter中,Text控件用于显示和编辑多行文本。以下是一个基本的教程案例,演示如何使用Text控件:
首先,导入Tkinter模块并创建一个顶级窗口。
import tkinter as tk
root = tk.Tk()
创建一个Text控件,并设置其大小和位置。
text_widget = tk.Text(root, width=30, height=10)
text_widget.pack()
在这个例子中,我们创建了一个宽30字符、高10行的Text控件,并将其添加到窗口中。
可以通过调用insert方法向Text控件中插入文本。
text_widget.insert('end', 'Hello, World!\n')
在这个例子中,我们在文本框的末尾插入了一行文本 “Hello, World!”。
如果需要在运行时获取或修改Text控件中的内容,可以使用get和delete方法。
# 获取所有文本
all_text = text_widget.get('1.0', 'end')
# 删除第一行
text_widget.delete('1.0', '1.end')
最后,启动主循环来显示窗口。
root.mainloop()
将这些代码片段组合起来,您将得到一个完整的Tkinter Text控件的使用示例:
3.8.1 代码演练
import tkinter as tk
def copy_text():
source_text = text_source.get('1.0', 'end')
text_destination.insert('end', source_text)
root = tk.Tk()
text_source = tk.Text(root, width=30, height=10)
text_source.pack()
text_destination = tk.Text(root, width=30, height=10)
text_destination.pack()
button_copy = tk.Button(root, text="Copy Text", command=copy_text)
button_copy.pack()
root.mainloop()
3.8.2 文本交互
运行此脚本后,您将看到两个文本框和一个按钮。当您在第一个文本框中输入文本并点击“Copy Text”按钮时,文本会被复制到第二个文本框中。
3.8.3 重定向终端text打印
这段代码的主要功能是重定向Python的sys.stdout和sys.stderr标准输出到一个基于Tkinter的ScrolledText控件中,并在窗口中显示。当点击start按钮时,程序会执行一个循环并打印数字,这些数字将通过自定义的myStdout类写入文本框而不是控制台。
import sys
import tkinter
import time
from tkinter import scrolledtext
class myStdout(): # 重定向类
def __init__(self):
# 将其备份
self.stdoutbak = sys.stdout
self.stderrbak = sys.stderr
# 重定向
sys.stdout = self
sys.stderr = self
def write(self, info):
# info信息即标准输出sys.stdout和sys.stderr接收到的输出信息
t.insert('end', info) # 在多行文本控件最后一行插入print信息
t.update() # 更新显示的文本,不加这句插入的信息无法显示
t.see(tkinter.END) # 始终显示最后一行,不加这句,当文本溢出控件最后一行时,不会自动显示最后一行
def restoreStd(self):
# 恢复标准输出
sys.stdout = self.stdoutbak
sys.stderr = self.stderrbak
def btn_func():
for i in range(5):
print(i)
# t.insert('end', i)
time.sleep(1)
"""按键的触发事件"""
mystd = myStdout() # 实例化重定向类
window = tkinter.Tk() # 实例化tk对象
t = scrolledtext.ScrolledText(window) # 创建多行文本控件
t.pack() # 布局在窗体上
b = tkinter.Button(window, text='start', command=btn_func) # 创建按钮控件,并绑定触发事件
b.pack() # 布局在窗体上
window.mainloop() # 显示窗体
mystd.restoreStd() # 恢复标准输出
点击运行效果如下:
3.9 图像Image
在Tkinter中,您可以使用PhotoImage类来加载和显示图像。以下是一个基本的教程案例,演示如何在Tkinter窗口中显示一张图片:
3.9.1 显示图像代码
首先,确保您有一个要使用的图片文件,并下面图片将其放在您的Python脚本所在目录下。
然后,编写以下代码:
import tkinter as tk
# 创建一个顶级窗口
root = tk.Tk()
# 加载图片
image_path = 'path_to_your_image.png' # 替换为实际的图片路径
image = tk.PhotoImage(file=image_path)
# 创建一个标签来显示图片
label = tk.Label(root, image=image)
label.pack()
# 开始主循环
root.mainloop()
在这个例子中,我们首先导入了Tkinter模块,并创建了一个顶级窗口(root)。然后,我们使用PhotoImage类从指定的路径加载了一张图片,并将该图片设置为一个新创建的Label控件的内容。最后,我们将这个Label添加到窗口中并启动主循环。
3.9.2 显示图像
确保将 image_path 变量替换为您要使用的图片的实际路径。如果一切正常,当运行此脚本时,应该会在窗口中看到您加载的图片。
请注意,为了防止图片资源被垃圾回收,通常需要将PhotoImage对象保存在一个变量中。在上面的例子中,我们在创建Label时传递了image对象,这实际上已经起到了保存引用的作用。如果您不打算将图片与Label关联,则可能需要手动保存对PhotoImage对象的引用。
4. 布局layout
对于任何⼀⻔图形界⾯编程来说,布局都是⾮常重要 的⼀关,它的英⽂翻译叫做“layout”。不管是MFC、Java、还是Qt等图形界⾯编程, 都会有有布局的相关知识。 Python 的 tkinter 也⼀样。
4.1 tkinter的三种布局:
- 其实我们已经接触过 tkinter 的⼀种布局,就是 pack 布局,它⾮常简单,我们不⽤做过多的设置,直接使⽤⼀个 pack 函数就可以了。
- grid 布局: grid 可以理解为⽹格,或者表格,它可以把 界⾯设置为⼏⾏⼏列的⽹格,我们在⽹格⾥插⼊我们想要 的元素。这种布局的好处是不管我们如何拖动窗⼝,相对 位置是不会变化的,⽽且这种布局也超简单。
- place 布局:它直接使⽤死板的位置坐标来布局,这样做 的最⼤的问题在于当我们向窗⼝添加⼀个新部件的时候, ⼜得重新测⼀遍数据,且我们不能随便地变⼤或者缩⼩窗⼝,否则可能会导致混乱。
4.1.1 pack 布局
- 我们使⽤ pack 函数的时候,默认先使⽤的放到上⾯,然 后 依次向下排,它会给我们的组件⼀个⾃认为合适的位置 和⼤⼩,这是默认⽅式,也是我们上⾯⼀直采⽤的⽅式。
- pack 函数也可以接受⼏个参数:
- side 参数指定了它停 靠在哪个⽅向,可以为 LEFT,TOP,RIGHT,BOTTOM,分别代表 左,上,右,下
- fill 参数可以是 X,Y,BOTH 和 NONE,即在⽔平⽅向填充,竖直⽅向填充,⽔平和竖直⽅向填充和不填充。
- expand 参数可以是 YES 和 NO,它的 anchor 参数可 以是 N,E,S,W(这⾥的 NESW 分别表示北东南⻄,这⾥分别 表示上右下左)以及他们的组合或者是CENTER(表示中 间)。
- ipadx 表示的是内边距的 x ⽅向,它的 ipady 表示 的是内边距的 y ⽅向,padx表示的是外边距的 x ⽅向, pady 表示的是外边距的 y ⽅向。
4.1.2 pack 的布局实例
- 根据上⾯的介绍,我们可以做出如下布局的样⼦:
- 按理说做的这么复杂本身没什么意思,只是想让⼤家看 ⼀下其实 pack 也可以完成相对复杂的布局,它的源代码如下:
from tkinter import *
root = Tk()
Button(root, text = "A").pack(side = LEFT, expand =YES, fill = Y)
Button(root, text = "B").pack(side = TOP, expand = YES, fill = BOTH)
Button(root, text = "C").pack(side = RIGHT, expand = YES, fill = NONE, anchor = NE)
Button(root, text = "D").pack(side = LEFT, expand = NO, fill = Y)
Button(root, text = "E").pack(side = TOP, expand = NO, fill = Y)
Button(root, text = "F").pack(side = BOTTOM, expand = YES)
Button(root, text = "G").pack(anchor = SE)
root.mainloop()
4.2 grid 布局
- 由于我们的程序⼤多数都是矩形,因此特别适合于⽹格 布局,也就是 grid 布局。
- 使⽤ grid 布局的时候,我们使⽤ grid 函数,在⾥⾯指 定两个参数,⽤ row 表示⾏,⽤ column 表示列,注意的是 row 和 column 的编号都从 0 开始。
- grid 函数还有个 sticky 参数,它可以⽤ N,S,W,E 表示 上,下,左,右 , 它决定了这个组件是从哪个⽅向开始的, 下⾯的例⼦可以很好的解释这⼀点。
- grid 布局直接⽤后⾯的⾏和列的数字来指定了它位于哪个位置,⽽不必使⽤其他参数。
- grid 函数也⽀持诸如 ipadx,ipady,padx,pady ,它们的意思和 pack 函数是⼀样的,默认边距是 0。
- 它还⽀持参数⽐如 rowspan ,表示跨越的⾏数, columnspan 表示跨越的列数。
- 它还有⼀些属性,可以在以后我们的demo中慢慢使⽤来 看出其重要性。
账号登陆例⼦的截图
界⾯如下:
代码如下:
from tkinter import *
py = Tk()
Label(py, text = "账号:").grid(row = 0, sticky = W)
Entry(py).grid(row = 0, column = 1, sticky = E)
Label(py, text = "密码:").grid(row = 1, sticky = W)
Entry(py).grid(row = 1, column = 1, sticky = E)
Button(py, text = "登录").grid(row = 2, column = 1, sticky = E)
py.mainloop()
- 代码说明: 代码⾮常简单,参考grid布局介绍理解,其中 Entry 表示“输⼊框”。
4.3 place 布局
- 关于 place 布局,这个的⼏何管理器组织放置在⼀个特定的位置
- 它使⽤ place 函数,它分为 绝对布局 和 相对布局 ,绝对布局使⽤ x 和 y 参数,相对布局使⽤ relx,rely, relheight 和 relwidth 参数。
- 该⽅法⽤的极少,⽽且极度不推荐⼤家⽤,这⾥就不详细说明了。
4.4 总结
- place 不推荐⽤,pack 和 grid 布局更常⽤⼀些。
- 但是 pack 和 grid 不能同时⽤。⽽且通常对于较为复杂点的界⾯, 还是建议⼤家⽤gird;如果布局相对简单,使⽤pack 也很不错。
5. 画布Canvas
窗⼝重绘
- 第⼀次认识到⼿绘图形的重要性还是在学习 MFC 的时候, 因为 MFC ⾃带的绘图功能实在过于丑陋,我们可以重绘标题栏、菜单栏、最⼩化按钮、最⼤化按钮、关闭按钮等窗 ⼝组件来让窗⼝得到美化,除了这些,还可以⼿绘按钮, 后来出了⼀⻔技术, 叫做“Direct UI”,也是这种思想的进⼀步发扬光⼤把。
- 但是 tkinter 没有这些⽅⾯的接⼝,我也深感遗憾。但是 tkinter 有⼀个绘图功能的组件,即 Canvas,翻译成汉 语即“帆布”,可以理解为“画布”,即⽤于绘制图形。
5.1 canvas
- 下⾯是该类的部分截图:
- 其实我们主要的也就是⽤上⾯的这些绘图函数来进⾏⼿ ⼯的绘制⼀些东⻄。
5.2 简单示例
- 我们第⼀个示例随便绘制了,先把背景⽤ rgb 格式刷成 蓝⾊,然后画⼀条线,然后写⼏个字。
- 代码截图:
from tkinter import *
root = Tk()
root.title("开心就好")
canv = Canvas(root, width = 400, height = 300, bg = "pink")
canv.create_line((0,0), (200,200), width = 8)
canv.create_line((400,0), (200,200), width = 8)
canv.create_text(300, 30, text = "Python教程")
canv.pack()
root.mainloop()
- 效果图如下:
5.3 中国象棋棋盘
-
其实⼿绘可以做很多事,很多东⻄都可以⼿绘,只不过 有些东⻄确实⼿绘挺累的。
-
下⾯是⼿绘了⼀个中国象棋棋盘的截图(关于中国象棋, 我还是挺喜欢玩的):
-
其实没啥技术难度,下⾯是代码截图,不过我还是希望 读者先亲⾃动⼿做⼀个,毕竟不难:
from tkinter import *
root = Tk()
root.title("中国象棋棋盘⼿绘")
canv = Canvas(root, width = 400, height = 450)
canv.create_line((0,2), (400,2), width = 2)
for i in range(10):
canv.create_line((0, i * 50), (400, i * 50), width = 2)
canv.create_line((3,0), (3,450), width = 2)
for i in range(8):
canv.create_line((i * 50,0), (i * 50,200), width = 2)
for i in range(8):
canv.create_line((i * 50,250), (i * 50,450), width = 2)
canv.create_line((397,0), (397,450), width = 2)
canv.create_line((150,0), (250,100), width = 2)
canv.create_line((150,100), (250,0), width = 2)
canv.create_line((150,450), (250,350), width = 2)
canv.create_line((150,350), (250,450), width = 2)
canv.create_text(110, 220, text = "汉界")
canv.create_text(290, 220, text = "楚河")
canv.pack()
root.mainloop()
6. 打包程序pyinstaller
6.1 配置pyinstaller环境
- 升级我们的pip版本
python -m pip install --upgrade pip
- 通过pip安装 pyinstaller:
pip --default-timeout=100 install pyinstaller -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
- 进⼊项⽬⽂件的⽂件夹,执⾏下⾯命令 pyinstaller -w *.py
常用参数 含义
-i 或 -icon 生成icon
添加icon:pyinstaller -F -w -i favicon.ico *.py
(注:图片资源需与源文件在同意路径,或指定对应资源图路径)
-F 创建一个绑定的可执行文件
-w 使用窗口,无控制台
-C 使用控制台,无窗口
-D 创建一个包含可执行文件的单文件夹包(默认情况下)
-n 文件名
6.2 贪吃蛇游戏
使用Tkinter库创建的简单贪吃蛇游戏。游戏包含一个黑色背景的300x300像素的棋盘,玩家通过键盘控制蛇移动并吃掉苹果以增加分数。
源代码snake.py
#!/usr/bin/env python3
"""
ZetCode Tkinter tutorial
This is a simple Snake game
clone.
Author: Jan Bodnar
Website: zetcode.com
Last edited: April 2019
"""
import sys
import random
from PIL import Image, ImageTk
from tkinter import Tk, Frame, Canvas, ALL, NW
class Cons:
BOARD_WIDTH = 300
BOARD_HEIGHT = 300
DELAY = 100
DOT_SIZE = 10
MAX_RAND_POS = 27
class Board(Canvas):
def __init__(self):
super().__init__(width=Cons.BOARD_WIDTH, height=Cons.BOARD_HEIGHT,
background="black", highlightthickness=0)
self.initGame()
self.pack()
def initGame(self):
'''initializes game'''
self.inGame = True
self.dots = 3
self.score = 0
# variables used to move snake object
self.moveX = Cons.DOT_SIZE
self.moveY = 0
# starting apple coordinates
self.appleX = 100
self.appleY = 190
self.loadImages()
self.createObjects()
self.locateApple()
self.bind_all("<Key>", self.onKeyPressed)
self.after(Cons.DELAY, self.onTimer)
def loadImages(self):
'''loads images from the disk'''
try:
self.idot = Image.open("dot.png")
self.dot = ImageTk.PhotoImage(self.idot)
self.ihead = Image.open("head.png")
self.head = ImageTk.PhotoImage(self.ihead)
self.iapple = Image.open("apple.png")
self.apple = ImageTk.PhotoImage(self.iapple)
except IOError as e:
print(e)
sys.exit(1)
def createObjects(self):
'''creates objects on Canvas'''
self.create_text(30, 10, text="Score: {0}".format(self.score),
tag="score", fill="white")
self.create_image(self.appleX, self.appleY, image=self.apple,
anchor=NW, tag="apple")
self.create_image(50, 50, image=self.head, anchor=NW, tag="head")
self.create_image(30, 50, image=self.dot, anchor=NW, tag="dot")
self.create_image(40, 50, image=self.dot, anchor=NW, tag="dot")
def checkAppleCollision(self):
'''checks if the head of snake collides with apple'''
apple = self.find_withtag("apple")
head = self.find_withtag("head")
x1, y1, x2, y2 = self.bbox(head)
overlap = self.find_overlapping(x1, y1, x2, y2)
for ovr in overlap:
if apple[0] == ovr:
self.score += 1
x, y = self.coords(apple)
self.create_image(x, y, image=self.dot, anchor=NW, tag="dot")
self.locateApple()
def moveSnake(self):
'''moves the Snake object'''
dots = self.find_withtag("dot")
head = self.find_withtag("head")
items = dots + head
z = 0
while z < len(items)-1:
c1 = self.coords(items[z])
c2 = self.coords(items[z+1])
self.move(items[z], c2[0]-c1[0], c2[1]-c1[1])
z += 1
self.move(head, self.moveX, self.moveY)
def checkCollisions(self):
'''checks for collisions'''
dots = self.find_withtag("dot")
head = self.find_withtag("head")
x1, y1, x2, y2 = self.bbox(head)
overlap = self.find_overlapping(x1, y1, x2, y2)
for dot in dots:
for over in overlap:
if over == dot:
self.inGame = False
if x1 < 0:
self.inGame = False
if x1 > Cons.BOARD_WIDTH - Cons.DOT_SIZE:
self.inGame = False
if y1 < 0:
self.inGame = False
if y1 > Cons.BOARD_HEIGHT - Cons.DOT_SIZE:
self.inGame = False
def locateApple(self):
'''places the apple object on Canvas'''
apple = self.find_withtag("apple")
self.delete(apple[0])
r = random.randint(0, Cons.MAX_RAND_POS)
self.appleX = r * Cons.DOT_SIZE
r = random.randint(0, Cons.MAX_RAND_POS)
self.appleY = r * Cons.DOT_SIZE
self.create_image(self.appleX, self.appleY, anchor=NW,
image=self.apple, tag="apple")
def onKeyPressed(self, e):
'''controls direction variables with cursor keys'''
key = e.keysym
LEFT_CURSOR_KEY = "Left"
if key == LEFT_CURSOR_KEY and self.moveX <= 0:
self.moveX = -Cons.DOT_SIZE
self.moveY = 0
RIGHT_CURSOR_KEY = "Right"
if key == RIGHT_CURSOR_KEY and self.moveX >= 0:
self.moveX = Cons.DOT_SIZE
self.moveY = 0
RIGHT_CURSOR_KEY = "Up"
if key == RIGHT_CURSOR_KEY and self.moveY <= 0:
self.moveX = 0
self.moveY = -Cons.DOT_SIZE
DOWN_CURSOR_KEY = "Down"
if key == DOWN_CURSOR_KEY and self.moveY >= 0:
self.moveX = 0
self.moveY = Cons.DOT_SIZE
def onTimer(self):
'''creates a game cycle each timer event'''
self.drawScore()
self.checkCollisions()
if self.inGame:
self.checkAppleCollision()
self.moveSnake()
self.after(Cons.DELAY, self.onTimer)
else:
self.gameOver()
def drawScore(self):
'''draws score'''
score = self.find_withtag("score")
self.itemconfigure(score, text="Score: {0}".format(self.score))
def gameOver(self):
'''deletes all objects and draws game over message'''
self.delete(ALL)
self.create_text(self.winfo_width() /2, self.winfo_height()/2,
text="Game Over with score {0}".format(self.score), fill="white")
class Snake(Frame):
def __init__(self):
super().__init__()
self.master.title('Snake')
self.board = Board()
self.pack()
def main():
root = Tk()
nib = Snake()
root.mainloop()
if __name__ == '__main__':
main()
依赖的三张图片,分别存为apple.png
dot.png
head.png
代码分为几个部分:
- 导入所需模块和自定义常量(Cons)。
- 定义了Board类,继承自Canvas类。这个类包含了游戏的主要逻辑:初始化游戏、加载图片、创建对象、检查碰撞、移动蛇、显示得分等。
- 定义了Snake类,继承自Frame类。这个类主要用于在窗口中显示游戏界面。
- main()函数用于启动游戏主循环。
当运行程序时,它会创建一个包含蛇和苹果的游戏界面。玩家可以使用键盘上的方向键来控制蛇的移动,并尝试吃掉随机出现的苹果。如果玩家让蛇撞到边界或自己的身体,游戏将结束,并显示“Game Over”消息以及最后的得分。
6.3 打包
以Tkinter Realsense D435相机采集图片tkinter_camera_Aligned.py
为例
import tkinter as tk
from tkinter import ttk
import pyrealsense2 as rs
import numpy as np
from PIL import Image, ImageTk
import os
def camera_aligned():
# 创建GUI界面
# global camera_static
root = tk.Tk()
style = ttk.Style()
style.configure('Custom.TButton', font=('Helvetica', 16))
root.title("Realsense D435i Camera")
root.geometry('380x400')
# 创建图像显示区域
color_label = tk.Label(root)
color_label.grid(row=2, column=0,columnspan=3)
depth_label = tk.Label(root)
depth_label.grid(row=2, column=4,columnspan=3)
# 创建保存图像函数
def save_image(color_image, depth_image):
# 创建data文件夹(如果不存在)
if not os.path.exists("data"):
os.makedirs("data")
# 获取data文件夹下已保存图像的数量
# num_files = len(os.listdir("data"))
# 获取data文件夹下最大的序号
num_files = 0
for file_name in os.listdir("./data"):
if file_name.endswith(".png"):
index = int(file_name.split(".")[0])
num_files = max(num_files, index)
# 保存彩色图为PNG格式
color_image_path = "data/{:04d}.png".format(num_files + 1)
color_image.save(color_image_path)
print(f"Color image saved as {color_image_path}")
# 保存深度图为对齐TIFF格式
depth_image_path = "data/{:04d}.tiff".format(num_files + 1)
depth_image.save(depth_image_path, "TIFF")
print(f"Depth image saved as {depth_image_path}")
# 创建打开相机按钮的回调函数
def open_camera():
# 创建Realsense管道
global pipeline
pipeline = rs.pipeline()
# 配置相机参数
config = rs.config()
config.enable_stream(rs.stream.color, 640, 480, rs.format.rgb8, 30)
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
# 启动相机
pipeline.start(config)
try:
while True:
# 等待相机数据
frames = pipeline.wait_for_frames()
color_frame = frames.get_color_frame()
depth_frame = frames.get_depth_frame()
# 将相机数据转换为可显示的图像
color_image = np.asanyarray(color_frame.get_data())
pil_color_image = Image.fromarray(color_image)
tk_color_image = ImageTk.PhotoImage(pil_color_image.resize((160, 120)))
depth_image = np.asanyarray(depth_frame.get_data())
pil_depth_image = Image.fromarray(depth_image)
tk_depth_image = ImageTk.PhotoImage(pil_depth_image.resize((160, 120)))
# 更新图像显示
color_label.config(image=tk_color_image)
depth_label.config(image=tk_depth_image)
# 保持图像显示的引用,防止被垃圾回收
color_label.image = pil_color_image
depth_label.image = pil_depth_image
# 更新GUI界面
root.update()
finally:
pipeline.stop()
root.destroy()
# 创建保存图像按钮的回调函数
def save_button_callback():
# 获取当前显示的彩色图和深度图
color_image = color_label.image
depth_image = depth_label.image
# 检查图像是否存在
if color_image is not None and depth_image is not None:
# 保存图像
save_image(color_image, depth_image)
else:
print("No image to save")
def close_camera():
# camera_static = 1
pipeline.stop()
# 创建退出按键的回调函数
def image_button_callback():
# 停止相机并关闭窗口
# pipeline.stop()
root.destroy()
la1=ttk.Label(root,text='Realsense D435相机图形采集', style='Custom.TButton')
la1.grid(row=0,column=0, ipady=6, pady=6, columnspan=7) # 0行0列
# 创建打开相机按钮
open_button = tk.Button(root, text="打开相机", command=open_camera, bg='green',fg='yellow')
open_button.grid(row=1, column=0)
# 创建打开相机按钮
close_button = tk.Button(root, text="关闭相机", command=close_camera, bg='red',fg='yellow')
close_button.grid(row=1, column=2)
# 创建保存图像按钮
save_button = tk.Button(root, text="保存图像", command=save_button_callback, bg='blue',fg='yellow')
save_button.grid(row=1, column=4)
# 创建退出图像按钮
image_Exit_button = tk.Button(root, text="退出采集", command=image_button_callback, bg='red',fg='yellow')
image_Exit_button.grid(row=1, column=6)
la2=ttk.Label(root,text='彩色图像')
la2.grid(row=3,column=1) # 0行0列
la2=ttk.Label(root,text='深度图像')
la2.grid(row=3,column=5) # 0行0列
# 运行GUI界面
root.mainloop()
if __name__ == '__main__':
camera_aligned()
- 直接打包:
pyinstaller -F tkinter_camera_Aligned.py
(生成的exe文件运行后,运行会有个控制台,即可见的黑框) - 不带控制台:
pyinstaller -F -w tkinter_camera_Aligned.py
(该命令会去除控制台,运行即运行仅程序窗口) - 添加icon:
pyinstaller -F -w -i favicon.ico tkinter_camera_Aligned.py
(注:图片资源需与源文件在同意路径,或指定对应资源图路径)
生成的exe文件在环境主目录dist文件夹下
7. 总结
- 本文粗略了解Tkinter GUI界面设计,围绕其基本组件设计简易的实验,总之纸上得来终觉浅,为知此事要躬行。
- 在以后的博文中我们将学会用项目系统,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。