Kivy Mapview: distinguish buttons pressed - python-3.x

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.

Related

Too many positional arguments are given

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):
...

Python - can call same class twice(or more) in thread?

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.

Best practices for multiple inheritance in this Python code

I'm having some doubts with the design of mutiple inheritance in some Python classes.
The thing is that I wanted to extend the ttk button. This was my initial proposal (I'm omitting all the source code in methods for shortening, except init methods):
import tkinter as tk
import tkinter.ttk as ttk
class ImgButton(ttk.Button):
"""
This has all the behaviour for a button which has an image
"""
def __init__(self, master=None, **kw):
super().__init__(master, **kw)
self._img = kw.get('image')
def change_color(self, __=None):
"""
Changes the color of this widget randomly
:param __: the event, which is no needed
"""
pass
def get_style_name(self):
"""
Returns the specific style name applied for this widget
:return: the style name as a string
"""
pass
def set_background_color(self, color):
"""
Sets this widget's background color to that received as parameter
:param color: the color to be set
"""
pass
def get_background_color(self):
"""
Returns a string representing the background color of the widget
:return: the color of the widget
"""
pass
def change_highlight_style(self, __=None):
"""
Applies the highlight style for a color
:param __: the event, which is no needed
"""
pass
But I realized later that I wanted also a subclass of this ImgButton as follows:
import tkinter as tk
import tkinter.ttk as ttk
class MyButton(ImgButton):
"""
ImgButton with specifical purpose
"""
IMG_NAME = 'filename{}.jpg'
IMAGES_DIR = os.path.sep + os.path.sep.join(['home', 'user', 'myProjects', 'myProject', 'resources', 'images'])
UNKNOWN_IMG = os.path.sep.join([IMAGES_DIR, IMG_NAME.format(0)])
IMAGES = (lambda IMAGES_DIR=IMAGES_DIR, IMG_NAME=IMG_NAME: [os.path.sep.join([IMAGES_DIR, IMG_NAME.format(face)]) for face in [1,2,3,4,5] ])()
def change_image(self, __=None):
"""
Changes randomly the image in this MyButton
:param __: the event, which is no needed
"""
pass
def __init__(self, master=None, value=None, **kw):
# Default image when hidden or without value
current_img = PhotoImage(file=MyButton.UNKNOWN_IMG)
super().__init__(master, image=current_img, **kw)
if not value:
pass
elif not isinstance(value, (int, Die)):
pass
elif isinstance(value, MyValue):
self.myValue = value
elif isinstance(value, int):
self.myValue = MyValue(value)
else:
raise ValueError()
self.set_background_color('green')
self.bind('<Button-1>', self.change_image, add=True)
def select(self):
"""
Highlights this button as selected and changes its internal state
"""
pass
def toggleImage(self):
"""
Changes the image in this specific button for the next allowed for MyButton
"""
pass
The inheritance feels natural right to his point. The problem came when I noticed as well that most methods in ImgButton would be reusable for any Widget I may create in the future.
So I'm thinking about making a:
class MyWidget(ttk.Widget):
for putting in it all methods which help with color for widgets and then I need ImgButton to inherit both from MyWidget and ttk.Button:
class ImgButton(ttk.Button, MyWidget): ???
or
class ImgButton(MyWidget, ttk.Button): ???
Edited: Also I want my objects to be loggable, so I did this class:
class Loggable(object):
def __init__(self) -> None:
super().__init__()
self.__logger = None
self.__logger = self.get_logger()
self.debug = self.get_logger().debug
self.error = self.get_logger().error
self.critical = self.get_logger().critical
self.info = self.get_logger().info
self.warn = self.get_logger().warning
def get_logger(self):
if not self.__logger:
self.__logger = logging.getLogger(self.get_class())
return self.__logger
def get_class(self):
return self.__class__.__name__
So now:
class ImgButton(Loggable, ttk.Button, MyWidget): ???
or
class ImgButton(Loggable, MyWidget, ttk.Button): ???
or
class ImgButton(MyWidget, Loggable, ttk.Button): ???
# ... this could go on ...
I come from Java and I don't know best practices for multiple inheritance. I don't know how I should sort the parents in the best order or any other thing useful for designing this multiple inheritance.
I have searched about the topic and found a lot of resources explaining the MRO but nothing about how to correctly design a multiple inheritance. I don't know if even my design is wrongly made, but I thought it was feeling pretty natural.
I would be grateful for some advice, and for some links or resources on this topic as well.
Thank you very much.
I've been reading about multiple inheritance these days and I've learnt quite a lot of things. I have linked my sources, resources and references at the end.
My main and most detailed source has been the book "Fluent python", which I found available for free reading online.
This describes the method resolution order and design sceneries with multiple inheritance and the steps for doing it ok:
Identify and separate code for interfaces. The classes that define methods but not necessarily with implementations (these ones should be overriden). These are usually ABCs (Abstract Base Class). They define a type for the child class creating an "IS-A" relationship
Identify and separate code for mixins. A mixin is a class that should bring a bundle of related new method implementations to use in the child but does not define a proper type. An ABC could be a mixin by this definition, but not the reverse. The mixin doesn't define nor an interface, neither a type
When coming to use the ABCs or classes and the mixins inheriting, you should inherit from only one concrete superclass, and several ABCs or mixins:
Example:
class MyClass(MySuperClass, MyABC, MyMixin1, MyMixin2):
In my case:
class ImgButton(ttk.Button, MyWidget):
If some combination of classes is particularly useful or frequent, you should join them under a class definition with a descriptive name:
Example:
class Widget(BaseWidget, Pack, Grid, Place):
pass
I think Loggable would be a Mixin, because it gathers convenient implementations for a functionality, but does not define a real type. So:
class MyWidget(ttk.Widget, Loggable): # May be renamed to LoggableMixin
Favor object composition over inheritance: If you can think of any way of using a class by holding it in an attribute instead of extending it or inheriting from it, you should avoid inheritance.
"Fluent python" - (Chapter 12) in Google books
Super is super
Super is harmful
Other problems with super
Weird super behaviour
In principle, use of multiple inheritance increases complexity, so unless I am certain of its need, I would avoid it. From your post you already look aware of the use of super() and the MRO.
A common recommendation is to use composition instead of multiple inheritance, when possible.
Another one is to subclass from only one instantiable parent class, using abstract classes as the other parents. That is, they add methods to this subclass, but never get instantiated themselves. Just like the use of interfaces in Java. Those abstract classes are also called mixins, but their use (or abuse) is also debatable. See Mixins considered harmful.
As for your tkinter code, besides logger code indentation, I don't see a problem. Maybe widgets can have a logger instead of inheriting from it. I think with tkinter the danger is the unwanted override by mistake of one of the hundreds of available methods.

Passing a Function as a Parameter for a Class, eventually turning it into a method

Sorry if the title is confusing. I'm writing a minimalist game engine, and trying to define a class called "Area" where if the player enters the area, a function defined by the user happens. For example, one could create an instance
Area(location,function) that would fire function on the player when the player enters location (for the sake of simplicity, let it be a point or something).
Note: in pseudo-python
# in init.py
...
def function(player):
kill player
deathZone = Area(location,function)
--------------------------------------
# in player.update()
...
for area on screen:
if player in area:
Area.function(player)
The point of this is that the developer (aka me) can use any function they choose for the area. Is there anyway to do this, or should I try a better approach?
Sure, this kind of thing is certainly possible. In python, everything is an object, even a function. So you can pass around a function reference as a variable. For example try the following code:
import math
def rectangle(a, b):
return a*b
def circle(radius):
return math.pi * radius**2
class FunctionRunner(object):
def __init__(self):
self.userFunction = None
self.userParams = None
def setUserFunction(self, func, *params):
self.userFunction = func
self.userParams = params
def runFunction(self):
return self.userFunction(*self.userParams)
if __name__ == '__main__':
functionRunner = FunctionRunner()
functionRunner.setUserFunction(rectangle, 6, 7)
print(functionRunner.runFunction())
functionRunner.setUserFunction(circle, 42)
print(functionRunner.runFunction())
Here you have two functions that are defined for an area, and a class called FunctionRunner which can run any function with any number of input arguments. In the main program, notice that you need only pass the reference to the function name, and any input arguments needed to the setUserFunction method. This kind of thing will allow you to execute arbitrary code on the fly.
Alternatively, you could also replace a method on your class with a reference to another function (which is what you are asking), though this seems less safe to me. But it is certainly possible. For example you could have a class like this:
class FunctionRunner2(object):
def __init__(self):
pass
def setUserFunction(self, func):
self.theFunction = func
def theFunction(self, *params):
pass
And then do this:
if __name__ == '__main__':
functionRunner2 = FunctionRunner2()
functionRunner2.setUserFunction(rectangle)
print(functionRunner2.theFunction(6,7))
functionRunner2.setUserFunction(circle)
print(functionRunner2.theFunction(42))

Passing StringVar object from Entry to Label within functions in tkinter

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)
...

Resources