Hi there smart people,
I have a small program where a combobox should be updated with a new list, depending on a User entry, when a Button is clicked.
Infact I would assume that no arguments need to be given since the called functions "gets" the user entries and then updates the combobox. No additional external Info needed.
Unfortunatley I get the Error:
TypeError:Func_Update_MA() takes 1positional argument but 2 were given.
How can I solve this issue?
To be honest I dont really get the whole "self" thing but I tried pretty much every combination of using self, not using it and combining it with something like args* or kwargs** (another mystery to me)
If you need more code I will provide it off course.
Thanks alot in advance!
class Class_MA_Win():
def __init__(self, Win_MA_Sel, Cockpit_Win):
Btt_Update_MA = Button(self.Mitarbeiter_Selection_Win, text="Liste Updaten")
Btt_Update_MA.bind("<Button-1>",self.Func_Update_MA)
Btt_Update_MA.grid(column=2, row=3, padx=10, pady=10)
def Func_Update_MA(self):
Entry_name = self.Ent_first_name_MA.get()
Entry_lastname = self.Ent_last_name_MA.get()
Entry_ID = self.Ent_ID_MA.get()
Whenever you use widget.bind(...), it will return an event object with a number of attributes describing the event. This is then passed to your func Func_Update_MA which accepts no argument, thus the error.
To solve this, simply accept the event as an arg:
def Func_Update_MA(self,event=None):
...
Also you mentioned about args and kwargs but you seem to wrongly position the asterisks. The correct is *args and **kwargs, like so:
def Func_Update_MA(self, *args, **kwargs):
...
Related
When I define `get_success_url' in my views, if I accept Pylance Autocomplete suggestion, I got this :
def get_success_url(self) -> str:
return super().get_success_url()
Didn't find anywhere how to use this.
By my side, I'm use to do :
def get_success_url(self, **kwargs):
return reverse_lazy('name_space:url_name', kwargs={'pk': foo})
How to (can I) use pylance's suggestion to achieve the same result as my method
The autocomplete version isn't actually doing anything.
Sometimes when you are overriding a function, you want to use the same function of the parent class plus something extra, eg, if you override save() you might set another property and then do a normal save, which you do by calling super().save().
def save(self, *args, **kwargs):
self.status = Model.SAVED
return super().save()
However, you don't always have to call super() if your function is doing the job on its own. In this case with the autocomplete, if all you do is return super().get_success_url() there's no point in overriding the function as you haven't done anything different to an parent function. Your existing get_success_url() performs a purpose and replaces any super() version, so you don't need to call super() in it.
Autocomplete is just a suggestion, it's not saying you need to be doing something a certain way.
Sorry for this noob question, im still learning and I find little documentation for the mapview module.
So for one screen page I have this:
class Mapspage(Screen):
def __init__(self, **kwargs):
self.aboutname="hi"
super(Mapspage, self).__init__(**kwargs)
gl = GridLayout(cols=1)
mapview = MapView(zoom=12, lat=55.6712674, lon=12.5938239)
self.buttons=[]
self.nums=range(0,len(df["name_en"]))
for i in self.nums:
name=list(df["name_en"])[i]
marker = MapMarkerPopup(lat=list(df["latitude"])[i], lon=list(df["longitude"])[i])
self.buttons.append(button(text=list(df["name_en"])[i],on_press=partial(self.pressbutton,num=self.nums[i]),size=(len((df["name_en"])[i])*7*1.05,15),size_hint=(None,None)))
marker.add_widget(self.buttons[i])
mapview.add_marker(marker)
gl.add_widget(mapview)
self.add_widget(gl)
def pressbutton(self,num, *args):
global aboutname
aboutname=(df["name_en"])[num]
chatapp.screenmanager.current = "About"
where I use from functools import partial.
The problem with my approach, despite I made sure the buttons are stored in a different variable (elements of the self.buttons list), and even made sure the numbers them self are stored in a separate list, I cant get to pass the number variable, that distinguishes the buttons (that appear when clicking the maps point), on to the pressbutton function. When I run my attempt I recieve the error, TypeError: pressbutton() got multiple values for argument 'num' where I think all buttons passed on their num variable.
The problem is with the definition of your pressbutton() method and its handling of keyword arguments. You can handle keywords by defining pressbutton() as:
def pressbutton(self, button_instance, num=99):
which defines num as a keyword argument and provides a default value.
Another option is something like:
def pressbutton(self, button_instance, **kwargs):
num = kwargs.pop('num', 99)
which does the same thing.
I don't very understand the classes logic in python but cannot answer on web.
I have create a class to generate person info:
class person:
def fristnameGen(gender):
...
def emailGen(firstname,surname):
...
i create a bot to call it like this:
from person import *
class bots:
def __init__(self):
self.person = person()
def createDB(self):
print(self.person.name)
#do something...
finally i call it by a button with thread
from bots import *
import threading
class Panel:
def __init__(self):
self.top = tk.Tk()
self.bot = bots()
self.buildUI()
def foo(self):
self.bot.createDB(self.stringPhone.get())
def threadTheAction(func, *args):
t = threading.Thread(target=func, args=args)
t.setDaemon(True)
t.start()
def buildUI(self):
Button = tk.Button(self.top, text ="Start", command = lambda :self.threadTheAction(self.foo))
I get this error:
TypeError: 'Panel' object is not callable
However, i call it directly, its work
Button = tk.Button(self.top, text ="Start", command = lambda :self.foo())
How to fix the error?
...
2. Moreover, i tried create p1 = person() and p2= person() and print it. Found p1 and p2 is a same person, i prefer each new a class have a new one. How to generate "new person" using classes?
Thank you
You seem to have a lot of confusion about Object Oriented Programming in Python. Some of your methods have self parameters and some do not, seemingly at random. That's the source of your current error.
The threadTheAction method in your Panel class is getting the Panel instance passed in as its first argument, but that's named func in the method (since you omitted self). The real function you're passing as an argument gets caught in the variable argument *args. When the thread tries unsuccessfully to call it, you get an exception. Adding self before func would fix the immediate problem:
def threadTheAction(self, func, *args):
I suspect if your code got further along, you'd run into other errors with other methods without self in their parameter lists. For instance, none of the methods you've shown in person are likely to work correctly.
As for your second question, you haven't shown enough of person to know what's happening, but you're probably doing instance variables wrong somehow. With no self parameter in the methods, that's almost inevitable (since you assign to self.whatever to set a whatever attribute on the current instance). If you need help squaring that away, I suggest you ask a separate question (Stack Overflow is best when each question is self-contained) and provide the full code for your person class.
The program works as intended when I simply use tkinter's widgets. When I use ttk's widgets the program repeats itself twice. I tried almost everything in my knowledge to fix this, I believe that *args have something to do with it. Is there anyway to prevent my function _up_options from running twice?
from tkinter import *
from tkinter import ttk
root = Tk()
first = StringVar(root)
second = StringVar(root)
Ore = {'Options': [''], 'Yes': ['One'], 'No': ['Two']}
entry1 = ttk.OptionMenu(root, first, *Ore.keys())
entry2 = ttk.OptionMenu(root, second, '')
entry1.pack()
entry2.pack()
def _up_options(*args):
print('update_options')
ores = Ore[first.get()]
second.set(ores[0])
menu = entry2['menu']
menu.delete(0, 'end')
for line in ores:
print('for')
menu.add_command(label=line, command=lambda choice=line: second.set(choice))
first.trace('w', _up_options)
root.mainloop()
PS, I used *args in my function to work. If anyone can explain this, I would be very grateful
I think I figured this out. The problem is that the variable actually is set twice by the ttk OptionMenu.
Take a look at this piece of code from the tkinter OptionMenu:
for v in values:
menu.add_command(label=v, command=_setit(variable, v, callback))
This adds a button to the menu for each value, with a _setit command. When the _setit is called it sets the variable and another callback if provided:
def __call__(self, *args):
self.__var.set(self.__value)
if self.__callback:
self.__callback(self.__value, *args)
Now look at this piece of code from the ttk OptionMenu:
for val in values:
menu.add_radiobutton(label=val,
command=tkinter._setit(self._variable, val, self._callback),
variable=self._variable)
Instead of a command this adds a radiobutton to the menu. All radiobuttons are "grouped" by linking them to the same variable. Because the radiobuttons have a variable, when one of them is clicked, the variable is set to the value of the button. Next to this, the same command is added as in the tkinter OptionMenu. As said, this sets the variable and then fires another command of provided. As you can see, now the variable is updated twice, once because it is linked to the radiobutton and once more because it is set in the _setit function. Because you trace the changing of the variable and the variable is set twice, your code also runs twice.
Because the variable is set twice from within the ttk code, I guess there's not much you can do about that. If you don't change the variable from any other part of your code than from the OptionMenu though, you could choose to not trace the variable, but instead add your function as command to the OptionMenu:
entry1 = ttk.OptionMenu(root, first, *Ore.keys(), command=_up_options)
P.S. this was introduced with this commit after this bugreport.
I guess when adding the variable=self._variable the command should have been changed to just command=self._callback.
You can understand the problem in the error message:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\tkinter__init__.py", line 1699, in call
return self.func(*args)
TypeError: _up_options() takes 0 positional arguments but 3 were given
Initially, you don't use _up_options When you change the Options you call _up_options to trace the first StringVar and change it to the value of the next object in the dictionary.
Now when you do that you are running on all the objects in the dictionary, therefore, you need the *args so the lambda function will run on all args given!
As for your problem:
When I use ttk's widgets the program repeats itself twice.
EDIT
See #fhdrsdg's answer!
The solution is just to change command=tkinter._setit(self._variable, val, self._callback) to command=self._callback.
Hope you find this helpful!
Instead of tracing the StringVar, add a callback as command argument for OptionMenu constructor.
I created a subclass of ttk.OptionMenu to solve this (as well as to provide slightly simpler usage of the widget and a more useful callback). I think this is a more stable approach than modifying the original class directly or just overriding the original method because it guarantees compatibility with potential changes to the built-in/original widget in future Tkinter versions.
class Dropdown( ttk.OptionMenu ):
def __init__( self, parent, options, default='', variable=None, command=None, **kwargs ):
self.command = command
if not default:
default = options[0]
if not variable:
variable = Tk.StringVar()
if command:
assert callable( command ), 'The given command is not callable! {}'.format( command )
ttk.OptionMenu.__init__( self, parent, variable, default, *options, command=self.callBack, **kwargs )
else:
ttk.OptionMenu.__init__( self, parent, variable, default, *options, **kwargs )
def callBack( self, newValue ):
self.command( self, newValue )
You can then use it like this:
def callback( widget, newValue ):
print 'callback called with', newValue
print 'called by', widget
options = [ 'One', 'Two', 'Three' ]
dropdown = Dropdown( parent, options, command=callback )
dropdown.pack()
Besides avoiding the double-trace issue, other notable differences from the original ttk.OptionMenu includes not needing to supply a Tkinter variable or default value if you don't need them (the default item will be the first item in the options list if not provided), and being able to get the widget that called the callback function when it fires. The latter is very helpful if you have many dropdown widgets sharing the same callback and you need to know which one is being used within the call.
Soon after writing this, I also found another solution using lambda: Passing OptionMenu into a callback (or retrieving a reference to the used widget)
I thought I might still share this Dropdown widget anyway since it can make the higher-level code simpler, and it provides a good base if you have some other custom methods to add in.
Hi I've been struggling to get this to work, each time i change something I receive another error. I've been trying to create an entry box with a function and then get the variable from the entry box into a label, created by a button press. When I tried to do this often this error came up.
TypeError: get() missing 1 required positional argument: 'self'
I then put self in in the method brackets.
command = lambda: x.myFunc(self.my_variable.get(self))
Then another error, which I'm not sure how to sort out.
AttributeError: 'My_Class' object has no attribute '_tk'
Here's the full code, I'm new to classes and self, so any corrections are welcome.
from tkinter import *
import time
class My_Class:
def start(self):
self.root=Tk()
self.my_variable=StringVar
self.entry_box=Entry(self.root, textvariable=self.my_variable)
self.entry_box.pack()
self.button=Button(self.root,text="Pass variable now",
command=lambda:x.myFunc(self.my_variable.get(self)))
self.button.pack()
def myFunc(self,my_variable):
self.lab=Label(self.root,text=self.my_variable)
self.lab.pack()
x=My_Class()
x.start()
This is the correct way to create a StringVar object:
text = StringVar() # note additional ()
Can you explain me what x is in the following statement:
lambda: x.myFunc(self.my_variable.get(self))
x is not visible inside the class, because it's declared outside the class.
myFunc is not indented correctly: you should indent it like the __init__ method.
I really recommend you to watch some tutorials on OOP before proceeding. You are basically trying to guess how OOP works.
If you make myFunc A method if the class (which you might be trying to do; it's hard to know because your indentation is wrong), you don't have to pass anything to myFunc. That function has access to everything in the class, so it can get what it needs, when it needs it. That lets you eliminate the use of lambda, which helps reduce complexity.
Also, you normally don't need a StringVar at all, it's just one more thing to keep track of. However, if you really need the label and entry to show exactly the same data, have them share the same textvariable and the text is updated automatically without you having to call a function, or get the value from the widget, or set the value n the label.
Here's an example without using StringVar:
class My_Class:
def start(self):
...
self.entry_box = Entry(self.root)
self.button = Button(..., command = self.myFunc)
...
def myFunc(self):
s = self.entry_box.get()
self.lab = Label(..., text = s)
...