python – Tkinter canvas move留下像素轨迹

我正在制作一个Tkinter画布上的游戏,其中点在屏幕上移动.我将每个点放在一个带有tkinter.Canvas.create_oval(…)的位置,然后使用tkinter.Canvas.move(pointID,delta_x,delta_y)移动这些点.

我的问题是这些点在被移动时似乎留下了痕迹.我做了一个简化的例子来说明我的问题.

from tkinter import Canvas,mainloop,Tk
import numpy as np
import random
import traceback
import threading
import time
from queue import Queue

class Point:
    def __init__(self,the_canvas,uID):
        self.uID = uID
        self.location = np.ones((2)) * 200
        self.color = "#"+"".join([random.choice('0123456789ABCDEF') for j in range(6)])
        self.the_canvas = the_canvas
        self.the_canvas.create_oval(200,200,200,200,
                     fill=self.color,outline=self.color,width=6,
                     tags=('runner'+str(self.uID),'runner'))
    def move(self):
        delta = (np.random.random((2))-.5)*20
        self.the_canvas.move('runner'+str(self.uID),delta[0],delta[1])

def queue_func():
    while True:
        time.sleep(.25)
        try:
            next_action = the_queue.get(False)
            next_action()
        except Exception as e: 
            if str(e) != "": 
                print(traceback.format_exc())

the_queue = Queue()
the_thread = threading.Thread(target=queue_func)
the_thread.daemon = True
the_thread.start()

window = Tk()
window.geometry('400x400')
the_canvas = Canvas(window,width=400,height=400,background='black')
the_canvas.grid(row=0,column=0)

points = {}
for i in range(100):
    points[i] = Point(the_canvas,i)

def random_movement():
    while True:
        for point in points.values():
            point.move()

the_queue.put(random_movement)

mainloop()

结果是这样的:

《python – Tkinter canvas move留下像素轨迹》

我需要能够干净地移动点,而不会留下任何东西.

>我尝试更改move()函数,以便根据其标记删除每个点并在新位置重新绘制,但这会导致相同的问题.
>我在Canvas.oval配置中尝试过fill =”和outline =”,但这没有用.
>这些像素试验的行为似乎不稳定,就像它们会随着时间的推移而消失,只会留下有限的足迹.
>我尝试从运动循环中删除time.sleep(.2),这似乎使问题变得更加明显.

《python – Tkinter canvas move留下像素轨迹》

>我发现清除这些流氓彩色像素的唯一方法是运行canvas.delete(“all”),所以截至目前,我唯一的解决方案是删除所有内容并不断重绘所有内容.这对我来说似乎不是一个很好的解决方案.

什么是避免这些“像素痕迹”的好方法?这对我来说真的只是一个小虫,但也许我在某个地方犯了一个大错.

最佳答案 经过一番挖掘后,我在这里找到了这篇文章:
Python3 tkinter.Canvas.move() method makes artifacts on screen

那里的问题是椭圆形的边界.所以我所做的就是移除边框并使椭圆稍大一些以便进行补偿,看起来就像这样做了.

如果您更改此行:

self.the_canvas.create_oval(200, 200, 200, 200, 
                            fill=self.color, outline=self.color, width=6,
                            tags=('runner' + str(self.uID), 'runner'))

对此:

self.the_canvas.create_oval(200,200,206,206,
                            fill=self.color,outline='', width=0,
                            tags=('runner'+str(self.uID),'runner'))

无论是否有线程,问题都应该消失.

如果你想在没有线程的情况下看到你的代码看起来像是一个例子:

import tkinter as tk
import numpy as np
import random


class Point:
    def __init__(self, the_canvas, uID):
        self.uID = uID
        self.location = np.ones((2)) * 200
        self.color = "#"+"".join([random.choice('0123456789ABCDEF') for j in range(6)])
        self.the_canvas = the_canvas
        self.the_canvas.create_oval(200, 200, 206, 206,
                                    fill=self.color, outline='', width=0,
                                    tags=('runner'+str(self.uID), 'runner'))

    def move(self):
        delta = (np.random.random((2))-.5)*20

        self.the_canvas.move('runner'+str(self.uID), delta[0], delta[1])

window = tk.Tk()
window.geometry('400x400')
the_canvas = tk.Canvas(window, width=400, height=400, background='black')
the_canvas.grid(row=0, column=0)

points = {}
for i in range(100):
    points[i] = Point(the_canvas, i)

def random_movement():
    for point in points.values():
        point.move()
    window.after(50, random_movement)

random_movement()
window.mainloop()

结果:

《python – Tkinter canvas move留下像素轨迹》

点赞