В основном я пытаюсь сделать так, чтобы при изменении Entry
полей ввода кнопка будет добавить его ярлык на правильный вход.
Я использую active_entry
для таргетинга на вход, который был только что сфокусирован. По какой-то причине привязка события неправильно переключает его на новое поле ввода.
Фактический результат после изменения от по умолчанию Entry
затем нажмите button_1
: TypeError: getattr(): attribute name must be string
from tkinter import *
class App(Tk):
def __init__(self):
Tk.__init__(self)
self.set_active_entry('entry_1_var') # set initial active entry
self.entry_1_var = StringVar()
self.entry_2_var = StringVar()
self.entry_1 = Entry(self, width=10, font='Helvetica 32', textvariable=self.entry_1_var)
self.entry_2 = Entry(self, width=10, font='Helvetica 32', textvariable=self.entry_2_var)
self.create_widgets()
self.entry_binding()
def set_active_entry(self, name):
self._active_entry = name
print(self._active_entry)
@property
def active_entry(self):
return getattr(self, self._active_entry)
@active_entry.setter
def active_entry(self, value):
setattr(self, self._active_entry, value)
def create_widgets(self):
self.entry_1.pack()
self.entry_2.pack()
label = '1'
button_1 = Button(self, text=label, width=10, height=5, command=lambda x=label: self.num_pad(x))
button_1.pack()
def entry_binding(self):
self.entry_1.bind('<FocusIn>', lambda x='entry_1_var': self.set_active_entry(x))
self.entry_2.bind('<FocusIn>', lambda x='entry_2_var': self.set_active_entry(x))
def num_pad(self, label):
current_text = self.active_entry.get()
self.active_entry.set(current_text+label)
app = App()
app.mainloop()
Проблема в этих строках
self.entry_1.bind('<FocusIn>', lambda x='entry_1_var': self.set_active_entry(x))
self.entry_2.bind('<FocusIn>', lambda x='entry_2_var': self.set_active_entry(x))
Когда вы нажимаете одну из записей, которые вы видите <FocusIn event>
, а вместо этого вы ожидали, что это будет либо entry_1_var
либо entry_2_var
?
Случается, что функция bind
автоматически передает объект события в указанную вами функцию. В вашей лямбда-функции первым аргументом является x
. Вы указали значение по умолчанию, но поскольку фактический объект передается функцией bind
, x является объектом события. Итак, в def set_active_entry(self, name):
name
не является именем вашего виджета, а скорее объектом события. Поэтому, когда вы вызываете getattr(self, self._active_entry)
, self._active_entry
- это объект события, и вы получаете сообщение об ошибке.
Исправить это довольно просто, просто примите аргумент в своей лямбда-функции, чтобы принять объект события, и убедитесь, что вы фактически передаете строку с именем функции set_active_entry
:
self.entry_1.bind('<FocusIn>', lambda e, x='entry_1_var': self.set_active_entry(x))
self.entry_2.bind('<FocusIn>', lambda e, x='entry_2_var': self.set_active_entry(x))
или же
self.entry_1.bind('<FocusIn>', lambda e: self.set_active_entry('entry_1_var'))
self.entry_2.bind('<FocusIn>', lambda e: self.set_active_entry('entry_2_var'))