Python Kivy代码转exe报Unable to get window错误求解决方案
KivyMD代码打包exe解决「Unable to get window, abort」问题
本人开发的Python KivyMD代码可正常运行,但转换为exe可执行文件时出现「Unable to get window, abort」错误。已尝试cx_freeze、重装Kivy等方案,均未解决,求可行的打包实现方法。
原代码如下:from kivymd.app import MDApp from kivy.uix.boxlayout import BoxLayout from kivy.uix.image import Image from kivy.clock import Clock from kivymd.uix.textfield import MDTextField from kivymd.uix.button import MDFloatingActionButton class main(BoxLayout,MDApp): def __init__(self, **kwargs): super().__init__(**kwargs) self.orientation = "vertical" self.a = MDTextField(size_hint_y=.1, hint_text="Write for translate", helper_text="Press the button for translate",helper_text_mode="on_focus", icon_right="cursor-text", size_hint_x=None, width=300,pos_hint={'center_x':0.5,'center_y':0.96}) self.add_widget(self.a) self.b = MDFloatingActionButton(size_hint_y=.1, icon='translate',pos_hint={'center_x':0.5,'center_y':0.96}) self.add_widget(self.b) self.b.bind(on_release=self.show_data) self.layout = BoxLayout(size_hint_y=.8) self.add_widget(self.layout) def show_data(self, show): self.list = self.a.text.split() for i in range(len(self.list)): if not self.list[i].endswith(".png"): self.list[i] += ".png" print(self.list) Clock.schedule_once(self.call) def call(self, call): self.numb = 0 Clock.schedule_interval(self.do, 0.7) def do(self, do): if (self.numb < len(self.list)): self.layout.clear_widgets() self.layout.add_widget(Image(source=self.list[self.numb])) self.numb += 1 else: self.numb = 0 self.list = [self.a.text] Clock.unschedule(self.do) self.layout.clear_widgets() class app(MDApp): def build(self): return main() if __name__ == "__main__": app().run()
一、先修正代码中的核心错误
原代码中main类同时继承BoxLayout和MDApp是错误逻辑——MDApp是应用入口类,布局类只需单独继承BoxLayout。同时添加资源路径处理函数,适配打包后的文件读取:
from kivymd.app import MDApp from kivy.uix.boxlayout import BoxLayout from kivy.uix.image import Image from kivy.clock import Clock from kivymd.uix.textfield import MDTextField from kivymd.uix.button import MDFloatingActionButton import sys import os def get_resource_path(relative_path): # 兼容打包前后的资源路径读取 try: base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) class main(BoxLayout): def __init__(self, **kwargs): super().__init__(**kwargs) self.orientation = "vertical" self.a = MDTextField(size_hint_y=.1, hint_text="Write for translate", helper_text="Press the button for translate",helper_text_mode="on_focus", icon_right="cursor-text", size_hint_x=None, width=300,pos_hint={'center_x':0.5,'center_y':0.96}) self.add_widget(self.a) self.b = MDFloatingActionButton(size_hint_y=.1, icon='translate',pos_hint={'center_x':0.5,'center_y':0.96}) self.add_widget(self.b) self.b.bind(on_release=self.show_data) self.layout = BoxLayout(size_hint_y=.8) self.add_widget(self.layout) def show_data(self, show): self.list = self.a.text.split() for i in range(len(self.list)): if not self.list[i].endswith(".png"): self.list[i] += ".png" # 转换为兼容打包的资源路径 self.list[i] = get_resource_path(self.list[i]) print(self.list) Clock.schedule_once(self.call) def call(self, call): self.numb = 0 Clock.schedule_interval(self.do, 0.7) def do(self, do): if (self.numb < len(self.list)): self.layout.clear_widgets() self.layout.add_widget(Image(source=self.list[self.numb])) self.numb += 1 else: self.numb = 0 self.list = [self.a.text] Clock.unschedule(self.do) self.layout.clear_widgets() class app(MDApp): def build(self): return main() if __name__ == "__main__": app().run()
二、使用PyInstaller打包的具体步骤
1. 安装PyInstaller
pip install pyinstaller
2. 生成spec配置文件
在代码所在目录执行:
pyi-makespec --name translate_app main.py
生成translate_app.spec文件。
3. 修改spec文件适配KivyMD
打开translate_app.spec,修改Analysis部分,添加KivyMD资源、你的图片文件及缺失的模块:
# -*- mode: python ; coding: utf-8 -*- import os from kivymd import hooks_path as kivymd_hooks_path block_cipher = None a = Analysis( ['main.py'], pathex=[], binaries=[], # 配置需要打包的资源:当前目录下的png图片、KivyMD内置图标 datas=[ ('*.png', '.'), (os.path.join(os.path.dirname(__file__), 'venv/Lib/site-packages/kivymd/images'), 'kivymd/images') ], # 手动添加KivyMD动态导入的模块,避免打包遗漏 hiddenimports=['kivymd.uix.button', 'kivymd.uix.textfield', 'kivy.uix.image', 'kivy.clock'], hookspath=[kivymd_hooks_path], hooksconfig={}, runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, ) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE( pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='translate_app', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=True, # 若要隐藏控制台窗口,改为False disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, )
注意:kivymd/images的路径需根据你的虚拟环境实际位置调整
4. 执行打包
pyinstaller translate_app.spec
打包完成后,exe文件位于dist/translate_app目录下,将你的png图片放入该目录即可运行。
三、关键注意事项
- 禁止布局类继承MDApp,否则会导致应用初始化冲突,引发窗口创建失败;
- 必须通过
sys._MEIPASS处理资源路径,打包后代码无法直接读取本地相对路径; - 利用KivyMD的hookspath可自动处理部分依赖,减少手动添加hiddenimports的工作量;
- 若仍报错,尝试关闭杀毒软件——部分杀毒软件会拦截PyInstaller生成的启动程序。
内容的提问来源于stack exchange,提问作者NUrluk
相关产品推荐
相关产品推荐

