I have a function, start_round()
that initializes the round and creates temporary round variables. Then I have a nested function, rd_animate()
that does the animation. Now when I make this rd_animate()
function a method, the code does not work. When I do not include self, it works fine. Can anyone explain why this happens?
Code
Without self
def start_round(self):
def rd_animate():
#--::Animation::--#
self.PF_ani_lbl.place(relx = 0.5, rely = 0.5, anchor = "center")
self.PF_ani_lbl["text"] = "ROUND {}".format(self.round_no)
self.after(500)
self.PF_ani_lbl.place_forget()
print("start_round")
#--::Creation of round dictionary::--#
self.round = {}
#--::Animation::--#
threading.Timer(0.05, rd_animate).start()
With self
def start_round(self):
def rd_animate(self):
#--::Animation::--#
self.PF_ani_lbl.place(relx = 0.5, rely = 0.5, anchor = "center")
self.PF_ani_lbl["text"] = "ROUND {}".format(self.round_no)
self.after(500)
self.PF_ani_lbl.place_forget()
print("start_round")
#--::Creation of round dictionary::--#
self.round = {}
#--::Animation::--#
threading.Timer(0.05, self.rd_animate).start()
Error
It gives an error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\raghavendra\anaconda3\lib\tkinter\__init__.py", line 1892, in __call__
return self.func(*args)
File "C:\Users\raghavendra\Desktop\Pratham\My Coding\MY APPS\RPS Multiplayer Game\root-recreated.py", line 348, in <lambda>
command = lambda: self.start_match(retrieve()))
File "C:\Users\raghavendra\Desktop\Pratham\My Coding\MY APPS\RPS Multiplayer Game\root-recreated.py", line 613, in start_match
super().start_match(username, "Computer", match_settings)
File "C:\Users\raghavendra\Desktop\Pratham\My Coding\MY APPS\RPS Multiplayer Game\root-recreated.py", line 533, in start_match
self.start_round()
File "C:\Users\raghavendra\Desktop\Pratham\My Coding\MY APPS\RPS Multiplayer Game\root-recreated.py", line 616, in start_round
super().start_round()
File "C:\Users\raghavendra\Desktop\Pratham\My Coding\MY APPS\RPS Multiplayer Game\root-recreated.py", line 445, in start_round
self.rd_animate()
File "C:\Users\raghavendra\anaconda3\lib\tkinter\__init__.py", line 2354, in __getattr__
return getattr(self.tk, attr)
AttributeError: '_tkinter.tkapp' object has no attribute 'rd_animate'
I want to have it with self
since it would be nice
CodePudding user response:
All tkinter parts of the code need to run in the same thread so running rd_animate in a separate thread is probably causing the problem. Replace the threading
code with self.after
. after
returns immediately so .place_remove
runs before the label is placed
. Put the remove in a separate function and use that as a callback in .after
def start_round(self):
def remove_label():
self.PF_ani_lbl.place_forget()
def rd_animate():
#--::Animation::--#
self.PF_ani_lbl.place(relx = 0.5, rely = 0.5, anchor = "center")
self.PF_ani_lbl["text"] = "ROUND {}".format(self.round_no)
self.after(500, remove_label )
print("start_round")
#--::Creation of round dictionary::--#
self.round = {}
#--::Animation::--#
self.after( 50, rd_animate)
CodePudding user response:
Functions are just objects. As the error says, self
is an instance of the tkinter app. It won't have your rd_animate
function unless you set it.
self.rd_animate = rd_animate
threading.Timer(0.05, self.rd_animate).start()
You'll also want to create a partial function to actually pass the app instance into the parameter of the animate function. That way, the lines within the function won't throw an error saying 1 parameter is expected, but got zero
Alternatively, not really clear why you're nesting things since the above code would be similar to this since self
refers to the enclosing class, only for functions definitely directly in the class body
class App(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.round_no = 0
self.PF_ani_lbl =...
def rd_animate(self):
#--::Animation::--#
self.PF_ani_lbl.place(relx = 0.5, rely = 0.5, anchor = "center")
self.PF_ani_lbl["text"] = "ROUND {}".format(self.round_no)
self.after(500)
self.PF_ani_lbl.place_forget()
def start_round(self):
threading.Timer(0.05, self.rd_animate).start()
You can make rd_animate
"private" function by adding two underscores in front like def __rd_animate