我想讓許多圓圈同時在給定的軌跡上移動。一切正常,只有一個人在移動。每當我添加另一個數字時,它就會開始加速,直到它明顯開始凍結。無論我使用執行緒或 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()
uj5u.com熱心網友回復:
使用執行緒會增加不必要的復雜性。使用的代碼after很容易制作影片。
但是,您有一個嚴重的缺陷。你打電話move_figures()每次你畫一條線的時間,每次呼叫一次啟動另一個影片回圈。由于影片回圈移動所有內容,第一個物件每秒移動 1000 次。當您添加兩個元素時,每個元素每秒移動 1000 次兩次。三個元素,它每秒移動 1000次,以此類推。
因此,首先洗掉執行緒代碼。然后,只呼叫move_figures()一次,在它里面,你不應該呼叫它,after(1, ...)因為它試圖每秒影片 1000 次。相反,您可以通過使用after(10, ...)或 其他一些大于 1 的數字將負載減少 90% 。
您可以通過 fromApp.__init__而不是 in呼叫該函式一次App.callback。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/393605.html
標籤:Python 特金特 python-多线程 tkinter-canvas
下一篇:我怎樣才能增加分數?
