【发布时间】:2022-01-23 21:06:09
【问题描述】:
我想让多个圆圈同时在给定的轨迹上移动。一切正常,只有一个人移动。每当我添加另一个数字时,它就会开始加速,直到它开始明显冻结。无论我使用什么线程或 canvas.move() 和 canvas.after() 方法,都会发生这种情况。
其实这也很奇怪,因为我的完整版代码在添加更多数字后开始变慢。我发送的那个被简化以显示移动的问题。也许会发生这种情况,因为我用自己的方法绘制了带有许多小方块的轨迹线,但这不是重点。
如何才能以相同的速度同时移动人物而没有太多延迟?我想尝试使用进程而不是线程,但并没有真正理解它们是如何工作的,我怀疑这会显着改变任何事情。
也许您还可以就如何在画布中使用单个像素而不绘制宽度为一个像素的矩形提供建议?
编辑: 忘了提。出于某种原因,即使有一个人物在移动,如果我移动我的鼠标人物的移动速度会减慢,直到我停止触摸鼠标。我想原因是 tkinter 开始注册事件,但我需要它来绘制轨迹,所以删除并不是一个真正的选择。有什么办法可以解决这个问题?
import math
import tkinter as tk
from enum import Enum
import threading
class Trajectory:
# This trajectory should do the same trick both for circles, squares and maybe images
# x0, y0 - start point, x1, y1 - end point
def __init__(self, x0, y0, x1, y1, id, diameter):
print('aaaa', id)
self.x0 = x0
self.y0 = y0
self.x1 = x1
self.y1 = y1
self.id = id
self.sign = 1
self.diameter = diameter
self.dir = self.get_normalized_dir()
def has_arrived(self, x, y):
return math.sqrt((self.x1 - (x + self.diameter // 2)) * (self.x1 - (x + self.diameter // 2)) +
(self.y1 - (y + self.diameter // 2)) * (self.y1 - (y + self.diameter // 2))) < 1
def get_normalized_dir(self):
L = math.sqrt((self.x1 - self.x0) * (self.x1 - self.x0) + (self.y1 - self.y0) * (self.y1 - self.y0))
return (self.x1 - self.x0) / L, (self.y1 - self.y0) / L
def swap_points(self):
self.x0, self.y0, self.x1, self.y1 = self.x1, self.y1, self.x0, self.y0
def __str__(self):
return f'x0 {self.x0} y0 {self.y0} x1 {self.x1} y1 {self.y1} id {self.id} sign {self.sign}'
class App(tk.Tk):
def __init__(self):
# action_33 was intented as an Easter egg to smth (at least I think so). However,
# I forgot what it meant :(
super().__init__()
self.bind('<Motion>', self.on_mouse)
self.geometry('400x400')
self.resizable(False, False)
self.canvas = tk.Canvas(self, bg='white', width=400, height=400)
self.canvas.pack(fill="both", expand=True)
self.start_point = []
self.end_point = []
self.is_drawing = False
self.OUTLINE = 'black'
self.canvas.bind("<Button-1>", self.callback)
self.title('Object trajetory')
self.bg_line = None
self.figure_color = 'green'
self.figures = [] # will store only trajectory class
self.diameter = 40
def move_figures(self):
# if not self.is_drawing:
for figure in self.figures:
self.canvas.move(figure.id, figure.dir[0] * 0.1 * figure.sign, figure.dir[1] * 0.1 * figure.sign)
if figure.has_arrived(self.canvas.coords(figure.id)[0], self.canvas.coords(figure.id)[1]):
figure.sign = -figure.sign
figure.swap_points()
self.canvas.after(1, self.move_figures)
def move_for_thread(self, figure):
while True:
self.canvas.move(figure.id, figure.dir[0] * 0.1 * figure.sign, figure.dir[1] * 0.1 * figure.sign)
if figure.has_arrived(self.canvas.coords(figure.id)[0], self.canvas.coords(figure.id)[1]):
figure.sign = -figure.sign
figure.swap_points()
def delete_shadow_line(self):
if self.bg_line is not None:
self.canvas.delete(self.bg_line)
def on_mouse(self, event):
if self.is_drawing:
self.delete_shadow_line()
self.bg_line = self.canvas.create_line(self.start_point[0], self.start_point[1], event.x, event.y)
def callback(self, event):
if not self.is_drawing:
self.start_point = [event.x, event.y]
self.is_drawing = True
else:
self.is_drawing = False
self.bg_line = None
self.end_point = [event.x, event.y]
fig = self.canvas.create_oval(self.start_point[0] - self.diameter // 2,
self.start_point[1] - self.diameter // 2,
self.start_point[0] + self.diameter // 2,
self.start_point[1] + self.diameter // 2,
fill=self.figure_color, outline='')
# self.figures.append(
# Trajectory(self.start_point[0], self.start_point[1], self.end_point[0], self.end_point[1], fig,
# self.diameter))
# self.move_figures()
traj = Trajectory(self.start_point[0], self.start_point[1], self.end_point[0], self.end_point[1], fig, self.diameter)
t = threading.Thread(target=self.move_for_thread, args=(traj,))
t.start()
if __name__ == '__main__':
print('a')
app = App()
app.mainloop()
【问题讨论】:
-
“也许您还可以就如何在画布中使用单个像素而不绘制一个像素宽度的矩形提供建议?” - 画布是基于矢量的小部件,无法处理单个像素。
-
不管怎样,结果证明应用程序非常慢,因为我试图用绘制小矩形的像素来复制工作。用 canvas.create_line() 改变我的绘图方法就可以了,但是我被禁止使用内置函数。我发现使用 PhotoImage 类我可以处理单个像素,所以我稍后会尝试这样做。
标签: python tkinter python-multithreading tkinter-canvas