python3tkinter.Canvas.move()方法在屏幕上生成工件

python3tkinter.Canvas.move()方法在屏幕上生成工件,python,tkinter,python-3.5,tkinter-canvas,artifacts,Python,Tkinter,Python 3.5,Tkinter Canvas,Artifacts,我正在尝试执行Stackoverflow答案之一中的代码。它是一个单窗口应用程序,有两个圆圈,可以用鼠标移动。 当我移动圆圈时,我看到了人工制品。看 程序代码: import tkinter as tk TOKENWIDTH = 10 class Example(tk.Frame): '''Illustrate how to drag items on a Tkinter canvas''' def __init__(self, parent): tk.Fr

我正在尝试执行Stackoverflow答案之一中的代码。它是一个单窗口应用程序,有两个圆圈,可以用鼠标移动。 当我移动圆圈时,我看到了人工制品。看

程序代码:

import tkinter as tk

TOKENWIDTH = 10

class Example(tk.Frame):
    '''Illustrate how to drag items on a Tkinter canvas'''

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        # create a canvas
        self.canvas = tk.Canvas(width=400, height=400, bg="white")
        self.canvas.pack(fill="both", expand=True)

        # this data is used to keep track of an
        # item being dragged
        self._drag_data = {"x": 0, "y": 0, "item": None}

        # create a couple of movable objects
        self._create_token((100, 100), "red")
        self._create_token((200, 100), "black")

        # add bindings for clicking, dragging and releasing over
        # any object with the "token" tag
        self.canvas.tag_bind("token", "<ButtonPress-1>", self.on_token_press)
        self.canvas.tag_bind("token", "<ButtonRelease-1>", self.on_token_release)
        self.canvas.tag_bind("token", "<B1-Motion>", self.on_token_motion)

    def _create_token(self, coord, color):
        '''Create a token at the given coordinate in the given color'''
        (x,y) = coord
        self.canvas.create_oval(x-25, y-25, x+25, y+25,
                                outline="blue", fill=color, tags="token", width = TOKENWIDTH)

    def on_token_press(self, event):
        '''Begining drag of an object'''
        # record the item and its location
        self._drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0]
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y
        self.canvas.update_idletasks()

    def on_token_release(self, event):
        '''End drag of an object'''
        # reset the drag information
        self._drag_data["item"] = None
        self._drag_data["x"] = 0
        self._drag_data["y"] = 0
        self.canvas.update_idletasks()

    def on_token_motion(self, event):
        '''Handle dragging of an object'''
        # compute how much the mouse has moved
        delta_x = event.x - self._drag_data["x"]
        delta_y = event.y - self._drag_data["y"]
        # move the object the appropriate amount
        self.canvas.move(self._drag_data["item"], delta_x, delta_y)
        # record the new position
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y
        self.canvas.update_idletasks()

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()
将tkinter作为tk导入
宽度=10
类示例(tk.Frame):
''演示如何在Tkinter画布上拖动项目''
定义初始化(自身,父级):
tk.Frame.\uuuu init\uuuuu(自,父)
#创建画布
self.canvas=tk.canvas(宽度=400,高度=400,bg=“白色”)
self.canvas.pack(fill=“both”,expand=True)
#此数据用于跟踪
#正在拖动的项目
self._drag_data={“x”:0,“y”:0,“item”:None}
#创建两个可移动的对象
self.\u创建\u标记((100100),“红色”)
自我。创建令牌((200100),“黑色”)
#添加用于单击、拖动和释放的绑定
#任何带有“token”标记的对象
self.canvas.tag\u bind(“token”,self.on\u token\u press)
self.canvas.tag\u bind(“token”,“”,self.on\u token\u release)
self.canvas.tag\u bind(“token”,“”,self.on\u token\u运动)
def_create_令牌(self、coord、color):
''在给定坐标以给定颜色创建标记''
(x,y)=坐标
自我。画布。创建椭圆(x-25,y-25,x+25,y+25,
outline=“blue”,fill=color,tags=“token”,width=TOKENWIDTH)
令牌上的def按下(自身,事件):
''开始拖动对象''
#记录项目及其位置
self._drag_data[“item”]=self.canvas.find_closest(event.x,event.y)[0]
self._drag_data[“x”]=event.x
self._drag_data[“y”]=event.y
self.canvas.update_idletasks()
令牌释放时的def(自身、事件):
''对象的结束拖动''
#重置拖动信息
self._drag_data[“item”]=无
自拖动数据[“x”]=0
自身数据[“y”]=0
self.canvas.update_idletasks()
def on_token_运动(自身、事件):
''处理对象的拖动''
#计算鼠标移动了多少
delta_x=event.x-self._拖动_数据[“x”]
delta_y=event.y-self.\u拖动数据[“y”]
#将对象移动适当的量
self.canvas.move(self.\u拖动数据[“项”]、增量x、增量y)
#记录新位置
self._drag_data[“x”]=event.x
self._drag_data[“y”]=event.y
self.canvas.update_idletasks()
如果名称=“\uuuuu main\uuuuuuuu”:
root=tk.tk()
示例(root).pack(fill=“both”,expand=True)
root.mainloop()
代码具有在标准Canvas.create_oval()方法中使用的TOKENWIDTH

我做了一些实验,发现当TOKENWIDTH设置为6或更多时,代码在移动对象时会在画布上生成工件。如果TOKENWIDTH在1..5范围内,一切都很好

以下代码行没有帮助:

self.canvas.update_idletasks()

如何解决这些问题?有什么想法吗?
作为一种解决方法,我考虑将两个不同颜色的圆圈相互叠加,以形成圆形的“边框”效果。

我尝试了
TOKENWIDTH
的各种值,但在Python 3.6.0上没有任何工件,运行在带有KDE窗口管理器的Debian派生Linux上。你在用什么操作系统?你是如何运行这个脚本的?您是直接从shell运行它,还是使用IDE运行它?我在OSX上也没有看到任何工件。顺便说一句,可以删除对
update\u idletasks()
的调用。在这种情况下,它们是完全不必要的。@PM2Ring我在Win10、3.6.1上看到了工件,怀疑Dmitry也是。我强烈怀疑这是圆圈绘制算法中Windows特有的错误。(无论是在tk还是Windows图形原语中,我都不知道。)当运动的水平分量向左(deltax为负数)时,点来自右边缘的最后一个1像素投影,没有被正确擦除。在标记静止的情况下,最右边的像素列不会像应该的那样居中于水平轴上(与左边缘不同)。宽度为5时,不对称和圆点消失。要将画布放在框架上而不是根窗口上,请在画布调用中添加
self
作为第一个参数。我也可以在Windows 7、3.6.1上看到工件。它们似乎只在将鼠标向左移动时出现,而将令牌移回工件上方(不向左移动时)会移除它们。当您为我将
TOKENWIDTH
(圆圈轮廓的宽度)更改为7或以下时,瑕疵消失。当值为8+时,工件可见。我怀疑这与移动对象时的轮廓有关,至少在Windows上还有一些像素。因此,同时,尝试减少
标记宽度