John Doe
John Doe

Reputation: 11

Tkinter Entry widget requires two events to update

I've been trying to develop a small gui to calculate some totals with weighting etc. While trying to get a total to update real-time with a changing entry, I noticed it took two events to update; This is a simplified version of my code that shows the problem:

from Tkinter import *
root=Tk()
frame=Frame(root)
frame.pack()
entry=Entry(frame)
entry.pack()
label=Label(frame,text="entry:")
label.pack()
def updatelabel(event):
    label=Label(frame,text="entry:"+entry.get())
    label.pack()
    print "called"
entry.bind("<Key>", updatelabel)

root.mainloop()

When you input into the field the function calls, but does not update to what was typed until the next character is typed. How would I go about getting the label to update to what is in the field at the time?

Upvotes: 0

Views: 1160

Answers (3)

martineau
martineau

Reputation: 123531

You don't really need to explicitly process events and use callback functions to accomplish what you want. In other words it's possible to get Tkinter to do it for you automatically using a StringVar().

from Tkinter import *

root=Tk()
frame=Frame(root)
frame.pack()

entry_var = StringVar()
entry_var.set('')

entry = Entry(frame, textvariable=entry_var)
entry.pack()

label = Label(frame, text='entry: ')
label.pack(side=LEFT)

contents = Label(frame, textvariable=entry_var)
contents.pack(side=LEFT)

entry.focus_set()  # force initial keyboard focus to be on entry widget
root.mainloop()

Upvotes: 1

Reblochon Masque
Reblochon Masque

Reputation: 36732

No it doesn't require two entries to be called, it is called on the first entry. The key bindings are on the Entry widgets to avoid the problems that a binding to the root will create if you have more than one entry widget.

import tkinter as tk

class SmallApp(tk.Frame):
    def __init__(self, master = None):
        tk.Frame.__init__(self, master)
        self.master = master
        self.pack()
        self.entry = tk.Entry(self)
        self.entry.pack()
        self.var = "entry:"
        self.label = tk.Label(text = self.var)
        self.label.pack()
        self.entry.bind("<Key>", self.updatelabel)

    def updatelabel(self, event):
        self.var += event.char
        self.label.configure(text=self.var)

root = tk.Tk()
app = SmallApp(root)
app.mainloop()

Upvotes: 0

Camon
Camon

Reputation: 1043

Instead of using entry.bind("<Key>", update label), I used the root window instead: root.bind("<Key>", update label). This did the trick, however it is important to realize that the function updatelabel() will be called every time a key is pressed in your tkinter window. This could cause some problems if you have more than one entry box updating labels.

Here is the code I wrote with a few modifications:

from Tkinter import *

root=Tk()
frame=Frame(root)
frame.pack()
update_label = StringVar()  # Made a StringVar so you don't get new labels every time a key is pressed.
update_label.set("entry:")
entry=Entry(frame)
entry.pack()

label=Label(frame,textvariable=update_label)  # Used textvariable= instead of text=
label.pack()

def updatelabel(event):
    update_label.set("entry:" + entry.get())  # Setting the variable used in textvariable=
    print "called"

root.bind("<Key>", updatelabel)  # Changed entry.bind to root.bind

root.mainloop()

Upvotes: 0

Related Questions