Chuox
Chuox

Reputation: 793

Change multiple and codependent tkinter Entry value

So I'm trying to create something like the goole unit conversion tool So far I have this:

import tkinter

rate = 3.281

def command_P():
    print("button pressed")

def callback1(arg):
    try:
        float(amount1.get())
        amount2.delete(0,"end")
        amount2.insert(0,float(amount1.get())*rate)
    except Exception as e:
        print(e)

def callback2(arg):
    try:
        float(amount2.get())
        amount1.delete(0,"end")
        amount1.insert(0,float(amount2.get())/rate)
    except Exception as e:
        print(e)

trade_w = tkinter.Tk()
trade_w.title("Unit Converter")


label_mont1 = tkinter.Label(trade_w,
                    text = "Metre:")
label_mont1.grid(column=0, row=1)

sv = tkinter.StringVar()
sv.trace("w", lambda name, index, mode, sv=sv: callback1(sv))

amount1 = tkinter.Entry(trade_w,textvariable=sv)
amount1.grid(column=1, row=1)

label_mont2 = tkinter.Label(trade_w,
                    text = "Foot:")
label_mont2.grid(column=2, row=1)

vs = tkinter.StringVar()
vs.trace("w", lambda name, index, mode, vs=vs: callback2(vs))


amount2 = tkinter.Entry(trade_w, textvariable=vs)
amount2.grid(column=3, row=1)


trade_w.mainloop()

Everything seem to work fine but when I write something on either box it moves the text cursor to the end of the Entry box, thats becouse when I do the .get() for amount1 or amount2 it does the callback function and recalculate the value.

Any idea of how to bypass or solve this?

Thanks!

Upvotes: 0

Views: 52

Answers (2)

acw1668
acw1668

Reputation: 46678

You can use <KeyRelease> event callback instead of tracing change of tkinter variable:

import tkinter

rate = 3.281

def on_entry_change(event):
    try:
        if event.widget is amount1:
            value = float(sv.get())
            vs.set(value * rate)
        else:
            value = float(vs.get())
            sv.set(value / rate)
    except Exception as e:
        print(e)

trade_w = tkinter.Tk()
trade_w.title("Unit Converter")

label_mont1 = tkinter.Label(trade_w, text="Metre:")
label_mont1.grid(column=0, row=1)

sv = tkinter.StringVar()
amount1 = tkinter.Entry(trade_w, textvariable=sv)
amount1.grid(column=1, row=1)
amount1.bind('<KeyRelease>', on_entry_change)

label_mont2 = tkinter.Label(trade_w, text="Foot:")
label_mont2.grid(column=2, row=1)

vs = tkinter.StringVar()
amount2 = tkinter.Entry(trade_w, textvariable=vs)
amount2.grid(column=3, row=1)
amount2.bind('<KeyRelease>', on_entry_change)

trade_w.mainloop()

Upvotes: 0

Bryan Oakley
Bryan Oakley

Reputation: 385970

Since you know (or can determine) which widget has focus, just have the callback do nothing unless the focus is in a particular window.

Example:

def callback1(arg):
    if trade_w.focus_get() == amount1:
        try:
            float(amount1.get())
            amount2.delete(0,"end")
            amount2.insert(0,float(amount1.get())*rate)
        except Exception as e:
            print(e)

def callback2(arg):
    if trade_w.focus_get() == amount2:
        try:
            float(amount2.get())
            amount1.delete(0,"end")
            amount1.insert(0,float(amount2.get())/rate)
        except Exception as e:
            print(e)

There are more efficient ways to do that, but this illustrates the point that you can determine which widget has the focus so that you only update the other widget.

Upvotes: 1

Related Questions