Having one entry influence the value in the other entry and visa versa

Viewed 42

I am new to using Tkinter (just started today) and I followed a worked example to make a converter with a button from Celsius to Fahrenheit, however now I am trying to modify it as an exercise such that typing the value in one box will output the opposite in the other box.

For example, a value of 10.30 should output 50.54 in the Fahrenheit input box, or an input of 32.0 to the Fahrenheit box should output 0.0 in the Celsius box as some live update. Here is the code I have so far which works but not exactly in the best way:

from tkinter import *

class App:

    def __init__(self, master):

        frame = Frame(master)
        frame.pack()

        labelCelsius = Label(frame, text="Celsius")
        labelCelsius.grid(row=0, column=0)

        labelFahrenheit = Label(frame, text="Fahrenheit")
        labelFahrenheit.grid(row=1, column=0)

        self.celsius = DoubleVar()
        self.celsius.trace("w", self.C2F)
        entryCelsius = Entry(frame, textvariable=self.celsius)
        entryCelsius.grid(row=0, column=1)

        self.fahrenheit = DoubleVar()
        self.fahrenheit.trace("w", self.F2C)
        entryFahrenheit = Entry(frame, textvariable=self.fahrenheit)
        entryFahrenheit.grid(row=1, column=1)

    def C2F(self, *args):
        IN = self.celsius.get()
        self.fahrenheit.set(1.8 * IN + 32)

    def F2C(self, *args):
        IN = self.fahrenheit.get()
        self.celsius.set((IN-32)/1.8)

root = Tk()
root.wm_title("Temperature converter")
app = App(root)
root.mainloop()

This seems to create some infinite loop where Celsius updates Fahrenheit, then Fahrenheit updates Celsius, and visa versa.

Essentially, if typing in the Celsius Entry, the Fahrenheit should me modified, but should not then modify Celsius -- the same the other way around.

Thankyou for any help :)

1 Answers

One of the ways is, you can remove the trace then add it back after setting the value.

def __init__(self, master):
    ...
    ...
    self.celsius = DoubleVar()
    self.celsius.trace_id = self.celsius.trace("w", self.C2F) #keep the trace_id
    ...
    ...
    self.fahrenheit = DoubleVar()
    self.fahrenheit.trace_id = self.fahrenheit.trace("w", self.F2C) #keep the trace_id

def C2F(self, *args):
    IN = self.celsius.get()
    self.fahrenheit.trace_vdelete("w", self.fahrenheit.trace_id) #remote the trace
    self.fahrenheit.set(1.8 * IN + 32)
    self.fahrenheit.trace_id = self.fahrenheit.trace("w", self.F2C) #add it back

def F2C(self, *args):
    IN = self.fahrenheit.get()
    self.celsius.trace_vdelete("w", self.celsius.trace_id) #remote the trace
    self.celsius.set((IN-32)/1.8)
    self.celsius.trace_id = self.celsius.trace("w", self.C2F) #add it back
Related