Reputation: 1
I am new to python and have been messing with Tkinter and PyInstaller.
When I package my script using;
pyinstaller --onefile --noconsole window.py
and try to open it I get this error;
Traceback (most recent call last):
File "window.py", line 10, in <module>
File "tkinter\__init__.py", line 4093, in __init__
File "tkinter\__init__.py", line 4038, in __init__
_tkinter.TclError: couldn't open "orange.png": no such file or directory
Maybe I am missing something,
Here is my code;
import tkinter as tk
from tkinter import PhotoImage
casement = tk.Tk() # Window
casement.title('Squeeze') # Window Title
casement.geometry('800x800') # Window Size
casement.resizable(True, True) # Winow Resizable x, y
casement.configure(bg='white') # Window Background Color
icon=PhotoImage(file="orange.png") # Window Icon File Var
casement.iconphoto(True,icon) # Window Icon
icon = tk.PhotoImage(file='orange.png') # Button Icon
button = tk.Button(casement, image=icon, text="Open Image", compound=tk.LEFT, bg='orange') # Button
button.pack(ipadx=5, ipady=5) #Button Placement
casement.mainloop()
Upvotes: 0
Views: 985
Reputation: 6810
When you create a single-file executable with Pyinstaller
it will place resources in a specially created "MEI" directory in your user temp folder (named something like "_MEI1234"). You'll need to tell Pyinstaller
where to look for assets when you run the build command like so:
pyinstaller -w -F -i ".\src\assets\icons\appicon.ico" "<your filename.py here>" --add-data ".\src\assets\;assets"
This way, Pyinstaller
understands that it needs to include everything from your source assets folder (src\assets\
in my example, but yours is probably different). Then, everything in your assets
folder will be included in the MEI directory used by the executable.
To access these resources when your Python app runs as an exe, you can retrieve the sys._MEIPASS
and prepend it to the resource path. I've put together a function that handles exactly this below!
import sys
from pathlib import Path
def fetch_resource(rsrc_path):
try:
base_path = sys._MEIPASS
except AttributeError: # running as script, return unmodified path
return rsrc_path
else: # running as exe, return MEI path
return base_path.joinpath(rsrc_path)
Then, for any external assets you can retrieve them by calling fetch_resource()
on them like this
icon = PhotoImage(file=fetch_resource("my_assets/orange.png"))
Just make sure that whatever the root directory containing my_assets/orange.png
is included with the build via --add-data ".\my_source_code_dir\my_assets\;my_assets"
(and again, use whatever path names are appropriate to your particular project)
Upvotes: 2