PySimpleGUI调用Blender渲染返回None,求非阻塞执行解决方案
PySimpleGUI执行Blender渲染命令返回None且窗口冻结问题解决
问题根源
- 路径引号冗余:你在命令列表里给带空格的路径手动加了双引号,但
sg.execute_command_subprocess会自动处理含空格的路径参数,额外的引号会被系统识别为路径的一部分,导致Blender程序或.blend文件无法被正确找到,最终子进程启动失败返回None。 - 单次结果获取无效:
sg.execute_get_results仅调用一次且timeout设为1秒,Blender渲染启动需要时间,第一次调用时进程还没输出内容,直接返回None;同时没有持续监听进程输出,也没利用窗口的超时机制实现非阻塞更新。 - 未维护非阻塞事件循环:原代码没有在事件循环中定期检查子进程状态,长时间任务会导致窗口失去响应。
修复方案
1. 清理命令参数中的多余引号
把cmd_list里所有路径的双引号去掉,比如:
原路径:'"C:\\Program Files\\Blender Foundation\\Blender 3.4\\blender.exe"'
改为:'C:\\Program Files\\Blender Foundation\\Blender 3.4\\blender.exe'
2. 用窗口超时监听实现非阻塞输出
修改事件循环,通过window.read(timeout=100)定期触发检查子进程的逻辑,持续读取输出直到进程结束,同时保证窗口不冻结。
修正后的完整代码
import PySimpleGUI as sg layout = [ [sg.Multiline(size=(110, 30), echo_stdout_stderr=True, reroute_stdout=True, autoscroll=True, background_color='black', text_color='white', key='-MLINE-')], [sg.T('Prompt> '), sg.Input(key='-IN-', focus=True, do_not_clear=False)], [sg.Button('Run', bind_return_key=True), sg.Button('Exit')]] window = sg.Window('Realtime Shell Command Output', layout) current_process = None # 保存当前运行的子进程 while True: # 用timeout实现定期检查,避免窗口冻结 event, values = window.read(timeout=100) if event in (sg.WIN_CLOSED, 'Exit'): # 退出前终止正在运行的进程 if current_process and current_process.poll() is None: current_process.terminate() break elif event == 'Run': # 清理之前的进程(如果有的话) if current_process and current_process.poll() is None: current_process.terminate() # 去掉所有路径的多余引号 cmd_list = [ 'C:\\Program Files\\Blender Foundation\\Blender 3.4\\blender.exe', '-b', 'C:\\Users\\***\\Desktop\\blendertest\\Astor_Blue.blend', '-o', 'C:\\Users\\***\\Desktop\\blendertest\\out\\Astor_Blue\\Astor_Blue.####', '-s', '50', '-e', '52', '-t', '6', '-a' ] print("执行命令:", " ".join(cmd_list)) # 启动非阻塞子进程,管道输出 current_process = sg.execute_command_subprocess( cmd_list[0], *cmd_list[1:], pipe_output=True, wait=False ) # 定期检查子进程输出 if current_process and current_process.poll() is None: # 持续读取输出,直到进程结束 results = sg.execute_get_results(current_process, timeout=0) if results: stdout, stderr = results if stdout: print(stdout, end='') if stderr: print(stderr, end='') elif current_process and current_process.poll() is not None: # 进程结束,读取剩余输出 results = sg.execute_get_results(current_process, timeout=0) if results: stdout, stderr = results if stdout: print(stdout, end='') if stderr: print(stderr, end='') print(f"进程结束,退出码:{current_process.returncode}") current_process = None window.close()
关键说明
- 非阻塞机制:通过
window.read(timeout=100)让事件循环每隔100毫秒触发一次,既可以响应用户操作,又能定期检查子进程输出,避免窗口冻结。 - 输出处理:每次检查时调用
sg.execute_get_results读取进程的实时输出,确保渲染日志能实时显示在Multiline组件中。 - 进程管理:维护
current_process变量,在启动新进程前终止旧进程,退出程序时也会清理运行中的进程,避免资源泄漏。
内容的提问来源于stack exchange,提问作者nekoshaurman
相关产品推荐
相关产品推荐

