Sixwinged
Sixwinged

Reputation: 155

Constantly Update Label Widgets From Entry Widgets TKinter

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

Answers (1)

furas
furas

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

Related Questions