Where is my fault
"this code is only part of my code
I just copied part of it"
import turtle
wn=turtle.Screen()
wn.bgcolor("black")
wn.title("Pacman")
wn.setup(900,700)
class Pacman(turtle.Turtle):
def __init__(self):
turtle.Turtle.__init__(self)
self.shape("square")
self.color("yellow")
self.penup()
self.speed(0)
def up(self):
self.goto(self.xcor(),self.ycor()+24)
def down(self):
self.goto(self.xcor(),self.ycor()-24)
def left(self):
self.goto(self.xcor()-24,self.ycor())
def right(self):
self.goto(self.xcor()+24,self.ycor())
wn.listen()
wn.onkey(Pacman.down, "Down")
wn.onkey(Pacman.up, "Up")
wn.onkey(Pacman.right, "Right")
wn.onkey(Pacman.left, "Left")
wn.tracer(0)
while True:
wn.update()
Fail
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\asus\AppData\Local\Programs\Python\Python37-
32\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:\Users\asus\AppData\Local\Programs\Python\Python37-
32\lib\turtle.py", line 686, in eventfun
fun()
TypeError: up() missing 1 required positional argument: 'self'
When I click Right,Down,Up or Left Button square not moving and in console writing this fail
"Pacman" is a class template, so you can't call methods on it like that. You should either create a Pacman object (like so):
new_pacman = Pacman()
And then you could run your functions like so:
new_pacman.up()
Or (if I'm not mistaken) you could try this, which I think should also work:
Pacman().up() which
do pacman_instance = Pacman() right before wn.listen()
The issue is that you're trying to do an operation on a class rather than an instance of the class
If you just add Pacman = Pacman() before the line wn.listen(), it'll work!
The issue is you're trying to access a class that was not instantiated, and with this line you create this instance, and everything will work perfectly ;)
Related
I am in the process of making an OOP Countdown GUI with the letters, numbers and conundrum games.
This is a snippet of my code so far.
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Main")
self.configure(bg=LIGHT_BLUE)
self.title=tk.Label(master=self,bg=LIGHT_BLUE,font=("Arial",12,"bold"),text="!Countdown Games!",pady=5,padx=5)
self.title.pack()
self.frame=tk.Frame(master=self,bg=LIGHT_BLUE)
self.LettersButton=tk.Button(master=self.frame,bg=LIGHT_BLUE,font=("Arial",12,"bold"),text="Letters",command=self.start_letters)
self.LettersButton.grid(row=0,column=0,sticky="NESW",pady=10,padx=2)
self.NumbersButton=tk.Button(master=self.frame,bg=LIGHT_BLUE,font=("Arial",12,"bold"),text="Numbers",command=self.start_numbers)
self.NumbersButton.grid(row=0,column=1,sticky="NESW",pady=10,padx=2)
self.LettersButton=tk.Button(master=self.frame,bg=LIGHT_BLUE,font=("Arial",12,"bold"),text="Conundrum",command=self.start_conundrum)
self.LettersButton.grid(row=0,column=2,sticky="NESW",pady=10,padx=2)
self.frame.pack()
self.mainloop()
def start_letters(self):
self.withdraw()
self.Letters=Letters()
def start_numbers(self):
self.withdraw()
self.Numbers=Numbers()
def start_conundrum(self):
self.withdraw()
self.Conundrum=Conundrum()
class Conundrum(tk.Toplevel):
def __init__(self):
super().__init__()
self.configure(bg=LIGHT_BLUE)
self.geometry("400x150")
self.title("Conundrum")
self.frameA=tk.Frame(master=self,bg=LIGHT_BLUE)
self.letterList=[]
self.answer=r.choice(ninewords)
self.anagram=anagram(self.answer)
for x in range(9):
self.letterList.append(ConundrumDisplay(self.frameA,x))
self.frameA.pack()
self.frameB=tk.Frame(master=self,bg=LIGHT_BLUE)
self.letterEntryList=[]
for y in range(9):
self.letterEntryList.append(ConundrumEntry(self.frameB,y))
self.frameB.pack()
self.timer=tk.Label(master=self,bg=LIGHT_BLUE,font=("Arial",12,"bold"),text="31")
self.update_timer()
self.timer.pack()
self.mainloop()
m.showinfo("Startgame","The game will start when you press OK")
for x in range(9):
self.letterlist[x].add_letter(x,self.anagram)
self.bind("<Key>",self.process_key)
self.bind("Return",self.process_guess)
self.bind("BackSpace",self.process_back)
The upper bit of code is a method from an App class which inherits from tk.Tk
The error is in the super()._ _ init _ _() line in the conundrum class after you press the Conundrum button in the main wn
This conundrum class is obviously the bit of code just below which inherits from tk.Toplevel.
I have used tk.Toplevel before but it hasn't shown the error before.
I have tried to reduce the amount of code that I am posting but if any more of it is necessary to figure out the error, then I can amend the question.
Error Message:
Traceback (most recent call last):
File "/nix/store/2vm88xw7513h9pyjyafw32cps51b0ia1-python3-3.8.12/lib/python3.8/tkinter/__init__.py", line 1892, in __call__
return self.func(*args)
File "main.py", line 50, in start_conundrum
self.Conundrum=Conundrum()
File "main.py", line 55, in __init__
super().__init__()
File "/nix/store/2vm88xw7513h9pyjyafw32cps51b0ia1-python3-3.8.12/lib/python3.8/tkinter/__init__.py", line 2624, in __init__
self.title(root.title())
TypeError: 'Label' object is not callable
The error is telling you exactly what is wrong: you can't call a Label as if it was a function.
You are doing this: self.title(root.title()). root.title is an instance of Label but you are trying to call it as if it was a function. You get the same error if you do something like this:
foo = Label(...)
foo()
Since foo is a Label rather than a function, you can't call it.
If you want to call the title function of the root window, you should not name the label self.title. Name it something else so that you can use the title method of the base class.
In Python turtle, if I want to pass an event handler arguments that differ from what the event system specifies, I can use a lambda to bridge the difference:
from turtle import Screen, Turtle
from functools import partial
def change_color(color, x=None, y=None):
screen.bgcolor(color)
screen = Screen()
screen.onclick(lambda x, y: change_color('blue'))
screen.mainloop()
Or I can use the partial function imported from functools to replace the lambda with:
screen.onclick(partial(change_color, 'blue'))
And that works fine. Returning to our original program, we can replace our onclick() event with an ontimer() event, updating our lambda, and everything works fine:
screen.ontimer(lambda: change_color('blue'), 1000)
But, when we replace this lambda with a partial:
screen.ontimer(partial(change_color, 'blue'), 1000)
It fails immediately (not when the timer would have fired) with:
Traceback (most recent call last):
File "test.py", line 9, in <module>
screen.ontimer(partial(change_color, 'blue'), 1000)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/turtle.py", line 1459, in ontimer
self._ontimer(fun, t)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/turtle.py", line 718, in _ontimer
self.cv.after(t, fun)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 755, in after
callit.__name__ = func.__name__
AttributeError: 'functools.partial' object has no attribute '__name__'
>
Since turtle sits atop tkinter, and tkinter is implicated in the stack trace, we can go down a level:
import tkinter as tk
from functools import partial
def change_color(color):
root.configure(bg=color)
root = tk.Tk()
root.after(1000, change_color, 'blue')
root.mainloop()
Which works fine. We can also do:
root.after(1000, lambda: change_color('blue'))
Which works fine. But when we do:
root.after(1000, partial(change_color, 'blue'))
it again immediately fails with:
Traceback (most recent call last):
File "test.py", line 9, in <module>
root.after(1000, partial(change_color, 'blue'))
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 755, in after
callit.__name__ = func.__name__
AttributeError: 'functools.partial' object has no attribute '__name__'
>
The functools documentation for partial states its return value will behave like a function but clearly it's different, if not lacking, somehow. Why is that? And why does tkinter/turtle accept partial functions as click event handers, but not as timer event handlers?
Why is that?
It's designed this way.
By default, partial stores the packed function without attributes, however they are still available:
partial_func = partial(change_color, 'blue')
print(partial_func.func.__name__)
You should use update_wrapper function (or a decorator counterpart) to explicitly set correct options:
from turtle import Screen, Turtle
from functools import partial, update_wrapper
def change_color(color, x=None, y=None):
screen.bgcolor(color)
def partial_change_color(color):
partial_f = partial(change_color, color)
update_wrapper(partial_f, change_color)
return partial_f
screen = Screen()
screen.ontimer(partial_change_color('blue'), 1000)
screen.mainloop()
And why does tkinter/turtle accept partial functions as click event handers, but not as timer event handlers?
Again, it's designed this way.
Because binding and scheduling algorithms are slightly different in the tkinter wrapper, which can be observed if you track down your error.
tkinter creates additional wrapper callit, which handles unscheduling of a target function using __name__ (hence, AttributeError), while the binding does not have such an algorithm for implicit unbinding.
From here, it looks like functools.partial does not copy the __module__ and __name__ attributes from the inner function. You can work around it by defining __name__ manually:
import tkinter as tk
from functools import partial
def change_color(color):
root.configure(bg=color)
root = tk.Tk()
c = partial(change_color, 'blue')
c.__name__ = "c"
root.after(1000, c)
root.mainloop()
I'm trying to create a simple Gui with tkinter using classes.
But I don't really understand how to make the for-loop work inside the count method, could anyone tell me where should I add the missing argument?
from tkinter import *
import time
class App:
def __init__(self, master):
self.container1 = Frame(master)
self.container1.pack()
self.button1 = Button(self.container1, text="count")
self.button1.bind("<Button-1>", self.count)
self.button1.pack()
def count(self):
for i in range(100):
self.button1["text"] = str(i)
time.sleep(1)
root = Tk()
Myapp = App(root)
root.mainloop()
The error is:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.5/tkinter/__init__.py", line 1553, in __call__
return self.func(*args)
TypeError: count() takes 1 positional argument but 2 were given
When you bind an event, a positional argument event is provided to the callback function.
Change your count method to this:
def count(self, event):
You will also need to get rid of time.sleep(1) since .sleep() is a blocking call, which means that it will block the tkinter mainloop which will cause your program to not respond.
In all the tutorials on the web I've seen with Pyglet, it doesnt seems that any of them have used classes to contain the pyglet.window.Window instance. For example, most tutorials seem to go something like
import pyglet
game_window = pyglet.window.Window()
#game_window.event
def on_draw():
#dostuff
while __name__ == "__main__":
pyglet.app.run()
I'm having trouble restructuring this code into a class. My code which is intended to do so, is here:
import pyglet
from pyglet.gl import *
from Board import Board
class Frontend:
def __init__(self,xs, ys):
self.GameInstance = Board(xs,ys)
self.GameWindow = pyglet.window.Window(width=512, height=512,visible=False)
#GameWindow.event
def on_draw(self):
self.GameWindow.clear()
f = Frontend()
When I run this code, I get the following error:
Traceback (most recent call last):
File "C:/Users/PycharmProjects/Nothing/2048/Frontend.py", line 7, in <module>
class Frontend:
File "C:/Users/PycharmProjects/Nothing/2048/Frontend.py", line 13, in Frontend
#GameWindow.event
NameError: name 'GameWindow' is not defined
When I replace #GameWindow.event with #self.GameWindow.event in an attempt to resolve the NameError I get:
Traceback (most recent call last):
File "C:/Users/PycharmProjects/Nothing/2048/Frontend.py", line 7, in <module>
class Frontend:
File "C:/Users/PycharmProjects/Nothing/2048/Frontend.py", line 13, in Frontend
#self.GameWindow.event
NameError: name 'self' is not defined
Which i expect. However, I'm not sure why this code isnt working - can someone explain why and how to fix it?
You can inherit from Window.
This should work:
class Frontend(pyglet.window.Window):
def __init__(self, xs, ys):
self.GameInstance = Board(xs,ys)
super().__init__(width=512, height=512,visible=False)
def on_draw(self):
self.clear()
Your code is not working because you can not reference the instance of the Frontend class outside the methods. If you will have only one instance of the Frontend class you can do something like:
class Frontend:
window = pyglet.window.Window()
def __init__(self):
...
#window.event
def on_draw():
...
As I've commented on ragezor's answer, the pyglet docs recommend inheritance.
But another option may be to separate the event handling logic in its own class, as an EventDispatcher:
http://pyglet.org/doc-current/programming_guide/events.html#creating-your-own-event-dispatcher
Personally, if I knew would only have one Frontend instance, I would question the necessity of having a class. But that's a whole can of worms. Thought I'd give you another nice option, at least, you can't go wrong inheriting from Window though, especially if all your events are Window-related.
A third idea (fourth I guess since ragezor gave you two options):
class Frontend:
def __init__(self,xs, ys):
self.GameInstance = Board(xs,ys)
self.GameWindow = pyglet.window.Window(width=512, height=512,visible=False)
self.on_draw = self.GameWindow.event(self.on_draw)
def on_draw(self):
self.GameWindow.clear()
In other words, apply the #GameWindow.event decorator manually.
One last thing, don't use camelcase for attributes, it goes against PEP8 convention and confused me for a second while editing this code. Call it game_window instead.
My guess is that you need to do
#self.Gamewindow.event
I get an AttributeError I can't seem to work out.
I'm working with two classes.
The first class goes something like that.
class Partie:
def __init__(self):
# deleted lines
self.interface = Interface(jeu=self)
def evaluerProposition(self):
# computations
self.interface.afficherReponse()
Introducing second class (in a separate file).
class Interface:
def __init__(self, jeu):
self.jeu = jeu
self.root = tkinter.Tk()
# stuff
def onClick(self, event):
# talk
self.jeu.evaluerProposition()
def afficherReponse(self):
# stuff
I start the whole thing by
partie = Partie()
All manipulations on my widget work fine until some click event causes
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1442, in __call__
return self.func(*args)
File "C:\Users\Canard\Documents\My Dropbox\Python\AtelierPython\Mastermind\classeInterface.py", line 197, in clic
self.jeu.evaluerProposition()
File "C:\Users\Canard\Documents\My Dropbox\Python\AtelierPython\Mastermind\classeJeu.py", line 55, in evaluerProposition
self.interface.afficherReponse()
AttributeError: 'Partie' object has no attribute 'interface'
I typed in the interpretor
>>> dir(partie)
and got a long list in return with 'interface' among the attributes.
Also typed
>>> partie.interface
<classeInterface.Interface object at 0x02C39E50>
so the attribute seems to exist.
Following the advice in some former post, I checked the instance names do not coincide with module names.
I am confused.
Most likely, in some code that you're not showing us, you're doing something like this:
self.some_button = tkinter.Button(..., command=self.interface.onClick())
Note the trailing () on onClick(). This would cause the onClick method to be called at the time the button is created, which is probably before your constructor is done constructing the instance of the Partie class.