【发布时间】:2019-06-09 16:16:45
【问题描述】:
我正在 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()
结果是这样的:
我需要能够干净利落地移动点,不留下任何东西。
- 我尝试更改
move()函数,以便根据其标记删除每个点并在新位置重新绘制,但这会导致相同的问题。 - 我在
Canvas.oval配置中尝试了fill=''和outline='',但这没有帮助。 - 这些像素试验的行为似乎不稳定,就像它们会随着时间的推移而消失,只留下有限数量的足迹。
- 我尝试从移动循环中删除
time.sleep(.2),这似乎使问题更加明显。
- 我发现清理这些流氓彩色像素的唯一方法是运行
canvas.delete("all"),所以到目前为止,我唯一的解决方案是删除所有内容并不断重绘所有内容。这对我来说似乎不是一个很好的解决方案。
什么是避免这些“像素痕迹”的好方法?这对我来说真的只是一个错误,但也许我在某个地方犯了错误。
【问题讨论】:
-
FWIW,我无法在我的 Mac 上复制这个问题。我没有看到您的屏幕截图中的任何工件。这可能与您对线程的使用有关——tkinter 有时在线程方面遇到困难。除非您尝试移动数万个点,否则我认为您不需要线程的所有开销。
-
@BryanOakley FWIW 我可以在我的 Windows 7 机器上重现它,但我也认为线程是主要问题,尽管即使在删除线程之后我确实注意到有非常少在其中一次运行中出现重影。
-
相同的结果。当您删除线程并改用
after()循环时,伪影确实会消失。不过还是有一些人为因素。 -
看来问题可能至少与窗口中椭圆的边框有关。我通过移除边框对其进行了测试,所有伪影都消失了。