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

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

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

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

创建一个输入框

我们来尝试一下:

import tkinter as tk
 
master = tk.Tk()

e1 = tk.Entry(master)
e1.pack(padx=10,pady=10)

master.mainloop()

运行一下:

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

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

我们这里试一下 :

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

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

import tkinter as tk
 
master = tk.Tk()

e1 = tk.Entry(master)
e1.pack(padx=10,pady=10)

e1.delete(0,'end') #删除输入框中的第0个到最后一个字符
e1.insert(0,'默认文本...') #在索引下标为0的地方插入"默认文本..."

master.mainloop()

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

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

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

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

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

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

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

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

我们一起来实现吧:

import tkinter as tk
 
root = tk.Tk()

frame = tk.Frame(root)
frame.pack(padx=10,pady=10)

lable1 = tk.Label(frame,text='作品:    ').grid(row=0,column=0)
label2 = tk.Label(frame,text='作者:    ').grid(row=1,column=0)

e1 = tk.Entry(frame)
e1.grid(row=0,column=1,padx=10,pady=5) 
e2 = tk.Entry(frame)
e2.grid(row=1,column=1,padx=10,pady=5)
#这里要注意:上面的话不能写成如下所示
#e1 = tk.Entry(frame).grid(row=0,column=1,padx=10,pady=5) 
#如果像上面一样写的话会导致e1是一个空对象,空对象没有get()方法

def show() :
    print("作品:《%s》" %e1.get())
    print("作者:%s" %e2.get())
    e1.delete(0,'end')
    e2.delete(0,'end')

button1 = tk.Button(frame,text='获取信息',width=10,command=show)\
                            .grid(row=3,column=0,sticky='w',padx=10,pady=10)
button2 = tk.Button(frame,text='退出',width=10,command=frame.quit)\
                            .grid(row=3,column=1,sticky='e',padx=10,pady=10)

root.mainloop()

我们首先生成两个 Label ,来自于 root 窗口,显示作品和作者,关于布局,我们传统的做法是用两个 Frame 把它包围起来,现在教你一个新的方法,tkinter 总共提供了三种不同的 布局组件的方法,一种就是我们熟悉的 pack,还有一种就是 grid (网格),就是使用表格的形式来管理你的组件。另一种就是 place(在后面的笔记中介绍)。

grid() 是允许你使用表格的形式来管理组件的位置,它有选项 row 表示 column 表示 。(行数列数都是从0开始。)

然后是生成两个输入框。

最后是添加两个按钮。第一个是 “获取信息”,设置宽度 widthcommand 为**show()函数,另一个是“退出”**按钮,我们直接调用 quit() 方法即可。

关于按钮的布局,因为我们不仅要放在最后一行,还要分别靠左、靠右,这就需要设置 grid() 的 sticky 选项

sticky 用法

1. 控制组件在 grid 分配的空间中的位置

2. 可以使用 “n”, “e”, “s”, “w” 以及它们的组合来定位(ewsn代表东西南北,上北下南左西右东)

3. 使用加号(+)表示拉长填充,例如 “n” + “s” 表示将组件垂直拉长填充网格,“n” + “s” + “w” + “e” 表示填充整个网格

4. 不指定该值则居中显示

然后我们运行程序:

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

当我们按下 获取信息 时,
《零基础入门学习Python》第067讲:GUI的终极选择:Tkinter4

但是当我们按 退出 按钮时,没有任何反应,这是为什么呢?

这是因为 我们使用的 IDLE 也是使用 tkinter 写出来的,这里会发生冲突。我们可以直接 右键使用Python直接运行 该程序,就会正常工作了。

接下来就是如何设计一个密码输入框(用星号*代替你实际输入的内容)。

这个很简单,我们只需要设置一个 show 选项就可以了。

show 用法

1. 设置输入框如何显示文本的内容

2. 如果该值非空,则输入框会显示指定字符串代替真正的内容

3. 将该选项设置为 “*”,则是密码输入框(你这是为什么字符,就以什么字符代替

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

import tkinter as tk
 
root = tk.Tk()

frame = tk.Frame(root)
frame.pack(padx=10,pady=10)

string1 = tk.StringVar()
string2 = tk.StringVar()

lable1 = tk.Label(frame,text='账号:    ').grid(row=0,column=0)
label2 = tk.Label(frame,text='密码:    ').grid(row=1,column=0)

e1 = tk.Entry(frame,textvariable=string1)
e1.grid(row=0,column=1,padx=10,pady=5) 
e2 = tk.Entry(frame,textvariable=string2,show='*')
e2.grid(row=1,column=1,padx=10,pady=5)
#这里要注意:上面的话不能写成如下所示
#e1 = tk.Entry(frame).grid(row=0,column=1,padx=10,pady=5) 
#如果像上面一样写的话会导致e1是一个空对象,空对象没有get()方法

def show() :
    print("账号:%s" %e1.get())
    print("密码:%s" %e2.get())
    #e1.delete(0,'end')
    #e2.delete(0,'end')

button1 = tk.Button(frame,text='获取信息',width=10,command=show)\
                            .grid(row=3,column=0,sticky='w',padx=10,pady=10)
button2 = tk.Button(frame,text='退出',width=10,command=frame.quit)\
                            .grid(row=3,column=1,sticky='e',padx=10,pady=10)

root.mainloop()

这里我们还使用了另一种获取输入框内容的方法:“你也可以将一个 tkinter 的变量(通常是一个 StringVar 变量)挂钩到 textvariable 选项,然后通过变量的 get() 方法来获取。”

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

基本的问题都解决了。

接下来我们试图设计一个计算器,大家都知道,计算器不能够输入除了数字之外的任何字符,这又该如何限制呢?

这也是可以实现的,Entry 本身就自带了 验证功能。用于验证输入框里的内容的合法性,比如要求输入数字,你输入了字母那就是非法。实现该功能,需要通过设置 validate validatecommand invalidcommand 选项

首先启用验证的“开关”是 validate 选项,该选项可以设置的值有:(焦点指的就是 输入字符的光标《零基础入门学习Python》第067讲:GUI的终极选择:Tkinter4

含义
'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()

#focusout 就是焦点离开时验证
e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=test)
e2 = tk.Entry(master)
e1.pack(padx=10, pady=10)
e2.pack(padx=10, pady=10)
 
master.mainloop()

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

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

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

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

import tkinter  as tk
 
master = tk.Tk()
 
def test1():
    if e1.get() == "一只没有脚的猪":
        print("正确!")
        return True
    else:
        print("错误!")
        e1.delete(0, "end")
        return False
 
def test2():
    print("我被调用了......")
    return True

v = tk.StringVar()

#focusout 就是焦点离开时验证
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()

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

最后,其实 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() 方法将验证函数包装起来:


运行一下:

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


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

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

#针对输入框为空时按下计算按钮会报错的问题,修改 calc() 函数:    
def caculate():
        if v1.get() == "" or v2.get() == "":
                result = ""
                v3.set(str(result))                
        else:
                result = int(v1.get() )+ int(v2.get())
                v3.set(str(result))

testCMD = frame.register(test)  #冷却,就是调用 register() 方法将验证函数包装起来
e1 = tk.Entry(frame, textvariable=v1, width=10,validate="focusout", validatecommand=(testCMD, '%P'))
e1.grid(row=0,column=0)

lable1= tk.Label(frame,text='+')
lable1.grid(row=0,column=1)

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

lable1= tk.Label(frame,text='=')
lable1.grid(row=0,column=3)

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

button = tk.Button(frame,text='计算结果',command=caculate)
button.grid(row=1,column=2,pady=10)
 
frame.mainloop()

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