我正在Tkinter画布上进行游戏,其中点在屏幕上移动。我将每个点放置在methods: {
throttledValuePush: undefined,
},
mounted() {
this.throttledValuePush = _.throttle((value) => console.log(value), this.throttled);
}
的位置,然后使用tkinter.Canvas.create_oval(...)
移动这些点。
我的问题是,移动这些点时似乎留下了痕迹。我做了一个简化的例子来说明我的问题。
tkinter.Canvas.move(pointID,delta_x,delta_y)
结果是这样的:
我需要能够整洁地移动Point,而不会留下任何东西。
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()
配置中尝试过fill=''
,也尝试过outline=''
,但这无济于事。 Canvas.oval
,这似乎使问题更加明显。time.sleep(.2)
,因此,到目前为止,我唯一的解决方案是删除所有内容并不断重绘所有内容。这对我来说似乎不是一个很好的解决方案。 什么是避免这些“像素痕迹”的好方法?在我看来,这确实像是个虫子,但也许我在某个地方犯了一个错误。
答案 0 :(得分:3)
经过一番挖掘,我在这里找到了这篇文章: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()
结果:
答案 1 :(得分:3)
很奇怪,问题似乎来自
width=6
中的create_oval()
摆脱它似乎可以解决问题。
您最初设置create_oval()
的方式是制作一个椭圆形的零区域(即不存在),并且边框宽度为6 ...这显然是麻烦的组合。
这是新代码,其中有一些额外的修改:
from tkinter import Canvas,mainloop,Tk
import numpy as np
import random
import traceback
import time
class Point:
def __init__(self,uID):
self.uID = uID
self.location = np.ones((2)) * 200
self.color = "#" + "".join([random.choice('0123456789ABCDEF') for j in range(6)])
def move(self):
delta = (np.random.random((2)) - .5) * 20
self.location += delta
def draw(self,canv):
x0, y0 = self.location
canv.create_oval(
x0, y0, x0 + 2, y0 + 2,
fill=self.color, outline=self.color,
tags=('runner'+str(self.uID),'runner')
)
def repeater(window):
the_canvas.delete('all')
for i in points:
i.move()
i.draw(the_canvas)
window.after(25, repeater, window)
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.append(Point(i))
repeater(window)
window.mainloop()
顺便说一句,删除画布上的所有元素是清除它的方法。这并不浪费,因为您仍然要更新其中的所有元素。