Ошибка Tkinter при обратном вызове — количество аргументов

#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. Согласен, но аннотация типа очень помогает, если ваш редактор поддерживает ее, и это делает код более четким в отношении типа полученного события. . Поскольку переполнение стека помогает, я не вижу причин не добавлять его.