【问题标题】:Removing Effect Of tkinter canvas.scan_mark on mouse coordinates删除 tkinter canvas.scan_mark 对鼠标坐标的影响
【发布时间】:2019-02-27 19:56:13
【问题描述】:

我正在使用 tkinter 开发带有 python 的 GUI。我编写了用于提供缩放功能的代码,例如“放大”、“缩小”、“窗口缩放”、“以前的缩放”、“恢复全缩放”,最后是“平移”。对于“平移”命令,我使用了 canvas.scan_mark() 和 canvas.scan_dragto() 方法。所有提到的命令都可以正常工作,除了当我按“平移”然后“窗口缩放”或尝试绘制选择矩形时,我意外地发现窗口缩放或选择矩形从当前鼠标位置移动了 shift pan 命令的值,尽管我在“pan”命令的末尾解除了所有鼠标事件的绑定。 我尝试了类似xi, yi = canvas.xview()[0], canvas.yview()[0] 然后 canvas.xview_moveto(xi), canvas.yview_moveto(yi)。它将画布视图恢复到其原始位置,但尚未解决问题。此外,它会干扰“恢复全缩放”和“缩放上一个”命令。 请帮我解决这个问题。

非常感谢。

有关问题的简短描述,请参阅下面的代码。这不是我在程序中使用的,但它描述了问题。尝试先按变焦按钮并平移。先按平移按钮再按缩放按钮再试一次,看看有什么不同。

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)

【问题讨论】:

  • 请出示说明问题的minimal reproducible example。请确保它尽可能小。我们不需要查看所有函数的代码,只需运行程序并查看调用scan_mark 的负面影响即可。您的代码中存在错误,但代码的简单描述不足以让我们对其进行调试。

标签: python canvas tkinter zooming panning


【解决方案1】:

当您绑定到鼠标事件时,报告的坐标是相对于窗口的。如果您滚动了画布,则鼠标点击量将减少您滚动和/或缩放的量。

要解决这个问题,您需要将窗口坐标转换为画布坐标。您可以使用画布的 canvasxcanvasy 方法来做到这一点:

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)
    ...

【讨论】:

  • 感谢您的回复。请参阅我在问题下方添加的代码以获得更多说明。但是,我会尝试您在评论中的建议。
  • 谢谢,布莱恩。我已经尝试了您在评论中的建议。窗口缩放工作正常。鼠标位置回到画布坐标系。但是,“以前的缩放”和“完全恢复缩放”仍然无法正常工作。
  • 谢谢,布莱恩。现在代码运行良好。除了您的建议外,我还在“上一次缩放”功能的代码中使用了 canvas.xview_moveto() 方法,以便在平移后回滚视图。
猜你喜欢
  • 1970-01-01
  • 2018-11-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-10
  • 1970-01-01
  • 2015-07-03
  • 2023-03-31
  • 2021-01-05
相关资源
最近更新 更多