Невозможно связать функцию после травления - tkinter - PullRequest
0 голосов
/ 10 ноября 2018

У меня есть простой код, который создает два поля нажатием кнопки. Есть две другие кнопки для сохранения и загрузки созданных полей ввода. Я использовал функцию bind для привязки поля A и поля B. Нажатие кнопки Enter на поле A после ввода числа выведет его значение, умноженное на 5, в поле B. На этом этапе связывание функция работает отлично.

Когда я создаю три поля ввода и сохраняю прогресс, не вводя никаких входных данных, и компилирую программу, а затем загружаю файл, функция связывания, похоже, не работает. Кажется, работает только для последнего созданного поля. Мой код выглядит следующим образом. Я старался изо всех сил упростить код.

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 ]

0 голосов
/ 10 ноября 2018

Обе ваши функции test() обращаются к переменной n из включающей функции. В случае add() петли нет; n имеет одно значение. test() каждой записи получает свои n, потому что они были связаны отдельным вызовом add(). Однако в load() вы перебираете значения n; каждый test() ссылается на один и тот же n, который будет иметь свое окончательное значение к тому времени, когда возможна любая привязка. Другой ответ дает разумный способ дать каждому экземпляру test() свой собственный n, поэтому я не буду повторять это здесь.

0 голосов
/ 10 ноября 2018

Вам нужно «закрытие». Вы можете сделать замыкание в python с помощью функции functools.partial.

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