不断从Entry小部件更新Label小部件TKinter

1 投票
1 回答
12982 浏览
提问于 2025-04-18 13:53

我正在尝试用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 个回答

7

while True 这个写法不行,因为 mainloop() 本身就是一种 while True 的循环,它会一直运行,直到你停止程序。


你需要使用 after(time_in_millisecond, function_name),这个方法会把 function_name 加入一个特殊的队列,然后 mainloop() 会在 time_in_millisecond 毫秒后执行它(只执行一次)。被执行的函数可以再用 after() 来自己调用自己,等 time_in_millisecond 毫秒后再执行。


第二种解决方案:你可以用 StringVarEntry,并且可以通过 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()

#------------------------------------

使用 StringVartrace 的示例

这可能是大多数组件的最佳解决方案。

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()

#------------------------------------

撰写回答