ipycanvas画布绘制时机及强制触发方法咨询(Jupyter场景)
为什么你的代码看不到分步移动?
你用time.sleep(3)会直接卡住Jupyter的主线程——这就导致所有画布的更新操作都被压着,直到整个脚本跑完才一起发给浏览器显示,自然看不到分步移动的过程。
ipycanvas的绘制时机:它是基于ipywidgets实现的,画布的更新是异步传递给前端的。只有当Python主线程空闲时,Jupyter才会把画布的变化推送给浏览器触发绘制。如果主线程被time.sleep这类阻塞操作占用,所有更新都会攒到最后才处理。
怎么改才能看到分步动画?
核心是避免阻塞主线程,用异步休眠替代time.sleep,让Jupyter有机会处理画布更新。用asyncio.sleep()配合异步函数就能解决:
from ipywidgets import Image from ipycanvas import Canvas import asyncio char = Image.from_file("Bilder/charRight.png") bg = Image.from_file("Bilder/map.png") xchar = 150 ychar = 170 tilesize = 48 canvas = Canvas(height=800, width=800) canvas.draw_image(bg, 0, 0) canvas.draw_image(char, xchar, ychar) async def step(): global xchar # 异步休眠,不阻塞主线程 await asyncio.sleep(3) # 重绘背景擦除旧角色位置 canvas.draw_image(bg, 0, 0) xchar += tilesize canvas.draw_image(char, xchar, ychar) async def run_demo(): await step() print("yay") await step() print("yay") # 在Jupyter里直接await运行异步函数 await run_demo() canvas
怎么强制ipycanvas触发绘制?
如果需要手动推送画布更新,可以调用canvas.send_update()——它会立刻把当前画布状态发给前端。比如在修改画布后加一行:
canvas.draw_image(char, xchar, ychar) canvas.send_update()
不过上面的异步方案里主线程没被阻塞,一般不需要手动调用,更新会自动处理。
如果要做更流畅的连续动画,还可以用ipycanvas的requestAnimationFrame,它会跟着浏览器的帧率自动触发绘制:
def animate(dt): global xchar canvas.draw_image(bg, 0, 0) xchar += 1 # 每次移动1像素 canvas.draw_image(char, xchar, ychar) # 控制移动次数,比如移动两次tilesize的距离就停 if xchar < 150 + tilesize*2: canvas.request_animation_frame(animate) # 启动动画 canvas.request_animation_frame(animate)
内容的提问来源于stack exchange,提问作者Astrina
相关产品推荐
相关产品推荐

