#python #tkinter
#python #tkinter
Вопрос:
Работа над функцией обратного вызова, которая передает результат из одного поля со списком в другое. Застрял на более простой версии кода. Это неправильно структурировано или я неправильно понимаю ООП? полная трассировка:
Exception in Tkinter callback Traceback (most recent call last): File "C:UsersTimAnaconda3libtkinter_init_.py", line 1705, in call return self.func(*args) TypeError: on_field_change() takes 1 positional argument but 2 were given
импортируйте tkinter как tk
из tkinter импортируйте ttk
def main():
# Create the entire GUI program
program = Converter()
# Start the GUI event loop
program.window.mainloop()
#class Converter(tk.Tk): # opens two windows, one odd
class Converter():
def __init__(self):
#super().__init__() # is this needed?
self.window = tk.Tk()
self.window.geometry("800x200 10 10")
self.window.title("Unit Conversion App")
self.CreateWidgets()
self.comboBox_contents = tk.StringVar()
#self.on_field_change() # doesn't appear to need to be initiated
def on_field_change(self): # should go here or outside class declaration?
print( "combobox updated to ", self.c1.get() ) # does print the updated values
self.choice_label.configure(text=self.c1.get() )
self.choice_label.update() #REQUIRED OR ABOVE LINE NEVER SHOWS
#self.c2.set(self.c1.get)
def CreateWidgets(self):
v=tk.StringVar()
self.c1 = ttk.Combobox(self.window, textvar='Box 1',width=30, values=["Mass", "Distance", "Volume"])
self.c1.set('Click Arrow to choose Property')
self.c1.grid(row=0, column=1)
self.c1.bind("<<ComboboxSelected>>", self.on_field_change)
#self.increment_button['command'] = self.increment_counter
self.c2 = ttk.Combobox(self.window, textvar='Box 2', width=30,values=["Inch", "Foot", "Mile"])
self.c2.set('Click to choose Source Unit')
self.c2.grid(row=1, column=1)
self.c3 = ttk.Combobox(self.window, textvar='Box 3', width=30, values=["Inch", "Feet", "Mile"])
self.c3.set('Click to choose Target Unit')
self.c3.grid(row=1, column=2)
self.choice_label = ttk.Label(self.window,text="Unit Chosen" )
#the_choice_label = c1.cget("text")
self.choice_label_text= self.c1.get
#the_choice_label.update() # does not update
#choice_label = Label(text= v ) #does not update
self.choice_label.grid(row=3, column=0)
self.quit_button = ttk.Button(self.window, text="Quit")
self.quit_button.grid(row=4, column=1)
self.quit_button['command'] = self.window.destroy
if __name__ == "__main__":
main()
Комментарии:
1. Пожалуйста, предоставьте код для
on_field_change
метода и код, который его вызывает.2. Это должно быть
def on_field_change(self,event)
3. Майк, код теперь доступен. Возникли некоторые проблемы с отправкой.
4. Большое спасибо, @Cool Cloud, сработало хорошо. Следующая проблема: я раскомментировал последнюю строку определения функции on_field_change, но вместо переноса текста выбора в combobox2 текст в combobox гласит:
5. Я добавил ответ
Ответ №1:
Я внимательно изучил и выяснил проблемы, на которые вы указывали:
- Вам нужно передавать
event
в качестве параметра всякий раз, когда выbind
переходите к виджету. Таким образом, ваша строка изменится на:
def on_field_change(self, event):
....
- Затем следующая строка должна иметь
()
, например:
self.c2.set(self.c1.get())
- Также я рекомендую добавить опцию,
state='readonly'
, для всех ваших выпадающих списков, чтобы пользователь не мог редактировать поле, например:
self.c2 = ttk.Combobox(self.window, textvar='Box 2', width=30, values=["Inch", "Foot", "Mile"],state='readonly')
- Кроме того, вы можете сказать
event=None
, что вы можете вызвать функцию в другом месте, не передавая никаких аргументов.
Комментарии:
1. Еще раз спасибо — работает так, как задумано. Теперь я, конечно, изменю ситуацию, чтобы добавить способ привязки выбранных единиц измерения к коэффициенту преобразования и обработчику событий для выполнения преобразования единиц измерения при нажатии! Я подозреваю, что я снова опубликую здесь.
Ответ №2:
Функции, привязанные к событию, должны иметь аргумент события. ( self.c1.bind("<<ComboboxSelected>>", self.on_field_change)
)
Измените прототип функции на:
def on_field_change(self,event:tk.Event):
событие tk.Event
— это событие, которое передает информацию относительно события, которое запустило вашу функцию. Описание события смотрите здесь:
https://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
Комментарии:
1.
event:tk.Event
не обязательно, простоevent
отлично2. Согласен, но аннотация типа очень помогает, если ваш редактор поддерживает ее, и это делает код более четким в отношении типа полученного события. . Поскольку переполнение стека помогает, я не вижу причин не добавлять его.