python, number of arguments trouble - python

I have seen plenty of this question around, but I am still not able to see what I'm doing wrong.
I have several sliders, and I want the value of the one I am moving, and which of the slider is being moved.
to do that:
def reading(self,value):
sender=self.sender()
slider=sender.objectName()[6:]
value_slider=value
return slider, value_slider
That seems to work, the problem is with the next function.
Now, I want to do some stuff with the value of the slider moved:
def prsn(self,slider,value_slider):
wv=np.linspace(380,780,401)
leds=np.genfromtxt('led_psd.txt')
leds_norm=leds/leds.max()
Pot_ajust=0
for i in range(0,leds_norm.shape[1]):
Pot_ajust=Pot_ajust+value_slider*leds_norm[:,slider];
And I have the error : prsn() takes exactly 3 arguments (1 given)
How come I am not "giving" to prsn() 3 arguments? It is like it is not reading value_slider and slider
How should I pass value_slider and slider to the other functions?
Thank you very much for any tip

Here's how you should call prsn:
s = stuff
vs = other_stuff
thingy.prsn(s,vs)
OR
thingy.prsn(slider=s,value_slider=vs)
This means that in prsn's scope:
self = thingy
slider = s
value_slider = vs
Please for now on when you ask a question include the line of code that causes the exception.

Related

Tkinter: how to make functions in after() work with variable objects?

I'm a beginner programmer and I'm trying to learn how to make code run continuously in tkinter.
My aim for testing is just to get a label to change colour every 2 seconds regardless of input.
I understand I can use the following format (with lbl initialised as a Label)
def switch():
if lbl.cget('bg') == 'blue':
lbl.config(bg='black')
else:
lbl.config(bg='blue')
lbl.after(2000, switch)
This works fine. However, I want to be able to call switch for any label rather than just lbl specifically.
If I try the below I immediately get a recursion depth error
def switch(i):
if i.cget('bg') == 'blue':
i.config(bg='black')
else:
i.config(bg='blue')
i.after(2000, switch(i))
lbl.after(2000, switch(lbl))
I'm not sure why this is a the case, or what I could do to get round it so any help would be appreciated!!!
You can pass positional arguments to after. To run switch(i) after 2 seconds you can call after like this, adding the positional arguments after the function:
i.after(2000, switch, i)
Likewise, to run switch(lbl) do this:
lbl.after(2000, switch, lbl)

How to fix 'TypeError: MOVE() takes 0 positional arguments but 1 was given' in Python

Trying to make a simple drawing program based on x an y coordinates an i'm using a function to draw and modify the coordinates in one call without actually giving valuea to the function itself using global variables for what needs modification by the function but it still seees as if i've given it actual direct input.
In a previous version i got away by using a class to memorize the ghanging coordinates and functions of the respective class to do the drawing, but in this case the input method is slightly different since i'm using the scale widget isntead of the buttons and as i mentioned before i did try using global variables in both programs actually and it doesn't work in either of them.
from tkinter import *
win=Tk()
win.title("Etch a Schetch")
win.configure(background="grey")
win.configure(bd=5)
global xa
xa=0
global ya
ya=0
def MOVE():
tabla.create_line(xa,ya,sx.get(),sy.get())
xa=sx.get()
ya=sy.get()
tabla=Canvas(win,width=300,height=300)
sx=Scale(win,from_=0,to=300,length=300,orient="horizontal",command=MOVE)
sy=Scale(win,from_=0,to=300,length=300,command=MOVE)
ex=Button(win,text="Exit",command=exit)
tabla.grid(row=1,column=1)
sx.grid(row=2,column=1)
sy.grid(row=1,column=2)
ex.grid(row=2,column=2)
win.mainloop()
If it would work it would be kinda like an etch a sketch.
I actually just realized what the problem was, to quote mkiever who commented first but i didn't understand untill i did some individuall testing on the interaction between "Scale" and the command that is calling. To put it short and easier to understand the function that is beeing called by "Scale" as its command automaticly takes the value of the scale as an input to the function, as a rezult i only need one declared variable in the paranthesis when i define the function but no paranthesis or input variable is required to give an input to it from the scale.
EXAMPLE:
from tkinter import *
import time
win=Tk()
def P(a):
print(a)
sx=Scale(win,from_=0,to=300,length=300,orient="horizontal",command=P)
sx.pack()
win.mainloop()
Some alteration to the code is still required but it'll be much easier without that pesky error showing up.
Thank you everyone for your advice.

TypeError: printName1() takes 0 positional arguments but 1 was given

So I have this very simple thing I wrote and it's killing me trying to figure out why it won't work. All it does it print a statement when you click.
So for the first example I had a button and assigned the function printName1 directly to it, which worked perfectly fine.
Then the next thing was to bind it using the .bind() function. So in this case we just have a frame that prints out certain things based on which button you press. But unfortunately whenever I use bind, it throws the error show above. References tkinter\__init__.py for the error, so it's not something directly in my code but maybe it needs to be done differently? Thanks guys.
from tkinter import *
root = Tk()
def printName1():
print('Jack')
def printName2():
print('John')
def printName3():
print('Jill')
frame = Frame(root, width=300, height=250)
frame.bind("<Button-1>", printName1)
frame.bind("<Button-2>", printName2)
frame.bind("<Button-3>", printName3)
frame.pack()
root.mainloop()
EDIT: The error is confusing because it made it seem like there was an extra argument when there should be 0. But actually I needed to add an argument to the functions and that was event. so it should be def printName1(event) and so on. Just figured I would let you guys know what worked for me in case anyone stumbles upon this.
If you refer to the documentation regarding tkinter events and bindings, you will see that when an event is triggered, the associated event object will be passed as the first (and only) argument to the bounded function (being printName1 and friends in your case).
So what you need to do is to modify those printName* functions to accept the event argument.
def printName1(event):
print('Jack')
Then what you desired to achieve should work.
Naturally, you could make the event argument optional as #TigerhawkT3 suggested.
Events, such as from the keyboard/mouse, are all sent to the application with information about the event: which key was it, where was the mouse when you clicked, that sort of thing. This means that any callback bound to such an event needs to take an argument. If you want to also bind it to a Tkinter Button, which doesn't take an event, you can handle that as well. Just define your functions with a default argument:
def printName1(event=None):
...

Python - Curses - Addstr -multicolored string/understanding functions

I don't know what the right words are to ask my question, so please excuse the extra detail below. I am as much asking for the right words/concepts as for an answer to the specific question.
I'm trying to put a simple console in front of a script of mine using curses in Python. I want the console to look relatively familiar and have key shortcuts for 3 commands (Load, Exit, Continue). To highlight which key is the hotkey for an action, I wanted that letter to be in a different colour. (e.g. Exit with hotkey being the x). I figure this must be made up of 3 "addstr" commands- write the first letter in normal ("E"), then the x with a colour attribute, then "it" in normal colour again.
I thought that because I do this 3 times, and maybe more in future screens, I should make a function to do it for me to see if that works. What I can't figure out though, is how to edit the screen without hardcoding the function to the variable name. I want to be able to call the function in a number of different windows. I thought at first I could just pass the screen's variable into my function but that doesn't seem right.
Here is my pseudo code I started working on:
def keyString(menuString,fastChar,highlight,startX,startY,cScreen):
#menuString is the word that has a letter to bring to attention
#fastChar is the character that will be in a different colour
#highlight is binary value to determine which colour pair to use
#definition expects 'h' and 'n' to be colour pairs
#startX and startY are the beginning cursor positions
#cScreen would be global screen variable
fCidx = menuString.find(fastChar) #index of the character to highlight
fXadj = startX + fCidx #set the x position for character to highlight
sHx = fXadj + 1 #set the x position for the remainder of the string
fH = menuString[0:fCidx] #Slice the first half of the string
sH = menuString[(fCidx+1):] #slice the remainder of the string
if highlight:
txtColor = h
else:
txtColor = n
cScreen.addstr(startY,startX,fH,txtColor)
cScreen.addstr(startY,fXadj,fastChar)
cScreen.addstr(startY,sHx,sH,txtColor)
return cScreen
Please ignore the awful variable names..I was getting tired of typing and started shorthanding. I realise that I didn't need to worry about explicitly stating x,y coords because the cursor position is remembered. So a lot of that can be cut out. I'm not asking for someone to fix my function. I just don't have a concept of how to have a function that will write out a word using different colours for different characters. I could probably stick a "global screen" in the function and only use it for editing "screen", but then (for example) I wouldn't be able to use the function for "screen2".
If it helps anyone searching in the future, I found that I can use Windows (curses.newwin) and those can be fed into, and returned from functions.
So for example, if the above code was in a file called "curse_tools.py":
import curses
import curse_tools
def Main(screen):
curses.init_pair(1,curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(2,curses.COLOR_BLACK, curses.COLOR_GREEN)
n = curses.color_pair(1)
h = curses.color_pair(2)
curse_tools.n = n
curse_tools.h = h
try:
screen.border(0)
box1 = curses.newwin(20, 20, 5, 5)
box1.box()
box1=curse_tools.keyString("Exit","x",False,1,1,box1)
screen.refresh()
box1.refresh()
screen.getch()
finally:
curses.endwin()
curses.wrapper(Main)
This code would work. I'm going to re-write my original code because I learned a lot along the way but maybe a future beginner will somehow come across this question so I thought I'd post the 'solution'. Although I still don't know the right words.
Most of the code in this post came from Why won't my curses box draw? (in case it looks familiar)

top down friction in pymunk

Been struggling with this for a couple of days, hard to find code examples on the net.
I'm making a topdown game and having trouble getting the player to move on key press. At the moment i'm using add_force or add_impulse to move the player in a direction, but the player doesn't stop.
I've read about using surface friction between the space and the player to simulate friction and here is how it's done in the tank.c demo.
However I don't understand the API enough to port this code from chipmunk into pymunk.
cpConstraint *pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(tankControlBody, tankBody, cpvzero, cpvzero));
So far, I have something that looks like this:
class Player(PhysicalObject):
BASE_SPEED = 5
VISIBLE_RANGE = 400
def __init__(self, image, position, world, movementType=None):
PhysicalObject.__init__(self, image, position, world)
self.mass = 100
self.CreateBody()
self.controlBody = pymunk.Body(pymunk.inf, pymunk.inf)
self.joint = pymunk.PivotJoint(self.body, self.controlBody, (0,0))
self.joint.max_force = 100
self.joint.bias_coef = 0
world.space.add(self.joint)
I don't know how to add the constraint of the space/player to the space.
(Need someone with 1500+ rep to create a pymunk tag for this question).
Joe crossposted the question to the Chipmunk/pymunk forum, and it got a couple of more answers there. http://www.slembcke.net/forums/viewtopic.php?f=1&t=1450&start=0&st=0&sk=t&sd=a
Ive pasted/edited in parts of my answer from the forum below:
#As pymunk is python and not C, the constructor to PivotJoint is defined as
def __init__(self, a, b, *args):
pass
#and the straight conversion from c to python is
pivot1 = PivotJoint(tankControlBody, tankBody, Vec2d.zero(), Vec2d.zero())
# but ofc it works equally well with 0 tuples instead of the zero() methods:
pivot2 = PivotJoint(tankControlBody, tankBody, (0,0), (0,0))
mySpace.add(pivot1, pivot2)
Depending on if you send in one or two arguments to args, it will either use the cpPivotJointNew or cpPivotJointNew2 method in the C interface to create the joint. The difference between these two methods is that cpPivotJointNew want one pivot point as argument, and the cpPivotJointNew2 want two anchor points. So, if you send in one Vec2d pymunk will use cpPivotJointNew, but if you send in two Vec2d it will use cpPivotJointNew2.
Full PivotJoint constructor documentation is here: PivotJoint constructor docs
I'm not familiar with either system you've mentioned, but some basic game ideas that may relate are:
If you add a force (or impulse) which affects movement, for the entity to stop, you must also take it away. In my games if I had a function AddImpulse()/AddForce() I would have a corresponding one such as Apply_Friction() which would reverse the effect by however much you want (based on terrain?) until movespeed is zero or less. I personally wouldn't bother with this method for movement unless needed for gameplay since it can add more computations that its worth each update.
There should be some way to track KeyPressed and/or KeyPosition and then using those x/y coordinates are incrememnted based on player speed. Without knowing what you've tried or how much the API does for you, it's hard to really say more.
Hope this helps. If this is stuff you already knew kindly ignore it.

Categories