You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter项目循环内sleep()函数异常,无法正常展示3D立方体缩放动画

解决Tkinter中sleep导致动画不逐帧显示的问题

问题原因

  • Tkinter是单线程GUI框架,调用time.sleep()会直接阻塞主事件循环,所有界面绘制操作都会被延迟到所有sleep执行完毕后才一次性渲染,因此你看不到中间帧的变化,只能看到最后一帧。
  • sys.stdout.flush()是针对控制台输出的刷新操作,和Tkinter的GUI界面刷新完全无关,所以无效。

解决方案

使用Tkinter自带的after(delay_ms, callback)方法实现帧延迟,它会在指定毫秒后异步调用回调函数,不会阻塞主循环,能让界面及时更新每一帧。

修改后的完整代码

from tkinter import *

# 像素绘制相关函数
tk = Tk()
tk.attributes('-fullscreen', True)
canvas = Canvas(tk, width=1366, height=768, background='#fff')
canvas.pack()
colors = [[(255, 255, 255) for i in range(223)] for i in range(321)]

def color(a, b, c):
    def hex_str(val):
        val = val % 256
        return f"{val:02x}"
    return f'#{hex_str(a)}{hex_str(b)}{hex_str(c)}'

def colr(lis):
    return color(lis[0], lis[1], lis[2])

def fill_rect(a, b, c, d, e):
    a = a + 683
    b = -b + 384
    fill_color = e if isinstance(e, str) else colr(e)
    canvas.create_rectangle(a+2, b+2, c+a+2, d+b+2, fill=fill_color, outline='')
    for x in range(c):
        for y in range(d):
            if 0 <= (a+x) <= 320 and 0 <= (b+y) <= 222:
                colors[a+x][b+y] = e

def set_pixel(a, b, e):
    fill_rect(a, b, 1, 1, e)

def get_pixel(x, y):
    if 0 <= x <= 320 and 0 <= y <= 222:
        return colors[x][y]
    else:
        return (0, 0, 0)

# 3D绘制相关函数
def draw_line(xa, ya, xb, yb):
    canvas.create_line(round(xa)+683, -round(ya)+384, round(xb)+683, -round(yb)+384, fill="black", width=1)

focal_length = 100
def dproj(xa, ya, za, xb, yb, zb):
    draw_line(focal_length*xa/za, focal_length*ya/za, focal_length*xb/zb, focal_length*yb/zb)

# 立方体顶点定义
a = [-1, -1, 1]
b = [1, -1, 1]
c = [1, 1, 1]
d = [-1, 1, 1]
e = [-1, -1, 3]
f = [1, -1, 3]
g = [1, 1, 3]
h = [-1, 1, 3]

# 动画帧循环函数
def animate_frame(i):
    if i >= 300:
        return  # 动画结束条件
    canvas.delete("all")
    global focal_length
    focal_length = i
    # 绘制立方体所有边
    dproj(a[0], a[1], a[2], b[0], b[1], b[2])
    dproj(a[0], a[1], a[2], d[0], d[1], d[2])
    dproj(a[0], a[1], a[2], e[0], e[1], e[2])
    dproj(c[0], c[1], c[2], b[0], b[1], b[2])
    dproj(c[0], c[1], c[2], d[0], d[1], d[2])
    dproj(c[0], c[1], c[2], g[0], g[1], g[2])
    dproj(f[0], f[1], f[2], b[0], b[1], b[2])
    dproj(f[0], f[1], f[2], e[0], e[1], e[2])
    dproj(f[0], f[1], f[2], g[0], g[1], g[2])
    dproj(h[0], h[1], h[2], d[0], d[1], d[2])
    dproj(h[0], h[1], h[2], e[0], e[1], e[2])
    dproj(h[0], h[1], h[2], g[0], g[1], g[2])
    # 10毫秒后触发下一帧,对应原sleep(0.01)
    tk.after(10, animate_frame, i+1)

# 启动动画并进入主事件循环
animate_frame(0)
tk.mainloop()

关键修改点说明

  1. 移除了time.sleep(),改用tk.after()实现非阻塞的帧延迟,确保每帧绘制后界面能及时刷新。
  2. 将原for循环改为递归的animate_frame函数,通过参数i控制帧进度,直到达到300帧时停止。
  3. 添加了tk.mainloop()启动Tkinter主事件循环,原代码缺少这一行也是界面无法正常更新的原因之一。
  4. 优化了颜色转换函数的代码逻辑,简化十六进制字符串生成(不影响核心功能)。

内容的提问来源于stack exchange,提问作者IskallMAN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 23:45:40