I used to work with this way of coding and it worked fine, but after going back to it a few weeks later, it does not anymore. I simplidied my code so it is easy to type here.
import tkinter as tk
from tkinter import ttk
class wind(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
# id shutter
self.SOURCE_SHUTTER = "/dev/ttyUSB0"
# menu deroulant
self.listeFlux = ["/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2", "/dev/ttyUSB3"]
self.listeCombo = ttk.Combobox(self, values=self.listeFlux)
self.listeCombo.current(0)
self.listeCombo.bind("<<ComboboxSelected>>", self.action)
self.listeCombo.pack(side="top")
def action(self):
self.SOURCE_SHUTTER = self.listeCombo.get()
print(self.SOURCE_SHUTTER)
if __name__ == "__main__":
win = wind()
win.geometry("800x600")
win.mainloop()
This code gives me the error : TypeError: action() takes 1 positional argument but 2 were given. Does someone know why ? I have seen people make this mistake but their error was that a parameter was missing "self" somewhere in their code, which I don't think I am forgetting here.
Thanks a lot for your help. Valentin
I tried looking in another topic that had the same problem but mine seems different here.
CodePudding user response:
Event bindings in tkinter will inherently pass an event
parameter to the bound function, so you'll need deal with it one way or another
Option 1
Add an _event
parameter to the action
method.
The leading underscore _
is convention to let people know that the value is unused by the function, and event
is the conventional name for the event argument taken by event-driven functions in tkinter. The default value of None
isn't strictly necessary, but it's good practice.
def action(self, _event=None):
self.SOURCE_SHUTTER = self.listeCombo.get()
print(self.SOURCE_SHUTTER)
Option 2
Use *_args
in your method definition to allow it to accept any number of arguments (as suggested in @3ddavies' answer!). Again, the _
is convention for unused values, and args
is convention for this type of parameter. As has been mentioned, the caveat here is that now your action
method will accept any number of arguments - this is unlikely to be an issue in this particular case, but keep it in mind!
def action(self, *_args):
self.SOURCE_SHUTTER = self.listeCombo.get()
print(self.SOURCE_SHUTTER)
Option 3
Use a lambda to absorb the event and call action
as an anonymous function
def __init__(self):
... # code omitted for brevity
self.listeCombo.bind("<<ComboboxSelected>>", lambda event: self.action)
...
def action(self, _event = None):
self.SOURCE_SHUTTER = self.listeCombo.get()
print(self.SOURCE_SHUTTER)
CodePudding user response:
A quick and dirty fix would be to change the definition of action
to:
def action(self, *args):
The underlying issue here is that <<ComboboxSelected>>
seems to return a tuple, so when the event is triggered, both the self
object and the tuple are being passed to the action
function, which is causing the error.
The above solution is a "dirty fix" because it will allow the function to take any number of arguments greater than one.