《零基础入门学习Python》第067讲:GUI的终极选择:Tkinter4

今天我们来学习 Entry 组件,也就是我们平时所说的 输入框。

输入框是跟程序打交道的途径,比如 程序要求你输入 账号 和 密码。那么它就要提供两个输入框,并且接收密码的输入框还会用 星号 * 将实际的内容给隐藏起来。

我们学了还几个 tkinter 的组件之后,你自然就会发现,其实,很多方法和选项,它们之间都是通用的,这些选项对于不同的组件来说,名字一样,内容也一样。比如说,在输入框中,用代码增加和删除内容,也就是使用 insert() 和 delete() 方法。

创建一个输入框

我们来尝试一下:

 
  
  1. import tkinter as tk

  2. root = tk.Tk()

  3. e = tk.Entry(root)

  4. e.pack(padx = 20, pady = 20)

  5. root.mainloop()

运行一下:

就得到了一个输入框,我们可以在里面填写任意的字符,当字符太长时,它会自动滚动。

我们这里试一下 :

e.delete(0, END) (这就是清空输入框)

e.insert(0, "默认文本...")

 
  
  1. import tkinter as tk

  2. root = tk.Tk()

  3. e = tk.Entry(root)

  4. e.pack(padx = 20, pady = 20)

  5. e.delete(0, "end") #清空输入框

  6. e.insert(0, "默认文本...") #在 索引0 位置写入字符

  7. root.mainloop()

运行一下:

那我们如何获取输入框中的内容呢?

我们可以使用 Entry 组件的 get() 方法,和之前的方法也是一样的。

你也可以将一个 tkinter 的变量(通常是一个 StringVar 变量)挂钩到 textvariable 选项,然后通过变量的 get() 方法来获取。

下面这个例子 ,就要实现如图的效果,按 获取信息 按钮时,会清空输入框,然后打印信息。

  

当我们按下 获取信息 按钮时:

我们一起来实现吧:

 
  
  1. import tkinter as tk

  2. root = tk.Tk()

  3. #生成两个 Label,显示作品和作者

  4. tk.Label(root, text = "作品:").grid(row = 0, column = 0)

  5. tk.Label(root, text = "作者:").grid(row = 1, column = 0)

  6. e1 = tk.Entry(root)

  7. e2 = tk.Entry(root)

  8. e1.grid(row = 0, column = 1, padx = 10, pady = 5)

  9. e2.grid(row = 1, column = 1, padx = 10, pady = 5)

  10. def show():

  11. print("作品:《%s》" %e1.get())

  12. print("作者:%s" %e2.get())

  13. e1.delete(0, "end")

  14. e2.delete(0, "end")

  15. tk.Button(root, text = "获取信息", width = 10, command = show)\

  16. .grid(row = 3, column = 0, sticky = "w", padx = 10, pady = 5)

  17. tk.Button(root, text = "退出", width = 10, command = root.quit)\

  18. .grid(row = 3, column = 1, sticky = "e", padx = 10, pady = 5) #退出就直接调用窗口的 quit() 方法

  19. 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. 将该选项设置为 "*",则是密码输入框(你这是为什么字符,就以什么字符代替)

我们直接在上面的代码上修改:

 
  
  1. import tkinter as tk

  2. root = tk.Tk()

  3. tk.Label(root, text = "账号:").grid(row = 0, column = 0)

  4. tk.Label(root, text = "密码:").grid(row = 1, column = 0)

  5. v1 = tk.StringVar()

  6. v2 = tk.StringVar()

  7. e1 = tk.Entry(root, textvariable = v1)

  8. e2 = tk.Entry(root, textvariable = v2, show = "*")

  9. e1.grid(row = 0, column = 1, padx = 10, pady = 5)

  10. e2.grid(row = 1, column = 1, padx = 10, pady = 5)

  11. def show():

  12. print("账号:%s" %v1.get())

  13. print("密码:%s" %v2.get())

  14. e1.delete(0, "end")

  15. e2.delete(0, "end")

  16. tk.Button(root, text = "登录", width = 10, command = show)\

  17. .grid(row = 3, column = 0, sticky = "w", padx = 10, pady = 5)

  18. tk.Button(root, text = "退出", width = 10, command = root.quit)\

  19. .grid(row = 3, column = 1, sticky = "e", padx = 10, pady = 5) #退出就直接调用窗口的 quit() 方法

  20. 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 键将焦点转移到第二个输入框的时候,验证功能被成功触发:

 
  
  1. import tkinter as tk

  2. master = tk.Tk()

  3. def test():

  4. if e1.get() == "来自江南的你":

  5. print("正确!")

  6. return True

  7. else:

  8. print("错误!")

  9. e1.delete(0, "end")

  10. return False

  11. v = tk.StringVar()

  12. e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=test)#focusout 就是焦点离开时验证

  13. e2 = tk.Entry(master)

  14. e1.pack(padx=10, pady=10)

  15. e2.pack(padx=10, pady=10)

  16. master.mainloop()

当输入信息不是 “来自江南的你” 的时候,就会打印错误,然后清空输入框。

然后,invalidcommand 选项指定的函数只有在 validatecommand 的返回值为 False 的时候才被调用。

下边的例子中,在第一个输入框输入“来自江南的我”,并通过 Tab 键将焦点转移到第二个输入框,validatecommand 指定的验证函数被触发并返回 False,接着 invalidcommand 被触发:

 
  
  1. import tkinter as tk

  2. master = tk.Tk()

  3. v = tk.StringVar()

  4. def test1():

  5. if v.get() == "来自江南的你":

  6. print("正确!")

  7. return True

  8. else:

  9. print("错误!")

  10. e1.delete(0, "end")

  11. return False

  12. def test2():

  13. print("我被调用了......")

  14. return True

  15. e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=test1, invalidcommand=test2)

  16. e2 = tk.Entry(master)

  17. e1.pack(padx=10, pady=10)

  18. e2.pack(padx=10, pady=10)

  19. 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() 方法将验证函数包装起来:

 
  
  1. import tkinter as tk

  2. master = tk.Tk()

  3. v = tk.StringVar()

  4. def test(content, reason, name):

  5. if content == "来自江南的你":

  6. print("正确!")

  7. print(content, reason, name)

  8. return True

  9. else:

  10. print("错误!")

  11. print(content, reason, name)

  12. return False

  13. testCMD = master.register(test) #冷却,就是调用 register() 方法将验证函数包装起来

  14. e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=(testCMD, '%P', '%v', '%W'))

  15. e2 = tk.Entry(master)

  16. e1.pack(padx=10, pady=10)

  17. e2.pack(padx=10, pady=10)

  18. master.mainloop()

运行一下:


有了以上的内容,我们就可以来设计一个计算器了。

 
  
  1. import tkinter as tk

  2. master = tk.Tk()

  3. frame = tk.Frame(master)

  4. frame.pack(padx = 10, pady = 10)

  5. v1 = tk.StringVar()

  6. v2 = tk.StringVar()

  7. v3 = tk.StringVar()

  8. def test(content):

  9. if content.isdigit():

  10. return True

  11. else:

  12. return False

  13. testCMD = master.register(test) #冷却,就是调用 register() 方法将验证函数包装起来

  14. e1 = tk.Entry(frame, width = 10, textvariable=v1, validate="key", validatecommand=(testCMD, '%P')).grid(row = 0, column = 0)

  15. tk.Label(frame, text = "+").grid(row = 0, column = 1)

  16. e2 = tk.Entry(frame, width = 10, textvariable=v2, validate="key", validatecommand=(testCMD, '%P')).grid(row = 0, column = 2)

  17. tk.Label(frame, text = "=").grid(row = 0, column = 3)

  18. e3 = tk.Entry(frame, width = 10, textvariable=v3, state = "readonly").grid(row = 0, column = 4)

  19. def calc():

  20. result = int(v1.get() )+ int(v2.get())

  21. v3.set(str(result))

  22. tk.Button(frame, text = "计算结果", command = calc).grid(row = 1, column = 2, pady = 10)

  23. master.mainloop()

针对网友提出的计算器程序存在的Bug,现对代码进行修改:

(修改日期:2019年1月7日09:34:40)

 
  
  1. import tkinter as tk

  2. master = tk.Tk()

  3. frame = tk.Frame(master)

  4. frame.pack(padx = 10, pady = 10)

  5. v1 = tk.StringVar()

  6. v2 = tk.StringVar()

  7. v3 = tk.StringVar()

  8. #针对输入框不能完全清空的问题,修改 test() 函数代码如下:

  9. #为什么不能清空,可以查看下方评论

  10. def test(content):

  11. if content.isdigit() or content == "":

  12. return True

  13. else:

  14. return False

  15. testCMD = master.register(test) #冷却,就是调用 register() 方法将验证函数包装起来

  16. e1 = tk.Entry(frame, width = 10, textvariable=v1, validate="key", validatecommand=(testCMD, '%P')).grid(row = 0, column = 0)

  17. tk.Label(frame, text = "+").grid(row = 0, column = 1)

  18. e2 = tk.Entry(frame, width = 10, textvariable=v2, validate="key", validatecommand=(testCMD, '%P')).grid(row = 0, column = 2)

  19. tk.Label(frame, text = "=").grid(row = 0, column = 3)

  20. e3 = tk.Entry(frame, width = 10, textvariable=v3, state = "readonly").grid(row = 0, column = 4)

  21. #针对输入框为空时按下计算按钮会报错的问题,修改 calc() 函数代码如下:

  22. def calc():

  23. if v1.get() == "" or v2.get() == "":

  24. result = ""

  25. v3.set(str(result))

  26. else:

  27. result = int(v1.get() )+ int(v2.get())

  28. v3.set(str(result))

  29. tk.Button(frame, text = "计算结果", command = calc).grid(row = 1, column = 2, pady = 10)

  30. master.mainloop()

你可能感兴趣的:(python零基础,python)