9

I would like to move a whole tkinter Canvas with Mouse Click (hold) + Motion of the mouse. I tried with canvas.move but it doesn't work unfortunately.

How can I scroll in the whole canvas ? (not move each element of the canvas, but rather scroll the displayed area of the canvas)

import Tkinter as Tk

oldx = 0
oldy = 0

def oldxyset(event):
    global oldx, oldy
    oldx = event.x
    oldy = event.y

def callback(event):
    # How to move the whole canvas here?
    print oldx - event.x, oldy - event.y

root = Tk.Tk()

c = Tk.Canvas(root, width=400, height=400, bg='white')
o = c.create_oval(150, 10, 100, 60, fill='red')
c.pack()

c.bind("<ButtonPress-1>", oldxyset)
c.bind("<B1-Motion>", callback)

root.mainloop()

1 Answer 1

15

The canvas has built-in support for scrolling with the mouse, via the scan_mark and scan_dragto methods. The former remembers where you clicked the mouse, and the latter scrolls the window an appropriate amount of pixels.

Note: the gain attribute tells scan_moveto how many pixels to move for each pixel the mouse moves. By default it is 10, so if you want 1:1 correlation between the cursor and the canvas you will need to set this value to 1 (as shown in the example).

Here's an example:

import Tkinter as tk
import random

class Example(tk.Frame):
    def __init__(self, root):
        tk.Frame.__init__(self, root)
        self.canvas = tk.Canvas(self, width=400, height=400, background="bisque")
        self.xsb = tk.Scrollbar(self, orient="horizontal", command=self.canvas.xview)
        self.ysb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.ysb.set, xscrollcommand=self.xsb.set)
        self.canvas.configure(scrollregion=(0,0,1000,1000))

        self.xsb.grid(row=1, column=0, sticky="ew")
        self.ysb.grid(row=0, column=1, sticky="ns")
        self.canvas.grid(row=0, column=0, sticky="nsew")
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        for n in range(50):
            x0 = random.randint(0, 900)
            y0 = random.randint(50, 900)
            x1 = x0 + random.randint(50, 100)
            y1 = y0 + random.randint(50,100)
            color = ("red", "orange", "yellow", "green", "blue")[random.randint(0,4)]
            self.canvas.create_rectangle(x0,y0,x1,y1, outline="black", fill=color)
        self.canvas.create_text(50,10, anchor="nw", 
                                text="Click and drag to move the canvas")

        # This is what enables scrolling with the mouse:
        self.canvas.bind("<ButtonPress-1>", self.scroll_start)
        self.canvas.bind("<B1-Motion>", self.scroll_move)

    def scroll_start(self, event):
        self.canvas.scan_mark(event.x, event.y)

    def scroll_move(self, event):
        self.canvas.scan_dragto(event.x, event.y, gain=1)


if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()
Sign up to request clarification or add additional context in comments.

7 Comments

Thank you so much, it is exactly what I needed ! Is it possible to have an infinite (or nearly infinite) Canvas, so that I can scroll as far as I want to the right/left/top/bottom ?
@Basj: I don't think it's infinite, though the actual limit isn't documented. Just experiment by making the scrollregion bigger and bigger. My guess is, the coordinates are 32 bit ints.
Thanks again for this scrolling code @BryanOakley. For "zooming", would you use something like canvas.scale ? I did an implementation by doing it myself from scratch when zooming, but I think there is probably something built-in in tkinter ?
Am I wrong, or this scrolling function won't move Text widgets embedded in a Canvas @BryanOakley ? I did some tests and it seems that it doesn't move such widgets...
@Basj: it depends on how you do the embedding. If you use create_window, they will scroll along with everything else. They won't scroll if you use pack, place or grid.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.