今天我们来学习 Entry 组件,也就是我们平时所说的 输入框。
输入框是跟程序打交道的途径,比如 程序要求你输入 账号 和 密码。那么它就要提供两个输入框,并且接收密码的输入框还会用 星号 * 将实际的内容给隐藏起来。
我们学了还几个 tkinter 的组件之后,你自然就会发现,其实,很多方法和选项,它们之间都是通用的,这些选项对于不同的组件来说,名字一样,内容也一样。比如说,在输入框中,用代码增加和删除内容,也就是使用 insert() 和 delete() 方法。
创建一个输入框
我们来尝试一下:
-
import tkinter as tk
-
root = tk.Tk()
-
e = tk.Entry(root)
-
e.pack(padx = 20, pady = 20)
-
root.mainloop()
运行一下:
就得到了一个输入框,我们可以在里面填写任意的字符,当字符太长时,它会自动滚动。
我们这里试一下 :
e.delete(0, END) (这就是清空输入框)
e.insert(0, "默认文本...")
-
import tkinter as tk
-
root = tk.Tk()
-
e = tk.Entry(root)
-
e.pack(padx = 20, pady = 20)
-
e.delete(0, "end") #清空输入框
-
e.insert(0, "默认文本...") #在 索引0 位置写入字符
-
root.mainloop()
运行一下:
那我们如何获取输入框中的内容呢?
我们可以使用 Entry 组件的 get() 方法,和之前的方法也是一样的。
你也可以将一个 tkinter 的变量(通常是一个 StringVar 变量)挂钩到 textvariable 选项,然后通过变量的 get() 方法来获取。
下面这个例子 ,就要实现如图的效果,按 获取信息 按钮时,会清空输入框,然后打印信息。
当我们按下 获取信息 按钮时:
我们一起来实现吧:
-
import tkinter as tk
-
root = tk.Tk()
-
#生成两个 Label,显示作品和作者
-
tk.Label(root, text = "作品:").grid(row = 0, column = 0)
-
tk.Label(root, text = "作者:").grid(row = 1, column = 0)
-
e1 = tk.Entry(root)
-
e2 = tk.Entry(root)
-
e1.grid(row = 0, column = 1, padx = 10, pady = 5)
-
e2.grid(row = 1, column = 1, padx = 10, pady = 5)
-
def show():
-
print("作品:《%s》" %e1.get())
-
print("作者:%s" %e2.get())
-
e1.delete(0, "end")
-
e2.delete(0, "end")
-
tk.Button(root, text = "获取信息", width = 10, command = show)\
-
.grid(row = 3, column = 0, sticky = "w", padx = 10, pady = 5)
-
tk.Button(root, text = "退出", width = 10, command = root.quit)\
-
.grid(row = 3, column = 1, sticky = "e", padx = 10, pady = 5) #退出就直接调用窗口的 quit() 方法
-
root.mainloop()
我们首先生成两个 Label ,来自于 root 窗口,显示作品和作者,关于布局,我们传统的做法是用两个 Frame 把它包围起来,现在教你一个新的方法,tkinter 总共提供了三种不同的 布局组件的方法,一种就是我们熟悉的 pack,还有一种就是 grid (网格),就是使用表格的形式来管理你的组件。另一种就是 place(在后面的笔记中介绍)。
grid() 是允许你使用表格的形式来管理组件的位置,它有选项 row 表示 行,column 表示 列。(行数列数都是从0开始。)
然后是生成两个输入框。
最后是添加两个按钮。第一个是 “获取信息”,设置宽度 width ,command 为show()函数,另一个是“退出”按钮,我们直接调用 quit() 方法即可。
关于按钮的布局,因为我们不仅要放在最后一行,还要分别靠左、靠右,这就需要设置 grid() 的 sticky 选项
sticky 用法
1. 控制组件在 grid 分配的空间中的位置
2. 可以使用 "n", "e", "s", "w" 以及它们的组合来定位(ewsn代表东西南北,上北下南左西右东)
3. 使用加号(+)表示拉长填充,例如 "n" + "s" 表示将组件垂直拉长填充网格,"n" + "s" + "w" + "e" 表示填充整个网格
4. 不指定该值则居中显示
然后我们运行程序:
当我们按下 获取信息 时,
但是当我们按 退出 按钮时,没有任何反应,这是为什么呢?
这是因为 我们使用的 IDLE 也是使用 tkinter 写出来的,这里会发生冲突。我们可以直接 右键使用Python直接运行 该程序,就会正常工作了。
接下来就是如何设计一个密码输入框(用星号*代替你实际输入的内容)。
这个很简单,我们只需要设置一个 show 选项就可以了。
show 用法
1. 设置输入框如何显示文本的内容
2. 如果该值非空,则输入框会显示指定字符串代替真正的内容
3. 将该选项设置为 "*",则是密码输入框(你这是为什么字符,就以什么字符代替)
我们直接在上面的代码上修改:
-
import tkinter as tk
-
root = tk.Tk()
-
tk.Label(root, text = "账号:").grid(row = 0, column = 0)
-
tk.Label(root, text = "密码:").grid(row = 1, column = 0)
-
v1 = tk.StringVar()
-
v2 = tk.StringVar()
-
e1 = tk.Entry(root, textvariable = v1)
-
e2 = tk.Entry(root, textvariable = v2, show = "*")
-
e1.grid(row = 0, column = 1, padx = 10, pady = 5)
-
e2.grid(row = 1, column = 1, padx = 10, pady = 5)
-
def show():
-
print("账号:%s" %v1.get())
-
print("密码:%s" %v2.get())
-
e1.delete(0, "end")
-
e2.delete(0, "end")
-
tk.Button(root, text = "登录", width = 10, command = show)\
-
.grid(row = 3, column = 0, sticky = "w", padx = 10, pady = 5)
-
tk.Button(root, text = "退出", width = 10, command = root.quit)\
-
.grid(row = 3, column = 1, sticky = "e", padx = 10, pady = 5) #退出就直接调用窗口的 quit() 方法
-
root.mainloop()
这里我们还使用了另一种获取输入框内容的方法:“你也可以将一个 tkinter 的变量(通常是一个 StringVar 变量)挂钩到 textvariable 选项,然后通过变量的 get() 方法来获取。”
运行一下:
基本的问题都解决了。
接下来我们试图设计一个计算器,大家都知道,计算器不能够输入除了数字之外的任何字符,这又该如何限制呢?
这也是可以实现的,Entry 本身就自带了 验证功能。用于验证输入框里的内容的合法性,比如要求输入数字,你输入了字母那就是非法。实现该功能,需要通过设置 validate、validatecommand 和 invalidcommand 选项。
首先启用验证的“开关”是 validate 选项,该选项可以设置的值有:(焦点指的就是 输入字符的光标)
值 | 含义 |
'focus' | 当 Entry 组件获得或失去焦点的时候验证 |
'focusin' | 当 Entry 组件获得焦点的时候验证 |
'focusout' | 当 Entry 组件失去焦点的时候验证 |
'key' | 当输入框被编辑的时候验证 |
'all' | 当出现上边任何一种情况的时候验证 |
'none' | 1. 关闭验证功能 2. 默认设置该选项(即不启用验证) 3. 注意,是字符串的 'none',而非 None |
其次是为 validatecommand 选项指定一个验证函数,该函数只能返回 True 或 False 表示验证的结果。一般情况下验证函数只需要知道输入框的内容即可,可以通过 Entry 组件的 get() 方法获得该字符串。
下边的例子中,在第一个输入框输入“来自江南的你” 并通过 Tab 键将焦点转移到第二个输入框的时候,验证功能被成功触发:
-
import tkinter as tk
-
master = tk.Tk()
-
def test():
-
if e1.get() == "来自江南的你":
-
print("正确!")
-
return True
-
else:
-
print("错误!")
-
e1.delete(0, "end")
-
return False
-
v = tk.StringVar()
-
e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=test)#focusout 就是焦点离开时验证
-
e2 = tk.Entry(master)
-
e1.pack(padx=10, pady=10)
-
e2.pack(padx=10, pady=10)
-
master.mainloop()
当输入信息不是 “来自江南的你” 的时候,就会打印错误,然后清空输入框。
然后,invalidcommand 选项指定的函数只有在 validatecommand 的返回值为 False 的时候才被调用。
下边的例子中,在第一个输入框输入“来自江南的我”,并通过 Tab 键将焦点转移到第二个输入框,validatecommand 指定的验证函数被触发并返回 False,接着 invalidcommand 被触发:
-
import tkinter as tk
-
master = tk.Tk()
-
v = tk.StringVar()
-
def test1():
-
if v.get() == "来自江南的你":
-
print("正确!")
-
return True
-
else:
-
print("错误!")
-
e1.delete(0, "end")
-
return False
-
def test2():
-
print("我被调用了......")
-
return True
-
e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=test1, invalidcommand=test2)
-
e2 = tk.Entry(master)
-
e1.pack(padx=10, pady=10)
-
e2.pack(padx=10, pady=10)
-
master.mainloop()
最后,其实 Tkinter 还有隐藏技能,不过需要冷却才能触发
Tkinter 为验证函数提供一些额外的选项:
额外选项 | 含义 |
'%d' | 操作代码:0 表示删除操作;1 表示插入操作;2 表示获得、失去焦点或 textvariable 变量的值被修改 |
'%i' | 1. 当用户尝试插入或删除操作的时候,该选线表示插入或删除的位置(索引号) 2. 如果是由于获得、失去焦点或 textvariable 变量的值被修改而调用验证函数,那么该值是 -1 |
'%P' | 1. 当输入框的值允许改变的时候,该值有效 2. 该值为输入框的最新文本内容 |
'%s' | 该值为调用验证函数前输入框的文本内容 |
'%S' | 1. 当插入或删除操作触发验证函数的时候,该值有效 2. 该选项表示文本被插入和删除的内容 |
'%v' | 该组件当前的 validate 选项的值 |
'%V' | 1. 调用验证函数的原因 2. 该值是 'focusin','focusout','key' 或 'forced'(textvariable 选项指定的变量值被修改)中的一个 |
'%W' | 该组件的名字,不过是 tk 变量在内部注册的名字,为一串数字。 |
为了使用这些选项,你可以这样写:validatecommand=(f, s1, s2, ...)
其中,f 就是你“冷却后”的验证函数名,s1、s2、s3 这些是额外的选项,这些选项会作为参数依次传给 f 函数。我们刚刚说了,使用隐藏技能前需要冷却,其实就是调用 register() 方法将验证函数包装起来:
-
import tkinter as tk
-
master = tk.Tk()
-
v = tk.StringVar()
-
def test(content, reason, name):
-
if content == "来自江南的你":
-
print("正确!")
-
print(content, reason, name)
-
return True
-
else:
-
print("错误!")
-
print(content, reason, name)
-
return False
-
testCMD = master.register(test) #冷却,就是调用 register() 方法将验证函数包装起来
-
e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=(testCMD, '%P', '%v', '%W'))
-
e2 = tk.Entry(master)
-
e1.pack(padx=10, pady=10)
-
e2.pack(padx=10, pady=10)
-
master.mainloop()
运行一下:
有了以上的内容,我们就可以来设计一个计算器了。
-
import tkinter as tk
-
master = tk.Tk()
-
frame = tk.Frame(master)
-
frame.pack(padx = 10, pady = 10)
-
v1 = tk.StringVar()
-
v2 = tk.StringVar()
-
v3 = tk.StringVar()
-
def test(content):
-
if content.isdigit():
-
return True
-
else:
-
return False
-
testCMD = master.register(test) #冷却,就是调用 register() 方法将验证函数包装起来
-
e1 = tk.Entry(frame, width = 10, textvariable=v1, validate="key", validatecommand=(testCMD, '%P')).grid(row = 0, column = 0)
-
tk.Label(frame, text = "+").grid(row = 0, column = 1)
-
e2 = tk.Entry(frame, width = 10, textvariable=v2, validate="key", validatecommand=(testCMD, '%P')).grid(row = 0, column = 2)
-
tk.Label(frame, text = "=").grid(row = 0, column = 3)
-
e3 = tk.Entry(frame, width = 10, textvariable=v3, state = "readonly").grid(row = 0, column = 4)
-
def calc():
-
result = int(v1.get() )+ int(v2.get())
-
v3.set(str(result))
-
tk.Button(frame, text = "计算结果", command = calc).grid(row = 1, column = 2, pady = 10)
-
master.mainloop()
针对网友提出的计算器程序存在的Bug,现对代码进行修改:
(修改日期:2019年1月7日09:34:40)
-
import tkinter as tk
-
master = tk.Tk()
-
frame = tk.Frame(master)
-
frame.pack(padx = 10, pady = 10)
-
v1 = tk.StringVar()
-
v2 = tk.StringVar()
-
v3 = tk.StringVar()
-
#针对输入框不能完全清空的问题,修改 test() 函数代码如下:
-
#为什么不能清空,可以查看下方评论
-
def test(content):
-
if content.isdigit() or content == "":
-
return True
-
else:
-
return False
-
testCMD = master.register(test) #冷却,就是调用 register() 方法将验证函数包装起来
-
e1 = tk.Entry(frame, width = 10, textvariable=v1, validate="key", validatecommand=(testCMD, '%P')).grid(row = 0, column = 0)
-
tk.Label(frame, text = "+").grid(row = 0, column = 1)
-
e2 = tk.Entry(frame, width = 10, textvariable=v2, validate="key", validatecommand=(testCMD, '%P')).grid(row = 0, column = 2)
-
tk.Label(frame, text = "=").grid(row = 0, column = 3)
-
e3 = tk.Entry(frame, width = 10, textvariable=v3, state = "readonly").grid(row = 0, column = 4)
-
#针对输入框为空时按下计算按钮会报错的问题,修改 calc() 函数代码如下:
-
def calc():
-
if v1.get() == "" or v2.get() == "":
-
result = ""
-
v3.set(str(result))
-
else:
-
result = int(v1.get() )+ int(v2.get())
-
v3.set(str(result))
-
tk.Button(frame, text = "计算结果", command = calc).grid(row = 1, column = 2, pady = 10)
-
master.mainloop()