PyInstaller打包含subprocess.Popen的PyQt5程序后多窗口重复弹出的问题求解
PyInstaller打包含subprocess.Popen的PyQt5程序后多窗口重复弹出的问题求解
我太懂你这种崩溃的感觉了——在PyCharm里调试一切正常,点按钮就乖乖跑子进程打日志,结果打包成exe后,点一下按钮就弹一个新的主窗口,简直没完没了!
问题根源
其实这个坑很多人都踩过:当你用pyinstaller -w参数打包GUI程序时,sys.executable指向的不是系统的Python解释器,而是你打包出来的gui_print_log.exe本身!所以你在start_process里写[sys.executable, 'subprocess_script.py'],本质上是反复启动自己的主程序,自然就会不断弹出新窗口了。
解决方案(完全符合你的要求:用subprocess.Popen、尽量不修改StreamReader)
下面给你两个可行的方案,选哪个看你的需求:
方案1:指定真实的Python解释器路径
直接把sys.executable替换成系统里Python解释器的绝对路径,或者让程序自动检测:
修改gui_print_log.py里的start_process方法:
def start_process(self): # 判断当前是否是打包后的环境 if getattr(sys, 'frozen', False): # 打包后,用系统的Python解释器(如果是虚拟环境,换成你虚拟环境的python.exe路径) python_exe = "python.exe" # 如果你不确定路径,可以从环境变量里找,比如: # import os # python_exe = os.path.join(os.environ.get('PYTHON_HOME', ''), 'python.exe') else: # 开发环境下,用原来的sys.executable python_exe = sys.executable process = subprocess.Popen( [python_exe, 'subprocess_script.py'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding="utf-8" ) self.stream_reader = StreamReader(process) self.stream_reader.append_text.connect(self.append_log) self.stream_reader.start()
然后打包后,把subprocess_script.py复制到dist/gui_print_log目录下(和exe同目录),这样子进程就能找到脚本了。
方案2:把子脚本也打包成独立exe
如果不想依赖系统Python,也可以把subprocess_script.py单独打包成exe:
- 先打包子脚本:
pyinstaller -D subprocess_script.py
- 把生成的
dist/subprocess_script/subprocess_script.exe复制到主程序的dist/gui_print_log目录下 - 修改主程序的
start_process方法:
def start_process(self): process = subprocess.Popen( ['subprocess_script.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding="utf-8" ) self.stream_reader = StreamReader(process) self.stream_reader.append_text.connect(self.append_log) self.stream_reader.start()
这个方案完全不依赖系统Python,而且你的StreamReader代码完全不需要修改,完美符合你的要求!
验证一下
不管选哪个方案,打包后运行主exe,点击按钮就只会有一个主窗口,子进程的日志会正常输出到文本框里,不会再弹新窗口了。
备注:内容来源于stack exchange,提问作者jyj789
相关产品推荐
相关产品推荐

