Arrow key code does not work in tkinter

Below is a short script. It is designed to print left and right when these arrow keys are held down, but I do not know why this does not work.

import Tkinter as tk right = False left = False up = False def keyPressed(event): if event.keysym == 'Escape': root.destroy() if event.keysym == 'Right': right = True if event.keysym == 'Left': left = True if event.keysym == 'Up': up = True def keyReleased(event): if event.keysym == 'Right': right = False if event.keysym == 'Left': left = False if event.keysym == 'Up': up = False def task(): if right: print 'Right' if left: print 'Left' if up: print 'Forward' root.after(20,task) root = tk.Tk() print( "Press arrow key (Escape key to exit):" ) root.bind_all('<Key>', keyPressed) root.bind_all('<KeyRelease>', keyReleased) root.after(20,task) root.withdraw() root.mainloop() 

The problem started when I started using root.after() .

+4
source share
1 answer

In python, functions create a new scope. If the variable is not found within the scope, python looks into the outer scope (module / file) for the variable. You add variables to the current area with the destination. All this means that:

 right = False def func(): right = True func() print (right) #right is still False in the outer scope. 

To really change the variable in the outer scope, you need to tell python that you want to do something like this explicitly:

 right = False def func(): global right right = True func() print (right) 

It works, but it is not considered good practice because you are changing the state of your program. Now the value of right depends on whether you called the function, which is a little disturbing.

The best way to exchange data between function calls is to use a class . Then the methods (functions associated with the class instance) can change the state of this single instance, but the rest of your program can continue as if nothing had happened.

 class Foo(object): def __init__(self): self.right = False def func(self): self.right = True a = Foo() #calls __init__ implicitly print(a.right) #should be False -- We set this in __init__ a.func() #change state of `a` print(a.right) #Now it True! 

Here is a slightly more cool version of your code:

 import Tkinter as tk class App(object): def __init__(self): self.right = False self.left = False self.up = False def keyPressed(self,event): print "HERE" if event.keysym == 'Escape': root.destroy() elif event.keysym == 'Right': self.right = True elif event.keysym == 'Left': self.left = True elif event.keysym == 'Up': self.up = True def keyReleased(self,event): if event.keysym == 'Right': self.right = False elif event.keysym == 'Left': self.left = False elif event.keysym == 'Up': self.up = False def task(self): if self.right: print 'Right' elif self.left: print 'Left' elif self.up: print 'Forward' root.after(20,self.task) application = App() root = tk.Tk() print( "Press arrow key (Escape key to exit):" ) root.bind_all('<Key>', application.keyPressed) root.bind_all('<KeyRelease>', application.keyReleased) root.after(20,application.task) root.mainloop() 
+6
source

All Articles