Tkinter画布移动留下像素痕迹

时间:2019-01-15 15:59:14

标签: python canvas tkinter

我正在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)

结果是这样的:

example1

我需要能够整洁地移动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,这似乎使问题更加明显。

example2

  • 我发现清理这些流氓彩色像素的唯一方法是运行time.sleep(.2),因此,到目前为止,我唯一的解决方案是删除所有内容并不断重绘所有内容。这对我来说似乎不是一个很好的解决方案。

什么是避免这些“像素痕迹”的好方法?在我看来,这确实像是个虫子,但也许我在某个地方犯了一个错误。

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()

结果:

enter image description here

答案 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()

顺便说一句,删除画布上的所有元素是清除它的方法。这并不浪费,因为您仍然要更新其中的所有元素。