0

I have simple code which creates two fields by the press of a button. There are two other buttons to save and load back the entry fields created. I have used the bind function to bind field A and field B. Pressing the Enter button on field A after entering a number will print out its value multiplied by 5 in field B. At this point the bind function works perfectly.

When I create three entry fields and save the progress without entering any inputs and compile the program, then load the file, the bind function does not seem to work. It seems to work only for the last field created. My code is as follows. I tried my best to simplify the code.

from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.filedialog import asksaveasfile
from tkinter import messagebox
import pickle

class Test(Frame):

    def Widgets(self):

        self.button_add = Button(self, text = "Add", command = self.add)
        self.button_add.grid(row=0, column =2)

        self.button_save = Button(self, text = "save", command = self.save)
        self.button_save.grid(row=0, column =3)

        self.button_load = Button(self, text = "load", command = self.load)
        self.button_load.grid(row=0, column =4)

    def add(self):

        def test(event):
            self.field_B[n].delete(0, END)
            self.field_B[n].insert(0, (float(self.field_A[n].get()))*5)

        self.field_A.append({})
        n = len(self.field_A)-1
        self.field_A[n] = Entry(self)
        self.field_A[n].grid(row=n, column =0)
        self.field_A[n].bind("<Return>", test)

        self.field_B.append({})
        n = len(self.field_B)-1
        self.field_B[n] = Entry(self)
        self.field_B[n].grid(row=n, column =1)

    def save(self):
        for n in range(len(self.field_A)):
            self.entry_A.append(self.field_A[n].get())
            self.entry_B.append(self.field_B[n].get())

        fname = asksaveasfile(mode = "w", defaultextension = ".est")
        data = {"fields": len(self.field_A), "entries_A": (self.entry_A),"entries_B": (self.entry_B)}

        with open(fname.name, "wb") as file:
            pickle.dump(data, file)

    def load(self):

        def test(event):
            print("Why is the value of n always equal to", n, "?")
            self.field_B[n].delete(0, END)
            self.field_B[n].insert(0, (float(self.field_A[n].get()))*5)

        fname = askopenfilename(filetypes = (("Estimation Files (est)", "*.est"),))
        location = fname.replace("/", "\\")
        if location:
            with open(location, "rb") as file:
                data = pickle.load(file)

            for n in range(data["fields"]):
                self.field_A.append({})
                self.field_A[n] = Entry(self)
                self.field_A[n].grid(row=n, column =0)
                self.field_A[n].insert(0, data["entries_A"][n])
                self.field_A[n].bind("<Return>", test)

                self.field_B.append({})
                self.field_B[n] = Entry(self)
                self.field_B[n].grid(row=n, column =1)
                self.field_B[n].insert(0, data["entries_B"][n])

    def __init__(self,master = None):
        Frame.__init__(self, master)
        self.field_A = []
        self.field_B = []
        self.entry_A = []
        self.entry_B = []
        self.grid()
        self.Widgets()

root = Tk()
app = Test(master = None)
app.mainloop()

2 Answers 2

2

You need a "closure". You can make a closure in python with the functools.partial function.

from functools import partial

def test(n, event=None):
    self.field_B[n].delete(0, END)
    self.field_B[n].insert(0, (float(self.field_A[n].get()))*5)

#other code ... 

self.field_A[n].bind("<Return>", partial(test, n))
Sign up to request clarification or add additional context in comments.

Comments

0

Both of your test() functions are accessing a variable n from the enclosing function. In the case of add(), there is no loop; n has a single value. Each Entry's test() gets its own n, because they were bound by a distinct call to add(). In load(), however, you are looping over n values; each test() is referring to the same n, which will have its final value by the time that any binding can possibly be invoked. The other answer gives a reasonable way to give each instance of test() its own personal n, so I'm not going to repeat that here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.