删除 tkinter canvas.scan_mark 对鼠标坐标的影响
Removing Effect Of tkinter canvas.scan_mark on mouse coordinates
我正在使用 tkinter python 开发一个 GUI。我已经编写了提供缩放功能的代码,例如 "zoom in"、"zoom out"、"window zoom"、"previous zoom"、"restore full zoom",最后是 "pan" .对于 'pan' 命令,我使用了 canvas.scan_mark() 和 canvas.scan_dragto() 方法。所有提到的命令都工作正常,除了当我按 'pan' 然后 'window zoom' 或尝试绘制选择矩形时,我意外地发现 window 缩放或选择矩形从当前鼠标位置由 pan 命令的 shift 值决定,尽管我在 'pan' 命令末尾解除了所有鼠标事件的绑定。
我尝试了类似 xi, yi = canvas.xview()[0], canvas.yview()[0]
然后
canvas.xview_moveto(xi), canvas.yview_moveto(yi)
。它使 canvas 视图回到原来的位置,但没有解决问题。此外,它会干扰 'Restore full zoom' 和 'zoom previous' 命令。
请帮我解决这个问题。
非常感谢。
关于问题的简短描述,请看下面的代码。这不是我在我的程序中使用的,但它描述了问题。尝试先按缩放按钮然后平移。先按平移按钮再按缩放按钮再试一次,看看有什么不同。
from tkinter import *
root = Tk()
root.resizable(False, False)
frame = Frame(root)
frame.pack(expand=YES, fill=BOTH)
canv = Canvas(frame, bg='white', width=800, height=600)
canv.pack(side=TOP, expand=YES, fill=BOTH)
canv.create_rectangle(100,100,200,200, fill='red', width=3)
canv.create_oval(250,250,450,450, fill='blue', width=3)
canv.create_line(500,500,500,500, fill='white')
def pan():
canv.bind('<Button-1>', startpan)
canv.bind('<B1-Motion>', dragpan)
canv.bind('<ButtonRelease-1>', endpan)
canv.config(cursor='hand1')
def startpan(event):
canv.scan_mark(event.x, event.y)
def dragpan(event):
canv.scan_dragto(event.x, event.y, 1)
def endpan(event):
unbind_events()
def unbind_events():
canv.unbind('<Button-1>')
canv.unbind('<B1-Motion>')
canv.unbind('<ButtonRelease-1>')
canv.config(cursor='arrow')
def zoom_window():
canv.bind('<Button-1>', startzoomwindow)
canv.bind('<B1-Motion>', dragzoomwindow)
canv.bind('<ButtonRelease-1>', endzoomwindow)
def startzoomwindow(event):
global x1, y1
x1, y1 = event.x, event.y
def dragzoomwindow(event):
global rect
x2, y2 = event.x, event.y
rect = canv.create_rectangle(x1, y1, x2, y2, width=2, outline='red')
canv.delete(canv.find_below(rect))
def endzoomwindow(event):
canv.delete(rect)
x, y = 0.5 * (x1 + event.x), 0.5 * (y1 + event.y)
rect_width = abs(event.x - x1)
rect_height = abs(event.y - y1)
canvwidth = canv.winfo_width()
canvheight = canv.winfo_height()
factor = min(canvwidth / rect_width, canvheight / rect_height)
canv.scale(ALL, x, y, factor, factor)
unbind_events()
butnframe = Frame(frame)
butnframe.pack(side=TOP, expand=YES, fill=X)
Button(butnframe, text='Zoom Window', command=zoom_window).pack(side=LEFT)
Button(butnframe, text='Pan', command=pan).pack(side=RIGHT)
当您绑定到鼠标事件时,报告的坐标是相对于 window 的。如果您滚动 canvas,鼠标点击将减少您滚动 and/or 缩放的数量。
要解决此问题,您需要将 window 坐标转换为 canvas 坐标。您可以使用 canvas:
的 canvasx
和 canvasy
方法来执行此操作
import tkinter as tk
...
canvas = tk.Canvas(...)
canvas.bind('<3>', do_something)
...
def do_something(event):
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
...
我正在使用 tkinter python 开发一个 GUI。我已经编写了提供缩放功能的代码,例如 "zoom in"、"zoom out"、"window zoom"、"previous zoom"、"restore full zoom",最后是 "pan" .对于 'pan' 命令,我使用了 canvas.scan_mark() 和 canvas.scan_dragto() 方法。所有提到的命令都工作正常,除了当我按 'pan' 然后 'window zoom' 或尝试绘制选择矩形时,我意外地发现 window 缩放或选择矩形从当前鼠标位置由 pan 命令的 shift 值决定,尽管我在 'pan' 命令末尾解除了所有鼠标事件的绑定。
我尝试了类似 xi, yi = canvas.xview()[0], canvas.yview()[0]
然后
canvas.xview_moveto(xi), canvas.yview_moveto(yi)
。它使 canvas 视图回到原来的位置,但没有解决问题。此外,它会干扰 'Restore full zoom' 和 'zoom previous' 命令。
请帮我解决这个问题。
非常感谢。
关于问题的简短描述,请看下面的代码。这不是我在我的程序中使用的,但它描述了问题。尝试先按缩放按钮然后平移。先按平移按钮再按缩放按钮再试一次,看看有什么不同。
from tkinter import *
root = Tk()
root.resizable(False, False)
frame = Frame(root)
frame.pack(expand=YES, fill=BOTH)
canv = Canvas(frame, bg='white', width=800, height=600)
canv.pack(side=TOP, expand=YES, fill=BOTH)
canv.create_rectangle(100,100,200,200, fill='red', width=3)
canv.create_oval(250,250,450,450, fill='blue', width=3)
canv.create_line(500,500,500,500, fill='white')
def pan():
canv.bind('<Button-1>', startpan)
canv.bind('<B1-Motion>', dragpan)
canv.bind('<ButtonRelease-1>', endpan)
canv.config(cursor='hand1')
def startpan(event):
canv.scan_mark(event.x, event.y)
def dragpan(event):
canv.scan_dragto(event.x, event.y, 1)
def endpan(event):
unbind_events()
def unbind_events():
canv.unbind('<Button-1>')
canv.unbind('<B1-Motion>')
canv.unbind('<ButtonRelease-1>')
canv.config(cursor='arrow')
def zoom_window():
canv.bind('<Button-1>', startzoomwindow)
canv.bind('<B1-Motion>', dragzoomwindow)
canv.bind('<ButtonRelease-1>', endzoomwindow)
def startzoomwindow(event):
global x1, y1
x1, y1 = event.x, event.y
def dragzoomwindow(event):
global rect
x2, y2 = event.x, event.y
rect = canv.create_rectangle(x1, y1, x2, y2, width=2, outline='red')
canv.delete(canv.find_below(rect))
def endzoomwindow(event):
canv.delete(rect)
x, y = 0.5 * (x1 + event.x), 0.5 * (y1 + event.y)
rect_width = abs(event.x - x1)
rect_height = abs(event.y - y1)
canvwidth = canv.winfo_width()
canvheight = canv.winfo_height()
factor = min(canvwidth / rect_width, canvheight / rect_height)
canv.scale(ALL, x, y, factor, factor)
unbind_events()
butnframe = Frame(frame)
butnframe.pack(side=TOP, expand=YES, fill=X)
Button(butnframe, text='Zoom Window', command=zoom_window).pack(side=LEFT)
Button(butnframe, text='Pan', command=pan).pack(side=RIGHT)
当您绑定到鼠标事件时,报告的坐标是相对于 window 的。如果您滚动 canvas,鼠标点击将减少您滚动 and/or 缩放的数量。
要解决此问题,您需要将 window 坐标转换为 canvas 坐标。您可以使用 canvas:
的canvasx
和 canvasy
方法来执行此操作
import tkinter as tk
...
canvas = tk.Canvas(...)
canvas.bind('<3>', do_something)
...
def do_something(event):
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
...