1

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

Sixwinged
  • 145
  • 2
  • 2
  • 6
  • With a little more thought, would a top.after-scheduled function work? – Sixwinged Jul 18 '14 at 19:21
  • First of all, where are the `StringVar()` and the `textvariable=` argument in Entry widgets? Then you can write inside a function the Label widget, and callback it with the `.after()` method of each Entry widgets. – Trimax Jul 18 '14 at 19:50

1 Answers1

7

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

#------------------------------------
furas
  • 134,197
  • 12
  • 106
  • 148
  • Hey, why is the label one character behind?How can i make it real time? – 0n10n_ May 26 '17 at 16:53
  • @0n10n_ it is 3 years old question I don't remeber it – furas May 28 '17 at 14:08
  • 1
    @0n10n_ `bind('')` and `bind('')` execute function before key is send to widget so you can't get last key from widget - `e1.get()`. `bind('')` executes function after key is send to widget so you can get last key from widget - `e1.get()`. – furas May 28 '17 at 14:15