【Tkinter 入门教程】

1. Tkinter库的简介:

Tkinter是Tk GUI工具包的Python绑定包。它是Tk GUI工具包的标准Python接口,并且是Python的业界标准GUI工具包。Tkinter同时也包含在Python的Linux、Microsoft Windows和Mac OS X标准库中。Tkinter的名字来自Tk interface。

  1. 若在命令行执行 python -m tkinter,应会弹出一个简单的 Tk 界面窗口, 表明 tkinter 包已安装完成,还会显示当前安装的 Tcl/Tk 版本,以便阅读对应版本的 Tcl/Tk 文档。Python=3.8.10
    在这里插入图片描述
  2. Tkinter 支持众多的 Tcl/Tk 版本,带或不带多线程版本均可。官方的 Python 二进制版本捆绑了 Tcl/Tk 8.6多线程版本。关于可支持版本的更多信息,请参阅 _tkinter 模块的源代码。
  3. 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编程

  1. 如果有过 C 或者 Python等语⾔的编程经验,开发GUI界面手到擒来,在 Python ⾥⾯这种⼯具并不多,这也是和 Python 是⼀个脚本语⾔有关。
  2. 要说 tkinter,先说 tk,它原本是 Tcl 编程语⾔的界⾯库, 后来开发出了Python 接⼝,Tkinter 在 Python2 和 Python3 中的变化较⼤,在 Python2 中叫做 Tkinter,在 Python3 中叫做 tkinter,⽽且在导⼊类库的时候也有些许的变化,请读者稍加注意。

1.2 Tkinter的定位

  1. 掌握⼀⻔ Python 的界 ⾯编程也很有意思。有时候我们需要⼀些界⾯程序,但是⼜不想⽤那些庞⼤ ⽽繁杂的类库的时候,tkinter 的优势就显现出来了,那就是简洁简单。💕💕💕
  2. 我感觉 tkinter 是⼀个还不错的界⾯库,但是我感觉 Python 并不是特别擅⻓复杂的应⽤(🐧🐧🐧🐧麻雀虽小五脏俱全🐧🐧🐧),⽽且我感觉⽐如 wxPython 或者 pyQt 等更胜⼀筹,但是不管怎么样,我们可以通过Python⾃带的tkinter,进⼊GUI编程的世界。🎉🎉🎉
  3. 鹏鹏只用两周就完成项目啦!相信接下来可以帮助你😘😘😘

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~100boldredgreenblue

您也可以根据需要更改字体颜色和其他属性。例如,您可以创建多个不同的自定义字体对象,用于表示不同的颜色主题,并在程序运行时动态地切换它们。
在这里插入图片描述

3. 组件讲解

3.1 tkinter 的核⼼组件

  1. 在 tkinter 中,有 21 个核⼼组件,它们提供 了GUI开发的完整功能,因为使⽤频率较⾼。
  2. 这 21 个核⼼组件是 : Label、Button、Entry、Menu、 Radiobutton 、Checkbutton、Text、Image、Canvas、Frame、LabelFrame、Toplevel、 Listbox、Menubutton、Message、OptionMenu、PaneWindow 、 Scale 、Scrollbar 、Spinbox、Bitmap。

3.2 组件的使⽤

  1. 各个组件都有相应的类,我们可以通过⾯向对象的⽅式 去使⽤它们。
  2. 这些组件的使⽤也很相似,在实例化这些组件的时候, 第⼀个参数都是⽗窗⼝或者⽗组件,后⾯跟着的就是该组 件的⼀些属性,⽐如上⾯我们学到的 Label 的 text属性和 background 属性。
  3. 多个组件的位置控制⽅式也很相似,我们可以⽤ pack ⽅法来进⾏简单的布局,具体的个例我们后⾯再说。
  4. 组件也会有些⽅法是共⽤的,⽐如 configure ⽅法来设置属性等等。

3.3 标签Label

标签就是输出显示信息可动态也可静态✨✨✨

3.3.1 标签显示内容

  1. 所谓 标签 ,就是贴在物品前⾯的⼀个简短的说明, 它⽤于说明⼀些⽂字信息。
  2. 标签可以说是最简单的窗⼝组件了,它不需要执⾏任何功能,只是⽤来显示信息。
  3. 下⾯是代码示例:
from tkinter import *
root = Tk()
root.wm_title("这是⼀个Tkinter程序窗⼝标题")
wl= Label(root, text = "欢迎来到tkinter")
wl.pack()
root.mainloop()

在这里插入图片描述

代码分析

  1. 这⾥的 Label 是⼀个类,可以在 init.py ⽂件⾥查看 相应的源代码。
  2. wl 是⼀个 Label 的实例,它有⼀个 text 属性 ,⽤来指定 它的⽂本内容。
    在这里插入图片描述
  1. ⼤家可以看到它的标准属性,⽐如有 background , font , bitmap , padx ,relief 等等, 还有 underline 等等。
  2. 该类有个 pack ⽅法,没错,这个 pack ⽅法我们后⾯会 讲,⼤家可以理解为它的作⽤就是找个合适的位置进⾏放置即可,即 pack() 之后就选定位置放上去了。
  3. 这⾥的初始化的时候,需要先指定 root,是说 wl 这个组 件是在 root 这个窗⼝的,不是属于别的窗⼝的,以后我们 有了多窗⼝的应⽤程序,不会混淆。

Widget 类

  1. 我们上⾯发现,Label 类是继承⾃ Widget 类的,并且⾃ ⼰只有⼀个⽅法,就是⽤来
    初始化⾃身的,那么要想彻底 理解 Label,就必须彻底理解 Widget。

  2. 我们找到了 Widget 的代码,发现它更加短⼩,甚⾄连个 ⽅法都没有,下⾯是
    Widget 的截图:
    在这里插入图片描述

  3. 通过这个注释,我们可以理解如下:它是⼀个可以指定 位置并且可以使⽤
    pack , place 和 grid 来布局管理的窗⼝ 组件。

  4. 然后我们找到 BaseWidget ,发现它的代码也很短⼩,代 码截图如下:
    在这里插入图片描述

  5. 该类继承⾃ Misc ,包含了四个函数,函数的功能通过名 字就可以知道了。⾄于Misc类,我们后⾯会讲解的。Misc其实是英⽂ Miscellaneous 的前四个字⺟,杂项、混合体、⼤杂烩的意思。在软件⾥经常可以看到与misc相关的⽂件或函数名,使⽤misc来命名主要是表示该⽂件⽬前还没归类好,不知道将它归到哪个⽅⾯或者放置在哪个地⽅⽐较好,所以暂时⽤misc。

3.3.2 多标签的应⽤程序

  1. 如果我们想要多个标签,该怎么办呢?
  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 总结

  1. 我们这⼀节学习了 Label 这个组件,它的创建使⽤ Label 这个类,实例化的时候⾸
    先要指定它的⽗窗⼝,然后就是 ⽤字典的⽅式设置⾃⼰的⼀些特征,这些特征上⾯
    都列出 了,但是没有实例演示。
  2. 然后使⽤ pack() ⽅法布局上去,关于布局,我们后⾯会详 细讲,这⾥我们统⼀使⽤
    pack() 就可以了。

3.4 按钮Button

  1. 按钮也是⾮常重要的组件, 按钮的重要性在于它可以执⾏相应 的功能。
  2. 按钮的英⽂表述是 button ,它随处可⻅,当我们单 击的时候,它可以执⾏相应的功能。
  3. 按钮在 tkinter 中有⼀个类专⻔负责它,叫做 Button ,该类也⾮常简短。
    在这里插入图片描述

3.4.1 按钮与功能的绑定

  1. 上⽂说到,按钮可以执⾏相应的功能,这⾥的功能我们 可以理解为⼀个函数,或者这些功能通过相应的函数去实 现。
  2. 绑定⽅式通常有如下⼏种:第⼀种,在按钮组件被声明 的时候⽤ 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()

运⾏结果:(⼀开始是只有⼀个按钮的,点击⼀下,就会在这个窗⼝上多⼀个标签,下⾯是我点击了三次之后的截图):
在这里插入图片描述

代码解读

  1. 其实很简单,这⾥只需要注意 command 属性后⾯不要加任何的标点符号。
  2. 这⾥的 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()

和第⼀种⽅法的结果⼀样
在这里插入图片描述

代码解读:

  1. bind这个⽅法是在 Misc 类中的,可以接受三个参数,但是本例中我们只传递了两个参数。
  2. 第⼀个参数可能对刚使⽤它的⼈来说有点复杂,常⻅的⿏标左键单击如下: <Button1> (也就是上⾯的代码⽤到的),或者 等。
  3. 第⼆个参数可以是⼀个函数名,记住,不要加任何的标 点符号,否则运⾏时会报错的。
  4. 使⽤ bind 函数的时候,第⼆个参数是⼀个函数名,该函数必须接受⼀个参数,即表示该事件。 这个参数通常⽤ event 来表示,如果我们调⽤的函数不接 受任何参数,则会报错如下 : TypeError: myLabel() takes no arguments
    (1 given)

bind的第⼀个参数是⽤字符串包含的事件类型,它采⽤的描述⽅式是: <MODIFIER-MODIFIER-TYPE-DETAIL>

  1. 这⾥的 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
  2. 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
  3. 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 总结

  1. 关于按钮,我们重点理解的就是它如何和事件进⾏绑定的。
  2. 当然,使⽤⼀些其他属性来美化按钮也很重要。
  3. 下⾯要讲⼀讲布局⽅⾯的东⻄了。

3.5 输⼊框Entry

3.5.1 输⼊框的重要性

应⽤程序要取得⽤户的信息,输⼊框是必不可少的,虽然执⾏命令可以使⽤按钮,但是总不能让⽤户⼀直点击按钮吧。

  1. 输⼊框是 Entry,可以阅读它的源代码。
  2. 源代码截图:
    在这里插入图片描述
  3. ⽐较重要的也就是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()

  1. 其实密码框和输⼊框基本是⼀样的,都是向⾥⾯输⼊信 息⽤的。

  2. 如果要说不⼀样,也就⼀个地⽅不⼀样:密码框需要输 ⼊的信息的显示字符⽐较单⼀。

  3. ⽐如 e 是⼀个输⼊框,我们可以设置它的 show 属性让它 变成⼀个密码框,即 e[‘show’] = ‘*’ 就可以了。

  4. 下⾯是⼀个⼩型登录程序,它的⽤户名是 qq_group ,密码是945348278 ,如果输⼊正确,那么点击“登录”按钮之后,就会显 示“登录成功”,如果输⼊不符合,那么就会显示“⽤户 名或者密码错误”,并且清空两个输⼊框。

  5. 运⾏结果:

  • 输⼊正确的⽤户名和密码,显示登录成功:
    在这里插入图片描述

  • 输⼊错误的⽤户名或密码,显示⽤户名错误密码错误:
    在这里插入图片描述

3.6 菜单Menu

  • 菜单的信息量是⾮常⼤的,给用户提供导航使用,由于菜单⼜可以有⼦菜单,因此菜单的信息量⾮常⼤。
  • 菜单的分类也较多,通常可以分为下拉菜单、弹出菜单 等等。

3.6.1 添加顶层菜单

  1. 我们可以使⽤ Menu 类来新建⼀个菜单, Menu 和其他的组件⼀样,第⼀个是parent ,这⾥通常可以为窗⼝。
  2. 然后我们可以⽤ add_commmand ⽅法来为它添加菜单项, 如果该菜单是顶层菜单,则添加的菜单项依次向右添加。 如果该菜单时顶层菜单的⼀个菜单项,则它添加的是
    下拉 菜单的菜单项。
  3. add_command 中的参数常⽤的有 label 属性,⽤来指定的 是菜单项的名称, command属性⽤来指定被点击的时候调⽤ 的⽅法, acceletor 属性指定的是快捷键, underline 属性 是是否拥有下划线。
  4. 最后可以⽤窗⼝的 menu 属性指定我们使⽤哪⼀个作为它 的顶层菜单。

3.6.2 代码演练

  1. 这⾥只是做出了顶级菜单,它们四个是并列的⼀⾏,并 没有实现什么功能,效果图如下:
    在这里插入图片描述
  2. 下⾯是代码演示:
from tkinter import *
root = Tk()
menuBar = Menu(root)
for item in ["⽂件", "编辑", "视图", "关于"]:
    menuBar.add_command(label = item)
root["menu"] = menuBar
root.mainloop()

  1. 可以看到,⾮常简单的⽅式,我们使⽤ add_command 来 添加菜单项即可。

3.6.3 有⼦菜单的情况

  1. 如果有⼦菜单,则情况稍微复杂点,这个时候,我们需 要使⽤ add_cascade ,cascade 可以理解为“级联”,即它 的作⽤只是为了引出后⾯的菜单。
  2. add_cascade 的⼀个很重要的属性就是 menu 属性,它指 明了要把那个菜单级联到该
    菜单项上,当然,还必不可少 的就是 label 属性,⽤于指定该菜单项的名称。
  3. 我们先新建⼀个 Menu 的实例,然后使⽤ add_command 来 添加菜单项,这样等该菜单
    建⽴完毕,我们要把它作为另 ⼀个菜单项的⼦菜单,就需要使⽤ add_cascade ⽅法。

3.6.4 代码演练

  1. 下⾯我们使⽤了下拉菜单,这也是我们通常使⽤的菜单 形式,即⼀⾏菜单项,点击之后会产⽣⼀个下拉菜单。
  2. 效果
    在这里插入图片描述
  3. 代码演示:
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 弹出菜单

  1. 弹出菜单⼜叫“上下⽂菜单”,也叫“右键菜单”,它 通常是⿏标单击右键产⽣的菜单,因此会有“右键菜单” 的说法。
  2. 其实很多界⾯库⾥⾯都是给出了弹出菜单的简单的制作 ⽅法的,但是 tkinter ⾥⾯我们却只能使⽤⽐较原始的事 件绑定的⽅式去做。
  3. ⼤体思路就是:我们先新建⼀个菜单,然后向菜单项中 添加各种功能,最后我们监听⿏标右键消息,如果是⿏标 右键被单击,此时可以根据需要判断下⿏标位置来确定是 哪个弹出菜单被弹出,然后使⽤ Menu 类的 pop ⽅法来弹出 菜单。
  4. ⼤体思路就是如此,⾄于具体的细节,让我们到代码实 战中⼀探究竟。
  5. Menu 类⾥⾯有⼀个 post ⽅法,它接收两个参数,即 x 和 y 坐标,它会在相应的位置弹出菜单。
  6. 还记得⽤ bind ⽅法来绑定事件吗?⽽且要记得⿏标右键 是⽤的

3.6.6 代码演练

  1. 界⾯效果(该右键菜单中如果点击 python 选项,则会新 建⼀个标签,标签内容是“我的Python课程”):
    在这里插入图片描述

  2. 代码演示

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 复选按钮

  1. 复选按钮就是 Checkbutton 类,它的实例化和 Button 很 相似。
  2. 既然是按钮,那就可以有 command 属性,该属性可以对 应到⼀个函数上去来执⾏某些功能。
  3. 复选框通常是⽤来选择信息的时候的⼀种选择,它前⾯ 有个⼩正⽅形的⽅块,如果选中则有⼀个对号,也可以再 次点击以取消该对号来取消选中。

3.7.2 复选框代码实例

  1. 该实例,使⽤了两个复选框,点击那个复选框,如果处 于选中状态,则在下⾯的标签中显示被选中的字样,如果 没有被选中,则显示未被选中的字样。

  2. 效果截图:
    在这里插入图片描述

  3. 代码:

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 单选框

  1. 单选框和复选框⾮常相似,只是把 Checkbutton 换成 Radiobutton。
  2. 我就不代码示例了,因为实在是太相似且简单了。
  3. 可以参考单选框类源代码。

3.8 文本Text

  1. 所谓⽂本域,也就是⽂本,其实它可以看做⼀个⼤型的⽂本框,它的属性也更多⼀些。
    在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的三种布局:

  1. 其实我们已经接触过 tkinter 的⼀种布局,就是 pack 布局,它⾮常简单,我们不⽤做过多的设置,直接使⽤⼀个 pack 函数就可以了。
  2. grid 布局: grid 可以理解为⽹格,或者表格,它可以把 界⾯设置为⼏⾏⼏列的⽹格,我们在⽹格⾥插⼊我们想要 的元素。这种布局的好处是不管我们如何拖动窗⼝,相对 位置是不会变化的,⽽且这种布局也超简单。
  3. place 布局:它直接使⽤死板的位置坐标来布局,这样做 的最⼤的问题在于当我们向窗⼝添加⼀个新部件的时候, ⼜得重新测⼀遍数据,且我们不能随便地变⼤或者缩⼩窗⼝,否则可能会导致混乱。

4.1.1 pack 布局

  1. 我们使⽤ pack 函数的时候,默认先使⽤的放到上⾯,然 后 依次向下排,它会给我们的组件⼀个⾃认为合适的位置 和⼤⼩,这是默认⽅式,也是我们上⾯⼀直采⽤的⽅式。
  2. 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 的布局实例

  1. 根据上⾯的介绍,我们可以做出如下布局的样⼦:
  2. 按理说做的这么复杂本身没什么意思,只是想让⼤家看 ⼀下其实 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 布局

  1. 由于我们的程序⼤多数都是矩形,因此特别适合于⽹格 布局,也就是 grid 布局。
  2. 使⽤ grid 布局的时候,我们使⽤ grid 函数,在⾥⾯指 定两个参数,⽤ row 表示⾏,⽤ column 表示列,注意的是 row 和 column 的编号都从 0 开始。
  3. grid 函数还有个 sticky 参数,它可以⽤ N,S,W,E 表示 上,下,左,右 , 它决定了这个组件是从哪个⽅向开始的, 下⾯的例⼦可以很好的解释这⼀点。
  4. grid 布局直接⽤后⾯的⾏和列的数字来指定了它位于哪个位置,⽽不必使⽤其他参数。
  5. grid 函数也⽀持诸如 ipadx,ipady,padx,pady ,它们的意思和 pack 函数是⼀样的,默认边距是 0。
  6. 它还⽀持参数⽐如 rowspan ,表示跨越的⾏数, columnspan 表示跨越的列数。
  7. 它还有⼀些属性,可以在以后我们的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()
  1. 代码说明: 代码⾮常简单,参考grid布局介绍理解,其中 Entry 表示“输⼊框”。

4.3 place 布局

  1. 关于 place 布局,这个的⼏何管理器组织放置在⼀个特定的位置
  2. 它使⽤ place 函数,它分为 绝对布局 和 相对布局 ,绝对布局使⽤ x 和 y 参数,相对布局使⽤ relx,rely, relheight 和 relwidth 参数。
  3. 该⽅法⽤的极少,⽽且极度不推荐⼤家⽤,这⾥就不详细说明了。

4.4 总结

  1. place 不推荐⽤,pack 和 grid 布局更常⽤⼀些。
  2. 但是 pack 和 grid 不能同时⽤。⽽且通常对于较为复杂点的界⾯, 还是建议⼤家⽤gird;如果布局相对简单,使⽤pack 也很不错。

5. 画布Canvas

窗⼝重绘

  1. 第⼀次认识到⼿绘图形的重要性还是在学习 MFC 的时候, 因为 MFC ⾃带的绘图功能实在过于丑陋,我们可以重绘标题栏、菜单栏、最⼩化按钮、最⼤化按钮、关闭按钮等窗 ⼝组件来让窗⼝得到美化,除了这些,还可以⼿绘按钮, 后来出了⼀⻔技术, 叫做“Direct UI”,也是这种思想的进⼀步发扬光⼤把。
  2. 但是 tkinter 没有这些⽅⾯的接⼝,我也深感遗憾。但是 tkinter 有⼀个绘图功能的组件,即 Canvas,翻译成汉 语即“帆布”,可以理解为“画布”,即⽤于绘制图形。

5.1 canvas

  1. 下⾯是该类的部分截图:
    在这里插入图片描述
  2. 其实我们主要的也就是⽤上⾯的这些绘图函数来进⾏⼿ ⼯的绘制⼀些东⻄。

5.2 简单示例

  1. 我们第⼀个示例随便绘制了,先把背景⽤ rgb 格式刷成 蓝⾊,然后画⼀条线,然后写⼏个字。
  2. 代码截图:
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()
  1. 效果图如下:
    在这里插入图片描述

5.3 中国象棋棋盘

  1. 其实⼿绘可以做很多事,很多东⻄都可以⼿绘,只不过 有些东⻄确实⼿绘挺累的。

  2. 下⾯是⼿绘了⼀个中国象棋棋盘的截图(关于中国象棋, 我还是挺喜欢玩的):
    在这里插入图片描述

  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环境

  1. 升级我们的pip版本 python -m pip install --upgrade pip
  2. 通过pip安装 pyinstaller:
    pip --default-timeout=100 install pyinstaller -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
  3. 进⼊项⽬⽂件的⽂件夹,执⾏下⾯命令 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
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码分为几个部分:

  1. 导入所需模块和自定义常量(Cons)。
  2. 定义了Board类,继承自Canvas类。这个类包含了游戏的主要逻辑:初始化游戏、加载图片、创建对象、检查碰撞、移动蛇、显示得分等。
  3. 定义了Snake类,继承自Frame类。这个类主要用于在窗口中显示游戏界面。
  4. 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()

  1. 直接打包:pyinstaller -F tkinter_camera_Aligned.py (生成的exe文件运行后,运行会有个控制台,即可见的黑框)
  2. 不带控制台:pyinstaller -F -w tkinter_camera_Aligned.py (该命令会去除控制台,运行即运行仅程序窗口)
  3. 添加icon:pyinstaller -F -w -i favicon.ico tkinter_camera_Aligned.py (注:图片资源需与源文件在同意路径,或指定对应资源图路径)

生成的exe文件在环境主目录dist文件夹下
在这里插入图片描述

7. 总结

  • 本文粗略了解Tkinter GUI界面设计,围绕其基本组件设计简易的实验,总之纸上得来终觉浅,为知此事要躬行。
  • 在以后的博文中我们将学会用项目系统,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力
  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
非常详细的python图形界面组件开发教程,以代码的形式解析讲解,且所有代码都可直接运行,非常容易上手。 这系列教程完全以代码的形式来写的,目标是:读者看代码和注释就可以理解代码的意思。但这里的读者需要具备的几项技能: 1熟悉python语言的基础,如果还没有,先看一下python教程吧,英文官方(http://docs.python.org/tut/tut.html); 2对界面编程有一定的了解,知道基本的概念就可以了; 3对Tk有兴趣,别以为她是已经过时的技术,如果丧失了学习的兴趣,那肯定无法完成了; 4不要以Ctrl+C/Ctrl+V的方式使用本教程(虽然它可以这样直接运行),自己输入,你会发现自己原来也会犯这样的错误; 5安装了python2.5且确认安装了Tkinter模块(默认就安装了,如果你没有强制的把它去掉的话),下载python2.5(http://www.python.org/download/); 6如果在阅读教程中有不明白的,不要强迫自己,直接跳过去,继续下一个内容。 Tkinter教程系列教程的特点: 7他不是一本经过文字润色的文章,全部是代码,作者在必要的时候使用注释来解释; 8以组件为章节进行介绍,每个组件又分为不同的例子,各个例子可以单独使用,分别使用序号标注; 9各个例子的使用“注释+序号”的格式表示开始,下一个例子的开始为上一个例子的结束; 10全部使用结构化编程(SP),没有面向对象的概念(OO); 11基本上包含了TKinter的所有的控件,根据每个控件的使用方法,选择性的介绍了其属性和方法,没有全部介绍,全部的介绍查看Tkinter的官方参考(http://www.pythonware.com/library/tkinter/introduction/); 12例子不是百分百的完美,甚至有的例子没有按照Tkinter参考的描述完成,原因由于作者没有看懂:( 13参考书籍:http://www.pythonware.com/library/tkinter/introduction/,如有冲突以Tkinter参考为准
Python TkinterPython语言的一个GUI(图形用户界面)库。它提供了一组模块和类,用于创建应用程序的用户界面。TkinterPython内置的库,意味着我们可以轻松地将其集成到我们的Python项目中。 首先,我们需要导入Tkinter模块。通过使用Tkinter中的类和方法,我们可以创建窗口、标签、按钮、文本框等各种界面组件。我们可以使用如下代码创建一个简单的窗口: ```python import tkinter as tk # 创建主窗口 window = tk.Tk() window.title("我的第一个Tkinter窗口") window.geometry("300x200") # 运行窗口主循环 window.mainloop() ``` 这段代码首先导入了`tkinter`模块,并将其命名为`tk`,以便后续代码中的引用更简洁。然后,我们创建了一个名为`window`的主窗口,并设置了窗口的标题和大小。最后,我们调用了`mainloop`方法来启动窗口的主循环,使其保持可见状态。 除了创建窗口,我们还可以添加其他组件来构建一个完整的GUI界面。例如,我们可以添加一个标签和一个按钮: ```python import tkinter as tk window = tk.Tk() window.title("我的第一个Tkinter窗口") window.geometry("300x200") # 创建标签 label = tk.Label(window, text="欢迎使用Tkinter!") label.pack() # 创建按钮 button = tk.Button(window, text="点击我") button.pack() window.mainloop() ``` 这段代码中,我们首先创建了一个标签,它用于显示一段文本。然后,我们创建了一个按钮,该按钮可以执行一些操作(例如打印信息或调用其他函数)。最后,我们使用`pack`方法将标签和按钮添加到窗口中,并使用`mainloop`方法启动窗口的主循环。 通过使用Tkinter,我们可以轻松地创建各种类型的GUI应用程序,从简单的窗口到复杂的界面。如果想要深入了解Tkinter的更多功能和用法,可以参考官方文档或其他教程资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2345VOR

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值