Reputation: 1323
Finally figured out how to scroll the screen using only the keyboard in tkinter, took getting on the right website to show me the answer. Now I have one other small, but rather important problem that I'm experiencing.
The program is setup to scroll the underlying image using the cursor keys. If I push two keys(up/left) at the same time it will scroll either up one and left forever or up one and left forever instead of constantly switching back and forth.
How do get it to recognize that I'm pushing both and holding them down? It only recognizes one of the two, no matter which two keys I'm holding down.
import tkinter as tk
import random
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.canvas = tk.Canvas(self, background="bisque", width=400, height=400)
self.canvas.pack(fill="both", expand=True)
self.canvas.configure(scrollregion=(-1000, -1000, 1000, 1000))
self.canvas.bind("<Left>", self.keyleft)
self.canvas.bind("<Right>", self.keyright)
self.canvas.bind("<Up>", self.keyup)
self.canvas.bind("<Down>", self.keydown)
self.canvas.focus_set()
# the following two values cause the canvas to scroll
# one pixel at a time
self.canvas.configure(xscrollincrement=1, yscrollincrement=1)
# finally, draw something on the canvas so we can watch it move
for i in range(1000):
x = random.randint(-1000, 1000)
y = random.randint(-1000, 1000)
color = random.choice(("red", "orange", "green", "blue", "violet"))
self.canvas.create_oval(x, y, x+20, y+20, fill=color)
def keyup(self,event):
self.canvas.yview_scroll(-1,'units')
def keydown(self,event):
self.canvas.yview_scroll(1,'units')
def keyleft(self,event):
self.canvas.xview_scroll(-1,'units')
def keyright(self,event):
self.canvas.xview_scroll(1,'units')
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Upvotes: 0
Views: 1002
Reputation: 13729
This isn't a tkinter problem; it's the way your OS handles the long pressing a key. Go to a text editor and press some keys (text keys, not arrows) and you'll see the same behavior. You OS probably has some settings to modify that behavior.
You could take over the press and hold behavior in tkinter and handle multiple keys that way, but that would require disabling this feature in your OS first. How you do that is OS-specific, and I doubt it's possible to disable it for your application only.
Edit: if you are ok with shutting off the OS key repeat feature either manually or programatically, you could use this code to have tkinter take over the key repeat:
import tkinter as tk
import random
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.keys = dict.fromkeys(('Left', 'Right', 'Up', 'Down'))
self.canvas = tk.Canvas(self, background="bisque", width=400, height=400)
self.canvas.pack(fill="both", expand=True)
self.canvas.configure(scrollregion=(-1000, -1000, 1000, 1000))
parent.bind("<KeyPress>", self.keypress)
parent.bind("<KeyRelease>", self.keypress)
self.canvas.focus_set()
# the following two values cause the canvas to scroll
# one pixel at a time
self.canvas.configure(xscrollincrement=1, yscrollincrement=1)
# finally, draw something on the canvas so we can watch it move
for i in range(1000):
x = random.randint(-1000, 1000)
y = random.randint(-1000, 1000)
color = random.choice(("red", "orange", "green", "blue", "violet"))
self.canvas.create_oval(x, y, x+20, y+20, fill=color)
self.looper() # start the looping
def keypress(self,event):
if event.keysym in self.keys:
# event type 2 is key down, type 3 is key up
self.keys[event.keysym] = event.type == '2'
def looper(self):
if self.keys['Up']:
self.canvas.yview_scroll(-1,'units')
if self.keys['Down']:
self.canvas.yview_scroll(1,'units')
if self.keys['Left']:
self.canvas.xview_scroll(-1,'units')
if self.keys['Right']:
self.canvas.xview_scroll(1,'units')
self.after(20, self.looper) # set the refresh rate here ... ie 20 milliseconds. Smaller number means faster scrolling
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Edit edit: Some googling suggests that some OS's send repeated 'press' signals rather than the press - release - press - release cycle that I see in Linux Mint. If your OS does then you may be able to use this code without disabling the autorepeat.
Upvotes: 1