Maya中deleteUI删除UI后showWindow偶发不显示窗口问题
异常触发原因
这个随机bug的根源是Maya的UI事件循环、UI资源回收都是异步执行的,不是调用命令后就会立刻同步完成:
- 点击按钮触发回调时,被点击的按钮本身就属于待删除的旧testWin窗口的子控件,此时Maya还没处理完这次点击的完整事件链路,仍处在旧窗口的事件上下文里
- 回调里直接调用
cmds.deleteUI删旧窗口时,Maya不会立刻清空旧窗口的所有资源,只是给旧窗口打待删除标记、把回收操作塞进待执行队列。这时候立刻创建同名新窗口、调用showWindow,就有概率踩中两个问题:要么新窗口因为和待删除旧窗口同名,被Maya误判为旧对象连带回收;要么还没执行完的按钮点击事件持有旧窗口引用,直接拦截新窗口的显示操作 - 每次点击时Maya待处理的事件数量、系统资源调度速度都不固定,因此异常触发没有固定规律,本质是操作执行顺序冲突导致的偶发问题。
修复方法
核心解决思路是不要在当前点击事件的执行上下文里同步做删旧窗、建新窗的操作,把重建逻辑延后到当前所有UI事件处理完成、旧窗口资源彻底回收之后再执行,用Maya自带的cmds.evalDeferred接口即可实现延迟调度,同时建议创建窗口时接住返回的窗口实例,不要硬靠字符串名匹配窗口,减少识别误差。
修复后的完整代码如下:
import maya.cmds as cmds testWin = 'testWin' def ui(): def _do_rebuild(): # 检测到旧窗存在则先删除 if cmds.window(testWin, exists=True): cmds.deleteUI(testWin) # 接住新窗口的实例引用 win_instance = cmds.window(testWin, widthHeight=(200, 55)) cmds.columnLayout() # 按钮回调同样走延迟调度,避免卡入点击事件上下文 cmds.button( label='Run AGAIN', c=lambda *args: cmds.evalDeferred(ui, lowestPriority=True) ) cmds.setParent('..') cmds.showWindow(win_instance) # 把重建逻辑放到事件队列最低优先级,等前面的事件全跑完再执行 cmds.evalDeferred(_do_rebuild, lowestPriority=True) # 首次启动UI ui()
代码里的lowestPriority=True参数会强制让重建操作排在所有待执行任务的最后,确保旧窗口的删除回收操作先执行完成,从根源上避免执行顺序冲突,修改后无论点击多少次按钮都不会出现新窗口不显示的问题。
内容的提问来源于stack exchange,提问作者Ken Sui
相关产品推荐
相关产品推荐

