Reputation: 155
I am trying to make a form using TKinter that takes information from a/multiple entry widget(s) and uses them as the value for text widgets. For example, this could work:
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()
The issue is that this does not automatically update itself. I know it could be done using a button, but I would like to have the information calculated/updated in the Label widget as the user types into the Entry widgets. What would be the best was to do this? The following implementation of a while loop does not work as the program enters the top.mainloop() and does not exit:
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()
Thank you in advance. Six
Upvotes: 1
Views: 13230
Reputation: 142651
while True
will not work because mainloop()
is some kind of while True
loop and it works all the time till you stop program.
You have to use after(time_in_millisecond, function_name)
which add function_name
to special queue and mainloop()
will run it (only once) after time_in_millisecond
. Executed function can use after()
to run itself again after time_in_millisecond
.
Second solution: You can use StringVar
with Entry
and you can assign function to StringVar
(using trace()
) and this function will be executed every time when StringVar
will be changed.
Third solution: you can bind event (<Key>
) to Entry
which will call some function when you press key in Entry.
Last solution: You can use validatecommand=
with validate=
in Entry
to call some function when text in entry will be changed.
See Tkinterbook:
The Tkinter Entry Widget,
Events and Bindings,
The Variable Classes (BooleanVar, DoubleVar, IntVar, StringVar)
EDIT:
Example with validatecommand=
with validate=
.
Not all widgets have 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()
#------------------------------------
Example with StringVar
and trace
Probably the best solution for most widgets.
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()
#------------------------------------
Example with bind(<Key>, ...)
Binded function is called before char is placed in Entry
so you get text without last char in Entry
. This method is not good for this situation but I keep it.
Eventually you can get event.char
and add missing char to text.
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()
#------------------------------------
Example with after()
.
Used for different repeated jobs.
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()
#------------------------------------
Upvotes: 6