【问题标题】:Tkinter Canvas invalidation issue (object clipped while moved)Tkinter Canvas 失效问题(移动时被剪裁的对象)
【发布时间】:2017-10-18 18:47:41
【问题描述】:

我对 Python 还是很陌生,我目前正在玩一些 Tkinter,它看起来非常简单。我尝试使用以下代码实现一个简单的拖放效果(鼠标右键创建一个圆圈,鼠标左键允许拖动):

from tkinter import *

class Point:
    def __init__(self, ref, x, y):
        self.ref = ref
        self.x = x
        self.y = y

points = []
selected = None

def OnSelect(event):
    global selected
    for p in points:
        if event.x>=(p.x-10) and event.y>=(p.y-10) and event.x<(p.x+10) and event.y<(p.y+10):
            selected = p
            break

def OnMMove(event):
    if selected is not None:
        selected.x = event.x
        selected.y = event.y
        canvas.coords(selected.ref, event.x-10, event.y-10, event.x+10, event.y+10)

def OnStopDrag(event):
    global selected
    selected = None

def OnCreate(event):
    point = canvas.create_oval(event.x-10, event.y-10, event.x+10, event.y+10, fill="black")
    points.append(Point(point, event.x, event.y))

window = Tk()
window.wm_title("Python")

canvas = Canvas(window, width=800, height=600, background='white')
canvas.bind("<Button-1>", OnSelect)
canvas.bind("<B1-Motion>", OnMMove)
canvas.bind("<ButtonRelease-1>", OnStopDrag)
canvas.bind("<Button-3>", OnCreate)
canvas.pack(fill=BOTH, expand=YES)

window.mainloop()

从这段代码中可以看出,我使用canvas.cords 来移动拖动的对象。当鼠标光标在拖动时缓慢移动时一切正常,但是当鼠标光标快速移动时,拖动的圆圈似乎被部分剪裁在矩形移动时,如图所示(整个当拖动停止或减速时,圆圈再次正确绘制):

当我在 Win32 C 应用程序中使用 GDI 时,我已经遇到过类似的问题,当调用屏幕失效以在当前拖动的圆的初始位置所覆盖的唯一区域上重新绘制窗口客户区时。

确实,当在我的示例代码中创建的窗口被放置在一个不断且完全被重绘的窗口之上时,就像一个视频游戏窗口一样,拖动元素时的裁剪效果是看不到的,整个圆圈被正确地重绘因为它被拖动。

有没有办法解决这个问题,比如画布设置使窗口失效在更广泛或整个客户区被调用?我想坚持使用 Tkinter,所以我对切换到另一个 GUI API/框架并不感兴趣。此代码已在 Windows 10 上测试。

【问题讨论】:

  • 我无法在 linux 上复制它,也无法访问 windows 框。对于更改 tkinter 刷新窗口的方式,您无能为力。这不会在 tkinter 级别公开。

标签: python windows tkinter tkinter-canvas


【解决方案1】:

这个答案可能会让你感到困惑(它让我感到困惑)。但解决方案是在 OnMMove 中配置光标。这是我在 Windows 上工作的摘录。

def OnMMove(event):
    if selected is not None:
        canvas.configure(cursor='arrow')
        selected.x = event.x
        selected.y = event.y
        canvas.coords(selected.ref, event.x-10, event.y-10, event.x+10, event.y+10)

【讨论】:

  • 可能会导致另一轮布局...也许?只是猜测。 -- 在使用.after()... 设置椭圆形的coords() 时,我注意到同样的剪辑问题,当它运行每个 任务调度程序切片(我的盒子上为15.625ms)时,它会剪辑,但如果每次移动有两个时间片,它看起来可以接受。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-10
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
  • 2015-05-25
  • 2014-09-07
  • 2017-10-06
相关资源
最近更新 更多