开发者

Slowing down Tkinter Canvas scrolling in Python

Basically I have the following code working, but i can not find a way to slow down my canvas view dragging, as of now it's going too fast to be functional for my App. This is just a small example that shows what i'm trying to troubleshoot:

from Tkinter import * 
import Image, ImageTk

class GUI:
    def __init__(self,root):
        frame = Frame(root, bd=2, relief=SUNKEN)

        frame.grid_ro开发者_StackOverflow社区wconfigure(0, weight=1)
        frame.grid_columnconfigure(0, weight=1)
        xscrollbar = Scrollbar(frame, orient=HORIZONTAL)
        xscrollbar.grid(row=1, column=0, sticky=E+W)
        yscrollbar = Scrollbar(frame)
        yscrollbar.grid(row=0, column=1, sticky=N+S)
        self.canvas = Canvas(frame, bd=0, xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set)
        self.canvas.grid(row=0, column=0, sticky=N+S+E+W)

        File = "JPG FILENAME HERE"

        self.img = ImageTk.PhotoImage(Image.open(File))
        self.canvas.create_image(0,0,image=self.img, anchor="nw")
        self.canvas.config(scrollregion=self.canvas.bbox(ALL))
        xscrollbar.config(command=self.canvas.xview)
        yscrollbar.config(command=self.canvas.yview)

        frame.pack()

        self.canvas.bind("<Button 3>",self.grab)
        self.canvas.bind("<B3-Motion>",self.drag)

    def grab(self,event):
        self._y = event.y
        self._x = event.x

    def drag(self,event):
        if (self._y-event.y < 0): self.canvas.yview("scroll",-1,"units")
        elif (self._y-event.y > 0): self.canvas.yview("scroll",1,"units")
        if (self._x-event.x < 0): self.canvas.xview("scroll",-1,"units")
        elif (self._x-event.x > 0): self.canvas.xview("scroll",1,"units")
        self._x = event.x
        self._y = event.y

root = Tk()   
GUI(root)
root.mainloop()

ANSWER:

Bryan Oakley's answer did the trick I just changed:

self.canvas = Canvas(frame, bd=0, xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set)

to:

self.canvas = Canvas(frame, bd=0, xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set,xscrollincrement=10,yscrollincrement=10)

and it worked like a charm.


Try setting the value of the xscrollincrement and yscrollincrement attributes of the canvas to something greater than zero. These settings correspond to the units used when you do call xview and yview with a "units" argument (eg: self.canvas.xview("scroll",-1,"units").

According to the official Tk documentation, if these values are zero (the default), xview and yview adjusts "...in units of the [x,y]ScrollIncrement option, if it is greater than zero, or in units of one-tenth the window's [width, height] otherwise"


I don't really know what I'm doing here, but this moves more controllably, at least. First, explicitly set the canvas size:

self.canvas = Canvas(frame, bd=0, height=600, width=800,
                     xscrollcommand=self.xscrollbar.set,
                     yscrollcommand=self.yscrollbar.set)

Then, in __init__(), add a couple of instance variables to keep track of the current position:

self.pos_x = self.pos_y = 0.0

Then, replace the drag method with this:

def drag(self, event):
# Note canvas dimensions are used here
    self.pos_x += float(self._x-event.x) / 800.0
    self.pos_y += float(self._y-event.y) / 600.0

    if self.pos_x < 0.0: self.pos_x = 0.0
    elif self.pos_x > 1.0: self.pos_x = 1.0
    if self.pos_y < 0.0: self.pos_y = 0.0
    elif self.pos_y > 1.0: self.pos_y = 1.0

    self.canvas.xview("moveto", self.pos_x)
    self.canvas.yview("moveto", self.pos_y)

    self._x = event.x
    self._y = event.y

I don't know why you have to cast those numbers to float, but it doesn't work if you don't. It's brittle; if you multiply the mouse movement by anything, even just 0.99 or 1.01, the movement gets really wonky; I suspect there's some kind of feedback going on between the mouse movement and the canvas movement. It doesn't play nicely with the scroll bars, either; I suppose we'd have to update pos_x and pos_y when they're moved. As I said, don't really know what I'm doing; I haven't done much GUI programming. Anyway, hope this helps.


Try this, change drag to just use the calculated value:

    self.canvas.yview("scroll",self._y-event.y,"units")
    self.canvas.xview("scroll",self._x-event.x,"units")

And change your scroll increments to 1.

Now your image should click & drag in sync with the mouse cursor, similar to popular map and document viewers.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜