Reputation: 7413
I'm writing a python application which makes use of Tkinter and it's canvas is used for drawing diagrams from a pallette. The diagrams could get pretty big and I'm currently using mouse button (ButtonPress-1) to press-hold and drag the entire canvas.
I'm having difficulty understanding how to implement scrolling of an entire canvas just by using arrow keys (keyboard Up, Down, Left and Right).
Help!
Upvotes: 4
Views: 3119
Reputation: 386240
The xview
and yview
methods of the canvas are used to scroll the canvas. These are the very same methods you use to connect scrollbars to a canvas. You can scroll by "units" or "pages". "units" is defined by the canvas options xscrollincrement
and yscrollincrement
.
The events you want to bind to are <Up>
, <Down>
, <Left>
and <Right>
.
Putting it together, you would create bindings that look something like this:
self.canvas.bind("<Left>", lambda event: self.canvas.xview_scroll(-1, "units"))
self.canvas.bind("<Right>", lambda event: self.canvas.xview_scroll( 1, "units"))
self.canvas.bind("<Up>", lambda event: self.canvas.yview_scroll(-1, "units"))
self.canvas.bind("<Down>", lambda event: self.canvas.yview_scroll( 1, "units"))
You need to make sure the canvas has focus. You can explicitly give it focus, but you probably also want a mouse click to give focus to the canvas as well:
self.canvas.focus_set()
self.canvas.bind("<1>", lambda event: self.canvas.focus_set())
Here is a complete working example:
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")
self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.hsb = tk.Scrollbar(self, orient="horizontal", command=self.canvas.xview)
self.canvas.configure(xscrollcommand=self.hsb.set, yscrollcommand=self.vsb.set)
self.canvas.grid(row=0, column=0, sticky="nsew")
self.vsb.grid(row=0, column=1, sticky="ns")
self.hsb.grid(row=1, column=0, sticky="ew")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
for i in range(100):
x = random.randint(0, 1000)
y = random.randint(0, 1000)
width = random.randint(10, 50)
height = random.randint(10, 50)
fill = random.choice(("red", "orange", "yellow", "green", "blue", "violet"))
self.canvas.create_rectangle(x, y, x+width, y+height, fill=fill)
self.canvas.configure(scrollregion = self.canvas.bbox("all"))
self.canvas.bind("<1>", lambda event: self.canvas.focus_set())
self.canvas.bind("<Left>", lambda event: self.canvas.xview_scroll(-1, "units"))
self.canvas.bind("<Right>", lambda event: self.canvas.xview_scroll( 1, "units"))
self.canvas.bind("<Up>", lambda event: self.canvas.yview_scroll(-1, "units"))
self.canvas.bind("<Down>", lambda event: self.canvas.yview_scroll( 1, "units"))
self.canvas.focus_set()
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Upvotes: 8