不断从Entry小部件更新Label小部件TKinter
我正在尝试用TKinter创建一个表单,这个表单可以从一个或多个输入框中获取信息,并把这些信息用作文本框的内容。例如,下面的代码可以实现这个功能:
import Tkinter
from Tkinter import *
top = Tk()
e1 = Entry(top)
e2 = Entry(top)
t = Label(top, text = e1.get() + e2.get())
e1.pack()
e2.pack()
t.pack()
top.mainloop()
但是,问题是这个内容不会自动更新。我知道可以通过点击按钮来实现更新,但我希望在用户输入内容时,标签(Label)里的信息能够实时计算和更新。请问有什么好的方法可以做到这一点呢?我尝试用一个循环来实现,但这样做不行,因为程序会一直停留在顶层的mainloop()里,无法退出:
import Tkinter
from Tkinter import *
top = Tk()
e1 = Entry(top)
e2 = Entry(top)
t = Label(top, text = e1.get() + e2.get())
e1.pack()
e2.pack()
while True:
t = Label(top, text = e1.get() + e2.get())
t.pack()
top.mainloop()
提前谢谢你们的帮助。
六
1 个回答
while True
这个写法不行,因为 mainloop()
本身就是一种 while True
的循环,它会一直运行,直到你停止程序。
你需要使用 after(time_in_millisecond, function_name)
,这个方法会把 function_name
加入一个特殊的队列,然后 mainloop()
会在 time_in_millisecond
毫秒后执行它(只执行一次)。被执行的函数可以再用 after()
来自己调用自己,等 time_in_millisecond
毫秒后再执行。
第二种解决方案:你可以用 StringVar
和 Entry
,并且可以通过 trace()
给 StringVar
绑定一个函数,这个函数会在 StringVar
发生变化时被执行。
第三种解决方案:你可以把事件(<Key>
)绑定到 Entry
上,这样当你在 Entry
中按下某个键时,就会调用一个函数。
最后一种解决方案:你可以在 Entry
中使用 validatecommand=
和 validate=
,这样当输入框中的文本发生变化时,就会调用某个函数。
参考 Tkinter 书籍:
Tkinter 输入框组件,
事件和绑定,
变量类(BooleanVar, DoubleVar, IntVar, StringVar)
编辑:
使用 validatecommand=
和 validate=
的示例。
并不是所有的组件都有 validatecommand=
from Tkinter import *
#------------------------------------
def my_validater():
new_text = e1.get() + e2.get()
# different method to set label text (without StringVar)
#t['text'] = new_text
t.config(text=new_text)
# validater have to return True or False
return True
#------------------------------------
top = Tk()
#---
t = Label(top)
t.pack()
#---
e1 = Entry(top, validate='key', validatecommand=my_validater) # validate every key
e1.pack()
#---
e2 = Entry(top, validate='key', validatecommand=my_validater) # validate every key
e2.pack()
#---
top.mainloop()
#------------------------------------
使用 StringVar
和 trace
的示例
这可能是大多数组件的最佳解决方案。
from Tkinter import *
#------------------------------------
def my_tracer(a, b, c): # trace send 3 arguments to my_tracer
#print a, b, c
# using StringVar to get and set text
new_text = e1_var.get() + e2_var.get()
t_var.set(new_text)
#------------------------------------
top = Tk()
#---
t_var = StringVar() # or StringVar(top)
t = Label(top, textvariable=t_var)
t.pack()
#---
e1_var = StringVar() # or StringVar(top)
e1_var.trace('w', my_tracer) # run my_tracer if value was changed (w = write)
e1 = Entry(top, textvariable=e1_var)
e1.pack()
#---
e2_var = StringVar() # or StringVar(top)
e2_var.trace('w', my_tracer) # run my_tracer if value was changed (w = write)
e2 = Entry(top, textvariable=e2_var)
e2.pack()
#---
top.mainloop()
#------------------------------------
使用 bind(<Key>, ...)
的示例
绑定的函数在字符被放入 Entry
之前被调用,所以你得到的文本是没有最后一个字符的。这种方法在这种情况下不太好,但我还是保留了它。最终你可以获取 event.char
并把缺失的字符加到文本中。
from Tkinter import *
#------------------------------------
def my_bind(event): # bind send 1 argument to my_bind
# different type of event can have different atributes
#print event, event.widget, event.char, event.keysym, event.keycode
new_text = e1.get() + e2.get()
t.config(text=new_text)
#------------------------------------
top = Tk()
#---
t = Label(top)
t.pack()
#---
e1 = Entry(top)
e1.pack()
e1.bind('<Key>', my_bind)
#---
e2 = Entry(top)
e2.pack()
e2.bind('<Key>', my_bind)
#---
top.mainloop()
#------------------------------------
使用 after()
的示例。
用于不同的重复任务。
from Tkinter import *
#------------------------------------
def my_after():
new_text = e1.get() + e2.get()
t.config(text=new_text)
# call again after 100 ms
top.after(100, my_after)
#------------------------------------
top = Tk()
#---
t = Label(top)
t.pack()
#---
e1 = Entry(top)
e1.pack()
#---
e2 = Entry(top)
e2.pack()
#---
# call first time
my_after()
# call first time after 100 ms
#top.after(100, my_after)
#---
top.mainloop()
#------------------------------------